core/docs/handoff/CLEANUP-C4-compositions-compile.md
Shay 89defef30b chore(audit): substrate cleanup — dead spike, gitignore, deprecation, reader diagnosis
C1: delete generate/math_versor_arithmetic.py and its 3 tests (ADR-0139
add-only arithmetic spike; no runtime consumers, no pipeline wiring,
follow-on lift paused per module docstring).

C3: gitignore engine_state runtime artifacts (manifest.json,
recognizers.jsonl, discovery_candidates.jsonl). Module code
(engine_state/__init__.py) remains tracked; generated checkpoint
files should not be.

C5: document reader zero-delta root cause in train_sample/v1/README.md.
Both Phase 2 (whole-problem) and Phase 1 (question-only) reader paths are
called but inert because all 47 refusals are statement-level NO_INJECTOR
gaps, not question-sentence gaps. Reader unblocks when injector coverage
expands (C2 work). report.json use_reader flag corrected to reflect last run.

C6: add deprecation header to generate/math_parser.py pointing at
generate.math_candidate_graph.parse_and_solve as the live path.

C2/C4 briefs: docs/handoff/CLEANUP-C2-run-lane-migration.md and
docs/handoff/CLEANUP-C4-compositions-compile.md added as operator
dispatch docs for the medium-scope wiring tasks.
2026-05-28 07:00:33 -07:00

127 lines
4.2 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# C4 — Compile and commit `compositions.jsonl` for the math pack
**Classification**: Half-built producer/consumer loop (audit finding C4)
**Risk**: Low — purely additive, wrong == 0 guaranteed by registry design
**Scope**: `language_packs/data/en_core_math_v1/`, `language_packs/compile_compositions.py`
---
## Problem
`language_packs/data/en_core_math_v1/compositions/multiplicative_composition.jsonl`
was ratified via ADR-0169 and is present on disk. But
`language_packs/data/en_core_math_v1/compositions.jsonl` (the compiled
artifact that the runtime reads) **does not exist**.
The consumer chain is:
```
compositions/multiplicative_composition.jsonl ← ratified source (EXISTS)
↓ compile_compositions.py
compositions.jsonl ← compiled registry (MISSING)
↓ comprehension/composition_registry.py::load_composition_registry()
↓ recognizer_anchor_inject.py (line 157159)
InjectorEmission[] ← runtime output (always empty)
```
`load_composition_registry()` handles the missing file gracefully — it
returns an empty registry when `compositions.jsonl` is absent and
`manifest.json` does not declare `composition_checksum`. So the system is
stable; the ratified claims simply have no effect on runtime decisions.
---
## What to do
### Step 1 — Run the compile step
```bash
uv run python -c "
from pathlib import Path
from language_packs.compile_compositions import compile_pack_compositions
pack = Path('language_packs/data/en_core_math_v1')
result = compile_pack_compositions(pack)
print('written to:', result.output_path)
print('sha256:', result.sha256)
print('entries:', result.entry_count)
"
```
Verify `entry_count > 0` (at least the multiplicative_composition entries).
### Step 2 — Update manifest.json with composition_checksum
The manifest checksum enforces that the committed compiled artifact matches
what `compile_compositions.py` would produce from the source files. Once the
compiled artifact is committed, `manifest.json` should be updated to declare
`composition_checksum` so any future drift raises
`CompositionRegistryLoadError` at load time (defense in depth).
```bash
sha=$(sha256sum language_packs/data/en_core_math_v1/compositions.jsonl | cut -d' ' -f1)
# or on macOS:
sha=$(shasum -a 256 language_packs/data/en_core_math_v1/compositions.jsonl | cut -d' ' -f1)
```
Then add `"composition_checksum": "<sha>"` to `manifest.json`.
### Step 3 — Verify the registry is non-empty at runtime
```bash
uv run python -c "
from generate.comprehension.composition_registry import load_composition_registry
r = load_composition_registry()
print('empty:', r.is_empty())
print('categories:', list(r.by_category.keys()))
"
```
Expected: `empty: False`, at least `multiplicative_composition` in categories.
### Step 4 — Run packs + smoke suites
```bash
uv run core test --suite packs -q
uv run core test --suite smoke -q
```
### Step 5 — Commit
```
language_packs/data/en_core_math_v1/compositions.jsonl (new)
language_packs/data/en_core_math_v1/manifest.json (updated: composition_checksum)
```
Commit message:
```
feat(packs): compile multiplicative_composition registry for math pack
Runs compile_compositions.py to produce compositions.jsonl from the
ratified multiplicative_composition.jsonl source. Updates manifest.json
with composition_checksum. load_composition_registry() now returns a
non-empty registry; recognizer_anchor_inject.py can emit InjectorEmission
for composition-shape matches. Closes the producer/consumer gap from
ADR-0169.
```
---
## Invariant gates
- `wrong == 0` is preserved by the registry's refusal-preferring discipline:
`is_falsified` returns `()` immediately; `is_affirmed` gates every emission.
- The `WrongCompositionCategory` check at load time prevents any unsafe
category from being accepted even if the source file is mutated.
- The manifest checksum (after Step 2) provides ongoing compile-drift
detection.
---
## Relation to other findings
- **C2** (run_lane migration): C4 should land at the same time or before C2
so the candidate-graph path immediately sees a non-empty composition
registry.
- **C5** (reader zero-delta): the reader's zero-delta is unrelated to
compositions — it is a statement-level injector gap. C4 does not fix C5.