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: packs/data/en_core_math_v1/, packs/compile_compositions.py
Problem
packs/data/en_core_math_v1/compositions/multiplicative_composition.jsonl
was ratified via ADR-0169 and is present on disk. But
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 packs.compile_compositions import compile_pack_compositions
pack = Path('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 packs/data/en_core_math_v1/compositions.jsonl | cut -d' ' -f1)
# or on macOS:
sha=$(shasum -a 256 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
packs/data/en_core_math_v1/compositions.jsonl (new)
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.