epiphany/spec/PASS12_BATCH.md

21 KiB
Raw Blame History

Pass 12 — Batch Tracker

Maintained by Agent F (testkit & tripwire), per spec/PHASE2_QUICKSTART.md: "Ambiguities discovered during Phase 2 implementation go into a Pass 12 batch, not into code improvisations. … Don't open Pass 12 until at least 3 items accumulate."

Status: OPEN. Agent H's landing (spelling + decomposition pre-passes) surfaced five candidates, crossing the ≥3 threshold. This file is the running collection; G ratifies (or defers/rejects) the batch when Phase 2's open questions are resolved. F collects, F does not resolve.

Pass 12 tranche 1 landed (2026-07-02): the audit spec-alignment set — places where spec text trailed an already-made disposition (catalog, crate DECISIONS, PHASE2_QUICKSTART) — was ratified directly into core_spec.tex / operation_catalog.tex (0.2.0 → 0.3.0); dispositions in PASS12_RATIFICATION_LOG.md. That tranche resolves none of the rows below; they remain open for G.

How an item lands here

When implementation hits a behavior the ratified spec does not determine, the responsible agent records it in their crate's DECISIONS.md with an ID (P12-<agent><n>) and a one-line rationale, then adds a row below. Improvising in code instead is the failure mode this batch exists to prevent.

Items

