Test 3 asserted phrase presence over the whole requirement block, so a referent
could leave the sentence carrying the normative force and survive in the closing
recap. Execution measured that escape and the annex recorded it; this commit
closes it by strengthening the guard rather than softening pin 4a's claim.
Test 3 now selects the normative clause -- the sentence carrying the sole
\MUST{} -- and runs all four assertions on that slice alone. Both halves of the
start rule are load-bearing and the helper's doc comment says why: last ". "
before the occurrence, falling back to just after the label only when there is
none. An unconditional fallback would return one slice spanning label to recap,
containing every needle; a period-only rule would swallow the label, which is
not a sentence.
Six mutations, six matching radii, test 3 alone in every case. Each attacks a
different layer: M22-M24 vary what the selected clause contains, M25 varies
which sentence is selected, M26 varies the fallback boundary -- starting after
the label versus widening before it -- and M27 varies whether selection is
unambiguous and therefore permitted at all. M27 is the one that reaches the
exactly-one assertion, because an assertion guarding the precondition of
selection cannot be exercised by any mutation that presupposes selection
succeeded.
Rows 4, 6, 7 and 8 only. core_spec.tex is not touched: the requirement's text
was always correct and only the guard was weak. The rung's original 38/38
matrix is preserved unchanged and amendment 3's evidence is appended beside it,
not merged into it.
One prose defect in ratified section 8.4 remains OPEN and is deliberately not
repaired here: that entry says M27 varies which clause is chosen, which M25 does
and M27 does not, since a correct implementation rejects M27 before selecting
any clause. Section 8.6 is unaffected and states something true. The annex
carries the corrected characterization and records the correction as open;
frozen text stays frozen regardless of severity, so the repair belongs to its
own amendment, which is not part of this commit.
Baseline unchanged at 43 suites, 1586 passing: amendment 3 alters an existing
test's scope and adds none.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ps1szk2mSfgp4Cz21eVH9x
|
||
|---|---|---|
| .. | ||
| benches | ||
| examples | ||
| src | ||
| tests | ||
| Cargo.toml | ||
| DECISIONS.md | ||
| README.md | ||
README.md
epiphany-testkit
Agent F's crate per spec/QUICKSTART.md: the
cross-cutting conformance testkit. It is the architecture's tripwire — the suite
that proves the other crates work end to end and that runs in CI (see
.github/workflows/ci.yml).
It provides:
- Deterministic property-test generators for the public types of A
(
epiphany-determinism), B (epiphany-core), C (epiphany-ops), D (epiphany-bundle), and E (epiphany-layout-ir). Agent B's score-graph generators/shrinkers are re-exported asgenerators::graph. - The canonical round-trip harness (
roundtrip) — v0 acceptance criterion 4 (typed values + bundle container; the bookkeepingMaterializedStateround-trip is retained asassert_reduction_serialization_stable). - The CRDT convergence harness (
convergence) — criteria 1 and 5. Criterion 1 proper is real-Score convergence throughreduce_onto(run_graph_convergence); the byte-canonical bookkeeping-projection convergence (assert_convergence) backs criterion 5. - The equivocation harness (
equivocation) — criterion 3. - The crash-recovery harness (
bundle_harness) — Agent D's gate, criterion 2. - The manifest-selection harness (
bundle_harness). - The layout round-trip harness (
layout_stub) — criterion 6. - The audit regression guards (
negative) — one guard per defect the Agent C framework audit surfaced (the M1 fixes), so a regression trips this suite directly.
All harnesses are real
The QUICKSTART charters Agent F to "build against A and stubs for the others."
All five implementation crates — A, B, C, D, and now E (epiphany-layout-ir) —
have shipped, so every harness drives the real crate.
| Harness | Backend | Status |
|---|---|---|
roundtrip (criterion 4) |
A + B + C + D, real | real |
bundle_harness (criterion 2, manifest selection) |
D, real | real |
convergence (criteria 1, 5) |
C (epiphany-ops), real |
real |
equivocation (criterion 3) |
C (epiphany-ops), real |
real |
layout_stub (criterion 6) |
E (epiphany-layout-ir), real |
real |
For criteria 1, 3, and 5 the testkit drives the real
epiphany_ops::OperationSet / canonical_reduction_order / reduce and also
re-exports Agent C's own authoritative gates
(convergence::ops_reduction_determinism_fuzz,
equivocation::ops_equivocation_fuzz). The layout_stub module — once a
faithful in-tree stub of Chapters 7 & 9 — now re-exports the real
epiphany-layout-ir IR types and stub solver behind the same round_trip
signature; the provenance-preservation contract is implemented and tested inside
that crate. (The "stub" in the module name now refers to the spec-sanctioned
stub constraint solver, not to a stubbed crate.)
Criterion 1: real-Score vs. reducer-bookkeeping convergence
Criterion 1 proper (convergence::run_graph_convergence, the acceptance
criterion_1_convergence test) is real-Score convergence: a real ~50-bar,
two-voice base epiphany_core::Score is edited by two replicas through
OperationSet::reduce_onto, and the entire materialized graph — arena, voices,
tombstones, cross-cutting, and the bookkeeping state — must be identical
under every delivery order, pass check_invariants, and genuinely grow both
edited voices (non-vacuity). The session targets the base's actual voice ids
(generators::graph_edit_session), so it exercises the integration point, not a
synthetic id space.
The earlier, narrower gate is retained and honestly renamed
(reducer_bookkeeping_convergence): it converges the byte-canonical
bookkeeping projection (OperationSet::reduce →
MaterializedState::canonical_bytes) — the Chapter 6 §6.3 ledger (effects,
conflicts, anomalies, tombstones, spellings, pending), not the full musical
graph. It still backs criterion 5 and proves causal-first ordering
(convergence::assert_causal_order_respected,
run_authoritative_reduction_gate). The bookkeeping two-staff scenario remains
instantiated — a real ~50-bar (TWO_STAFF_BARS) session whose staves are
asserted populated by generators::assert_two_staff_populated, not just modeled.
Criterion 4: what is and isn't tested
Criterion 4 has three tiers — two asserted now, one pending item 5:
-
Real decode round-trips (these catch decoder / canonicalization defects): the generic
CanonicalEncode/CanonicalDecodeproperty swept across every typed identifier, bothRationalTimearms, and everyTypedObjectIddiscriminant; the bundleManifest(encode → decode → encodefixpoint, with a rich generator exercising snapshots, blobs, extensions, varied profiles, retention, and the optional roots); theFixedHeader; and theSuperblockslot encoding. Crucially, the decoders are shown to validate: corrupting a manifest or header makesdecodereject it (assert_manifest_decode_rejects_corruption,assert_header_decode_rejects_corruption). -
A reducer-bookkeeping serialization tier (
reducer_bookkeeping_serialization, viaassert_reduction_serialization_stable): a realOperationSetis reduced to itsMaterializedState::canonical_bytes()— the canonical bookkeeping state, not the whole musicalScore— which is stored as aSnapshotchunk referenced by the manifest'scanonical_base, survives the bundle's content-addressed store (hash-verified on reopen), decodes throughMaterializedState::decode_canonical, compares structurally with the original reduction, and re-serializes byte-identically. The decoder validates nested tags, lengths, primitive values, canonical form, and trailing bytes. Musical sensitivity is proven two ways:assert_content_mutation_changes_serialization(a cloned operation set with identical ids/stamps/causal contexts but one changed payload reduces to different bytes — the rebuttal to an id-only serializer) andassert_distinct_scores_serialize_differently. The materialized realScoreitself is shown reproducible today (full_score_materialization_is_reproducible, structural equality across delivery orders) — the determinism precondition a byte codec depends on. -
The full-
Scorebyte round-trip (criterion_4_full_score_byte_roundtrip, viaassert_score_serialization_stable): item 5's whole-score codec (epiphany_core::Score::canonical_bytes/decode_canonical) has landed, so a real ~50-barScore— materialized through Agent C'sreduce_onto— nowencode → decode → re-encodes byte-identically through a real bundle snapshot (hash-verified on reopen), with the decodedScorestructurally equal to the original. This is the whole musical graph (arena, voices, regions, cross-cutting, tombstones), not the bookkeeping projection.
Decisions (per QUICKSTART "Make each one once and document it")
- No platform entropy in the harness. Appendix D §"Randomness" forbids
platform entropy in canonical state; the testkit holds itself to the stronger
rule that no platform entropy enters the harness at all. Everything draws
from
rng::Rng(a wrapper over Agent A's vendored SplitMix64, with unbiased bounded draws and an overflow-safe full-rangerange), so every failure reproduces from its seed. - Drive the real crate once it ships; stub only what hasn't landed. Earlier
in development
epiphany-ops(C) andepiphany-layout-ir(E) were in-flight and their harnesses ran against faithful in-tree stubs; now that both have shipped, every harness drives the real crate and re-exports its gates.
Flagged for a future spec pass (Pass 11 candidates)
Per the QUICKSTART, implementation-discovered gaps are batched, not improvised:
- Whole-graph (
epiphany_core::Score) wire format — landed (item 5). A direct canonical byte codec for the coreScorenow exists (epiphany_core::Score::canonical_bytes/decode_canonical), andcriterion_4_full_score_byte_roundtripexercises it on a realreduce_ontomaterialization through a bundle snapshot. The prototype byte form predates the Binary Format companion specification and is to be reconciled with it (seeepiphany-core/DECISIONS.md, P11-4). - Layout harness re-pointed.
epiphany-layout-irhas landed, solayout_stubnow drives the real IR types behind the sameround_tripsignature (done). IR coordinates are f32 staff spaces, quantized only when serializing canonicalResolvedLayoutIR(Appendix D); see that crate'sDECISIONS.mdfor the remaining layout-specific Pass 11 candidates (theOperationKindTagvariant set and the layout-object id derivation).
Performance benches (Chapter 10 budgets, worklist F1)
benches/ holds the criterion benches for the spec's measurable Chapter 10
budgets (see DECISIONS.md F0 for why they live in this crate, F1 for every
call made). Criterion measures; the budget gate (src/budget.rs) asserts:
each bench's main() ends by re-timing every budget row and exiting nonzero if
a Pass-marked row misses its threshold. Known-pending rows are marked
Xfail(reason) in the bench source next to the numeric budget — a miss is
reported and tolerated, and a pass prints a loud promotion notice so stale
markings cannot linger. This is the "F surfaces, K fixes" handshake, and its
inaugural round has completed: the bench documented the reducer's O(n²)
canonical_reduction_order failure at scale, and Agent K's subquadratic
rewrite (see epiphany-ops/DECISIONS.md) flipped the xfail row to Pass.
| row | budget (spec Chapter 10) | expectation |
|---|---|---|
reduction/1000 |
> 10,000 envelopes/s, cold | Pass (~674K env/s measured) |
reduction/10000 |
> 10,000 envelopes/s, cold | Pass (~257K env/s measured) |
reduction/50000 |
> 10,000 envelopes/s, cold | Pass (~87K env/s measured; promoted from Xfail by Agent K's reducer fix — was ~1.7K env/s) |
bundle/typical_edit_commit |
≤ 50 ms (append + manifest + superblock flip, fsync'd) | Pass (~15 ms) |
bundle/open_bootstrap_read |
≤ 200 ms (manifest + bootstrap chunks) | Pass (moderate-corpus stand-in) |
# Full run (includes the 50K cold-reduction point, ~0.6 s per iteration):
cargo bench -p epiphany-testkit
# The reduced CI shape: smaller sampling, 50K point skipped (PR CI runs this):
EPIPHANY_BENCH_QUICK=1 cargo bench -p epiphany-testkit
The gate is a calibrated median over a few iterations, deliberately not the
spec's p99-over-1000-iterations conformance methodology (that is the reference
suite's job; the deviation is documented in src/budget.rs).
Running
# Unit + acceptance tests (a meaningful slice, under the cargo test timeout):
cargo test -p epiphany-testkit
# The full conformance suite at scale, outside the test timeout (includes Agent
# A's 1,000,000-iteration determinism gate and Agent C's reduction/equivocation
# gates):
cargo run --release -p epiphany-testkit --example conformance_suite # scale 1
cargo run --release -p epiphany-testkit --example conformance_suite 10 # soak
cargo run --release -p epiphany-testkit --example conformance_suite 0 # smoke
The six v0 acceptance criteria are asserted in tests/acceptance.rs, one test
per architecture layer.