Feat/campaign methodology instruments - #6
Merged
Conversation
…g schedule Given a per-position class `schedule` (a k-value additive selector, e.g. derived from a related message), fit shift(i)=a[i%period]+d[schedule[i]] FREELY (the period-p additive plus per-class offsets) by monogram coordinate ascent, then z-score the de-keyed IoC against the same fit on SHUFFLED schedules. An additive shift is a bijection within each residue class, so the period-p key is un-recoverable from the ciphertext alone (every within-class statistic is invariant). Conditioning on the schedule defeats that: each (i%period, class) cell is a pure Caesar, so the de-keyed IoC snaps toward the language's iff the schedule is real. Fitting the key freely — rather than pinning it to a noisy alignment estimate before testing the schedule — is what makes a real schedule detectable. `max_offset` bounds the offsets to a "slight variation" range. Test (true schedule snaps z~7 / shuffled z~0), CHANGELOG; ruff + mypy clean; full "not slow" suite green. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EJjjwhsWqwb5GRvD4QiA5i
census: family-level exclusion instrument (which families can emit an observed statistic at the observed length, with structural infeasibility reported apart from distributional misses). crib_csp: known-plaintext recovery for bifid5(+p7 additive) as CP-SAT constraint propagation — register-free, UNSAT is a proof, longer cribs strictly help. evidence: Finding refuses to render without plant gate + matched null + coverage + family-size correction. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UrpA9d1jGn7fzbB1aV61JK
…ct, scoped closures, VOID state searched_fraction/Coverage.of_axes: intended-space size is the product of the declared free axes, so a coverage claim cannot silently hold an axis fixed. with_power: a negative whose measured power on same-shape plants is below MIN_POWER_Z renders as 'silent' — the statistic could not have seen the signal. scoped: a complete negative that names what it does NOT close renders as 'closed (scoped)' with reopen conditions, so it cannot be quoted as a family kill. voided: a broken-instrument result renders as 'void', distinguishable from a trusted null and citable as neither positive nor negative. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UrpA9d1jGn7fzbB1aV61JK
…le vs 2-sample labeling, per-family power expected_null_max/bank_scaling: the expected max of a noise bank grows like sqrt(2 ln n) — compute the margin BEFORE scaling a candidate bank, because a test justified at n=200 can have zero power left at n=7000. labeling_power: 2-sample AUC and held-out 1-sample accuracy answer different questions; quoting the former for a one-ciphertext claim is a measured false- closure mode. Returns both. family_power: per-family plant calibration (z vs matched null on each plant, P(z >= threshold)) — converts any statistic into a detector with measured power, feeding evidence.Finding.with_power. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UrpA9d1jGn7fzbB1aV61JK
…is invariant under null_is_degenerate + NullResult.degenerate encode the selection rule: an honest null preserves what the objective is GIVEN and destroys what it puts UNDER TEST. A statistic that is a function of what the null preserves (e.g. coset multisets under a coset-preserving shuffle) yields a point-mass null distribution that can never be beaten — its p=1 reads exactly like a real negative and is now flagged. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UrpA9d1jGn7fzbB1aV61JK
…or-normalized cross-model scores GaugeNormalizedScorer: an omitted/relabelled alphabet letter is a GAUGE — the correct decode emerges Caesar-shifted and the n-gram model scores it as junk, leaving the climb with no gradient toward the answer (one wrong gauge value was a measured 84% of a score cliff). Normalizing the shift away inside the objective (unigram chi-squared picks it, then the n-gram model scores) makes all 26 frames reachable from a single search. excision_score: score exactly the letters a contamination hypothesis claims are language — max over removing a contiguous k-block or one mod-width column — instead of letting an embedded key block drag every placement to junk. NgramScorer.anchored / anchored_score: normalize any model to its own random/language anchors so scores are comparable across models; a route-register decode sits at the English model's ghost ceiling but ~1.0 register-matched. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UrpA9d1jGn7fzbB1aV61JK
…e-pad annihilator
harmonic_corroboration: a real period p FORCES elevation at 2p (its cosets are
subsets), so {p,2p} is one signal, not two multiplicity draws — a cheap
refutation lever for a pinned period claim, complementing the scan-wide
period_family_significance.
lag_difference_scan: IoC of the mod-26 lag-L difference stream — goes
plaintext-like for a cycled running key (difference of two English letters) and
IS the plaintext for a ciphertext autokey at lag L (head returned for reading).
Empirical permutation null with scan-max correction; the analytic iid variance
is measured-wrong here (overlap dependence, z≈6 on random text).
separable_pad_annihilator: key-free detector for k[i]=a[i%p]+b[i%q] — lag-p
difference cancels a, per-mod-q-class best-shift LLR against the predicted
letter-difference distribution absorbs b. The tempting both-streams-at-once
second difference is POWERLESS (two convolutions flatten English to uniform,
measured z≈0); this design measures z≈3 at 450 letters, z≈7 at 1200.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UrpA9d1jGn7fzbB1aV61JK
…er cliff detector Generic (key, neighbors, objective) landscape profiling to run on a plant BEFORE scaling a search. Probe A: is the truth even a local max — a failure is a verdict on the objective, no search improvement helps. Probe B: do seeded steepest-ascent climbs reach truth (basin size); verdicts identifiable / needs-richer-seeds / dead-lane. Probe C (crib_floor): recovery rate vs letters locked to truth — the honest 'how much crib does the attack need' number. damage_ladder: score vs key damage with adjacent-level AUC; flags the cliff shape (first gap carries >=70% of the drop, deeper rungs stop separating) where 'SA reached 84% of the score' means nothing. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UrpA9d1jGn7fzbB1aV61JK
…er the cipher registry Fingerprint statistics rank families; solvers exclude them (a family can match eight statistics at mean |z| 0.4 and still be decode-refuted with power). This runs each registered cracker at the target's exact length on its own genuine plant (GATE), random letters (CTRL — never an absolute bar, search inflates structureless scores), and the target, anchoring the target between the bands. A solver whose gate never separates from its ctrl at this length is UNGATED and its row is suppressed rather than believed. length_threshold sweeps n to separate 'cipher is unclimbable' from 'text is too short'. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UrpA9d1jGn7fzbB1aV61JK
…sweep embed plants k non-language characters in the shapes real constructions embed them (contiguous block, scattered interrupters, grid column, periodic coset); sensitivity_sweep measures how far each shape/size moves a statistic off its clean value and reports the per-shape insert BUDGET — the k at which an exclusion built on that statistic dissolves. An exclusion quoted without its insert budget silently assumes a pure payload. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UrpA9d1jGn7fzbB1aV61JK
…ore its negatives count Tier A reproduces a solved sibling case within top-N (catches harness rot end-to-end: wrong plumbing, broken scoring, a solver scoring heap garbage). Tier B recovers the attack's own planted structure at the target length, built by THIS module's trusted encoder — never the attack under test, so a self-consistently-wrong implementation cannot pass on its own mis-encoding. A failed tier makes the attack VOID — distinct from a negative — and the result feeds evidence.Finding.voided directly. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UrpA9d1jGn7fzbB1aV61JK
…s/telegraphic/numeric registers Plant-gate recall is register-specific: a null proven on prose plants does not transfer to wordlist/coded/telegraphic payloads. register_corpus synthesizes deterministic corpora per register for (a) register-diverse plant gates and (b) register-matched genre models, gated by the rule that a register model must beat the prose model on its own register before any search runs behind it. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UrpA9d1jGn7fzbB1aV61JK
…gn identifiers Puzzle-specific identifiers (puzzle tags, campaign-exact axis sizes) replaced with neutral equivalents in docstrings, tests and the changelog — the library stays campaign-agnostic per the repo's convention. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UrpA9d1jGn7fzbB1aV61JK
…or mypy The base class lives on the module object returned by the lazy ortools import (what keeps [csp] an optional extra), which mypy cannot resolve as a name. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UrpA9d1jGn7fzbB1aV61JK
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
No description provided.