ID Source Summary Disposition target
P12-H1 epiphany-core H Ratify SpellingAlgorithmId::Default = Temperley line-of-fifths v1 (Pass 11 closed before H landed; the id "default" is the crate's proposal until ratified — not a byte layout, so nothing golden-locks on it). G (algorithm-choice ratification)
P12-H2 epiphany-core H KeySignatureChange / ClefChange are anchor-only placeholders; context-aware spelling infers tonal context from the melody (line-of-fifths centre of gravity) rather than a declared key. A real key/clef content model would let spelling/decomposition honour declared keys and place cancelling naturals. Flagged as a graph-model gap. G (graph model)
P12-H3 epiphany-core H Chromatic-run convention (ascending = sharps, descending = flats) is only a tiebreak in the centre-of-gravity rule, so an isolated chromatic run with no tonal context may pick the enharmonic the convention would not. Voice-leading refinement deferred. G / Pass 12 (spelling)
P12-H4 epiphany-core H Decomposition simplifications: single governing meter per region (multi/mid-region meter changes deferred); region origin assumed a barline (anacrusis deferred); compound-meter beat grouping beyond the dyadic default; tuplet nesting and cross-beat tuplet members; double+ augmentation dots (MAX_DOTS = 1). G (decomposition scope)
P12-H5 epiphany-core H Automatic spelling under aleatoric regions (the spec's open question). H spells pitches region-independently but performs no region-specific aleatoric spelling; defer if the algorithm does not generalise cleanly. G / Pass 12 (open question)
P12-I1 RESOLVED (I-1) epiphany-layout-ir / engrave / render-svg I The v0 pipeline was a structural placeholder (one arbitrary glyph per object at y = 0), not real notation. Resolved by I-1 (Phase 2-3): to_constrained now builds real notation — clef-relative noteheads (by NoteValue), spelling-derived accidentals, key/time signatures, rests, barlines, and the staff-line/stem strokes — and the Engraver re-spaces it; the human visual-acceptance gate is met (goldens locked against the stub and the real Engraver). The Ch 7 engraving-boundary question resolved to: notation construction lives in to_constrained, horizontal spacing in the Engraver. done
P12-I2 RESOLVED (wired) epiphany-determinism / epiphany-layout-ir I Stable layout-object id derivation (MUSCLOID, Pass-11 item 2.6). Wired: epiphany-determinism now reserves the built-in DomainTag::LAYOUT_OBJECT_ID (MUSCLOID), and layout-ir's provenance derivations (single / multiply-manifested / synthesized) plus the engraving-decision id route through it (no longer borrowing MUSCCONF). Layout ids stay non-canonical, so only data-prov hex in the render goldens changed; no durable/interchanged artifact. See layout-ir/DECISIONS.md and req:layoutir:object-id-derivation. done
P12-I3 RESOLVED (I-4a) epiphany-layout-ir I The bundled BRAVURA_METRICS were approximations disagreeing with the renderer's genuine outlines. Resolved by I-4a: the metrics table is re-extracted from the same SHA-pinned bravura-1.392 font the outlines come from, with bboxes rounded outward so each metric box contains the drawn ink (a render-svg test proves containment); BRAVURA_VERSION = SemVer(1, 392, 0). A coupled barline-placement bug it surfaced (bottom-origin glyph floated) was fixed in the same increment. done
P12-K1 epiphany-ops K A v0 RespellPitch carried a ContentHash fingerprint of the spelling, not the PitchSpelling. The v0→v1 migration (Operation Catalog, M1) cannot invert a fingerprint, so it recovers the spelling from the score-graph context (an explicit per-pitch spelling attachment whose canonical bytes hash to the fingerprint) and returns MigrationError::Irreversible (bundle opens read-only) when the context lacks it. Every other representative payload migrates self-contained; this is the lone exception. Confirm the read-only fallback is the intended disposition vs. requiring a v0 corpus that preserves spelling pre-images. G / Pass 12 (migration)
P12-K2 epiphany-ops K The Transpose op (Operation Catalog, M2 Group 1) carries a minimal chromatic_steps: i32 interval and reduce_onto applies it as a CMN alteration shift only. Faithful interval algebra (diatonic vs. chromatic intervals, octave/nominal renormalization, transposition in non-CMN pitch spaces) is the deferred Chapter 4 tuning-catalog territory. The prototype also clamps the shifted alteration to the i8 range, so an extreme transpose silently saturates instead of renormalizing — another reason the representation needs pinning. Pin the interval representation and transposition semantics when the tuning catalog lands. G / Pass 12 (tuning)
P12-H6 epiphany-core H Decomposition-attachment precedence: the spec says the decomposition pre-pass uses the "same precedence machinery" as spelling, but spelling's machinery is per-score configurable with priority/timestamp tie-breaks while DecompositionAttachment carries no priority and the graph has no DecompositionPrecedence field. The audit fix implements the fixed default order (UserChosen > Imported > Propagated > Inferred, canonical attachment order as tie-break). Decide whether decomposition precedence is configurable (a canonical-codec change) or fixed. G / Pass 12 (decomposition)
P12-H7 epiphany-core H Authored decompositions for inference-ineligible events: an authored attachment is exactly how a user would notate an ungriddable event, but the derived-annotation surface (mirroring spelling, which likewise ignores attachments on spelling-unavailable pitches) only resolves overrides where inferred output exists. Needs a spec answer for both pre-passes. G / Pass 12 (pre-passes)
P12-K3 epiphany-ops K Content modification of a SYSTEM_DERIVED pitch: ModifyEvent/ModifyIdentifiedPitch can rewrite a synthetic pitch's intrinsic content in place, silently invalidating the id's content-derivation (Invariant 11). The new reduction-time collision check deliberately does not treat in-place rewrites as mints. Decide whether reduction must refuse them outright. G / Pass 12 (identity)
P12-K4 epiphany-ops K ResolveConflict beyond the concurrent case: the spec pins outcomes only for concurrent differing resolves; the implementation applies the same rule to causally-later resolves (so an intentional re-resolution cannot supersede) and reads AlreadyApplied for any resolve against a Dismissed conflict. Also: the meta-conflict record cannot name the contested conflict in affected_objects because TypedObjectId has no Conflict kind. Pin the causally-later semantics and decide whether conflict records need an addressable object kind. G / Pass 12 (conflict resolution)
P12-C1 epiphany-ops C Multi-source cue re-anchoring: the rule table's action is plain "cascade-delete" (implemented: any source deletion cascades, like Tie) but its rationale ("a cue with no source is meaningless") implies truncate-while-any-source-survives. Pin one reading. G / Pass 12 (re-anchoring)
P12-C2 epiphany-ops C Graphic-gesture Range "truncate" is underdetermined. Implemented reading: a dead event-anchored range endpoint moves to its containing region's edge (start→Start, end→End, zero offset). Define "truncate" normatively. G / Pass 12 (re-anchoring)
P12-C3 epiphany-ops C Analytical-annotation range reconstruction: a wall-clock (region-relative) or indeterminate event span cannot be expressed as a stored Range anchor without region-origin resolution, so such annotations orphan. State whether orphaning is the sanctioned outcome or an expressible form is required. G / Pass 12 (re-anchoring)
P12-C4 epiphany-ops C ReanchorReason has no same-canvas variant: a rank-4 (same-canvas) survivor is recorded ExplicitFallback rather than appending a discriminant. Ratify a beyond-region reason or bless the fallback recording. G / Pass 12 (re-anchoring)
P12-K5 epiphany-ops K Equivocation resolution's third path — a profile-declared deterministic selection function (e.g. lowest-hash-wins) — is unpinned and unimplemented; the reducer has no policy hook. Referenced from the catalog §ResolveEquivocation rationale. G / Pass 12 (equivocation)
P12-K6 epiphany-ops K ResolveEquivocation edge semantics to pin: cascaded resolves (a promoted candidate that is itself a resolve does not govern a further promotion — single-pass implemented, vs. fixpoint); interaction with HLC-monotonicity quarantine (may a quarantined resolve govern?); a resolve held pending by its own causal gaps still governs promotion (set-level rule) while its effect stays pending; whether the invalid-target/chosen no-op warrants a dedicated PreconditionFailureReason (implemented: reuses TargetMissing). G / Pass 12 (equivocation)
P12-K7 epiphany-ops K Advisory-precondition catalog: the spec declares the duration-boundary advisory only for InsertEvent while the implementation also applies it to ModifyEvent's replacement value — state ModifyEvent's bucket explicitly. Also: which advisory checks are blocked on graph-model completion (Instrument declared range; a Region slur-spanning permission flag; which extent shapes constitute a resolvable musical end bound). G / Pass 12 (validation)
P12-I4 epiphany-layout-ir I Constraint-strength attachment: Ch9 defines ConstraintStrength and says the solver consumes constraints "in normalized form", but neither the normalized form nor Ch7's LayoutConstraint provides a channel for an instance to carry strength. Implemented rule: break strength = BreakKind (Hard→Required, Soft→Preferred{1.0}); other core families Required; Registered conservative Required. Bless the rule or add a strength field. G / Pass 12 (solver)
P12-I5 epiphany-layout-ir I No renderable status exists for "constraints present but not evaluated": every renderable SolveStatus is documented as "all hard constraints satisfied", leaving a below-conformance passthrough solver no honest report. Implemented encoding: SolvedWithWarnings + satisfied_hard_constraints == false + a warning. Sanction it or define a non-evaluating-tier report shape. G / Pass 12 (solver)
P12-I6 epiphany-layout-ir I The spacing pass MUST "build collision constraints" but no per-tier minimum emission set is named. Implemented floor: successive-notehead-column no-collision chains + per-glyph region containment + user-break constraints. A normative Minimal-tier floor would make the acceptance surface testable. G / Pass 12 (solver)
P12-D1 RESOLVED (Binary Format 0.1.0 §7.6, req:binfmt:opindex) epiphany-bundle D Operation-index provisional encoding (block-refs + id-sorted entries with u32 block ordinal and u32 in-block offset; golden-locked) awaiting Binary Format companion ratification, together with: the offset's meaning (first content byte within the uncompressed block payload), a normative definition of "stale" (implemented: index block-set ≠ manifest operation_roots under full-ChunkRef equality), the one-slot-per-id invariant, the load-bearing property that the envelope encoding leads with the 16-byte OperationId, and whether the commit-time "grown significantly" SHOULD gets a threshold or stays implementation-defined. Ratified as-implemented; refresh threshold pinned implementation-defined (open question retained in the companion). done
P12-E1 RESOLVED (Binary Format 0.1.0 §8.1, req:binfmt:ext-blobs) epiphany-layout-ir E Provisional canonical byte form for the EditBarrier/BarrierScope/BarrierCondition tree and the two ExtensionDeclaration blobs (push_set framing, u64 LE lengths; golden-locked). Ratified as-implemented. done
P12-E2 RESOLVED (Binary Format 0.1.0 §8.2, req:binfmt:condition-depth) epiphany-layout-ir E The spec places no bound on BarrierCondition recursion; the decoder needs one against adversarial bytes. MAX_CONDITION_DEPTH = 64 implemented — the companion pins 64 as the normative bound (decoders MUST reject deeper; writers MUST NOT emit deeper). done
P12-E3 RESOLVED (Binary Format 0.1.0 §8.1, req:binfmt:object-kind-open) epiphany-layout-ir E Barrier ObjectKind byte form = the TypedObjectId 16-bit discriminant (2 LE bytes) with open-value decode (unknown kinds never match, preserving append-only forward compat). Representation and open-value stance ratified. done
P12-E4 epiphany-editor-core E Barrier matching for operations with no graph target (SetMetadata, DeclareTransaction — implemented: score-wide barriers only) and for opaque Registered operations (implemented: fully conservative match) is unspecified. G (Ch. 8)
P12-E5 epiphany-editor-core E The unsafe-edit tombstone MUST has no defined mechanism: the manifest-side form (drop declaration + preserved roots? an explicit tombstone record?), interaction with required = true, and whether crossing immediately deactivates the extension's remaining barriers (implemented: yes, recorded via extensions_requiring_tombstone() for the next bundle write). G (Ch. 8)
P12-K8 epiphany-ops K Create score / canvas remain unavailable K1 slots: the document root and canvas are inline singletons (no TypedObjectId::Canvas; the root is never op-minted — genesis is Score::empty + bundle creation). Turning them into operations needs an addressable root/canvas object model. Decide: define one, or ratify genesis as deliberately outside the operation set. G (graph model)
P12-K9 epiphany-ops K Differing-value re-creates (a live id re-carried with different content: CreateStaff, the carried TimeSignature, container creates) refuse with TargetMissing, which misnames the situation. Decide whether a dedicated PreconditionFailureReason (appended) is warranted. G / Pass 12 (vocabulary)
P12-K10 epiphany-ops K Undo strand-blocks (StrictInverse refusing to tombstone a minted object still referenced by a live non-member, e.g. a staff with a surviving instance) reuse ConflictKind::TransactionConflict. Decide whether undo refusals deserve their own conflict kind. G / Pass 12 (undo)
P12-K11 epiphany-ops K An undo's value restorations enter the write chains as ordinary writes by the undo op, so a second undo of the same transaction sees the first as a superseding writer (Conflicted/skip) while absence-restorations repeat idempotently — a documented asymmetry. Decide whether chain writes need distinguished undo provenance so repeated undo is uniformly idempotent. G / Pass 12 (undo)
P12-I7 epiphany-engrave I Page geometry has no graph home: the spec names Canvas.layout_defaults ("paper size, margins") but defines no type, and adding a Canvas field is a schema-major change under the companion's frozen-layout rule. Casting-off therefore uses an engraver-side PageGeometry default (A4 at an 8mm staff: 105x148.5 ss, 7.5 ss margins, documented arithmetic). Define CanvasLayoutDefaults with the data-model schema-major; until then solvers MAY default. G (graph model, schema-major)
P12-I8 epiphany-engrave I Break-constraint satisfaction predicate: implemented as "a SystemBreakAt/PageBreakAt is satisfied iff the final layout starts a system/page at that slot" (a region-first slot is trivially satisfied). Ch7/Ch9 never define satisfaction for break constraints; ratify the predicate. G / Pass 12 (solver)
P12-I9 epiphany-layout-ir I Honouring a user break must attribute the decision to its override (DecisionSource::UserOverride(id)), but constraints carry no override identity; implemented via a ConstrainedLayoutIR.break_origins sidecar populated by to_constrained. Bless the sidecar or widen the normalized constraint record. G / Pass 12 (solver)
P12-I10 epiphany-layout-ir I System-spanning strokes split at system boundaries need synthesized provenance for continuation segments; implemented as SynthesisKind::Registered(SYSTEM_CONTINUATION_SYNTHESIS) with a deterministic (original, ordinal) instance key. Add a first-class continuation synthesis kind or bless the registered id. G / Pass 12 (provenance)
P12-I11 RESOLVED (engrave v3 widow-rebalance) epiphany-engrave I RS-1 honestly failed the Minimal casting-off threshold under the reference engraver (measured 1.0 vs 0.90): greedy first-fit left a two-measure stub last system (width CV 0.6145 ≥ the 0.5 anchor). Resolved the honest way — an engrave-side casting-off balance pass, no catalog change: casting-off gained a second widow-rebalance phase that 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 defines for the break family (width imbalance vs non-final underfill; both share the 0.5 anchor). RS-1 now casts six/four instead of eight/two: casting_off 1.0 → 0.4463, system_break 0.254 → 0.677, every axis ≤ 0.90. ENGRAVER_VERSION 2 → 3; render goldens regenerated; the suite's Xfail row promoted to a plain Pass. The casting_off 0.5 anchor and the Minimal column stood — the engraver improved, not the threshold — so the Quality Metric Catalog is normatively unchanged. done
P12-I12 epiphany-engrave I The Standard-tier spacing floor warns on short healthy scores: 38-column entries with a wide clef/key lead measure spacing CV 0.360.41 > the 0.32 Standard floor. Consider a lead-aware or duration-aware refinement of the spacing_distortion raw measurement (the catalog's optical-spacing open question). G / Pass 12 (quality)

Not yet open elsewhere

Agent I (Track A) has contributed P12-I1..I6. Track B's Agent K has contributed P12-K1..K7; H has contributed P12-H1..H7 (H6/H7 from the 2026-07 spec-compliance audit follow-up, alongside K3/K4). The 2026-07 Push-3 wiring work added C1..C4 (re-anchoring), D1 (bundle operation index), and E1..E5 (edit barriers). The Phase-3 first tranche (casting-off + K1 schema-fill + value-restoring undo, 2026-07-02) added C5, K8..K11, and I7..I10. The second tranche (Quality Metric Catalog 0.1.0 + Reference Suite 0.1.0 + real engraver metrics + the suite harness + the multi-system click fix, 2026-07-03) added I11..I12. A follow-up (2026-07-03) resolved I11 (struck through above): casting-off gained a widow-rebalance phase (engrave v3), so RS-1 passes every Minimal threshold with no catalog change — I12 (the Standard-tier spacing floor on short scores) stays open. Agent J's Binary Format companion now exists (spec/binary_format.tex, v0.1.0): it ratified the P12-D1/E1/E2/E3 inputs (struck through above) and discharged the crates' provisional-codec notes (core P11-4, ops "provisional canonical encoding", bundle P11-D2/D4/D5). Its three open questions (SnapshotId derivation, index-refresh threshold, u64/u32 prefix unification at the next schema major) live in the companion itself, not as batch rows.