|
| 1 | +# Feature: M0 — the two de-risking spikes (SPIKE-1 SubstKit toy, SPIKE-2 normalizer probe) |
| 2 | + |
| 3 | +## Summary |
| 4 | + |
| 5 | +The two week-one spikes from the RFC-1 program plan §1, specified to |
| 6 | +opening-an-issue precision. SPIKE-1 (the SubstKit toy) de-risks the |
| 7 | +stage-2 binder-metatheory grind — risk row 1 of the metatheory sketch, |
| 8 | +fallback F-A — by proving the two load-bearing de Bruijn lemmas end to end |
| 9 | +on a 3-constructor toy formula language before `Strat/SubstKit.lean` is |
| 10 | +scheduled. SPIKE-2 (the normalizer probe) de-risks the stage-2 TV-query |
| 11 | +design — risk row 3, fallback F-C — by measuring the syntactic-equality |
| 12 | +hit rate of a prototype normalizer over the conformance corpus's |
| 13 | +combinator contracts in raw-quantifier form. Both gate M0: no stage-1 or |
| 14 | +stage-2 implementation issue opens until both acceptance criteria are met. |
| 15 | +Umbrella: `.design/thermite2-program.md` (REQ-1). Baseline: |
| 16 | +`dollspace-gay/Thermite @ c46da3ac` or later. |
| 17 | + |
| 18 | +## Requirements |
| 19 | + |
| 20 | +### SPIKE-1 — the SubstKit toy |
| 21 | + |
| 22 | +- REQ-1: A toy formula language lives at `lean/Thermite/Spike/SubstKit.lean` |
| 23 | + inside the existing lake package (`lean/lakefile.toml`), namespace |
| 24 | + `Thermite.Spike`, core-Lean-only (no Mathlib import — the same hot-path |
| 25 | + discipline as `lean/Thermite/Denote.lean`). Exactly three `Frm` |
| 26 | + constructors (one atom, one connective, one binder) over a de Bruijn |
| 27 | + term language with `lift` and `subst`, denoting into `Bool`. The carrier |
| 28 | + is *parametric*, not fixed: a `CarrierAssign`-lite with one opaque sort |
| 29 | + carrying a **hand-rolled finiteness witness** — an enumeration `List` |
| 30 | + plus a completeness proof (`∀ x, x ∈ enum`) and `DecidableEq` (core |
| 31 | + Lean, via `deriving`), **not** Mathlib's `Fintype`. This is a |
| 32 | + deliberate correction to the metatheory sketch's CarrierAssign (which |
| 33 | + literally writes `Fintype`, a Mathlib type, contradicting the sketch's |
| 34 | + own §4 core-Lean-only-hot-path claim): SPIKE-1 must determine whether |
| 35 | + finite-carrier `Bool`-denotation can stay core-Lean-only with a |
| 36 | + hand-rolled witness, because "fights universe/`Decidable` plumbing" is |
| 37 | + one of the two failure signals the spike exists to probe, and the |
| 38 | + Mathlib-vs-core verdict is itself a stage-2 `Strat/Carrier.lean` input. |
| 39 | + (The lakefile pulls Mathlib transitively via the `smt` require, so a |
| 40 | + `Fintype` import would *compile* — which is exactly why the discipline |
| 41 | + must be enforced by intent here, not by the build failing.) |
| 42 | +- REQ-2: `sdenote_push_lift` and `sdenote_subst` (the metatheory sketch |
| 43 | + §4's statement shapes, specialized to the toy) are proven end to end: |
| 44 | + zero `sorry`, axioms of both lemmas ⊆ {propext, Classical.choice, |
| 45 | + Quot.sound} under `#print axioms`. |
| 46 | +- REQ-3: A micro-pin `lean/Thermite/Spike/PinBrokenLift.lean` refutes a |
| 47 | + deliberately broken `lift` (off-by-one cutoff shift) in the repo's |
| 48 | + established `Pin*.lean` style: the wrong lemma instance is disproven on |
| 49 | + a concrete small carrier via `decide`. |
| 50 | +- REQ-4: The conventions note — the spike's real deliverable — lands at |
| 51 | + `.design/strat/substkit-conventions.md` (one page): lift direction, |
| 52 | + environment push order, binder-traversal convention, the exact lemma |
| 53 | + statement shapes as proven (verbatim-inheritable by |
| 54 | + `lean/Thermite/Strat/Syntax.lean`), the final lemma count, the |
| 55 | + **carrier verdict** (did the hand-rolled finiteness witness keep the |
| 56 | + denotation core-Lean-only, or was Mathlib's `Fintype` needed? — a |
| 57 | + direct input to stage-2 `Strat/Carrier.lean` and a resolution of the |
| 58 | + metatheory sketch's §2/§4 tension), and an |
| 59 | + explicit failure-signal verdict: if the toy needed more than 40 lemmas |
| 60 | + or the instance plumbing fought back, the note says so and a fallback |
| 61 | + F-A review (locally nameless / single-prefix S₂⁻) is opened before the |
| 62 | + real SubstKit is scheduled. |
| 63 | + |
| 64 | +### SPIKE-2 — the normalizer probe |
| 65 | + |
| 66 | +- REQ-5: The fixture set is built per **combinator shape**, not per |
| 67 | + instance, to keep the hit-rate denominator meaningful. For each of the |
| 68 | + (≤8) registry combinator shapes that appears, write two raw-quantifier |
| 69 | + S₂ expansion templates: a production-style spelling (following the |
| 70 | + shape `thermite-lower/src/lower.rs` emits for that combinator today) |
| 71 | + and a reference-style spelling (following `lean/Thermite/RefEncode.lean`). |
| 72 | + Apply each shape's templates to (a) every combinator-bearing clause in |
| 73 | + `conformance/*.th` — which the plan analysis confirms is **only |
| 74 | + `binary_search.th`, 4 clauses** (`req sorted`, the `ens` None-arm |
| 75 | + `forall_in`, `inv forall_below`, `inv forall_from`) — and (b) a |
| 76 | + generator-drawn sample of instances of those same shapes from |
| 77 | + `thermite-tv/src/gen.rs`'s `gen_combinator` (≥ 5 per shape), so the |
| 78 | + denominator is ≥ ~30 rather than 4. Fixture home: |
| 79 | + `thermite-tv/tests/fixtures/strat_probe/`, one file per instance pair, |
| 80 | + README naming the source: a scheme-validated address for `inv` |
| 81 | + clauses (`binary_search.loop#1.inv#2`/`inv#3`) and an informal |
| 82 | + designation for `req`/`ens` clauses (`binary_search.req`, |
| 83 | + `binary_search.ens.None`), since `thermite-syntax/src/address.rs` |
| 84 | + addresses loop/inv/dec but not req/ens. |
| 85 | +- REQ-6: A prototype normalizer at `thermite-tv/src/normalize.rs` — |
| 86 | + experimental, exported but not referenced by any TV pipeline code path — |
| 87 | + implementing the four passes from metatheory §8.2 layer 1: NNF, prenex, |
| 88 | + canonical bound-name/de Bruijn form, atom ordering. Unit tests cover |
| 89 | + each pass on the fixtures (no soundness lemmas in the spike — those are |
| 90 | + stage-2 work; the spike wants the *number*). |
| 91 | +- REQ-7: The hit rate — the fraction of fixture pairs whose normalized |
| 92 | + forms are syntactically equal — is computed by a test/bin target, |
| 93 | + reported as a number in the SPIKE-2 issue and recorded in the fixtures |
| 94 | + README, **broken out two ways**: the corpus-only rate (n=4, flagged as |
| 95 | + small-n and not threshold-bearing on its own) and the |
| 96 | + corpus+generated rate (n ≥ ~30, the threshold-bearing number). The |
| 97 | + decision rule from the program plan is then applied to the |
| 98 | + corpus+generated rate and recorded: hit rate ≥ 90% → the stage-2 |
| 99 | + semantic TV phase ships as a thin fallback; below → a dedicated |
| 100 | + quantified-equivalence-query design issue opens before stage 2 |
| 101 | + commits. The per-shape breakdown is also reported so a single |
| 102 | + pathological shape is visible rather than averaged away. |
| 103 | + |
| 104 | +### The gate |
| 105 | + |
| 106 | +- REQ-8: M0 closes only when AC-1 through AC-7 hold. Per the umbrella's |
| 107 | + Q-TRACK split: each spike gets a GH issue on `dollspace-gay/Thermite` |
| 108 | + (gate-visible), with implementation increments tracked as crosslink |
| 109 | + issues referencing it. No stage-1 or stage-2 implementation issue opens |
| 110 | + before both GH spike issues close with results. |
| 111 | + |
| 112 | +## Acceptance Criteria |
| 113 | + |
| 114 | +- [ ] AC-1: `lake build` (from `lean/`) is green with the two Spike files |
| 115 | + present; `grep -r sorry lean/Thermite/Spike/` returns nothing; |
| 116 | + `import Mathlib` (and any `Mathlib.*` import) is absent from the Spike |
| 117 | + files (the core-Lean-only discipline); `#print axioms` on |
| 118 | + `sdenote_push_lift` and `sdenote_subst` shows only the gated three or |
| 119 | + fewer, run as a spike-local probe (not via `make audit`, whose theorem |
| 120 | + list is fixed and must not be perturbed by Spike files). (REQ-1, REQ-2) |
| 121 | +- [ ] AC-2: `PinBrokenLift.lean` contains a `lift` variant differing only |
| 122 | + in the cutoff arithmetic, and a `decide`-discharged theorem showing the |
| 123 | + push/lift lemma *fails* for it on a concrete carrier. (REQ-3) |
| 124 | +- [ ] AC-3: `.design/strat/substkit-conventions.md` exists with all six |
| 125 | + required sections (lift direction, push order, traversal, statement |
| 126 | + shapes, lemma count, carrier verdict) and a one-line failure-signal |
| 127 | + verdict. (REQ-4) |
| 128 | +- [ ] AC-4: If the verdict reports >40 lemmas or instance-plumbing |
| 129 | + fights, an F-A review issue exists before any `Strat/SubstKit.lean` |
| 130 | + issue is opened; otherwise the note states the count and that no |
| 131 | + trigger fired. (REQ-4) |
| 132 | +- [ ] AC-5: Each appearing combinator shape has production-style and |
| 133 | + reference-style expansion templates; they are applied to all 4 |
| 134 | + `binary_search.th` clauses and to ≥5 generator-drawn instances per |
| 135 | + shape, yielding ≥ ~30 fixture pairs under |
| 136 | + `thermite-tv/tests/fixtures/strat_probe/`; the README lists each |
| 137 | + source (scheme-validated address for `inv`, informal for `req`/`ens`); |
| 138 | + `cargo test -p thermite-tv` passes the normalizer unit tests. |
| 139 | + (REQ-5, REQ-6) |
| 140 | +- [ ] AC-6: No module in the TV pipeline path imports |
| 141 | + `thermite_tv::normalize` (mechanically: `grep -rn "normalize" thermite-tv/src/ forge/src/` shows |
| 142 | + no non-test, non-`normalize.rs` consumer). (REQ-6) |
| 143 | +- [ ] AC-7: Both hit-rate numbers (corpus-only n=4, flagged small-n; and |
| 144 | + corpus+generated n ≥ ~30, threshold-bearing) plus the per-shape |
| 145 | + breakdown appear in the SPIKE-2 GH issue and the fixtures README, with |
| 146 | + the decision rule's branch recorded against the corpus+generated rate; |
| 147 | + if < 90%, a quantified-equivalence design issue exists. (REQ-7) |
| 148 | +- [ ] AC-8: Two GH spike issues exist (open before any stage-labeled |
| 149 | + issue) quoting the acceptance text from the program plan §1 (GH issue |
| 150 | + #2, third comment — quoted via `gh issue view 2`, since the program |
| 151 | + plan lives as an issue comment, not a repo file), and both are closed |
| 152 | + with results before any stage-1/stage-2 implementation issue opens. |
| 153 | + (REQ-8) |
| 154 | + |
| 155 | +## Architecture |
| 156 | + |
| 157 | +**SPIKE-1.** Lives inside the audited lake package |
| 158 | +(`lean/lakefile.toml`) as a `Thermite.Spike` namespace — zero new build |
| 159 | +plumbing, and the de Bruijn conventions get proven against the exact |
| 160 | +toolchain pin (`lean/lean-toolchain`) that `Strat/` will use. The |
| 161 | +`make audit` axiom probe targets a fixed theorem list, so Spike files |
| 162 | +don't perturb it; the spike's own axiom discipline is checked by AC-1 |
| 163 | +directly. Style models in-tree: `lean/Thermite/Denote.lean` (Bool-valued |
| 164 | +total denotation), the `lean/Thermite/Pin*.lean` battery (the |
| 165 | +refute-a-plausibly-wrong-neighbor shape REQ-3 copies). The whole |
| 166 | +`Spike/` directory is deletable scaffolding: it is removed in the same |
| 167 | +change that lands `lean/Thermite/Strat/Syntax.lean` inheriting its |
| 168 | +conventions, with the conventions note (`.design/strat/`) as the |
| 169 | +surviving artifact — the note also seeds the `.design/strat/` area where |
| 170 | +stage-2 house docs will live. |
| 171 | + |
| 172 | +**SPIKE-2.** Lives in `thermite-tv` because its production successor is |
| 173 | +stage-2's two-phase TV (metatheory §8.2): the prototype normalizer |
| 174 | +evolves in place rather than being rewritten. `thermite-tv/src/gen.rs` |
| 175 | +(the SplitMix64 generator) and the existing TV pipeline are untouched — |
| 176 | +`normalize.rs` is a leaf module consumed only by its tests and the |
| 177 | +hit-rate target until stage 2 wires it in behind `nnf_sound`/ |
| 178 | +`prenex_sound` lemmas. The expansion templates are hand-written because |
| 179 | +neither emitter exists yet for stratified forms: the production-style |
| 180 | +spelling mimics `thermite-lower/src/lower.rs`'s current combinator |
| 181 | +emission conventions, the reference-style mimics |
| 182 | +`lean/Thermite/RefEncode.lean`'s — the two real columns the stage-2 TV |
| 183 | +will eventually compare. The hand-work is bounded *per combinator |
| 184 | +shape* (≤8 shapes), then instantiated across the 4 corpus clauses plus |
| 185 | +generator-drawn instances (read out of the existing `gen_combinator` — |
| 186 | +no new generator productions, those are stage-2 binder work) so the |
| 187 | +threshold-bearing denominator is meaningful rather than n=4. This is the |
| 188 | +plan analysis's most material correction: a 90% bar over 4 clauses is |
| 189 | +4/4, which the corpus alone cannot support. This mimicry is the probe's known |
| 190 | +approximation, and it biases the measured hit rate *downward* if |
| 191 | +anything (real stage-2 emitters can be nudged toward convergence, |
| 192 | +fallback F-C step 1), so a high measured rate is trustworthy evidence |
| 193 | +and a low one triggers the design issue — the asymmetry is safe. |
| 194 | + |
| 195 | +**What the spikes deliberately do not do:** no soundness lemmas for the |
| 196 | +normalizer passes, no `Strat/` modules, no classifier, no changes to |
| 197 | +`forge/`, no generator binder productions. Each of those belongs to a |
| 198 | +stage with its own design pass. |
| 199 | + |
| 200 | +## Open Questions |
| 201 | + |
| 202 | +None. The two genuine candidates — fixture format and emission-spelling |
| 203 | +derivation — are resolved by adopted defaults above (plain fixture files |
| 204 | +under `thermite-tv/tests/fixtures/strat_probe/`; spellings derived from |
| 205 | +the v1 emitters' current shapes), both cheap to revisit at stage-2 |
| 206 | +design time. |
| 207 | + |
| 208 | +## Out of Scope |
| 209 | + |
| 210 | +- The real `Strat/SubstKit.lean` (~25-lemma kit) and all |
| 211 | + `lean/Thermite/Strat/` modules — stage 2. |
| 212 | +- Normalizer soundness lemmas (`nnf_sound`, `prenex_sound`) and wiring |
| 213 | + the normalizer into TV — stage 2. |
| 214 | +- The classifier, the sort graph, restratification — stage 2. |
| 215 | +- Generator binder productions in `thermite-tv/src/gen.rs` — M2b. |
| 216 | +- Any `forge/` or `thermite-syntax/` change — stage 1. |
| 217 | + |
| 218 | +--- |
| 219 | + |
| 220 | +*M0 spike spec · child of `.design/thermite2-program.md` (REQ-1) · |
| 221 | +sources: RFC-1 program plan §1, metatheory sketch §4/§8.2/§11 · |
| 222 | +baseline `dollspace-gay/Thermite @ c46da3ac`.* |
0 commit comments