Skip to content

fix(classifier): clear #70 semantics debt (A5/A6/A8/A9; B3/B4 proposed) - #81

Merged
marcohost33-maker merged 1 commit into
mainfrom
fix/70-classifier-semantics
Jul 4, 2026
Merged

marcohost33-maker merged 1 commit into
mainfrom
fix/70-classifier-semantics

Conversation

@marcohost33-maker

@marcohost33-maker marcohost33-maker commented Jul 4, 2026

Copy link
Copy Markdown
Owner

Addresses #70 (A5/A6/A8/A9 fixed; B3/B4 analysed + proposed)

Dedicated classifier-semantics PR per AGENTS.md section 3 (physics rationale required).
DRAFT - merge decision is Marco/Vero's after verify. Runtime diagnose()
output is unchanged for all V1-V5 systems (golden-pinned); the changes correct
family labels, a dimensional-coherence bug, a degeneracy blind-spot, and a dead
verdict.

Baseline: main fda7442f1013661c536c4a682eb1cd36a09f7bad (freshness-verified at
clone: git rev-parse HEAD == gh api .../heads/main). Depends-on #68/#69/#79
which are already on main.

Findings - status per item

# Finding Status Where
A5 VERDICT_EXCLUDED unreachable fixed (removed) _types.py, _consts.py, classification.py
A6 A1 wrongly mapped to F1 fixed (-> "none") classification.py
A8 F5 rule dimensionally incoherent fixed (scale-invariant) classification.py
A9 lep_proximity blind to exact degeneracies fixed diagnostics/lep.py
B3 classes A6/A7/A9 unreachable proposed (not wired) PR body below
B4 gathered evidence unused proposed (not wired) PR body below

A6 - A1 maps to family "none", not F1 (fixed)

Physics. F1 is the Mori-Shirai overlap gap-FAILURE mechanism (PRL 125,
230604, 2020). _consts.F_FAMILY_DESCRIPTIONS["none"] = "No gap-failure
mechanism flagged". A1 = "Asymptotic-gap-controlled (primitive QMS)" is precisely
the case where the gap governs relaxation - the no-failure case. Labelling
the healthy gap-controlled result with a gap-FAILURE family is a category error.
A1 -> "none" is the physically correct family.

Change. All three return "A1", "F1" in _pick_a_class -> return "A1", "none".
Consistency with #79: tests/test_validation_systems/test_d17_gap_coherence.py
test_gap_controlled_reference_reaches_a1 updated to assert f_family == "none"
(a_class A1, verdict CONFIRMED, and the #69 D17 dimension-coherence logic are all
UNTOUCHED - only the family label).

Test evidence. test_branch_a1_strong_gap_consistency,
test_branch_a1_moderate_gap_consistency, test_a1_early_branch_reached_...
pin A1/"none"; the #79 adversarial phantom-shadow test still pins A10/F5.


A8 - F5 phantom-relaxation rule is now dimension-coherent + scale-invariant (fixed)

Physics / bug. The old rule pseudospectral_radius > 2.0 * gap_to_gns_ratio
compared a rate (D13 radius max{|z| : z in sigma_eps(L)}, units of inverse
time) against a dimensionless ratio (Delta / Delta_s). Rescaling the
Liouvillian L -> cL - a pure change of the unit of time, physically identical
dynamics - scales the radius by c but leaves gap_to_gns_ratio invariant, so
the A10/F5 verdict flipped with c.

Fix. Compare the dimensionless pseudospectral reach radius / gap: how
far the eps-pseudospectrum extends relative to the asymptotic decay rate Delta

  • the physical phantom-relaxation signature (Znidaric 2023, arXiv:2306.07876).
    Both sides are now dimensionless; radius/gap is scale-invariant to leading
    order (both scale as c). A vanishing gap is treated as infinite reach (the
    gapless/critical phantom limit). Guarded gap > 0.

Metamorphic test evidence (tests/test_classification.py):


A9 - lep_proximity (D16) no longer blind to exact degeneracies (fixed)

