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>
|
||
|---|---|---|
| .. | ||
| examples | ||
| src | ||
| tests | ||
| tools | ||
| Cargo.toml | ||
| DECISIONS.md | ||
| README.md | ||
README.md
epiphany-render-svg
Agent I's SVG renderer behind the Epiphany RenderIR interface (spec
Chapter 7): turns a ResolvedLayoutIR into well-formed SVG 1.1, drawing each
glyph as a genuine Bravura SMuFL outline <path>. It is the visible end of
the v0 Score → layout IR pipeline.
Status: renderer against the stub solver
This phase builds and golden-locks the renderer against the stub solver's
output (the QUICKSTART development pattern), before the real engraving solver and
the score→real-notation engraving pass land. The stub returns the IR geometry
verbatim — a structural projection (each object becomes one arbitrary glyph in a
row), not yet recognizable notation — so what is proven here is renderer
correctness and faithfulness: real outlines, provenance preserved, output
XML-valid and deterministic. The renderer consumes any solver's output, so the
picture improves with no renderer change once epiphany-engrave lands.
Demo
# Render a fixture to SVG (stub solver by default):
cargo run -p epiphany-render-svg --example render_fixture -- \
ten_measure_single_staff > out.svg
# Drive Agent I's engrave solver instead, to bisect renderer-vs-solver:
cargo run -p epiphany-render-svg --example render_fixture -- \
ten_measure_single_staff --solver=real > out.svg
Fixtures: ten_measure_single_staff, valid_score_rich, valid_score. Stats and
diagnostics go to stderr; the SVG goes to stdout.
Library
use epiphany_render_svg::{render, RenderOptions};
let out = render(&resolved_layout_ir, &RenderOptions::default());
assert!(out.is_well_formed());
println!("{}", out.svg);
render is pure and deterministic. RenderOptions controls SVG-encoding choices
only (display scale, margin, provenance attributes) — nothing that changes
engraving.
Bundled outlines
The glyph outlines in src/outlines_generated.rs are extracted from the official
OFL Bravura.otf by tools/extract_bravura_outlines.py. The font is not
vendored; only the generated Rust is committed. Bravura is © Steinberg Media
Technologies GmbH under the SIL Open Font License 1.1 (tools/OFL.txt); the
extracted outlines are redistributed under the same license. To regenerate:
cd crates/epiphany-render-svg/tools
python3 -m venv .venv && . .venv/bin/activate && pip install fonttools
python3 extract_bravura_outlines.py > ../src/outlines_generated.rs