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.
4.2 KiB
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 157–159)
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
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).
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
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
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 == 0is preserved by the registry's refusal-preferring discipline:is_falsifiedreturns()immediately;is_affirmedgates every emission.- The
WrongCompositionCategorycheck 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.