Physics / bug. A Liouvillian Exceptional Point is where two eigenvalues (and
their eigenvectors) coalesce, so eigenvalue separation -> 0 is the signature of
approaching an EP and an exact degeneracy is the STRONGEST proximity
signal. The old min-sep scan had if sep < min_sep and sep > atol, which
skipped every pair with sep <= atol - discarding exactly that signal. A
fully degenerate spectrum returned inf ("maximally FAR from an EP"), the exact
inverse of the physics. The candidate-count loop used 10*min_sep with no
matching filter (mutually inconsistent with the min-sep loop).

Fix. Keep all i < j pairs; a closest separation at/below atol is clamped
to 0.0 (coalesced = proximity 0). The candidate loop uses the same data and a
max(10*min_sep, atol) window, so when min_sep == 0 the window is atol
(counts the coalesced cluster) - the two loops are now consistent. D16 measures
eigenvalue proximity only; genuine defective EP vs semisimple/symmetry-protected
degeneracy stays the Petermann-factor (D9) job, as before.

Test evidence (tests/test_lep.py): exact-degenerate pair -> 0.0;
fully-degenerate spectrum -> 0.0 (not inf); sub-atol -> clamped 0.0;
non-degenerate unchanged (min sep 1.0); candidate loop consistency
([-1,-1,-50] -> prox 0.0, count 1). Anchor I (conjugate pairs included) stays
green.


A5 - unreachable EXCLUDED verdict removed (fixed)

Analysis. The confidence values diagnose() can produce are
{0.95, 0.85, 0.70, 0.50, 0.20}. The only sub-0.30 value (A12 = 0.20)
short-circuits to NOT_EXCLUDED before the threshold check, so
confidence < 0.30 -> EXCLUDED was never reached (CHANGELOG v0.4.1 already
flagged this). More fundamentally it is semantically inexpressible here: a
single-pass, maximum-evidence classifier reports the best-fit A-class with its
support - it never reports a class it is simultaneously ruling out. A per-class
"actively excluded" verdict needs a per-hypothesis scoring architecture. The old
branch was also wrong: low confidence in the best-fit class is epistemic
uncertainty ("unresolved" = NOT_EXCLUDED), not positive counter-evidence.

Chosen resolution (physically motivated): remove. "EXCLUDED" dropped from
the Verdict Literal and _consts.VERDICT_EXCLUDED; the dead branch removed so
low confidence correctly yields NOT_EXCLUDED.
API note: Verdict narrows from 5 to 4 members - a type-surface narrowing
only; runtime diagnose() output is unchanged (it never emitted EXCLUDED).
VERDICT_EXCLUDED is not in the public liouscope.__init__ __all__.

Test evidence. test_pick_verdict_tier_thresholds now pins conf 0.20 and
0.0 -> NOT_EXCLUDED (the corrected semantics).


B3 - classes A6/A7/A9 unreachable (analysed; NOT wired - decision to Marco/Vero)

_pick_a_class returns 9 of 12 classes; A6 (accelerated-decay /
operator-spreading), A7 (weak-dissipation singular, Mori 2024), A9
(prethermalization / ETH) are never emitted. Why: the heuristic tree has no
branch mapping evidence to them, and A7/A9 would require diagnostics that do not
exist yet (A7 needs a dissipation-strength / singular-perturbation detector; A9
needs ETH/level-statistics signals; both overlap A5 metastable). Proposal:
either (a) implement per-class branches in dedicated PRs with anchor coverage
and false-positive tests
(A6 is the most tractable: accelerated decay ~
beta_D_linear >> gap), or (b) mark A6/A7/A9 as a discoverable
"reserved / not-yet-reachable" code-level contract analogous to the existing
RESERVED_DIAGNOSTIC_SLOTS (D21-D23) so the taxonomy-vs-classifier gap is
honest. Not decided here to avoid guessing; recommend a follow-up issue.

B4 - gathered evidence unused (analysed; NOT wired - FP risk, decision to Marco/Vero)

