PWR-HYBRID-3/claude_memory/2026-04-27-scram-X_exit-shutdown-margin.md
Dane Sabo c5133401e0 Session work scratch: scram X_exit refactor, hot-standby SOS, fat scram tubes, model cheatsheet, journal entry
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
2026-05-02 23:02:50 -04:00

89 lines
4.2 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 2026-04-27 — Scram `X_exit` redefinition: shutdown-margin halfspace
## What changed
Replaced the scram-mode `X_exit` predicate from
`n <= 1e-4 AND T_f <= T_f0 + 50 C` to a single linear halfspace
`shutdown_margin`:
alpha_f * T_f + alpha_c * T_c <= -rho_SDM - U_SCRAM + alpha_f*T_f0 + alpha_c*T_c0
≈ 0.002972
with `rho_SDM = 0.01` (1% Δk/k tech-spec floor).
Files touched:
- `reachability/predicates.json` — added `shutdown_margin` under
`safety_limits`; updated `mode_definitions.q_scram.X_exit_predicate`
and `X_safe_predicate`; left a `_X_exit_history` field for forensics.
- `code/scripts/reach/reach_scram_pj.jl` — added `RHO_SDM`, `SDM_RHS`
constants; reach loop now reports ρ-bounds and the halfspace LHS sup
per probe horizon; `.mat` output gets `sdm_lhs_hi`, `rho_max`,
`sdm_ok` per horizon plus a global `sdm_rhs`, `rho_sdm`.
## Why
1. **Power threshold was nonlinear in PJ state.** In the prompt-jump
reduction, `n = Λ * sum(λ_i*C_i) / (β - ρ)`ρ depends on `T_f`,
`T_c`. So `n ≤ 1e-4` is *not* a halfspace in the reach state. We
were reconstructing it post-hoc on every probe, which works for a
diagnostic check but doesn't compose with halfspace-based discharge.
2. **`T_f ≤ T_f0 + 50` was infeasible-by-construction at 60 s.** Decay
heat (`Q_sg = 3% P0`) plus a fuel time constant `M_f*C_f / hA ≈ 0.3 s`
means `T_f` rapidly equilibrates with `T_c`, but the system loses
only ~5 °C in 60 s under constant decay — nowhere near the threshold,
and never going back up either. The bound was dressing, not work.
3. **Shutdown margin is the actual NRC criterion.** Tech specs phrase
scram success in Δk/k, not in flux. And ρ is *linear* in
`(T_f, T_c)` post-scram (constant `u = U_SCRAM`), so it's a clean
single-row halfspace.
## Result
`reach_scram_pj.jl` discharges `shutdown_margin` at all three probe
horizons (10, 30, 60 s), with massive margin:
| T (s) | reach-sets | wall (s) | ρ at horizon | discharged |
|-------|------------|----------|---------------------------|------------|
| 10 | 6919 | 98.6 | [-0.0507, -0.0504] | ✓ |
| 30 | 9900 | 130.5 | [-0.0506, -0.0503] | ✓ |
| 60 | 12340 | 164.2 | [-0.0503, -0.0500] | ✓ |
Required: `ρ ≤ -0.01`. Actual: `|ρ| ≈ 5%`. The Doppler/moderator
contributions vary by ~3% of `U_SCRAM`, so the margin is dominated by
rod worth — exactly what physical intuition predicts.
`.mat` output: `results/reach_scram_pj_result.mat`.
## Subtlety I tripped on
Hand-derived `SDM_RHS = 0.00402` using rounded `T_F0=320`, `T_C0=300`.
Actual values from `pke_params`: `T_C0 = 308.35`, `T_F0 = 328.35`
(because `DT_CORE = P0/(W_M*C_C) = 36.7 °C`, not 20). The script
computes `SDM_RHS` from constants so the run was correct (0.002972),
but the predicate JSON had the stale 0.00402. Fixed by switching the
`rhs_expr` to a symbolic form. **Rule for next time:** if a constant
in `predicates.json` is derivable from `pke_params`, write it as a
symbolic expression, not a baked number — that's what `T_cold0`,
`T_c0`, `T_standby` are for.
## What's still open
- `X_safe_predicate` still says "fuel_centerline AND cold_leg_subcooled"
but the reach script doesn't actually discharge those over the
trajectory — only at the probe horizons. Not a problem for the demo
(T_f and T_cold are monotone after scram), but the formal obligation
is reach-AVOID, not just reach. Worth a follow-up: discharge the
invariant halfspaces over the *full flowpipe*, not the endpoint.
- `prompt_critical_margin_heatup` is the controller-specific PJ-validity
predicate. Scram has its own analogous concern (PJ valid only when
`β - ρ > 0` with margin). Trivially satisfied here (ρ ≈ -0.05, far
from `β = 0.0065`), but worth a parallel `prompt_critical_margin_scram`
predicate for completeness — would document the assumption rather than
leave it implicit.
## Graduation candidates
- The "rhs_expr should be symbolic when derivable" rule probably belongs
in `code/CLAUDE.md` near the predicate-loading section. Hold for now —
one occurrence isn't a pattern yet.