fix: scale the default relaxation window to the system's own relaxation time - #115
fix: scale the default relaxation window to the system's own relaxation time#115marcohost33-maker wants to merge 5 commits into
Conversation
…on time The relaxation layer fits every rate it reports on a time grid, and a decay rate carries dimension 1/time, so the absolute default `linspace(0.0, 10.0, 80)` was an unstated claim about the caller's unit of time. Measured on an amplitude-damped qubit under the pure rescale `L -> cL` (identical physics, different unit of time): c beta_D/c beta_D_linear/c AICc A-class 1e+02 1.025 0.254 M0 A10 1e+00 1.029 0.482 M2 A5 1e-02 1.085 0.403 M0 A1 1e-04 1.167 0.965 M0 A12 1e-06 1.251 109.99 M0 A12 A 22% drift in beta_D, a factor ~430 error in the D17 linear rate, a model-selection flip, and four different mechanism classes for one system. Physical rates are MHz or GHz rather than O(1), so this was the common regime. The default window is now [0, RELAXATION_HORIZON / Delta] at 80 uniform samples: a fixed number of e-foldings of the slowest mode, the only window carried along by the rescaling. After the fix beta_D/c and beta_D_linear/c are invariant to <=1.2e-3 relative over twelve decades on both an amplitude-damped and a driven dephasing qubit, the AICc winner is stable, and the A-class is stable over c in [1e-6, 1]. The grid is uniform by requirement: the GLS layer whitens with a single AR(1) coefficient, which presumes a constant sample interval, so the transient layer's two-scale grid must not be reused here. Backward compatibility: HORIZON = 10 makes the grid bit-identical to the legacy linspace(0.0, 10.0, 80) at Delta = 1, and an unresolved gap (Delta <= 0 or NaN per #113) still returns the historical absolute window. `compute_relaxation_layer` gains an optional `gap=`; diagnose() forwards the D1 it already computed, and a direct caller who omits it gets it from `compute_spectral_layer` rather than a local re-derivation, so the certified zero-mode tolerance (#112) and the ambiguity rule (#113) cannot drift between the two entry points. An explicit t_grid remains authoritative. Audit trail: RelaxationResult gains additive, defaulted `t_grid_source` ("caller" / "gap_scaled" / "legacy_fixed") and `t_grid_span`. The run-manifest contract is unchanged and older serialised reports stay valid. Scope: this closes the time-grid unit dependence only. The solver's own convergence controls (#111) and the rate-dimensioned henrici_eta / resolvent_peak the classifier consumes (#101) remain open and are neither fixed nor asserted away; the latter is pinned as a measured boundary (henrici_eta == c exactly, flipping A5 -> A10 between c = 1 and c = 3). Test plan: 21 new tests in tests/test_relaxation_grid_scale.py; full suite 963 passed; anchors green; ruff and mypy clean. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019c8r6BNjBTkpN9KemEG6up
The scaling tests interrogate different fields of the SAME sweeps, so each assertion was re-running an identical pipeline call. Caching per (system, rate unit) cuts the module from 71.5s to 41.6s locally without changing coverage -- worth it on a five-version CI matrix. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019c8r6BNjBTkpN9KemEG6up
…r the next cut CITATION.cff's documented convention: unreleased changes go in the pending-for-next-cut block, and result-changing ones must be described as corrections rather than additions. This change alters numerical results for any run without an explicit t_grid whose gap is not 1, so it owes an entry (Definition-of-Done item 5). Bounded to what was measured, and explicitly NOT claiming general rate-unit invariance of the fitted rates: #111 (solver convergence controls) and #101 (rate-dimensioned henrici_eta gate) remain open. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019c8r6BNjBTkpN9KemEG6up
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 86442a07d9
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| """ | ||
| if not np.isfinite(gap) or gap <= 0.0: | ||
| return np.linspace(0.0, _LEGACY_T_MAX, n_points) | ||
| return np.linspace(0.0, horizon / float(gap), n_points) |
There was a problem hiding this comment.
Preserve early-time sampling for separated decay modes
When a system has widely separated rates, scaling the entire 80-point uniform grid by the smallest global gap makes the first nonzero sample occur after all faster dynamics have vanished. For example, with independent slow and fast channels of rates 1e-6 and 1, and an initial state that already equilibrates the slow subsystem, this grid samples the fast-only trajectory at t=0 and then around 2.5e5 onward, so its rate is unidentifiable; with both modes populated, the fast component is similarly lost. This can corrupt beta_D, beta_D_linear, M2/AICc selection, and therefore the mechanism classification precisely for multiscale/metastable systems. Retain unit-scaled early-time coverage as well as the 1/gap horizon, with whitening performed in a way that remains valid for the resulting sampling scheme.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Reproduced, and the mechanism is exactly as described — addressed in f132bea, though not by the suggested route. Detail on both parts.
The failure is real. Two independent amplitude-damped qubits at rates 1e-6 and 1: Δ = 5e-7, grid step 2.53e5, and the fast mode's amplitude at the first non-zero sample is exactly 0.0 (underflow, not merely small). It is unsampled, as you say.
But it is not a regression this PR introduced. On that same system, comparing the two windows directly:
| window | beta_D_linear |
vs true Δ = 5e-7 |
|---|---|---|
old absolute [0, 10] |
0.0177 | 3.5e4 relative |
new gap-scaled [0, 2e7] |
7.9e-7 | 0.58 relative |
The absolute window did resolve the fast mode — and missed the relaxation entirely, reporting a rate four to five orders of magnitude off the gap. Both windows fail on a system like this; they fail at opposite ends, and the new one fails on the quantity that is not the layer's headline output.
On the suggested fix. "Retain unit-scaled early-time coverage as well as the 1/gap horizon" is the right instinct, but the parenthetical — "with whitening performed in a way that remains valid for the resulting sampling scheme" — is where it runs aground here. fitting/gls.py::_whiten forms r_k − ρ·r_{k−1} with a single AR(1) coefficient, so a constant sample interval is not a convenience, it is an assumption of the noise model that also carries the parametric bootstrap and N_eff. A two-scale or log grid makes the lag-1 correlation a function of position, and the CI and AICc silently stop meaning what they claim. Making the whitening interval-aware is a genuine change to the inference layer, not a grid tweak, and does not belong in a PR scoped to the window.
There is also a hard limit worth naming: samples_per_fast_efolding = 1/(r_max·dt) ≈ 7.9·Δ/r_max on this grid, so one uniform 80-point window straddles at most about an eightfold spread of timescales. Six decades is not reachable by any choice of uniform window — only by more points (~1e6 here) or by giving up uniformity.
What I did instead — disclose rather than repair. The layer now measures samples_per_fast_efolding from the spectrum and emits an UnderResolvedTransientWarning below 1 sample per fast e-folding, recording the value on the result. Fitting a component that was never sampled is precisely what this project's fail-loud convention exists to prevent; quietly reporting it as if measured was the actual defect your finding points at.
Two details that mattered:
- I first tried a curve-shape heuristic (share of decay in the first interval) and rejected it: it measures the fast component's amplitude, not whether it was resolved. Measured 0.49 for the fully-unsampled
1e-6/1case against 0.46 for a mild0.1/1one — no discrimination. The spectral measure answers the actual question. - The measure is itself rate-unit invariant (identical
3.95atc ∈ {1e-4, 1, 1e4}, pinned by test). A guard that fired on one choice of time unit and not another would reintroduce, inside the guard, the very defect this PR removes.
V5 (Jaynes-Cummings near the EP, measured r_max/Δ = 396) legitimately trips it — correct signal. Those tests acknowledge the disclosure by message filter with the reason stated inline, and the disclosure is pinned positively in tests/test_relaxation_grid_scale.py (fires on separation, silent on single-timescale systems at three rate units) rather than only silenced.
Full suite 971 passed. Leaving this thread open for a maintainer: if the preference is to make the AR(1) whitening interval-aware and adopt a genuinely two-scale grid, that is a defensible larger change and I'm happy to open it as its own issue — say the word.
Generated by Claude Code
There was a problem hiding this comment.
Nachtrag zum Angebot von oben: die vorgeschlagene grössere Änderung ist jetzt als #122 erfasst statt als Absatz in einem Thread stehen zu bleiben — „Whitening assumes a uniform grid, so the sampling scheme cannot be improved on its own".
Es hält die Kopplung fest, die den Vorschlag hier scheitern liess (AR(1) mit einem Koeffizienten ⇒ konstantes Intervall ist Annahme des Rauschmodells, nicht Bequemlichkeit — und trägt Bootstrap und N_eff mit), die gemessene harte Grenze (≈ 7.9·Δ/r_max, also höchstens rund achtfacher Zeitskalen-Spreizung pro uniformem 80-Punkte-Fenster) und die beiden Messreihen, in denen altes und neues Fenster an entgegengesetzten Enden scheitern.
Aufgenommen ist auch eine Diskriminierungs-Auflage: ein Test auf dem 1e-6/1-System, in dem die jetzige Umsetzung fällt und die neue beide Raten zurückholt — nicht bloss ein Test, dass das neue Gitter läuft.
Dieser Thread bleibt offen: die Entscheidung, ob die Inferenz-Schicht angefasst wird, gehört dem Maintainer, nicht diesem PR.
There was a problem hiding this comment.
This finding stands, and the answer it received was too weak. Thank you for it.
The branch responded by disclosing the problem (UnderResolvedTransientWarning) rather than repairing it, on the stated grounds that a non-uniform grid "would make that lag-1 correlation a function of position on the grid and quietly invalidate the whitening". We measured that claim instead of trusting it, and it does not hold.
Setup: independent channels at rates 1e-6 and 1, OU-correlated noise generated from the exact transition density (Euler would be worthless across eleven decades of step size), 40 trials, fit start values deliberately detuned by 5x with a proof that the parameter actually moved -- otherwise an unmoved seed reads as a perfect fit, which is the same trap #123 describes.
uniform linspace(0, 10/gap, 80) |
two-scale grid | |
|---|---|---|
| fast rate identified | 0 / 40 | 40 / 40 (rel. err 3.8e-2) |
whitened residual |lag-1|, single rho |
-- | 0.4231 |
whitened residual |lag-1|, rho_k = exp(-theta*dt_k) |
-- | 0.0945 |
Positive control (a nearly-uniform grid): CAR(1) collapses back onto AR(1) exactly, 0.0728 vs 0.0728 -- so the correction is inert where it should be.
Both grounds for the disclosure therefore fall. The "constant sample interval" requirement is a property of the discrete parameterisation, not of the process: the continuous-time OU/CAR(1) process has Corr(t, t+d) = exp(-theta*d), so whitening with a per-step rho_k (and rescaling by sqrt(1 - rho_k^2) to keep the innovations homoscedastic) is valid on ANY grid.
A repair is now in progress rather than a disclosure: early-time coverage retained alongside the 1/gap horizon, with the fast scale taken from the spectrum (max |Re lambda|) instead of a guessed parameter, and the consequences carried through the GLS fit, the AR(1) bootstrap, N_eff and M2/AICc selection rather than stopping at the grid call. We will report back with the same mutation evidence used for the other findings on this stack, including which cases -- if any -- still need the warning.
There was a problem hiding this comment.
The repair is up: #127.
Following on from my earlier reply, where I said a repair was in progress rather than a disclosure. It is built and pushed.
What changed against what I wrote before: the whitening figures in that message (0.4231 vs 0.0945) came from my own reproduction on a hand-built two-scale grid. The delivered version measures on the grid the layer actually constructs, and reports 0.3738 with one constant rho against 0.0728 with the per-step rho_k — with the constant-rho case taken at the median step, i.e. that scheme's best case. The uniform positive control gives 0.0728 for both schemes, which is what shows the contrast comes from the grid rather than from the comparison. Different grids, both measurements valid; the delivered numbers are the ones that describe this code.
On your specific concern — that the fast scale would have to come from somewhere: it comes from the spectrum, max(-Re lambda), not from a supplied parameter, and the two-scale grid is built only when the uniform one fails to resolve it. On your case the early-time coverage goes from 1 support point to 21, and the AICc-selected model recovers the fast rate as 1.10004 against a true 1.0. The old window reported 2.173286e-05 for that same component — a "successful" two-exponential fit of a mode that was never sampled.
Three things the PR explicitly does not close, since the previous answer on this thread claimed more than it had: intermediate timescales are still under-resolved (the warning fires and names the mode), there is no small-sample bias correction on the CAR(1) path, and Geyer's N_eff is 2-4x optimistic on the uniform path — measured, filed as #128, and deliberately not touched here because swapping it would move every existing anchor.
So the warning stays, but it now means something narrower: caller-supplied grids that do not resolve their own system, and intermediate scales. It no longer fires on the case you reported.
Evidence re-run independently rather than taken from the build: 1019 passed, and 16/16 mutation cases discriminating against the delivered HEAD — that last one mattered, because the final commits were labelled docs: but changed source, so the original proof covered a state that was not being shipped.
There was a problem hiding this comment.
This finding is correct on this branch. Measured: default_relaxation_grid(1e-6) puts the first non-zero sample at t=126582, where exp(-1*t) is exactly 0.0 - 7.9e-06 samples per fast e-folding.
It is closed in PR #127, which contains this branch: src/liouscope/diagnostics/relaxation.py:116 takes fast_rate and makes the grid two-scale, and :652 passes the rate through from the pipeline. The same request there yields t1 = 0.25 and 4.0 samples per fast e-folding, with a uniform head.
Deliberately left unresolved here, for the same reason as #107: the fix is on the successor branch. Closing this PR as superseded is a maintainer decision.
Verified locally on the pushed branch: ruff and mypy clean, tests/test_anchors.py 21 passed. Reverse-mutation runs are recorded in an evidence ledger with one run_id per run; a run that dies by error rather than on an assertion is not counted as proof. CI on GitHub not measured here.
Two findings from the Codex review. P1 -- widely separated rates. A uniform window scaled to 1/Delta cannot also resolve a much faster mode: the window must reach ~1/Delta to see the slowest mode relax while the step must stay under ~1/r_max to see the fastest at all, and 80 uniform samples straddle only ~8x separation. Confirmed: with rates 1e-6 and 1 the fast mode decays to exactly 0.0 within one step. Not a regression from the new window -- on that same system the previous absolute window put beta_D_linear 3.5e4 relative from the true gap against 0.58 for the gap-scaled one -- but silently fitting a component that was never sampled is what the fail-loud convention exists to prevent. The layer now measures samples_per_fast_efolding = 1/(r_max*dt) and warns below 1, recording the value. A disclosure, not a repair: widening the window is strictly worse for the reported quantity and log spacing would invalidate the AR(1) whitening. A curve-shape heuristic was tried first and rejected -- the share of decay in the first interval measures the fast component's AMPLITUDE, not whether it was RESOLVED (0.49 for a fully unsampled 1e-6/1 separation vs 0.46 for a mild 0.1/1 one). The spectral measure is also itself rate-unit invariant, pinned by test, so the guard cannot fire on one choice of time unit and not another. V5 (JC near the EP, r_max/Delta = 396) legitimately trips it; those tests acknowledge the disclosure by message filter with the reason stated inline. P2 -- the span does not identify the sampling. [0, 1, 10] and [0, 9, 10] share a span of 10 while describing different trajectories, and the report already serialised three 80-point curves whose abscissa was missing. RelaxationResult now stores the grid itself as a snapshot copy. Additive, defaulted, no manifest-schema change. Test plan: 8 new tests (fires on separation, silent on single-timescale at three rate units, invariant guard, grid identifies sampling, snapshot not alias, length matches the curves); full suite 971 passed; ruff and mypy clean. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019c8r6BNjBTkpN9KemEG6up
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: f132bea3c7
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
Second-round Codex finding, against the guard added in the first round.
samples_per_fast_efolding used only dt = t[1] - t[0]. diagnose() permits any
non-negative grid start, so a late-starting grid leaves a lead-in from t=0
that no step size compensates for. Measured on linspace(100, 101, 101) with a
rate-1 mode: reported 100 samples per fast e-folding and emitted no warning,
while the amplitude at the first sample is e^-100 -- the entire
relative-entropy curve measures identically zero and the fit still returned a
confident beta_D = 1.0.
The denominator is now max(dt, t[0]), the largest interval the grid leaves
unsampled. That is exactly dt for any grid starting at zero, so the default
path is bit-for-bit unchanged (verified: 3.95 samples per e-folding at
c in {1e-4, 1, 1e4}, as before). The warning text now names which gap
dominates rather than always printing the step.
Test plan: 2 new tests (late-starting grid warns and reports 0.01; lead-in
inert when t[0] == 0); full suite 973 passed; ruff and mypy clean.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019c8r6BNjBTkpN9KemEG6up
Antwort auf "Preserve early-time sampling for separated decay modes"Der Befund ist inzwischen repariert, nicht mehr nur offengelegt — allerdings in PR #127, nicht auf diesem Zweig. Dieser Zweig trägt weiterhin nur die Offenlegung. Auf
Damit fällt unser Einwand aus der ersten Antwort („ein konstantes Intervall ist Annahme des Rauschmodells"): er galt für die diskrete Parametrisierung, nicht für den zugrundeliegenden Prozess. Das war unser Fehler in der Zuordnung, nicht Ihrer im Befund. 🤖 Generated with Claude Code |
Status 2026-09-07 — contained in #127, and a
|
Summary
The relaxation layer fits every rate it reports on a time grid, and a decay rate carries dimension
1/time— so the absolute defaultlinspace(0.0, 10.0, 80)was an unstated claim about the caller's unit of time. This replaces it with a window measured in the system's own relaxation time,[0, RELAXATION_HORIZON / Δ], and discloses the cases a uniform window cannot cover.The defect
Measured on an amplitude-damped qubit under the pure rescale
L → cL(identical physics, different unit of time), on #107's head:cbeta_D / cbeta_D_linear / cA 22 % drift in
beta_D, a factor ~430 error in the D17 linear rate atc = 1e-6, a model-selection flip between M0 and M2, and four different mechanism classes for one system. Since physical rates are MHz or GHz rather thanO(1), this was the common regime, not a corner case. It affects D5, D6, D7, the M0..M3b AICc comparison,beta_D, its BCa interval and the D17 gap-rate check.After
beta_D / candbeta_D_linear / cinvariant to ≤1.2e-3 relative overc ∈ [1e-6, 1e6](twelve decades) on both an amplitude-damped and a driven dephasing qubit; AICc winner stable; A-class stable overc ∈ [1e-6, 1].Design notes
sup_tsearch with no noise model) but would make the lag-1 correlation position-dependent here and quietly invalidate the whitening, the AR(1) bootstrap andN_eff.HORIZON = 10ise^-10 ≈ 4.5e-5of the initial deviation — deep enough to identify the rate, shallow enough that the tail is not almost entirely numerical floor.compute_relaxation_layergains an optionalgap=.diagnose()forwards the D1 it already computed; a direct caller who omits it gets it fromcompute_spectral_layer, not a local re-derivation — so the certified zero-mode tolerance (Stiff generators: dense eigensolver displaces the whole slow spectrum beyond any threshold's reach — structural deflation needed #112) and the ambiguity rule (Spectral dynamic-range ceiling: above ~4.5e12 spread the zero-mode filter discards the genuine slow modes and D1 reports a fast one #113) cannot drift between the paths. An explicitt_gridremains authoritative.samples_per_fast_efolding = 1 / (r_max · max(dt, t[0])) ≈ 7.9 · Δ / r_max— one uniform 80-point window straddles at most about an eightfold spread of timescales. Below one sample per fast e-folding the layer emits anUnderResolvedTransientWarningand records the value. A disclosure, not a repair: widening the window is strictly worse for the reported quantity (measured below), and log spacing is unavailable for the AR(1) reason above. The measure is itself rate-unit invariant, pinned by test.Backward compatibility
HORIZON = 10.0is chosen so the grid is bit-identical to the legacylinspace(0.0, 10.0, 80)atΔ = 1, and an unresolved gap (Δ ≤ 0, or NaN per #113) still returns the historical absolute window. No anchor changes:tests/test_anchors.pyis untouched and green.RelaxationResultgains four additive, defaulted fields —t_grid_source("caller"/"gap_scaled"/"legacy_fixed"),t_grid_span,t_grid(the sampling itself) andsamples_per_fast_efolding— so which window produced a given set of rates, and whether it resolved the dynamics, is recorded rather than inferred. The run-manifest contract is unchanged; older serialised reports stay valid.Review rounds (Codex)
Three rounds, all reproduced before acting; two changed the code, one changed only the claim.
1e-6and1the fast mode decays to exactly0.0within one step. But not a regression: on that same system the old absolute window putbeta_D_linear3.5e4relative from the true gap against0.58for the gap-scaled one. Both windows fail; they fail at opposite ends, and the new one fails on the quantity that is not this layer's headline output. The suggested fix (keep unit-scaled early coverage, adapt the whitening) is a change to the inference layer, not the grid — out of scope here. Addressed by disclosing instead.[0, 1, 10]and[0, 9, 10]share a span of 10. Sharper than stated: the report already serialised three 80-point curves whose shared abscissa was missing, so the gap predates this PR.t_gridis now stored as a snapshot copy.linspace(100, 101, 101)a rate-1 mode was called "100 samples per e-folding" with no warning, while the entire relative-entropy curve measures identically zero and the fit still returnedbeta_D = 1.0off its seed. The denominator is nowmax(dt, t[0])— exactlydtwhen the grid starts at zero, so the default path is bit-for-bit unchanged, pinned by test.Scope — what this does NOT fix
This closes the time-grid unit dependence only. Open and deliberately neither fixed nor asserted away:
henrici_eta/resolvent_peakthe classifier still consumes. Now pinned as a measured boundary:henrici_etaequalscexactly on the test system and crosses its absolute> 1.0gate betweenc = 1andc = 3, flipping A5 → A10 whatever the grid.test_henrici_eta_is_the_remaining_unit_dependence_above_unit_ratesasserts the rates stay invariant across that flip, so it can never be misread as a grid problem.beta_Dis returned from the fit seed when the curve is identically zero. The disclosure now makes that visible; making it fail closed is a separate change.Scope
Verification
pytest -qpasses locally — 973 passed (31 new); all 7 required checks green on CI at72b7da3tests/test_anchors.pyunchanged and green (21 passed)ruff check src tests benchmarksclean;mypy src/liouscopeclean (53 files).github/scripts/check_claim_safety.pypassed (21 public-facing markdown files)CITATION.cffupdated (DoD item 5): recorded in the documented pending for the next cut block, described as a correction rather than an addition, and explicitly bounded — it states that this does NOT make the fitted rates invariant under an arbitrary change of rate units, since Least-squares convergence is not rate-unit invariant at extreme time-grid spans #111 and F5 evidence path: scale-relative D8/D10/D11b/D13 and mechanism-valid calibration #101 remain openMANIFEST_SCHEMA.json: n/a — the manifest contract is untouched.github/workflows/: n/adocs/explanation/layers-and-taxonomy.mdstates the measured invariance range, the eightfold resolution ceiling, and the dependences that remain openQuality contract
RTOL_RATE = 1e-2) sits ~8× above the measured floating-point noise and ~20× below the regression it guards, so it can neither flake nor pass a revert. The new disclosure is pinned in both directions (fires on real separation, silent on single-timescale systems at three rate units), so it cannot decay into noise that reviewers filter wholesale.Reproducibility note
seed=1,bootstrap_B=10. Tested on V3 (amplitude-damped qubit,rho_0 = |+><+|,gap = c/2) and a driven dephasing qubit (gap = 0.3c) acrossc ∈ [1e-6, 1e6], plus a two-timescale pair of independent damped qubits for the disclosure. This CHANGES NUMERICAL RESULTS for anydiagnose()call that omitst_gridand whose gap is notΔ = 1; documented under[Unreleased] / FixedinCHANGELOG.mdwith the before/after table.V5 (Jaynes-Cummings near the EP, measured
r_max/Δ = 396) legitimately trips the new disclosure; those tests acknowledge it by message filter with the reason stated inline, and the disclosure is pinned positively elsewhere rather than only silenced.Canon-impact note
None of the canon-gated surfaces are touched: no diagnostic IDs or schema change, no A-class taxonomy semantics change, no manifest fields or hashes, no StabilityReport fields, no version metadata, no D24 wording, no branch-protection or visibility change.
RelaxationResultgains four additive defaulted fields, the same purely-additive pattern asbeta_D_linear/trace_distance_curve. The citation metadata change is confined to the unreleased pending-notes comment block;version,date-releasedand the DOI are untouched.Linked issues
Refs #101, #111, #116 (all scoped out above; the #101 boundary is now pinned by test). Depends on #107.