lep_proximity (D16), lep_candidate_count, D18 initial_state_sensitivity,
D11 bohr_ap_length, D12 ridge_fwhm, D20 mpemba_expansion_alpha do not
influence class/verdict. Wiring any of them is a class/verdict-influencing
design decision that can introduce false positives
, so per the issue this PR
does not blind-wire them. Safest proposed design (fail-safe first):

  • D18 as a confidence dampener for the state-dependent A1 label - high
    initial-state sensitivity means the observed single-exp-at-gap may be an
    artifact of the chosen rho_0; capping A1 confidence can only lower a claim,
    so it cannot create a false positive. (Needs a check that it does not regress
    the fix: make D17 gap-rate consistency dimension-coherent (#69) #79 gap-controlled reference, which expects A1 CONFIRMED - hence a
    dedicated PR.)
  • D16 + Petermann (D9) as an A10/F5 corroborator, D20 -> A11 confidence,
    D11 -> A8 (almost-periodic/oscillatory), D12 -> A2/F3 (gap-corrective
    scale)
    - each a confidence modifier on an already-picked class, never a new
    trigger.
    Recommend a dedicated PR per wiring with anchor coverage + FP tests. Follow-up
    issue suggested.

Verification (local, CI-parity; py = Python on this Windows box)

All exit 0, output observed (QuTiP not installable locally -> its cross-checks
skip; CI runs them):

Gate Command Result
ruff ruff check src tests benchmarks exit 0, "All checks passed!"
mypy mypy src/liouscope exit 0, "no issues found in 50 source files"
anchors (SACRED) pytest tests/test_anchors.py 19 passed, 2 skipped (QuTiP), exit 0
full + cov pytest --cov=liouscope --cov-fail-under=80 456 passed, 8 skipped, cov 94.46%, exit 0
workflow hardening .github/scripts/check_workflow_hardening.py exit 0 (10 files)
claim safety .github/scripts/check_claim_safety.py exit 0 (6 files)

Test plan checklist

No methodology/results or manifest-contract change -> CITATION.cff /
MANIFEST_SCHEMA.json untouched. Not a history-touching op (new branch push).

Open questions routed to Vero/Marco

  1. A5 resolution: confirm remove EXCLUDED (chosen) vs implement a
    per-hypothesis active-exclusion mode. Removal narrows the public Verdict type.
  2. B3: implement A6 branch now, or add the reserved-slot contract, or defer?
  3. B4: approve the fail-safe D18-confidence-dampener design as the first
    wiring in a dedicated PR, or leave all evidence advisory-only?

Generated with Claude Code (Codie / Coworkerz agent).


Verify-Nachtrag (Vero, 2026-07-04 — Equalita PASS 8/8 + Cross-Family gpt-5.5 GOOD)

A8-Caveat (ehrlich): Die radius/gap-Regel ist nur leading-order skalen-invariant, nicht exakt. Bei festem ε=1e-3 (D13) driftet reales radius/gap empirisch ~2.549→2.0 über c∈[1e-3,1e3] (~27%/6 Dekaden), weil sigma_eps(cL)=c·sigma_{eps/c}(L). Der Code-Kommentar sagt korrekt "to leading order"; Test-Name/Commit sind schärfer formuliert als belegt → als Residual getrackt (Follow-up-Issue), kein Korrektheits-Regress (neue Regel strikt besser als alte bare-radius-Regel). Ebenfalls getrackt: pre-existing NaN-Silent-Failure in lep_proximity.

Merge-Status: Equalita = Fakten PASS (Sacred-Gate grün, kein eingeführter Klassifikations-FP, 456 passed/cov 94.46%). Cross-Family = GOOD (gas +1). Offene Design-Urteile (A6-Taxonomie, A8-Schwelle, A9-Konvention, A5-API-Break) + Merge = Marco-Gate.

A6: A1 -> family "none" (was F1 = gap-FAILURE); A1 is the no-failure case.
A8: F5 rule dimension-coherent + scale-invariant (pseudospectral REACH
    radius/gap vs 2*gap_to_gns_ratio; L->cL no longer flips A10/F5).
A9: lep_proximity (D16) sees exact degeneracies (strongest EP signal ->
    proximity 0, not inf); candidate loop consistent.
A5: removed unreachable/semantically-wrong EXCLUDED verdict (single-pass
    best-class classifier cannot emit active rejection); low confidence ->
    NOT_EXCLUDED. Verdict Literal narrows 5->4 (runtime output unchanged).

B3/B4 analysed but not wired (design decisions with FP risk) -- see PR body.

Tests: +A8 metamorphic rescale (c in 1e-3..1e3) + old-rule-flip regression,
+A9 exact/full/sub-atol degeneracy edges. Sacred anchor gate green.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@marcohost33-maker marcohost33-maker added the agent:claude PR authored by Claude Code label Jul 4, 2026
@marcohost33-maker
marcohost33-maker marked this pull request as ready for review July 4, 2026 18:23
@marcohost33-maker
marcohost33-maker merged commit 73984da into main Jul 4, 2026
13 checks passed
@marcohost33-maker
marcohost33-maker deleted the fix/70-classifier-semantics branch July 4, 2026 18:23

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 8e5e64db2e

ℹ️ 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".

_psr_reach = (
ev["pseudospectral_radius"] / _gap if _gap > 0.0 else float("inf")
)
if _psr_reach > 2.0 * ev.get("gap_to_gns_ratio", 1.0) and ev["henrici_eta"] > 1.0:

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Make the F5 non-normality gate scale-free

For the rescale scenario this change is meant to fix, the condition still gates on raw henrici_eta > 1.0. henrici_eta_n is the Frobenius norm of the Schur off-diagonal, so henrici_eta_n(cL) scales linearly with the time-unit rescale c; only the pseudospectral radius was normalized here. As a result, a strongly non-normal phantom system near this threshold can fall through to A1/A12 when expressed in slower units even though the physics is unchanged, and the new synthetic rescale tests miss it because they keep Henrici fixed by hand. Please normalize this non-normality signal or use a scale-free gate before claiming/reserving scale-invariant F5 classification.

Useful? React with 👍 / 👎.

Comment thread CHANGELOG.md
Comment on lines +69 to +70
- **Classifier semantics debt cleared: A1 family, F5 dimensional coherence,
LEP degeneracy, dead EXCLUDED verdict** (issue #70, A5/A6/A8/A9). Four

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Update CITATION for methodology changes

This entry changes result-facing methodology/semantics for the classifier (A1 family assignment, the F5 rule, and D16 degeneracy handling), but the commit leaves CITATION.cff untouched. The repo instructions in AGENTS.md require changes touching results or methodology to update CITATION.cff; otherwise the citable metadata still describes the previous public surface while labels/verdict evidence have changed. Please update the citation metadata or explicitly move non-methodology-only changes out of this PR.

Useful? React with 👍 / 👎.

marcohost33-maker added a commit that referenced this pull request Jul 6, 2026
#85)

Completes the two sub-findings PR #81 left open (A5/A6/A8/A9 already on main).
Both are behaviour-preserving: no real-input classification result changes;
sacred anchors + V1-V5 golden classification stay byte-identical green.

B3 -- reserved A-classes A6/A7/A9: taxonomy A1-A12-v3.1 advertises twelve
classes but _pick_a_class emits only nine. A6/A7/A9 are now an explicit
reserved contract in _consts.RESERVED_A_CLASSES (mirroring RESERVED_DIAGNOSTIC_
SLOTS D21-D23). A static-AST reachability test forces the contract to track the
code, so a future wiring of A6/A7/A9 must update the reserved set in lock-step.

B4 -- advisory (unused) evidence: lep_proximity (D16), bohr_ap_length (D11),
mpemba_expansion_alpha (D20) are surfaced in evidence for audit but do NOT drive
class/verdict/confidence. classification.ADVISORY_EVIDENCE_KEYS names the
contract; a metamorphic test proves non-influence (perturbing each key across
{0, +/-1e9, +/-inf, nan} leaves the decision invariant). Wiring any is a
class-influencing, FP-risk design decision deferred to a dedicated PR.

Verification (local, py3.12): anchors 19 passed/2 QuTiP-skipped; V1-V5 golden
32 passed; new debt suite 8 passed; full suite 471 passed/8 skipped;
ruff clean; mypy 50 files clean.

Closes #70

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

agent:claude PR authored by Claude Code

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant