* docs(ADR-0136): statement-layer corridor + S.0 taxonomy + resolve math-file conflicts - Add ADR-0136-statement-layer-corridor.md: corridor overview, S.0-S.4 phase table, taxonomy summary (23 context-filler, 4 rate-class, 5 compound, 17 long-tail), standing invariants (admitted_wrong==0, context-filler safety rail, honest delta). - Restore generate/math_*.py to HEAD (main) — stash-pop conflict markers were cosmetic comment rewording; upstream version is authoritative. - Stage docs/reviewers.yaml math_expert_claims addition (already authored). * docs(briefs): archive all 2026-05-23 parallel-dispatch briefs (L1–L17 + README)
3.5 KiB
L2 brief — Opus#2 — Semantic-Symbolic Binding Graph, Phase 1 (data model only)
Worktree setup (do this first, non-negotiable):
git worktree add ../core-binding-graph-p1 -b feat/binding-graph-phase1 origin/main
cd ../core-binding-graph-p1
Scope. Ship Phase 1 only of the binding graph layer proposed in docs/implementation/semantic-symbolic-binding-graph-proposal.md (PR #170, now on main). Phase 1 is data-model-only: frozen dataclasses + invariants + tests. No runtime wiring, no adapter, no equation binding, no parser change. Phases 2–5 are deferred to follow-up PRs.
Reference docs (read these, only these):
docs/implementation/semantic-symbolic-binding-graph-proposal.md— your spec. The dataclass list under "Adds" is authoritative.generate/math_symbolic_normalizer.py(post-#167) — only to see the existingPolynomialdataclass style (frozen, terms-dict, variables-tuple). Match its idiom; do not import from it.
What to ship:
generate/binding_graph/__init__.py— public API surface.generate/binding_graph/model.py— frozen dataclasses per the proposal:SemanticSymbolicBindingGraphSymbolBindingBoundFactBoundEquationBoundUnknownBoundConstraintSourceSpanLinkUse@dataclass(frozen=True, slots=True). All collections immutable (tuple,frozenset,MappingProxyTypeif needed). No mutation methods.
generate/binding_graph/allocation.py— deterministic symbol allocator. Given a sorted iterable of NL noun-phrases, returns a stabletuple[SymbolBinding, ...]. Pure function. Deterministic across runs.tests/test_binding_graph_model.py— 30–50 tests covering: frozen invariants, equality, hashability where applicable, allocation determinism, refusal on bad input (empty span, duplicate binding id, etc.),SourceSpanLinkround-trip.docs/decisions/ADR-0132-binding-graph-data-model.md— short ADR ratifying Phase 1; cite #170's proposal doc; explicit "Phase 2+ deferred" section.
Hard constraints:
- Pure data layer. No I/O, no parser calls, no algebra calls, no
numpy, no runtime field touch. - Immutability. Every field is immutable; every collection is
tuple/frozenset. The "create new objects, never mutate" rule from coding-style.md is load-bearing here. - Deterministic allocation. Same input order → same
SymbolBindingids → byte-equal serialization. Lane test asserts this. - Refusal-first. Invalid construction raises a typed error (
BindingGraphError, sibling ofSymbolicError); never silently coerces. - No coupling to the symbolic normalizer. The binding graph references symbolic expressions by string canonical form, not by importing
Polynomial. Decoupling is the whole point of the layer.
Out of scope (do not touch — these are Phase 2+):
- Adapter from existing
MathProblemGraph(Phase 2). - Unit-aware equation binding (Phase 3).
- Question-target binding (Phase 4).
- Bounded grammar integration (Phase 5 / B3).
- Any change to
chat/,generate/intent.py,generate/realizer.py.
Target branch. PR against main. Title: feat(binding-graph): Phase 1 data model (ADR-0132). Body must reference #170 as parent and list Phase 2–5 as deferred follow-ups.
Exit criterion. PR opens with CI green, all new tests pass, pyright clean on new files, ADR-0132 included. Runtime behavior byte-identical to main (no integration yet, by design).
Do not stack on another agent's branch. Target main directly.