DashboardThree-Axis ProbesCandidate Registry Robustness › Iter 06

2026-06-16-candidate-registry-robustness-sota · iteration 06 · 2026-06-16

Iteration 06 — Lifecycle moves now policed (D3) + provenance backfilled onto all 44 rows DONE

Stage changes are now checked against a legal transition table (illegal jumps are refused), and every existing candidate was stamped with a content-identity hash so the dedup system covers the whole catalog.

✅ What has been grounded

Lifecycle moves are policed (D3). --set-stage now consults a single transition table: a move is allowed only if it's a legal edge. Illegal jumps like banned → promoted or pending → promoted are refused with a message listing what IS allowed. The promotion path becomes machine-checked, not a human convention. A --transitions command prints the whole table.
Every existing candidate now carries content-identity provenance. A one-time --migrate stamped all 44 rows with a dedup record + a content hash (spec_hash). Historical candidates are now first-class in the dedup system: re-adding any of them is caught by the O(1) content hash, not only by name. The migration is idempotent (re-running changes nothing).
Verified safely, then applied to the real ledger. On a throwaway copy: a legal move (pending → evaluating) was allowed; an illegal move and a terminal-state move were both rejected; migrate ran 44→0 (idempotent). Then on the real ledger: 44 rows migrated, --validate passes, and all ids/stages/history are unchanged — purely additive.
Still backward compatible. The new dedup field is additive; every existing command behaves the same; the 44 rows still validate. No new dependencies.

➡️ What I am doing next

1
Implement P2: pin each axis verdict to an input_lock + subject_digest (a verdict can't be reused on a different data window), and add the machine-enforced → promoting guard (all three axes PASS + both leakage gates PASS).
2
Add tamper-evident, hash-chained history (P2/D6) so any out-of-band edit to a past row is detectable.
3
Surface /registry:doctor + /registry:check-full (with mise tasks) per the Eon slash-command standard.
4
Optional: enable the semantic Tier-3 (offline embedding) for abbreviation synonyms.

🎯 How this moves us toward the end goal

This makes the stage-by-stage tracking trustworthy — exactly your requirement that a candidate's 'status is specifically stated according to its current stage'. A candidate can no longer silently jump to an illegal stage, and every candidate (old and new) is now identifiable by content, so the novelty gate covers the entire catalog. Once P2 lands, promotion becomes a fully machine-checked gate; until then the registry already refuses illegal lifecycle moves and records provenance on every row.

The legal lifecycle transitions (enforced)

identified   → pending · out_of_scope · banned
pending      → evaluating · deferred · out_of_scope · banned
evaluating   → evaluated · pending · deferred · out_of_scope
evaluated    → promoting · deferred · banned · out_of_scope
promoting    → promoted · evaluated · deferred · banned
promoted     → deferred · banned
deferred     → pending · banned · out_of_scope
out_of_scope → pending
banned       → ∅  (terminal / frozen)
Inspect: python3 findings/evolution/shared_data/candidate_ledger.py --transitions · backfill: --migrate (idempotent) · novelty: --novelty "NAME".