7.4 KiB
Epiphany — working agreements for agents
FOSS music-notation platform: a specified, deterministic, CRDT-based score model with a LaTeX specification suite as its source of truth.
Read this first
spec/HANDOFF_2026-08-07.md— current state of both tracks, what transfers between machines, environment setup, and what to do next. Start there; everything below is the standing rules that document assumes.spec/PASS13_CANDIDATES.md— the spec-track ledger. Status cells are appended to, not rewritten, so an opener can lag the truth by several rungs. Read the whole cell.- The contract for whatever you are about to touch:
spec/CONTRACT_*.md.
The two tracks
| Track | Lives in | Current head |
|---|---|---|
Spec / Pass 13 — wire format, bundle, ops, text projection, the .tex suite |
spec/, crates/epiphany-{core,ops,bundle,textproj,testkit} |
P13-S27 LANDED (4df8e25); P13-S16 LANDED (aee4ff9), its post-landing corrections amended in at CONTRACT_P13S16_PROJECTION.md §7 |
| Editor / T4 — the editing seam, engraving, the toolkit spike | spec/PLAN_EDITOR_APP.md, spec/CONTRACT_EDITOR_*, spikes/, crates/epiphany-{editor-core,editor-gui,engrave,layout-ir,glyphs,render-svg} |
T4 spike, round 2 built but not run |
They are currently independent. The T1b/P13-S27 collision in
epiphany-bundle/src/bundle.rs is resolved — S27 landed 2026-08-09. This does
not make T1b free: it stays blocked on Ruling B blocker (ii), versioned decode
(handoff §2.3). Any future epiphany-bundle rung re-creates a collision with T1b on
its own terms — that is a property of the crate, not of S27.
How work is done here
Contracts are ratified, then frozen. Substantive work is scoped into a
spec/CONTRACT_*.md with numbered pins, tests, mutations, a touch table and a
gate; it goes through adversarial review rounds before dispatch. After
ratification the pins are executed, not edited. A defect found during
execution is reported, not patched in place — if it needs a pin change,
that is its own amendment with its own review round.
The touch table is the staging allowlist. A file that must change but is
not listed silently drops out of the commit. Two recurring escapees, in no
contract's table: crates/epiphany-testkit/tests/requirement_labels.rs (its
hardcoded requirement counts move whenever a .tex gains a requirement), and
version literals in .tex prose.
Mutation-first. Every regression test is verified by re-introducing the bug and observing the failure. Reasoning that a mutation would fail signs nothing. A compile error is not a test failure — a mutation that does not compile observed nothing. Restore by hand-editing back, never with git.
Verify subagent claims before committing them. Re-run the tests, re-read the diff. Agents in this repo have misattributed failures, missed failing suites, and guarded the wrong code path — all found only by re-running.
Before believing a zero-result search, ask what it would miss if the claim
were false. Different encoding, different spelling, a propagating rather than
constructing path, output truncated by head. Never conclude a universal
negative from a piped head.
Guard every reachable path, not the one the spec sentence names. Enumerate the public entry points into an invariant and ask which a caller can actually reach today.
Git
- Stage explicit paths. Never
git add -A. - Never
git reset,git restore --staged,git checkout, orgit stashagainst the working tree — sessions have run concurrently here, and these destroy work that is not yours. Undo by hand-editing. - Re-check
HEADbefore staging and before committing. - Subagents do not commit. They leave work for review.
Build and environment traps
- Never run
cargo fmt --all. It reaches thespikes/workspace through path dependencies and reformats across workspaces. Usecargo fmt -p <crate>. The--checkform CI runs is safe; the writing form is not. - The spec builds with
xelatex, notpdflatex—fontspecrefuses pdfTeX outright:cd spec && latexmk -xelatex -interaction=nonstopmode <doc>.tex. Re-run untilundefined referencesclears; one pass is often not enough. The six PDFs are tracked and must be rebuilt when their.texchanges. - Toolchains: pinned stable 1.95.0, MSRV floor 1.85. The MSRV CI job
excludes
epiphany-editor-gui. spikes/is its own workspace — rootcargo test --workspacedoes not reach it. Gate it separately.
Green baseline
cargo test --workspace # expect 1583 passing, 0 failed, 0 ignored
cargo clippy --workspace --all-targets -- -D warnings # clean
This is the single origin for the count — spec/HANDOFF_2026-08-07.md used to
repeat it in three places and now points here. It moved 1570 → 1577 when P13-S27 landed,
and 1577 → 1583 when P13-S16 landed (six net-new tests).
Use --no-fail-fast whenever anything is failing. The bare command stops at the
first failing suite, so a partial failure set reads as the whole one — P13-S16's M6a
reported six failures over four suites bare, and seven over all forty-two with the flag.
If the count differs on arrival, reconcile that before starting new work — the mutation discipline above depends on a known-green baseline.
The canonical-base rule — the "one live constraint" is LIFTED
P13-S27 landed 2026-08-09 (4df8e25), so the blanket prohibition is gone. It read:
until P13-S27 lands, no bundle anywhere may carry a canonical base. It no longer
applies, and base-bearing bundles are constructible again through the ordinary API.
What replaced it, and it is not "anything goes": a canonical base is accepted only
when its reduction_algorithm_version equals the running authority,
epiphany_ops::CURRENT_REDUCTION_ALGORITHM_VERSION — currently 1. A mismatch is
CanonicalBaseRequiresRebuild { base, current }, refused on both the read side
(open) and the write side (commit/commit_versioned). Legacy-epoch bundles still
refuse a base outright.
Any base materialized before P13-S16 must be rebuilt, not reused — it declares 0
and holds state the current semantics would not have computed.
The bump discipline is the whole guarantee. Any change to a canonical reduction verdict or to canonical reduced state MUST bump that constant — no mechanism can detect a semantics change, so nothing will catch a missed bump. Both classes are named because a change leaving every verdict intact while altering the reduced graph is the easier one to overlook, and it invalidates a base just as completely.
P13-S16 made the first bump, 0 → 1, and carried one change of each kind:
CreateStaffGroup's verdict (applied → ContainerNotEmpty no-op) and CreateStaff's
reduced state (it still applies, but now maintains StaffGroup.members). The constant's
own Bumps list is the record of why each version exists; a bump without its entry
leaves a number nobody can account for.
Fixtures deliberately exercising arbitrary wire versions take
BundleCapabilities::synthetic_for_fixture(v); production paths take the crate-local
production_caps(). Never the former on a production path. craft_image /
craft_image_with_base still exist for hand-built images, but are no longer the only
way to get a base. See handoff §1.2, marked as a dated record.