2026-06-16-candidate-registry-robustness-sota · iteration 03 · 2026-06-16
Iteration 03 — Operator steer — Novelty ≠ Orthogonality (terminology locked) DONE
The operator caught a conflation in iteration 02: novelty and orthogonality are two DISTINCT gates. Locked the definition and corrected every artifact that blurred them.
✅ What has been grounded
Two different gates — never one word. Novelty = uniqueness against the catalog / existing chronicles (is this already recorded anywhere in our project?). Orthogonality = uniqueness against the existing columns — i.e. does it carry new information beyond what we already compute? Orthogonal includes new information; novelty does not. A candidate can be novel but not orthogonal (a renamed duplicate of a column) — so the two checks are independent and run at different stages.
Where the loop uses each. Stage 1 — Novelty check (fast, the dedup funnel against the chronicles) → produces the unique verdict, i.e. unique-and-pending. Stage 2 — Orthogonality test (the expensive bigblack probe against the panel of existing columns) → the real orthogonality verdict. The registry's pre-filter is a novelty gate; it does NOT and cannot decide orthogonality.
The error and the fix. Iteration 02 wrote 'a defensible orthogonal/novel claim' — that conflated the two. Corrected to: the input-lock pinning makes a defensible orthogonality claim; novelty is the separate, earlier catalogue gate. Fixed in the iteration-02 page and in the design SSoT (REGISTRY-ROBUSTNESS-BLUEPRINT.md), which now carries an explicit 'two distinct gates' definition.
➡️ What I am doing next
1Proceed to P0 implementation in candidate_ledger.py: the three-tier dedup funnel — which is precisely the NOVELTY gate (catalogue-unique / covered / needs_review) — plus the append-only safe-write path. Orthogonality stays the separate Stage-2 bigblack probe, untouched by this work.
2Add migrate() for the 44 rows, then P1 (lifecycle FSM + opaque ids) and P2 (input-lock verdict pinning + hash-chained history).
3Emit iteration-04 on the P0 implementation and re-sync the live dashboard.
🎯 How this moves us toward the end goal
Getting this distinction exactly right is load-bearing: the registry's fast pre-filter is a novelty gate (cheap, catalogue-based), and conflating it with orthogonality would risk either skipping the real orthogonality test or over-claiming. Keeping them separate means the loop spends cheap effort proving novelty up front and reserves the expensive bigblack compute for the orthogonality test only on candidates that are genuinely new to the catalog — which is the whole point of the pre-filter.
Novelty vs Orthogonality — the locked definition
| Novelty | Orthogonality |
|---|
| Question | Is it already in our catalog / chronicles? | Does it add information beyond existing columns? |
| Checked against | The catalog (both repos' ledgers, schema, ban-list, audits) | The panel of existing feature columns, on real bars |
| Mechanism | Dedup funnel (content-hash → lexical → semantic) | Orthogonality probe (|ρ|, conditional dependence) across regimes |
| Stage / cost | Stage 1 — fast, cheap, the pre-filter | Stage 2 — expensive, bigblack compute |
| Verdict | covered / unique / needs_review → unique = novel | orthogonal PASS / WATCH / FAIL |
A candidate can be novel but not orthogonal (new name, redundant information) or already catalogued (not novel). The two gates are independent — never collapse them into one word.