Implements Agent E per spec/QUICKSTART.md — the layout intermediate
representation (Chapter 7) and the constraint-solver interface (Chapter 9):
* Four IR stages: LogicalLayoutIR -> ConstrainedLayoutIR ->
ResolvedLayoutIR -> RenderIR (interface only), with the composite-object
taxonomy, spring slots/constraints, vertical-band model, pages/systems,
engraving decisions + overrides, and the incremental dependency/cache model.
* TimeAxisModel tagged enum (Metric/Proportional/Aleatoric/Registered).
* Provenance back-references with manifestation- and synthesis-aware ids
((source, region) and (source, kind, ordinal)), so multiply-manifested and
synthesized objects never collide.
* In-tree Bravura GlyphCatalog (Send+Sync, metrics + render-data interface),
MUSCFNTM-tagged metrics hash with anchors hashed as a name-keyed map.
* Edit-barrier types keyed on OperationKindTag, with precise EditContext /
EditOracle scope/condition evaluation.
* StubSolver: returns SolveStatus::Solved with the input geometry verbatim;
spec-compliant SolveReport, Minimal tier + all-worst (unmeasured) metric
vector (no false conformance claim); rejects ill-formed input.
* f32 staff-space IR coordinates, quantized to the 1/1024 grid only at
canonical ResolvedLayoutIR serialization (Appendix D); non-finite geometry
is rejected, not normalized. Canonical encoding is injective in glyph
identity, provenance, engraving decisions, and catalog identity.
Re-points Agent F's testkit layout harness from its in-tree stub to the real
crate (v0 acceptance criterion 6) and expands its generators to E's public
surface. Expands Agent C's OperationKindTag to the full normative variant set
so edit barriers can prohibit every operation class.
Workspace gates green: fmt, clippy -D warnings, 377 tests, doc tests, rustdoc
-D warnings, and the conformance suite at scale 1. Decisions and Pass 11
candidates recorded in crates/epiphany-layout-ir/DECISIONS.md.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
||
|---|---|---|
| .. | ||
| src | ||
| Cargo.toml | ||
| DECISIONS.md | ||
| README.md | ||
README.md
epiphany-layout-ir
The Epiphany layout intermediate representation and constraint-solver
interface, implementing the normative requirements of Chapter 7 ("Layout
Intermediate Representation") and the interface of Chapter 9
("Constraint-Solver Interface") of the core specification
(spec/core_spec.pdf). This is Agent E's crate per spec/QUICKSTART.md — it
lands last among the implementation crates, building on Agent A's
epiphany-determinism and Agent B's epiphany-core (and on Agent C's
OperationKindTag for the edit-barrier types — see DECISIONS.md).
The IR sits between the score graph and two downstream consumers: the constraint solver, which resolves spacing and positioning, and the renderer, which produces final visual output. — Chapter 7
The score graph is the canonical truth about the music; this crate is a downstream projection of it. The transformation is a pipeline of four stages, each with its own type and a deterministic, provenance-preserving contract for the next.
What's here
| Area | Items | Spec |
|---|---|---|
| Stage 1 — logical | LogicalLayoutIR, LayoutRegion, composite LayoutObject, overrides/cross-region objects, to_logical |
Ch. 7 §"LogicalLayoutIR" |
| Stage 2 — constrained | ConstrainedLayoutIR, SpringSlot, LayoutConstraint, GlyphObject, to_constrained |
Ch. 7 §"ConstrainedLayoutIR" |
| Stage 3 — resolved | ResolvedLayoutIR, pages/systems/staves/measures, ResolvedGlyph |
Ch. 7 §"ResolvedLayoutIR" |
| Stage 4 — render (interface only) | RenderIR, RenderPrimitive, RenderIRProducer, to_render |
Ch. 7 §"RenderIR" |
| Time axis | canonical TimeAxisModel plus dynamic TimeAxis, including registered payload preservation |
Ch. 7 §"Layout Regions" |
| Provenance | Provenance, LayoutObjectId, SynthesisKind, stable_layout_id (a pure function of the source — stable across relayouts) |
Ch. 7 §"Provenance" |
| Engraving decisions | EngravingDecision/EngravingDecisionId/EngravingDecisionKind, DecisionSource |
Ch. 7 §"Engraving Decisions" |
| Vertical bands | VerticalBand/VerticalBandId/VerticalBandKind |
Ch. 7 §"Vertical Bands" |
| Incremental cache | LayoutCache, DependencyIndex, granular stage caches and invalidation |
Ch. 7 §"Incremental Layout and Caching" |
| Glyph catalog | GlyphCatalog (metric-lookup interface) + in-tree BravuraCatalog, GlyphCatalogIdentity, SmuflVersion, FontId, GlyphMetric/GlyphAnchor, BRAVURA_METRICS/BRAVURA_VERSION, metrics_hash_for (MUSCFNTM-tagged) |
Ch. 7 §"Glyph Catalog Interface" / §7.3.2 |
| Edit barriers | EditBarrier, BarrierScope, BarrierCondition, ObjectKind, EditContext (precise scope evaluation), keyed on Agent C's OperationKindTag |
Ch. 8 §"Edit Barriers" |
| Solver interface | ConstraintSolver (solve/solve_incremental, Send + Sync), SolverConfig/SolverBudget, SolverState, InvalidationSet, SolveReport, SolveStatus, SolverTier/SolverVersion, the v0 StubSolver |
Ch. 9 |
| Round-trip | round_trip, RoundTripReport, laid_out_object_ids |
Ch. 7 (v0 acceptance criterion 6) |
The stub solver
Per the QUICKSTART, the v0 constraint solver is a stub: StubSolver returns
SolveStatus::Solved with the input geometry verbatim (each glyph's resolved
position is exactly its constrained baseline), preserves provenance, and reports
all hard constraints satisfied. The real solver — Cassowary or otherwise — comes
later (Chapter 9 specifies the interface, not the algorithm); v0 only needs to
round-trip IR through the solver interface to prove the contracts hold. The one
stub validates the full Chapter 7 §7.3.2 catalog identity and all slot, band,
and geometry cross-references before reporting Solved. Explicit constraints
are rejected because this interface-only solver cannot honestly evaluate them.
The round-trip (v0 acceptance criterion 6)
round_trip runs graph → LogicalLayoutIR → ConstrainedLayoutIR →
stub-solved ResolvedLayoutIR → RenderIR and asserts the contract every stage
must satisfy:
- the stub solver reports
Solvedwith all hard constraints satisfied; - the complete
Provenanceof every object —source,synthesis,dependencies, andstable_id— survives every stage unchanged; - no two objects ever share a
stable_id, so manifestation multiplicity is preserved (a source manifested in two regions stays two layout objects); - the stub solver returns the input geometry verbatim;
- the set of score-graph sources recovered from the
RenderIRis exactly the set laid out — a surjection onto graph identity (one source may back several manifestations, each with its own stable id).
Agent F's testkit drives this same entry point (layout_stub::round_trip) on the
10-measure single-staff hand-off fixture and the rich multi-region generator.
Algorithmic scope
Per the QUICKSTART ("a prototype baseline, not the product"), this crate implements the Chapter 7 IR contracts and interface types, not a production engraving engine. The real spacing and casting-off algorithms, quality-metric computation, constraint solver, and renderer remain later implementations of these interfaces.
Determinism
IR coordinates are single-precision staff spaces (StaffSpace(f32),
Chapter 7 §7.2); the canonical ResolvedLayoutIR output quantizes them to
the 1/1024 grid at serialization time
(ResolvedLayoutIR::canonical_bytes), exactly as Appendix D §"Quantized Layout
Coordinates" prescribes — quantization absorbs all f32 variation below 1/2048
staff space, so the canonical output is independent of the floating-point
environment. The glyph-catalog identity hashes its consulted metrics (advance,
bounding box, named anchors) under the MUSCFNTM domain tag, and the
edit-barrier types carry a canonical encoding with set-valued fields emitted in
canonical byte order (sorted and de-duplicated). See DECISIONS.md.
Tests
cargo test -p epiphany-layout-ir covers each module plus the round-trip on
Agent B's valid_score / valid_score_rich generators. The end-to-end v0
acceptance gate (criterion 6) lives in the testkit.