|
| 1 | +# P-037 A18-1F: population decomposition, final re-plan (pre-registered) |
| 2 | + |
| 3 | +> Status: **PRE-REGISTERED.** This file is committed before any executable |
| 4 | +> change of this gate. The boundaries below do not move after this SHA. |
| 5 | +> |
| 6 | +> - Base: `ca1433661cf6b62f10dfc4701fc9067647f2b612`, the exact head of #376 |
| 7 | +> (B1 evidence completion). It is **not** the over-budget #377. |
| 8 | +> - Branch: `research/p037-a18-1f`. |
| 9 | +> |
| 10 | +> `F` means **final attempt**. It is the last budget re-plan for the A18 |
| 11 | +> population-decomposition hypothesis. If this gate reaches any of its three |
| 12 | +> caps unfinished, the approach is **killed**. There will be no A18-1G. |
| 13 | +
|
| 14 | +## 0. Owner decision (OWNER RULING, 2026-09-28, recorded in meaning) |
| 15 | + |
| 16 | +- **#377 (A18-1R)** stays unchanged as a STOP research artifact: |
| 17 | + `STATE: STOP — 192 / 180`, `RUN: NONE`. It is not run, its cap is not |
| 18 | + edited, and it is not minified down to 180. |
| 19 | +- **#376** is accepted as case-4 evidence infrastructure. Its scope is exact: |
| 20 | + - Its 36-row snapshot is a **new supplemental per-row baseline** for A18. |
| 21 | + - It reproduces B1's aggregates and the 8 rows B1 committed individually. |
| 22 | + - It proves nothing historical, row by row, about the other 28 rows, |
| 23 | + because B1 never committed them per row. |
| 24 | + - The differing extractor DLL sha stays disclosed. |
| 25 | +- **Why a re-plan is allowed once.** The #377 STOP showed the cost |
| 26 | + structure. About 140 lines are measurement, coverage and reporting; about |
| 27 | + 52 are the kill harness. The decomposition itself does not grow into a new |
| 28 | + solver. So the premise is alive; the executable falsifiers were mispriced. |
| 29 | +- **Why the budget is split.** A new, prospectively frozen, split budget is |
| 30 | + allowed. Moving the falsifiers into another file does **not** make their |
| 31 | + lines free: the test module has its own cap *and* counts toward the total. |
| 32 | + The split is architectural, not a tax shelter. |
| 33 | + |
| 34 | +## A. Question |
| 35 | + |
| 36 | +Unchanged from A18-1 and A18-1R. On the frozen population `571669e`, is the |
| 37 | +already-registered two-seam model sufficient with **only** the known |
| 38 | +normalization reasons? |
| 39 | + |
| 40 | +```text |
| 41 | +G <-> L_canonical semantic_class: EQUAL | SUMMARY_REFINEMENT | LEGACY_HONESTY | UNEXPLAINED |
| 42 | +L_canonical <-> L_actual normalization_reason: EQUAL | CONSUMES_PARAM_FOLD | ARGUMENT_SHAPE_LOSS | UNEXPLAINED |
| 43 | +``` |
| 44 | + |
| 45 | +A third normalization mechanism, however understandable, is |
| 46 | +`RESULT: FAIL — A18-1F NORMALIZATION MODEL INCOMPLETE`. It is never an |
| 47 | +invitation to extend the enum. |
| 48 | + |
| 49 | +## B. Rows |
| 50 | + |
| 51 | +- The rows are exactly the **36** comparable rows of the #376 snapshot |
| 52 | + `docs/evidence/p037-b1/comparable-summary-rows.json`: 28 `EQUAL` and 8 |
| 53 | + `UNEXPLAINED`. Each is a B1 summary coordinate with both `G` and |
| 54 | + `L_actual`. |
| 55 | +- They are recomputed from the frozen population with the unchanged B1 |
| 56 | + instrument, one row per coordinate whose class is not |
| 57 | + `NO_GUARDED_EVIDENCE`. The row key is `(document, method, index)`. |
| 58 | +- The 68 `NO_GUARDED_EVIDENCE` rows and all application-level rows are |
| 59 | + outside this gate. |
| 60 | + |
| 61 | +## C. Definitions (fixed before measuring) |
| 62 | + |
| 63 | +For each document, the frozen facts are extracted with the unchanged B1 |
| 64 | +instrument. `L_actual`, `G` and B1's class come from `own-guarded-report` on |
| 65 | +those facts as emitted. |
| 66 | + |
| 67 | +### C.1 Forward sites and eligibility |
| 68 | + |
| 69 | +- **Coordinate:** a summary row `(method, index)` of the document's report |
| 70 | + whose function is in the document's facts. |
| 71 | +- **Forward site of a coordinate:** a sidecar (`guarded_facts.calls`) call in |
| 72 | + that function in which the coordinate's parameter (by `ordinal`) fills a |
| 73 | + `param` slot. |
| 74 | +- **Eligibility** is decided from frozen facts only. A site is **eligible** |
| 75 | + (canonicalized) when all of these hold: |
| 76 | + - **E1:** the parameter fills exactly one slot of that call; |
| 77 | + - **E2:** exactly one legacy body op names the parameter at the call's |
| 78 | + `statement_line`, and no other site already canonicalized that op; |
| 79 | + - **E3:** the callee coordinate resolves to exactly one report summary row |
| 80 | + `(callee, ordinal = slot)`, which gives the callee `index`. |
| 81 | +- A site that fails E1–E3 is **broken**. |
| 82 | +- **Eligibility never reads `L_actual`.** The #375 rule "rewrite only if the |
| 83 | + callee's `L_actual` disagrees" is forbidden. It is kept only as the |
| 84 | + test-only `local` mode that F0 must kill. |
| 85 | + |
| 86 | +### C.2 L_canonical and semantic_class |
| 87 | + |
| 88 | +- **`L_canonical`:** the unchanged production MOS, run once per document over |
| 89 | + facts in which **every** eligible forward site of **every** coordinate is |
| 90 | + represented as the canonical legacy `call`. That is A18-0's positional form: |
| 91 | + `{"op":"call","callee":…,"sig":…,"line":statement_line,"args":["_"]*callee_index+[param]}`. |
| 92 | + This applies whatever the site's current op is, and a site that is already |
| 93 | + a `call` is rewritten to the same form. |
| 94 | +- **`semantic_class`:** the class `own-guarded-report` assigns to the row on |
| 95 | + the canonical facts, which is the existing rule `G <-> L_canonical`. |
| 96 | +- **`G` must not move:** the row's `G` on the canonical facts must equal its |
| 97 | + `G` on the original facts. |
| 98 | + |
| 99 | +### C.3 Forward closure and broken propagation |
| 100 | + |
| 101 | +- **Forward closure of a row:** its own coordinate, plus every coordinate |
| 102 | + reachable through the callee coordinates of eligible sites, transitively. |
| 103 | +- **Broken closure:** the closure contains a broken site, or a coordinate |
| 104 | + with no entry (for example, its function is absent from the facts). A row |
| 105 | + whose closure is broken is normalization **`UNEXPLAINED`**, whatever its own |
| 106 | + site looks like, and even when `L_actual == L_canonical`. A canonical |
| 107 | + surface that could not be built honestly proves nothing. |
| 108 | + |
| 109 | +### C.4 Site mechanism and local witness |
| 110 | + |
| 111 | +The mechanism comes from the site's actual op. |
| 112 | + |
| 113 | +| actual op | mechanism | local witness | |
| 114 | +|------------|-----------------------|---------------| |
| 115 | +| `call` | `EQUAL` | not needed | |
| 116 | +| `release` | `CONSUMES_PARAM_FOLD` | the actual representation at this honest-forward site is `release`, and this site was replaced by the canonical forward in the canonical facts | |
| 117 | +| `use` | `ARGUMENT_SHAPE_LOSS` | the fold witness above, plus the already-registered wrapper probe: the frozen source with only `(T)x` / `x!` removed on that line re-extracts to `release` there | |
| 118 | +| other | `UNKNOWN` | none | |
| 119 | + |
| 120 | +- A `use` site whose wrapper probe fails is `UNKNOWN`. |
| 121 | +- The probe is evaluated wherever it can decide a reason, which means at |
| 122 | + every `use` site in the closure of a row with `L_actual != L_canonical`. |
| 123 | +- In the closure of an `EQUAL` row, mechanisms are reported only as |
| 124 | + metadata. |
| 125 | + |
| 126 | +### C.5 normalization_reason |
| 127 | + |
| 128 | +The rules apply in this order: |
| 129 | +1. **Broken closure** gives `UNEXPLAINED`. |
| 130 | +2. **`L_actual == L_canonical`** gives `EQUAL`, even if canonicalization |
| 131 | + physically rewrote sites. It is counted separately: |
| 132 | + - `equal_identity`: every site in the closure already was a `call`, or |
| 133 | + there is no site; |
| 134 | + - `equal_after_rewrite`: at least one site in the closure had a non-`call` |
| 135 | + op. This is the hidden, currently value-neutral normalization debt. |
| 136 | +3. **`L_actual != L_canonical`** gives the non-`EQUAL` reason `R` only if |
| 137 | + all of these hold: |
| 138 | + 1. the closure contains exactly one non-`EQUAL` mechanism kind, and it is |
| 139 | + `R`; |
| 140 | + 2. `R` is `CONSUMES_PARAM_FOLD` or `ARGUMENT_SHAPE_LOSS`; |
| 141 | + 3. every site of `R` in the closure satisfies its local witness (C.4); |
| 142 | + 4. there is no `UNKNOWN` and no broken site in the closure. |
| 143 | + |
| 144 | + Otherwise the reason is `UNEXPLAINED`. A closure with both a fold and a |
| 145 | + shape loss is `UNEXPLAINED`, even though the composition is intuitively |
| 146 | + understood. The hypothesis promises one reason per non-equal row. |
| 147 | + |
| 148 | +## D. Necessary conditions |
| 149 | + |
| 150 | +- **N1: coverage.** Every snapshot row is decomposed exactly once, with no |
| 151 | + missing, extra or duplicated `(document, method, index)`. |
| 152 | +- **N2: no drift.** For every row, `L_actual`, `G` and the B1 class equal the |
| 153 | + snapshot. Any drift makes the gate **VOID**. |
| 154 | +- **N3:** semantic `UNEXPLAINED = 0`. |
| 155 | +- **N4:** normalization `UNEXPLAINED = 0`, and no broken closure. |
| 156 | +- **N5:** every non-`EQUAL` reason satisfies C.5.3, including the executable |
| 157 | + per-site witnesses. |
| 158 | +- **N6:** `G` moved by canonicalization `= 0`. |
| 159 | +- **N7:** A18-0 consistency. The 8 A18-0 rows reproduce A18-0's committed |
| 160 | + `L_canonical` (`docs/evidence/p037-a18/eight-rows.json`), with eight-row |
| 161 | + drift `= 0`. |
| 162 | + |
| 163 | +## E. Falsifiers (run first; the population runs only if all fire) |
| 164 | + |
| 165 | +The falsifiers live in a separate, non-auto-discovered test module, |
| 166 | +`tests/p037_a18_1f_falsifiers.py`. It is not named `test_*.py`: `run_tests.py` |
| 167 | +auto-discovers those, and CI has no frozen-population extractor build. Its |
| 168 | +output is committed as evidence before the population run, and the |
| 169 | +population is run only if it exits 0. |
| 170 | + |
| 171 | +- **F0 (first): transitive A → B → C.** The fixture is built from the frozen |
| 172 | + facts of `guard-forward-bare`: |
| 173 | + - B = `ShapeForwardBare.Outer` forwards to C = `ShapeForwardBare.Inner`. |
| 174 | + - A test-only caller A forwards to B with a legacy `release`, which agrees |
| 175 | + with `B_actual = must`. A is never population. |
| 176 | + |
| 177 | + Both halves must hold: |
| 178 | + - the **new rule passes**: `A_canonical == B_canonical != B_actual`, and |
| 179 | + A's reason is `CONSUMES_PARAM_FOLD`; |
| 180 | + - the **old #375 local-honesty rule fails**: `A_canonical == B_actual`. |
| 181 | + |
| 182 | + If the old rule is not killed by this fixture, F0 is built wrongly: the |
| 183 | + gate STOPs and does not run the population. |
| 184 | +- **F1:** a fold row with canonicalization disabled is no longer |
| 185 | + `CONSUMES_PARAM_FOLD`. |
| 186 | +- **F2: broken links give `UNEXPLAINED`.** |
| 187 | + - F2a: in a cast/bang row whose own sidecar-to-forward link is broken |
| 188 | + (the site's `statement_line` shifted off the legacy op), the reason is |
| 189 | + `UNEXPLAINED`, not a fold. |
| 190 | + - F2b, closure propagation: in the F0 fixture, only B's site is broken. A |
| 191 | + must be `UNEXPLAINED`, although A's own site is intact. |
| 192 | +- **F3:** the pure rule (C.5) gives `UNEXPLAINED` in three cases: |
| 193 | + - `actual = unknown`, `canonical = must`, and no mechanism; |
| 194 | + - a closure holding both a fold and a shape loss; |
| 195 | + - a broken closure with `actual == canonical`. |
| 196 | +- **F4:** a `G` / `L_canonical` pair outside the three semantic cases is |
| 197 | + semantic `UNEXPLAINED`. This uses the cast row with canonicalization |
| 198 | + disabled (`may` vs `no`) and the real Rust classifier. |
| 199 | +- **F5 / F6:** coverage on the complete document passes. Deleting one row |
| 200 | + (F5), or duplicating one (F6), fails it. |
| 201 | + |
| 202 | +## F. Hard KILL: `RESULT: FAIL — A18-1F …` |
| 203 | + |
| 204 | +The gate fails on any of these: |
| 205 | +- F0 does not kill the old local-honesty rule, or any falsifier misses. The |
| 206 | + population is then not run. |
| 207 | +- semantic `UNEXPLAINED > 0`; |
| 208 | +- normalization `UNEXPLAINED > 0`; |
| 209 | +- a broken canonicalization in any closure; |
| 210 | +- a new normalization mechanism is needed; |
| 211 | +- a snapshot coverage problem (missing, extra or duplicate) or drift (VOID); |
| 212 | +- `G` changes under the canonical rewrite; |
| 213 | +- A18-0 eight-row drift; |
| 214 | +- information beyond the frozen facts is needed, other than the registered |
| 215 | + wrapper probe; |
| 216 | +- production semantics, `ConsumesParam`, the extractor, OwnIR or facts have |
| 217 | + to change; |
| 218 | +- **budget:** measurement `> 145`, tests `> 60`, or total `> 200`. |
| 219 | + |
| 220 | +Reaching any cap unfinished gives |
| 221 | +`RESULT: KILL — A18 POPULATION-DECOMPOSITION APPROACH (BUDGET)`. No further |
| 222 | +budget re-plan follows. |
| 223 | + |
| 224 | +## G. PASS: `RESULT: PASS — A18 POPULATION DECOMPOSITION HOLDS` |
| 225 | + |
| 226 | +PASS requires all of: |
| 227 | +- `covered = 36`, `missing = 0`, `duplicates = 0`, `extra = 0`, snapshot |
| 228 | + drift `= 0`; |
| 229 | +- semantic `UNEXPLAINED = 0`, normalization `UNEXPLAINED = 0`, broken |
| 230 | + closures `= 0`; |
| 231 | +- A18-0 eight-row drift `= 0`, and `G` changed by canonicalization `= 0`. |
| 232 | + |
| 233 | +For every row, the result reports `L_actual`, `L_canonical`, `G`, |
| 234 | +`semantic_class`, `normalization_reason`, the closure mechanisms and the |
| 235 | +witnesses. The aggregates are the semantic counts, the normalization counts, |
| 236 | +`equal_identity`, `equal_after_rewrite` and the |
| 237 | +`semantic_class × normalization_reason` cross-tab. |
| 238 | + |
| 239 | +A PASS does not make B1 pass. It establishes only this: "B1's original gate |
| 240 | +failed, and the A18 decomposition explains that failure population-wide." |
| 241 | +A B1 reconciliation gate needs its own authorization. |
| 242 | + |
| 243 | +## H. Budget (all three caps are binding) |
| 244 | + |
| 245 | +```text |
| 246 | +measurement / decomposition / report code: <= 145 lines (scripts/p037_a18_decompose.py, delta vs ca14336) |
| 247 | +falsifier test module: <= 60 lines (tests/p037_a18_1f_falsifiers.py, new file) |
| 248 | +----------------------------------------------------------------------------------------------------- |
| 249 | +TOTAL executable handwritten delta: <= 200 lines |
| 250 | +``` |
| 251 | + |
| 252 | +- The counting rule is the same as in A18-0 and A18-1R: added or changed |
| 253 | + lines in `git diff ca14336`, excluding blank lines and lines whose stripped |
| 254 | + text starts with `#`. Docstrings count. |
| 255 | +- Test-module lines count toward the total; they are not an exclusion. |
| 256 | +- No minification: the code is written in the repository's ordinary style. |
| 257 | +- This note and the evidence JSON are not code. |
| 258 | + |
| 259 | +## I. Non-goals |
| 260 | + |
| 261 | +This gate does not touch any of these: |
| 262 | +- B1: #373 and its evidence, and the #376 snapshot; |
| 263 | +- #375 and #377; |
| 264 | +- production MOS and verdicts, and `ConsumesParam`; |
| 265 | +- extractor facts and semantics, OwnIR, R, A14, #368, Phase C; |
| 266 | +- the three P-037 classes, `own-guarded`, and the application level. |
| 267 | + |
| 268 | +It adds no normalization reason. |
0 commit comments