Multi-session work bundle on a draft branch. Splits into a clean
sequence of commits later; pushed here so it isn't lost on a reboot.
Reach work
- code/scripts/reach/reach_scram_pj.jl: shutdown_margin halfspace
X_exit (replaces "n <= 1e-4 AND T_f bound" framing); per-step
envelope extraction added.
- code/scripts/reach/reach_scram_pj_fat.jl: per-step envelope
extraction added; shutdown_margin discharge logic mirrored from the
tight scram script. 3 probes (10/30/60s) all discharge from the
fat union polytope.
- code/scripts/reach/reach_scram_full_fat.jl (NEW): full nonlinear
PKE scram reach with fat entry. Hits the stiffness wall at
~1.5 s plant time as expected; saves NaN-tolerant per-step
envelopes. Demonstrates concretely why PJ is the right tool for
the longer-horizon proof.
- code/scripts/reach/reach_heatup_pj.jl: T_REF_START_C constant
(entry-conditioned ramp) replaces T_STANDBY-init that was making
the FL controller command cooling at t=0. Per-step extraction
already in place.
- code/configs/heatup/tight.toml: bumped maxsteps; probe horizon
parameterized.
Hot-standby SOS barrier
- code/scripts/barrier/barrier_sos_2d_shutdown.jl (NEW): mirrors the
operation SOS machinery on the hot-standby thermal projection.
Includes the eps-slack pattern (so feasibility doesn't silently
collapse to B == 0).
- code/scripts/barrier/barrier_sos_2d.jl: refactored to use the same
helper.
- code/src/sos_barrier.jl (NEW): solve_sos_barrier_2d helper module
factoring out the SOS construction; eps-slack with eps_cap=1.0 to
avoid unbounded primal.
Library
- code/src/pke_states.jl (NEW): single source of truth for canonical
initial-condition vectors per DRC mode (op, shutdown, heatup) keyed
off plant + predicates.
- code/scripts/sim/{main_mode_sweep,validate_pj}.jl, code/CLAUDE.md:
migrated to pke_states.
Predicates + invariants
- reachability/predicates.json: new shutdown_margin predicate (1%
dk/k tech-spec floor, expressed as alpha_f*T_f + alpha_c*T_c
halfspace). Used as scram X_exit.
Plot script
- code/scripts/plot/plot_reach_tubes.jl: plot_tubes_scram_pj() with
variant=:fat|:tight knob; plot_tubes_scram_full() for full-PKE
3-panel (T_c, T_f, rho); plot_tubes_heatup_pj() reads results/
not reachability/.
Journal + memory
- journal/entries/2026-04-27-shutdown-sos-and-scram-X_exit.tex (NEW):
long-form entry on the SOS hot-standby barrier and the scram X_exit
refactor.
- journal/journal.tex: input chain updated.
- claude_memory/ — three new session notes:
* 2026-04-27-scram-X_exit-shutdown-margin.md
* 2026-04-28-DICE-2026-conference-intel.md (people, sessions,
strategic notes for the May 12 talk)
* 2026-04-28-path1-sos-pj-sketch.md (sketch of nonlinear-SOS via
polynomial multiply-through; saved for an overnight session)
Docs
- docs/model_cheatsheet.md (NEW): one-page reference of state vector,
dynamics, constants, modes, predicates, sanity numbers — the talk
prep cheatsheet Dane asked for.
- docs/figures/reach_*_tubes.png: regenerated with the new mat data.
- presentations/prelim-presentation/outline.md: revised arc per the
April-28 review pass (cuts: Lyapunov-fails standalone slide,
operation-tube standalone slide, SOS standalone; adds: scopes-of-
control framing, scram on the headline result slide).
- app/predicate_explorer.jl: minor.
Hacker-Split: end-of-session scratch bundle
Following user's review feedback (point 1):
prompt_critical_margin_heatup: a new entry under safety_limits that
proves the PJ reduction's validity condition (beta - rho > 0 with
margin) rather than hand-waving it. Controller-specific
specialization for heatup: under feedback linearization,
rho_total = Kp*(T_ref - T_c), so rho ≤ 0.5*beta iff T_c ≥ T_ref -
32.5. Worst-case T_ref = T_c0 at ramp end, so T_c ≥ 275.85 is
sufficient, which our tight-entry reach clears trivially.
Conjoined into inv1_holds. Safety proofs now target BOTH the
physical bounds AND the conditions that make the PJ approximation
sound. Saves Dane's rigor-over-vibes instinct (saved to memory).
plot_reach_tubes.jl: four-panel visualization of a reach-result .mat:
(1) T_c / T_hot / T_cold envelopes overlaid
(2) ΔT_core = T_hot - T_cold (power proxy, right-axis MW)
(3) rho envelope in dollars, with ±1$ prompt lines
(4) n envelope
Operation-mode plot saved to docs/figures/reach_operation_tubes.png.
Heatup PJ version pending — needs full per-step data from the
running reach_heatup_pj_tight_full.jl.
reach_heatup_pj.jl + reach_heatup_pj_tight_full.jl now save
per-timestep envelopes (t_arr, Tc_lo_ts, Tc_hi_ts, ...) so the
plotting script can overlay tubes vs time.
Next up: polytopic / SOS barriers, Tikhonov error bound for PJ.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Adds mode_boundaries to predicates.json: per-DRC-mode X_entry, X_safe,
X_exit, T_max/T_min with the equilibrium-vs-transition taxonomy the
user articulated during walkthrough. T_max values are engineering-
reasonable guesses (5 hr heatup, 60 s scram); T_min = 7714 s for
heatup is physical floor from 28 C/hr rate limit over 60 F span.
WALKTHROUGH.md is a standalone document — read it cold without needing
the transcript. Covers:
- Per-mode reach-obligation taxonomy (eq. vs trans.)
- Formal reach-avoid claim per mode
- Mode boundary concretizations (X_entry/X_safe/X_exit/T_max)
- File-by-file code walkthrough of every reach artifact
- Results: operation reach passes all 6 inv2 halfspaces; Lyapunov
barrier fails all 6 (fundamental anisotropy limitation, quantified
via the OL/CL comparison)
- Caveats: soundness, alpha drift, saturation, DNBR, cold-shutdown
- Next: nonlinear reach via JuliaReach TMJets
This is the 'prelim example' doc; thesis defense will need real tech-
spec numbers replacing the placeholders.
Hacker-Split: user asked for standalone walkthrough capturing the
analysis step-by-step with figures embedded. This is that.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Earlier placeholder claimed ramp-rate limits weren't expressible as
state halfspaces without augmentation. That was wrong: dT_c/dt is
linear in (T_f, T_c, T_cold) directly from pke_th_rhs (no neutronics
coupling), so |dT_c/dt| <= r_max is two clean halfspaces over x.
Coefficients from pke_params:
a_f = hA / (M_c*c_c) = +0.4587 /s
a_c = -(hA + 2*W*c_c)/(M_c*c_c) = -0.9587 /s
a_cold = 2*W*c_c / (M_c*c_c) = +0.5000 /s
Sum = 0 exact (equilibrium when all T's equal).
Limit chosen: +/- 50 C/hr (tech-spec 28 C/hr + transient overshoot
budget). Verified on actual heatup sim: max dT_c/dt = 48.5 C/hr, min
= 0 C/hr. Passes our placeholder but tight — a strict 28 C/hr tech-
spec invariant would be violated by current ctrl_heatup tuning
(overshoot factor ~1.7x during mid-ramp).
Generalized load_predicates.m to accept multi-coefficient halfspace
rows via "row": [[state_idx, coeff], ...] format, in addition to the
existing single-coefficient {state_index, coeff} form. Backward
compatible.
inv1_holds now conjoins fuel_centerline, cold_leg_subcooled, and the
two rate halfspaces. DNBR still not modeled (would need an
augmented predicate with a correlation-based safety margin).
Hacker-Split: Dane asked about heatup rate invariant; realizing
my earlier 'needs state augmentation' claim was wrong and the rate
constraint is already linear. Fix it, verify against actual sim.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Previously conflated two different kinds of constraint:
- operational deadbands (|T_c - T_c0| <= 5 F) used by the DRC for mode
transitions. Symmetric bands around setpoint. Violating these is an
operator/operational issue, not a safety issue.
- safety limits (T_f <= 1200 C, T_c <= 320 C, n <= 1.15, etc.) are
hard one-sided halfspaces corresponding to physical damage mechanisms
or reactor-trip setpoints. THESE are what a safety barrier/reach must
discharge.
predicates.json now has three groups:
- operational_deadbands (t_avg_above_min, t_avg_in_range, p_above_crit)
- safety_limits (fuel_centerline, t_avg_high_trip, t_avg_low_trip,
n_high_trip, n_low_operation, cold_leg_subcooled)
- mode_invariants (inv1_holds, inv2_holds as conjunctions of safety_limits)
reach_operation.m and barrier_lyapunov.m both now report halfspace-by-
halfspace margins against inv2_holds. Attributable failure analysis:
we can see WHICH limit is tightest.
Reach tube (under +/-15% Q_sg load): passes all 6 safety halfspaces.
Tightest margin is n_high_trip at +0.138 (12% from trip). Temperature
directions have 10-870 K margin.
Lyapunov barrier (same): fails all 6. Worst is n_high_trip with -2365
margin — the ellipsoid says n could deviate by +/-2364, which is
physically meaningless. Anisotropy cost made visible per-direction.
Motivates SOS / polytopic barriers for the thesis chapter.
load_predicates.m now returns .operational_deadbands, .safety_limits,
and .mode_invariants. Existing callers that only used .constants or
.t_avg_in_range still work because those live under the old keys.
Hacker-Split: user caught that the barrier was checking the wrong
invariant; safety limits != operating deadband. Restructured so the
proof target matches the physical claim.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
predicates.json is the single source of truth for concretizing the
FRET-spec predicates (t_avg_above_min, t_avg_in_range, p_above_crit,
inv1_holds, inv2_holds) as polytopes {x : A x <= b}. Until now these
were abstract booleans in the synthesis spec; reach analysis
re-invented ad-hoc thresholds that weren't tied to the spec. Closes
the Thrust-1-meets-Thrust-3 seam.
T_standby now defined as T_c0 - 60 F = 275 C (from user review).
Replaces the earlier simplification where shutdown IC held all temps
at T_cold0. 275 C is inside the model's +/-50 C trust region around
operating point and above coolant saturation at reduced pressure.
load_predicates.m in MATLAB reads the JSON and resolves rhs_expr
strings (which reference plant-derived constants like T_c0, T_cold0,
T_standby) into numeric bounds. Returns per-predicate (A_poly, b_poly)
plus a constants struct.
main_mode_sweep.m now pulls T_standby from predicates and uses it
for shutdown + heatup ICs. Heatup horizon extended to 90 min to
cover the wider 60 F -> operating range at 28 C/hr tech-spec limit.
reach_operation.m reads delta_safe_Tc from the t_avg_in_range
halfspace instead of hardcoding +/-5 K. Current concretization is
+/-2.78 C (~5 F); LQR reach still shows 28x margin.
inv1_holds and inv2_holds are marked PLACEHOLDER in the JSON —
engineering best guesses, not derived from a specific plant's tech
specs or a DNBR correlation. Revisit before thesis defense.
Hacker-Split: single-source concretization for FRET predicates,
end seam with reach.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>