epiphany/crates/epiphany-engrave
Levi Neuwirth af297881e2 Agent I-3: criterion-6 round-trip and golden lock on the real Engraver
Criterion 6 (the Chapter 7 layout round-trip) and the render goldens previously
exercised only the verbatim StubSolver, so a regression in the real Engraver's
geometry could land unseen. I-3 drives both through the Engraver.

  - round_trip_with<S: ConstraintSolver> factors the solver-agnostic provenance
    contract out of round_trip (now a one-line stub wrapper): coverage, the
    complete Provenance surviving constrained -> resolved -> render, the source
    surjection, and no duplicate stable ids hold for *any* conformant solver. The
    Stub tier's verbatim-geometry clause is gated behind solver.tier() == Stub;
    every other tier re-spaces. The status gate accepts any renderable status
    (Solved / SolvedWithWarnings / PartialBudgetExhausted), not exactly Solved, so
    the helper matches its "arbitrary conformant solver" contract while still
    rejecting the diagnostic-only statuses that carry no authoritative layout.
  - criterion_six_round_trips_through_the_engravers_respacing (epiphany-engrave)
    runs the full graph -> logical -> constrained -> *engraved* -> render round
    trip over the criterion-6 hand-off fixtures -- ten_measure_single_staff (the
    measured fixture) and valid_score_rich (cross-cutting tuplet/tie/spanner),
    plus valid_score for breadth -- and asserts the whole provenance contract
    survives the Engraver's re-spacing. A non-vacuity check confirms the Engraver
    genuinely moved geometry, so provenance is preserved *through* a real geometry
    change -- the statement the verbatim stub can never make. This adds an
    epiphany-testkit dev-dep (no cycle: testkit does not depend on this crate).
  - The render-svg engraver acceptance test is upgraded from invariant-only to
    byte-locked: new .engrave.snapshot.txt / .engrave.svg goldens for both
    fixtures capture the Engraver's re-spaced output (e.g. ten_measure view_box
    width 82.26 vs the stub's 88.88, same glyph/stroke/class counts), so an
    Engraver geometry regression is caught at the byte level. A companion test
    asserts the engrave goldens genuinely differ from the stub goldens, catching
    the degeneracy where the Engraver echoes the stub (which would otherwise pass
    both golden checks independently).

Also corrects the epiphany-engrave package description, which still claimed it
reports SolverTier::Stub until it earns Minimal (it earned Minimal in I-2).

Full gate green: build, fmt, clippy, 580 tests, conformance scale 1.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-26 21:58:31 -04:00
..
src Agent I-3: criterion-6 round-trip and golden lock on the real Engraver 2026-06-26 21:58:31 -04:00
Cargo.toml Agent I-3: criterion-6 round-trip and golden lock on the real Engraver 2026-06-26 21:58:31 -04:00
DECISIONS.md Phase 2 (Agent I): visible-slice scaffold — Bravura SVG renderer vs stub 2026-06-23 20:01:40 -04:00
README.md Phase 2 (Agent I): visible-slice scaffold — Bravura SVG renderer vs stub 2026-06-23 20:01:40 -04:00

README.md

epiphany-engrave

Agent I's engraving constraint solver (spec Chapter 9): turns a ConstrainedLayoutIR into a ResolvedLayoutIR with real geometry. It is the production-side replacement for epiphany-layout-ir's interface-only StubSolver; the two live in separate crates so the spec's core/product boundary stays sharp.

Status: honest scaffold (renderer-against-stub phase)

Per the QUICKSTART development pattern, Agent I builds the SVG renderer (epiphany-render-svg) against the stub solver first, then grows this crate into the real two-pass spring solver. This commit is the first increment:

  • Engraver runs a deterministic horizontal spacing pass (the first axis of the planned two-pass spring layout): each spring slot is placed left-to-right by its preferred width instead of being echoed verbatim.
  • It honestly reports SolverTier::Stub — it does not yet evaluate the IR's declared hard constraints or compute quality metrics, so it has not earned Minimal. It is promoted to Minimal in the change that lands real constraint satisfaction.

The vertical spring pass, soft-constraint solve, hard-constraint evaluation, and the quality-metric vector are the next-phase / Phase-3 work. See DECISIONS.md.

use epiphany_engrave::Engraver;
use epiphany_layout_ir::{ConstraintSolver, SolverConfig};

let report = Engraver.solve(&constrained_ir, &SolverConfig::default());
assert!(report.satisfied_hard_constraints); // for constraint-free stub-pipeline input
let resolved = report.layout;               // hand to epiphany-render-svg