77 lines
12 KiB
Markdown
77 lines
12 KiB
Markdown
# Pass 12 — Ratification Log
|
||
|
||
## Tranche 1 (2026-07-02): audit spec-alignment
|
||
|
||
The 2026-07 six-agent spec-compliance audit sorted its findings into code-side
|
||
MUST fixes (landed separately; see the crate `DECISIONS.md` files and
|
||
`CONFORMANCE.md`) and places where the *spec text* trailed a disposition the
|
||
project had already made — a documented crate decision, the ratified Operation
|
||
Catalog, or the PHASE2_QUICKSTART model the implementation follows. This
|
||
tranche ratifies that second set. **No byte-layout changes; architecture
|
||
unchanged.** The main Pass 12 batch (`PASS12_BATCH.md`) stays open: the
|
||
P12-H/K rows await G's ratification alongside Phase 2's open questions and are
|
||
*not* resolved here.
|
||
|
||
`adopt` = blessed the implementation/catalog behavior as normative spec text.
|
||
`fixed` = the spec text was contradictory or stale and changed.
|
||
|
||
| Item | Disposition | Spec locus | Authority followed |
|
||
|---|---|---|---|
|
||
| ModifyEvent metric placement | **adopt** — the catalog's §ModifyEvent reduction rule now states: a *metric* move (different `Musical` position/duration) is materialised, re-sorting the owning voice (id-tiebroken), behind a **placement precondition** read from the reducer's canonical voice-occupancy index — a non-positive span or an overlap with another live event refuses as a clean `EventDurationInvalid` no-op; a materialised move updates the occupancy index; non-metric moves and tuplet-member trimming stay deferred; same-placement field edits apply in place | operation_catalog §ModifyEvent | ops DECISIONS "ModifyEvent materializes metric placement changes (trim/move)"; `reduce.rs::modify_event` |
|
||
| Slur/Spanner re-anchoring | **fixed (core-spec↔catalog contradiction)** — the rule-table rows now read: re-anchor to the nearest surviving endpoint/anchor while ≥ 1 survives, cascade-delete only when none does; a two-endpoint slur collapses onto its sole survivor (reference-clean degenerate form); proximity-aware re-targeting and per-spanner-kind bounds are deferred refinements (P11-C5 stand-in). Previously the Slur row said "nearest forward event in same voice; cascade if fewer than two members survive" | core_spec §The Re-Anchoring Rule Table | operation_catalog §DeleteEvent Re-anchoring; `reduce.rs` ledger + `materialize_graph_delete` (kept consistent per ops DECISIONS "the graph follows the ledger") |
|
||
| RewriteTuplets payload | **adopt (id-only v1)** — core spec drops `TupletRewrite { tuplet, new_ratio, new_members }` for the catalog's `RewriteTuplets { tuplets: Vec<TupletId> }`, and states normatively that graph-aware reduction MUST refuse the variant as an ill-formed compensation rather than fabricate rewritten values; a future value-carrying payload revision reopens it (`ReplaceWithRest`/`CascadeDeleteTuplets` are the applicable compensations until then). Keeps v1 bytes stable; the functionality hole is documented instead of contradictory | core_spec §DeleteEvent (payload, preconditions, effect) | operation_catalog §DeleteEvent; `reduce.rs` refusal (`TupletCompensationInvalid`) |
|
||
| Operation-block summaries | **adopt (bundle M4)** — an `OperationEnvelopeBlock` chunk payload is the envelope vector only (the spec'd `block_id` field was unrealizable: a content-addressed chunk cannot embed its own id); `OperationBlockSummary { dvv_summary, min_stamp, max_stamp }` lives in the **manifest**, keyed by the block's `ChunkId`, as opaque ops-supplied, non-canonical, optional metadata; the "writers SHOULD order blocks by min_stamp" line is dropped — the canonical manifest encoding sorts chunk references ascending by encoded form (Appendix D), so stamp-ordered scanning goes through the summaries | core_spec Ch8 §Operation Envelope Blocks + §Manifest | bundle DECISIONS "Operation-envelope block summary metadata is carried (M4 follow-up)"; `manifest.rs::OperationBlockSummary` |
|
||
| Pre-pass output model | **fixed (stale Ch2/Ch3 text)** — the spelling and decomposition pre-passes produce **canonical derived annotations**: deterministic functions of (materialized graph, profile, versioned algorithm id), recomputed on materialization, never stored as graph state or serialized into canonical chunks — replacing "the pre-pass MUST produce / write `Inferred`-source attachments" and "stored as an attachment on the event". The pre-pass now MUST NOT mint attachments; promotion to a stored `UserChosen` attachment happens only via explicit editing operations. The incremental-re-run MUST is demoted to MAY (cache/incremental recompute permitted; neither observable in output; cache invalidates on derivation-key change). Ch1 design-principle retitled "notational rhythm is *derived*" | core_spec Ch2 §Spelling Source/Precedence/Pre-Pass + rationale; Ch3 §Notational Decomposition + §Decomposition Pre-Pass; Ch1 design principles | PHASE2_QUICKSTART "Canonical model: derived annotations, not stored objects"; `prepass.rs::derive_annotations` |
|
||
| Spelling tie-break | **adopt** — conflicts break by precedence, then attachment `priority` (higher wins), then **canonical attachment order** (earliest in the score's canonical serialization wins); the "attachment creation timestamp" tie-break is deleted — attachments carry no timestamp, and one would hang resolution on non-canonical state | core_spec Ch2 §Configurable Precedence | `prepass.rs::resolve_spelling` |
|
||
| Conflict-registry location | **fixed** — `Score.conflicts: ConflictRegistry` removed from the graph root; the registry is a component of canonical **materialized state** (which Ch6's requirement already said), i.e. a reduction product, not authored content; the hierarchy table, chapter overview, and §Conflict Records prose updated to match | core_spec Ch5 §Score root; Ch6 §Conflict Records / §The Conflict Registry | `reduce.rs::MaterializedState.conflicts` |
|
||
| SolverTier::Stub | **adopt** — the spec enum gains the code's `Stub` variant: not a conformance tier, an interface-only/passthrough solver ordered below every conformant tier; declaring it makes no conformance claim and satisfies no minimum-tier requirement. Never canonically serialized, so no byte impact | core_spec Ch7 §Conformance Tiers | `layout-ir/solver.rs::SolverTier` |
|
||
|
||
**Version movements.** Operation Catalog 0.2.0 → 0.3.0 (ModifyEvent
|
||
reduction-rule behavior text). Core spec: revision-history row "Pass 12
|
||
tranche 1 (audit spec-alignment)" appended.
|
||
|
||
## Tranche 1 addendum (2026-07-02, Push-3 enablers)
|
||
|
||
Two further ratifications landed the same day as spec-side *enablers* for the
|
||
Push-3 wiring work — each defines normative text the implementation then built
|
||
against (spec-first, per the batch discipline):
|
||
|
||
| Item | Disposition | Spec locus | Consumer |
|
||
|---|---|---|---|
|
||
| `ResolveEquivocation` meta-operation | **fixed (dangling prose reference)** — the core spec named the operation only in prose (§Equivocation, resolution path 2) with no payload schema, no catalog entry, no K1 slot. Ratified: catalog §ResolveEquivocation pins `ResolveEquivocationPayload { target: OperationId, chosen: EnvelopeHash }`, order-independent earliest-resolve-governs promotion, `AlreadyApplied` idempotence, `StructuralFieldCollision` on `equivocation_resolution` for differing resolves, precondition no-ops, and the equivocated-resolve exclusion; core spec `OperationPayload` gains the variant. Catalog 0.3.0 → 0.4.0. The profile-policy path stays open (P12-K5) | operation_catalog §ResolveEquivocation; core_spec §Operation Envelope | `epiphany-ops` (payload discriminant 3 appended; set-level promotion pre-pass) |
|
||
| Anchored break overrides | **fixed (representational gap)** — `OverrideKind::SystemBreak`/`PageBreak` were nullary, so a break's *position* was unrepresentable and the logical-stage projection required by §Engraving Overrides could not exist. Ratified: both kinds carry `anchor: TimeAnchor`; the `ScoreGraph` target names the owning region; projected break overrides carry `Internal` origin (authorship lives in the op log, P11-C8) | core_spec Ch7 §Engraving Overrides listing + note | `epiphany-layout-ir` (`to_logical` projection + paired `UserOverride` decisions) |
|
||
|
||
**Deliberately not touched here** (still open in `PASS12_BATCH.md`): every
|
||
P12-H/K row (algorithm-id ratification, decomposition precedence
|
||
configurability, authored decompositions for ineligible events, system-pitch
|
||
content modification, ResolveConflict beyond the concurrent case, RespellPitch
|
||
v0 migration fallback, Transpose interval algebra), plus the audit's Push-3
|
||
wiring tracks (constraints, overrides, validation modes, edit barriers,
|
||
operation index) — those are code work, not spec alignment.
|
||
|
||
## P12-I11 resolution (2026-07-03) — no spec change
|
||
|
||
The batch's one measured-and-tracked conformance miss, **P12-I11** (RS-1
|
||
honestly failed the Minimal `casting_off_quality` threshold — greedy first-fit
|
||
left a two-measure stub last system, width CV 0.6145 clamped to 1.0 > 0.90),
|
||
is resolved **entirely on the implementation side**, so it appears here only to
|
||
record that the Quality Metric Catalog and the core spec were **not** changed.
|
||
|
||
| Item | Disposition | Spec locus | Consumer |
|
||
|---|---|---|---|
|
||
| P12-I11 casting-off stub last system | **no spec change (engrave fix)** — casting-off gained a second **widow-rebalance** phase (`epiphany-engrave` v3): it moves whole trailing measures from a region's penultimate system into its final one, choosing the shift that minimizes the larger of the two distribution penalties the catalog already defines for the break family (`casting_off_quality` width imbalance vs `system_break_penalty` non-final underfill; both share the 0.5 anchor). RS-1 casts six/four instead of eight/two — `casting_off` 1.0 → 0.4463, every axis ≤ 0.90 — so the suite's asserted Xfail row is promoted to a plain Pass. This is the deliberately-chosen *honest* resolution: the `casting_off` 0.5 anchor and the Minimal 0.90 column were **vindicated, not relaxed** (the engraver improved, no anchor rescale / threshold loosening / RS-1 per-entry override). Core spec Chapter 9's "Minimal makes no optimality claim" already permits the heuristic; nothing normative changed | — (no spec locus; core spec + Quality Metric Catalog unchanged) | `epiphany-engrave` (`casting::rebalance_widows`, `ENGRAVER_VERSION` 3); `epiphany-testkit` (RS-1 xfail row removed); render goldens regenerated |
|
||
|
||
## P12-I12 resolution (2026-07-03) — Quality Metric Catalog 0.1.0 → 0.2.0
|
||
|
||
Unlike P12-I11, the second measured finding's honest fix is a **catalog
|
||
change**: the defect was in the metric's own definition, not the engraver.
|
||
|
||
| Item | Disposition | Spec locus | Consumer |
|
||
|---|---|---|---|
|
||
| P12-I12 spacing floor on short scores | **fixed (metric measurement domain)** — `spacing_distortion`'s raw measurement is scoped to the system's **rhythmic columns** (spring slots bearing a notehead or rest); the clef / key-signature / time-signature lead and barlines contribute no column, so a note-to-note advance spans them. Rationale: the leading clef-to-first-note gap is furniture width, not note spacing, and folding it into the CV flagged perfectly-spaced short lines as distorted purely for carrying a clef. The three warning entries drop from 0.36–0.41 to 0.2188 / 0.0819 / 0.0856 (below the Standard 0.32 floor), and the axis stays live on real irregularity. The `1.0` anchor, orientation, range, tier thresholds, and the eight other axes are **unchanged**; this is measurement-only — no layout, canonical bytes, render golden, or `ENGRAVER_VERSION` change. Catalog **0.1.0 → 0.2.0** (a normative refinement of one axis's measurement domain). The duration-aware optical-spacing open question stays open | quality\_metric\_catalog §`spacing_distortion` (`req:qmc:spacing`); revision-history row 0.2.0 | `epiphany-engrave` (`quality::census` rhythmic-column filter, `is_rhythmic`); `epiphany-testkit` (RS-3/5/6 measured values drop, still Pass) |
|
||
|
||
**Version movements.** Quality Metric Catalog 0.1.0 → 0.2.0
|
||
(`spacing_distortion` scoped to rhythmic columns). Core spec unchanged (the
|
||
axis's formal definition is delegated to the catalog; Chapter 9 carries only
|
||
the field, which is unchanged).
|