Commit Graph

14 Commits

Author SHA1 Message Date
Levi Neuwirth 9b5339f8f3 Schema major 2 Phase D: the repeat-authoring pair (code tranche)
CreateRepeatStructure / DeleteRepeatStructure land end-to-end,
review-hardened (five-dimension workflow review; 19 findings triaged —
12 verifier agents lost to a session limit were verified by hand).

epiphany-ops:
- CreateRepeatStructureOp { repeat } (lp(RepeatStructure), wire 28,
  BORN AT V2: schema_major always 2 — kind/voltas are unconditional
  fields) and DeleteRepeatStructureOp { repeat } (bare id, wire 29,
  major 0: minimal stamping over a major-0 layout; the discriminant a
  schema-minor append). OperationKindTag 28/29 name-verbatim with
  validating decode; golden tables grown to 30; migrate/v0 identity
  arms; lib re-exports.
- Reduction: set-union mint (live-id => AlreadyApplied without value
  comparison — the cross-cutting discipline; RecreateContentMismatch
  scope unchanged) with the ALL-anchor-sites-live precondition;
  delete-wins tombstone; the "Repeat structure / Anchor" rule-table
  row wired into BOTH the ledger (reanchor_for_tombstone arm, min-id
  survivor, cascade when dry) and the graph (every dead site rewrites
  to the same survivor), agreement asserted by tests incl. the
  DalSegno jump-target case.
- Undo: materialize_graph_tombstones gains RepeatStructure — and the
  pre-existing SPANNER GHOST fix (an undone spanner mint never left
  the graph), regression-locked.
- validate.rs: VoltaEndingsIllFormed advisory (non-empty, 1-based,
  strictly ascending; interactive-only).
- Canonical-base honesty: blake3 re-pinned for the corpus stream
  shift, its comment corrected (the seeded repeat creates all no-op),
  and the property covered surgically by
  the_canonical_base_embeds_no_repeat_values (two reductions
  differing only in repeat v2 content => byte-identical bases).

epiphany-core:
- RepeatStructure::anchor_sites()/anchor_sites_mut(): THE single
  site-set walk (start/end, jump targets, volta spans), consumed by
  reduction, the editor barrier seam, the invariant walk, and the
  cross-reference index — replacing five hand-rolled copies and
  fixing a SIXTH, silently-stale one (indexes.rs had never learned
  the Phase-B kind/volta anchors; regression-locked).
- RepeatStructure joins the CanonicalValue seam (strict per-value
  decode); decode-fuzz corpus gains valid_score_rich_with_repeats
  (DalSegno + voltas) CORPUS-LOCAL — shared render fixtures stay
  repeat-free until E1 (zero golden churn).

editor-core / gui / testkit / layout-ir:
- Barrier seam: repeat_event_refs + subjects_of arms +
  graph_structure_endpoints arm, gated end-to-end by
  repeat_authoring_kinds_derive_subjects_and_gate_on_barriers.
- Generators: operation_payload -> below(30); graph-session gen ->
  below(14); ops fuzz gen_payload -> below(27); layout_stub
  gen_operation_kind_tag unstaled 24..=29 (the Phase-3 tags were
  already missing); GUI name table.

Spec touch-ups (review findings): catalog says "strictly ascending";
the survivor tie-break is now explicit in the core rule-table row and
catalog (identifier-order minimum among multiple survivors;
proximity-aware four-key selection deferred, as for spanners).

Trail: ops + core DECISIONS entries; spec/PASS13_CANDIDATES.md opens
the Pass-13 ledger at three candidates (P13-K1; P13-D1 undo-driven
tombstones bypass ledger re-anchoring — pre-existing class; P13-D2
cue-cascade repair-trail ordering).

Full gate: fmt, clippy -D warnings, rustdoc -D warnings, 30 workspace
suites, conformance scale 1 (8/8).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NEs4aYiu8MXjdYdMxw8PTd
2026-07-07 20:06:18 -04:00
Levi Neuwirth 794400c4c7 Schema major 2 Phase B: snapshot side + honest stamps (data-model fills)
The nine type bodies fill to the ratified Ch5 shapes and the wire moves
to the Binary Format §Schema Major 2 layouts, review-hardened (high-
effort review; 8 findings, 7 fixed + 1 deferral sharpened).

epiphany-core:
- 19 new leaf types in graph.rs (SlurKind/CurveDirection/
  CurvatureOverride/SpanStyle/LineStyle/SpaceUnit/SubBeam/
  BeamGeometryOverride/SpannerKind+5 payload types/RepeatKind/Volta/
  StaffBracketKind/MetadataEntry/MetadataValue/Timestamp/
  SoundConfiguration/TranspositionInterval/UnpitchedMember) with the
  ratified discriminants (cstyle_enum_codec! reused; tagged unions
  hand-written); nine struct fills appended in wire order.
- The frozen wire forms generalized to a SHARED sub-codec layer
  (enc_/dec_*_v1, v0==v1 for every type major 2 changed; vec framing
  through enc_/dec_vec_v1) used by the new decode_v1_score/
  encode_v1_score AND the rerouted v0 pair — major 2 touched types the
  v0 walk had treated as unchanged (metadata, staves, cross_cutting,
  staff instances transitively). Strict-canonical guards on every
  versioned path; decode_canonical_versioned dispatches {0,1,2} with
  composed default-fill migration.
- Invariants extended to the new reference-bearing fields (REVIEW
  FIX): Beam.sub_beams events, RepeatKind DaCapo/DalSegno anchors,
  Volta spans now covered by CrossCuttingRefsResolve + the anchor
  model walk, with negative tests.
- Tests: v1 migration size-anchor (v1 omits exactly the appended
  default bytes — the frozen encoder cannot drift), a non-default
  round-trip covering every new field and every SpannerKind/RepeatKind
  wire arm, fuzzer corpus gains genuine-v1 forms + the major-2 seam
  with enforced must-decode-Ok on unmutated frozen forms.

epiphany-ops + epiphany-bundle (Phase C's semantic core, landed here
deliberately — the live codec flip makes CrossCutting/Staff/Metadata
payload bytes v2 immediately; shimming nine transitively-embedded
types the major-1 D1 way was throwaway):
- Minimal-stamping OperationKind::schema_major per the ratified rule
  (CrossCutting/CreateStaff/SetMetadata always 2; CreateRegion 2 iff a
  carried instance bears Some(staff_lines_override) else 1;
  CreateStaffInstance/SetStaffLayout 2 iff Some else 0), unit-locked.
- Bundle op-block accept-set [0,2]; SchemaVersion::V2;
  beyond-accept-set tests moved to major 3; testkit V2
  stamp-derivation test.
- the_canonical_base_is_byte_identical_across_data_model_majors:
  pinned blake3 of a seeded reduction — the companion's SHOULD that
  the canonical base never moves across data-model majors.
- The op-payload migrate-on-read deferral restated precisely in
  DECISIONS (no consumer byte-reconstructs op payloads today; the
  first one must bring per-type frozen payload decoders).

Zero golden churn (fixtures deliberately carry v2 defaults).
Instrument::new consolidates the sweep's default fills. Full gate:
fmt, clippy -D warnings, rustdoc -D warnings, 30 workspace suites,
conformance scale 1 (8/8).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NEs4aYiu8MXjdYdMxw8PTd
2026-07-07 16:30:07 -04:00
Levi Neuwirth 93f3dfde93 G-pass follow-up: unsupported pre-pass algorithm ids error
Post-commit review finding: req:pitch:spelling-algorithm /
req:time:decomposition-algorithm ratified MUST-error for unregistered
algorithm ids, but derive_annotations kept the pre-ratification
derive-nothing-under-honest-profile behavior (and a test locked it).
The spec text stands; the code moves: derive_annotations returns
Result<DerivedAnnotations, PrePassError>, rejecting unregistered ids
up front — a silently-empty derivation is indistinguishable from a
legitimately empty score, and would silently disagree with an
implementation that does support the requested id. All production
callers use the default profile (.expect); the stale lock test is
rewritten as unknown_algorithm_ids_error; PrePassError re-exported.

Full gate green: fmt, clippy -D warnings, rustdoc -D warnings, 30
workspace suites, conformance scale 1 (8/8).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NEs4aYiu8MXjdYdMxw8PTd
2026-07-07 11:32:05 -04:00
Levi Neuwirth aff1809421 Pass 12 G-pass: ratify the full batch (28 rows) — spec tranche
The G-ratification pass over the accumulated PASS12_BATCH backlog
(worklist: spec/PASS12_WORKLIST.md; dispositions:
PASS12_RATIFICATION_LOG "G-pass tranche"). Four project-lead
decisions: K12 slur permission = AND, H7 authored-uninferred
annotations SURFACE, K4 ResolveConflict = no supersede, K8 genesis
outside the operation set. Three named deferrals: H2 (narrowed;
spelling-v2 + notation refinement), K2 (tuning catalog), K5 (Profile
Conformance companion).

core_spec: spelling + decomposition move to profile-declared with
ratified v1 defaults (req:pitch:spelling-algorithm,
req:time:decomposition-algorithm — two open-question boxes closed);
authored-uninferred surfacing (req:pitch:authored-uninferred);
decomposition precedence pinned FIXED; system-derived content
immutability (K3); genesis note (K8); slur AND advisory (K12);
re-anchoring table C1/C2/C3 + SameCanvasNearer variant (C4); barrier
matching + unsafe-tombstone semantics (req:format:barrier-matching,
req:format:unsafe-tombstone); solver kind-strength /
sub-conformant-report / Minimal-floor requirements (I4/I5/I6); stale
OperationKindTag listing gains the eleven appended tags.

operation_catalog 0.5.0 -> 0.6.0: K1 migration fallback long-term;
K4 no-supersede; K6 edge semantics (single-pass, quarantine excluded,
pending governs); K5 deferral pinned; K8 slots RETIRED; K10 reuse
blessed; K11 asymmetry normative; K12 AND; K2 prototype pin;
K3/K9 preconditions.

binary_format 0.3.0 -> 0.4.0: appended vocab discriminants
SystemDerivedContentImmutable(12), RecreateContentMismatch(13),
SameCanvasNearer(6); E5 tombstone-encoding open question.

All three PDFs rebuilt clean, zero undefined references. Batch rows
struck 28 -> 0 (tracker CLOSED); CONFORMANCE.md caveat dropped;
DECISIONS cross-refs in core/ops/layout-ir/editor-core (new file).

Code tranche (H7 surfacing, K3/K9/C4 discriminants) follows.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NEs4aYiu8MXjdYdMxw8PTd
2026-07-07 10:23:30 -04:00
Levi Neuwirth 3e91a8302a Push 4: Binary Format companion, F1 benches, subquadratic reduction order
The audit's fourth push: the biggest outstanding Phase-2 item plus the
performance gate. 793 workspace tests pass; clippy -D warnings, fmt,
and rustdoc (deny-warnings) clean; all three spec documents build with
zero undefined references.

Binary Format companion (spec/binary_format.tex, v0.1.0 — Agent J's
deliverable, 43 pages):
- Twelve chapters transcribed from the golden-locked implementation:
  encoding conventions (the three prefix/endianness regimes, a
  normative no-varint rule, reject-never-normalize decode discipline),
  identifiers imported from the core spec's Canonical Byte-Layout
  Reference, primitive value encodings, the whole-Score positional
  codec ratified as the schema-major-0 wire form, operation wire
  forms (envelope field order with the normative id-leads property,
  the OperationPayload 0..=3 and OperationKind 0..=23 tables,
  effects/conflict/anomaly/MaterializedState vocabulary), the bundle
  physical layout (64-byte header, 256-byte superblock, chunk
  preimages and framing, ChunkRef, manifest body order), the
  operation-index payload, and the extension-blob/edit-barrier byte
  forms.
- Ratifies P12-D1 (req:binfmt:opindex), P12-E1 (req:binfmt:ext-blobs),
  P12-E2 (req:binfmt:condition-depth, MAX_CONDITION_DEPTH = 64
  normative), and P12-E3 (req:binfmt:object-kind-open) — batch rows
  struck through; discharges the provisional-codec notes in core
  (P11-4), ops, and bundle (P11-D2/D4/D5) DECISIONS with ratification
  cross-references.
- Pins the frozen-layout schema-evolution keystone: within schema
  major 0 every positional struct layout is frozen; a field-set change
  is a schema-major change with migration — formally grounding the
  data-model-expansion staging decision. Open questions kept honest
  in-document: SnapshotId derivation, index-refresh threshold, u64/u32
  prefix unification at the next major.
- Not yet delivered from J's charter: the cross-implementation decoder
  test and the wire-format fuzzer (follow-up harnesses).

F1 benches (crates/epiphany-testkit/benches/, per the F0 decision):
- criterion 0.5.1 (workspace dev-dependency; MSRV 1.77 respected with
  documented transitive pins: clap 4.5.53, half 2.4.1).
- reduction bench at 1K/10K/50K envelopes with the Chapter-10 budget
  (>10,000 envelopes/second cold) written in the bench as a Pass/Xfail
  gate; bundle benches for the typical-edit commit (<=50 ms; measured
  ~14.7 ms on real disk after catching that tmpfs neuters fsync) and
  the open/bootstrap read (<=200 ms; measured ~60 us).
- CI: quick budget gates in the conformance job, full gates nightly.

Subquadratic canonical_reduction_order (the F-surfaces/K-fixes
handshake, closing K's 10K-envelope acceptance gate):
- The bench documented the failure (50K at ~1.7K env/s, a 29 s cold
  reduction; two O(n^2) loops); the fix replaces pair enumeration with
  threshold/frontier readiness per replica plus explicit-dot dependent
  lists and a stamp-tuple binary heap — O((n + sum(context)) log n),
  never materializing covered pairs.
- Byte-identical order: same edge relation, same ready predicate, same
  total order; the old implementation is retained as a test-only
  oracle with element-for-element order-equality property tests over
  fuzz sets, adversarial sets, and directed shapes (2,000-envelope
  full-coverage chains, dot cycles, duplicate-id stamp ties),
  mutation-tested for sensitivity.
- Measured: 1K 155K->674K env/s, 10K 12.5K->257K, 50K 1.7K->87K; all
  three scale points now pass and the 50K row is promoted from Xfail.

Also: fixed nine rustdoc private/unresolved intra-doc links that had
accumulated across the pushes (the CI deny-doc-warnings job would have
failed on them).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NEs4aYiu8MXjdYdMxw8PTd
2026-07-02 19:02:07 -04:00
Levi Neuwirth 92aaccf7e2 Pushes 1+3: fix the MUST-level violations, wire the types-only machinery
Two audit pushes whose code edits interleave line-by-line in the same
files (reduce.rs, bundle.rs, the DECISIONS logs), committed together so
the tree at every commit builds. Gate: 784 workspace tests pass, clippy
-D warnings clean, fmt clean.

Push 1 — the true MUST violations, all fixed:
- bundle: zstd read support on both read paths, output bounded by the
  declared uncompressed_length, typed decompression errors, explicit
  CompressedManifest rejection (zstd 0.13 workspace dep; write path
  stays uncompressed per the Phase-3 deferral).
- ops: system-derived counter collision check — mint registry seeded
  from the base graph, canonical-order pre-walk, halt via the new
  PendingReason::HaltedBySystemCollision (discriminant 4, additive)
  with transaction-atomicity and causal-dependent closure; neither
  input set occupies a collided counter. canonical_pitch_bytes made
  pub in core for the MUSCSPCH preimage.
- ops: Transpose skips tombstoned targets per the catalog; missing
  targets still refuse the whole operation.
- ops: marker re-anchoring recorded as a RepairRecord in the
  triggering operation's effect; ResolveConflict meta-conflicts name
  both resolvers; base-free pitch-id freshness; reserved effect
  vocabulary annotated.
- core: decomposition pre-pass honors authored attachments
  (resolve_decomposition, spec-default precedence); inversion
  tolerance typed as a TempoIntegration-class Tolerance.
- CONFORMANCE.md: the determinism conformance statement required by
  Appendix D — all seven declarations.

Push 3 — wiring the types-only machinery:
- layout-ir/engrave: to_constrained emits real constraints (successive
  notehead no-collision chains, per-glyph region containment, soft
  user-break constraints); ConstraintStrength{Required, Preferred}
  with strength-by-rule; Preferred violations surface as warnings, not
  failures; StubSolver reworked honest-but-renderable. SVG goldens
  byte-identical; snapshot constraint counts regenerated (0->90/15).
- layout-ir: to_logical projects user system/page breaks as anchored
  EngravingOverrides with paired UserOverride-sourced decisions
  (OverrideKind::SystemBreak/PageBreak carry TimeAnchor, ratified in
  the spec alongside).
- layout-ir/ops/editor-core: edit-barrier bridge — decode mirrors for
  the whole barrier tree (reject-never-normalize, NFC revalidation,
  MAX_CONDITION_DEPTH = 64), golden-locked blob codec for the
  ExtensionDeclaration fields, a barrier gate in apply and
  apply_transaction backed by a Score oracle and real containment
  contexts, and apply_unsafe recording the crossed extensions in
  extensions_requiring_tombstone() for the next bundle write.
- ops: ResolveEquivocation meta-operation per the newly ratified
  catalog entry — payload discriminant 3 (appended), set-level
  earliest-resolve-governs promotion, ResolveConflict-mirrored
  meta-conflicts, permutation-invariance fuzz; the missing golden
  locks on the OperationKind/OperationPayload wire tables added.
- ops/editor-core: validation modes — ValidationMode + a non-canonical
  advisory layer (validate.rs), an authoring gate before minting, and
  reduction pinned as replay mode by construction (canonical bytes
  untouched).
- bundle: the operation index (opindex.rs) — provisional golden-locked
  payload, binary-search locate, staleness defined as full-ChunkRef
  set equality against operation_roots, and the reject-and-rebuild
  discipline (a defective index is never bundle corruption).
- ops: re-anchoring rule table completed — the four-key "nearest"
  ordering computed from base-free ledger indices; markers re-anchor
  to the nearest live event in the same staff instance (replacing the
  Push-1 region-start stand-in); cue-source cascade; graphic-gesture
  Events/Range/Free rows; comment and analytical-annotation orphaning.
  Zero appended discriminants.

Spec enablers ratified with Push 3: catalog §ResolveEquivocation
(0.3.0 -> 0.4.0) and anchored break overrides; 16 new Pass-12 rows
filed (C1-C4, K5-K7, I4-I6, D1, E1-E5). The data-model payload
expansion (SlurKind, beam geometry, voltas, instrument bodies,
metadata) is deliberately staged to the Binary Format companion — the
positional graph codec has no value-level versioning, so filling those
structs is a schema-major break that should land once, with J.

Also carries the pre-existing editor-track increment: the atomic
tuplet overwrite (CascadeDeleteTuplets prunes decomposition
attachments naming the cascaded tuplet).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NEs4aYiu8MXjdYdMxw8PTd
2026-07-02 17:10:50 -04:00
Levi Neuwirth 4556ede9f0 Phase 2 (Agent K) M1: value-typed operation payloads + Operation Catalog scaffold
Foundation milestone for Track B's Operation Catalog: shift epiphany-ops from
the v0 identifier-only payload projections to durable value-typed payloads, and
scaffold the companion spec. Scope: the representative §6.10 set (7 primitives +
2 meta-ops); the slice-driven K0 expansion follows.

Core (the K↔J seam):
- epiphany-core exposes a public `CanonicalValue` trait (canonical_bytes /
  decode_canonical) delegating to the existing private `Codec` machinery, for
  Event/Rest/PitchSpelling/Tie/Slur/Beam/Spanner/RegionTimeModel/TimeAnchor.
  No new byte layout — a value's bytes equal what the whole-score codec emits,
  so all goldens / criterion 4 stay byte-identical.

Ops (value-typed payloads, frozen reduction rules):
- InsertEventOp{staff_instance,event:Event}, RespellPitchOp{pitch,spelling:
  PitchSpelling}, CreateCrossCuttingOp{structure:CrossCuttingValue},
  ChangeRegionTimeModelOp{...,new_time_model:RegionTimeModel},
  SetUserSystemBreakOp{...,anchor:TimeAnchor}, ReplaceWithRest{rest:Rest}.
  Payloads frame each value's CanonicalValue bytes behind a u32 length prefix.
- reduce.rs: read-sites only moved onto the value (rules, conflicts, ordering,
  promotion, re-anchoring, undo, transactions unchanged); reduce_onto now
  materializes the real event/structure instead of the C4 placeholder.
  MaterializedState.spellings now stores PitchSpelling (encode + decode updated).
- v0.rs: frozen identifier-only shapes (migration regression guard).
- migrate.rs: migrate_v0_envelope(v0, &Score) + project_v1_to_v0 + MigrationError;
  deterministic and equivalence-preserving. Respell spelling recovered from the
  score context; irreversible case is P12-K1.
- valuegen.rs: shared value-type builders (reused by fuzz, migration, tests,
  testkit). Resolves P11-C1; P11-C10 Dismiss recorded.

Testkit (Agent F merge gate):
- migration.rs: reduce(v1)==reduce(migrate(project(v1))) byte-identical, plus
  migration determinism and a non-vacuity guard; wired into acceptance.rs as
  agent_k_migration_equivalence_gate. Generators/harnesses build v1 payloads.

Spec:
- spec/operation_catalog.{tex,pdf}: new companion (independent semver) — framework
  + per-primitive template, the 7+2 representative primitives, the v0→v1 migration
  contract, and K1 framework slots for the remaining K0 primitives. Builds clean.
- PASS12_BATCH.md: P12-K1 (respell fingerprint irreversibility).

Gates: cargo build/fmt/clippy -D warnings clean; cargo test --workspace green
(incl. criteria 1/4/5/6 and the new K gate); conformance_suite scale 1 passes.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-24 11:52:02 -04:00
Levi Neuwirth 732660988d Phase 2: spelling + decomposition pre-passes (Agent H) with F merge gate
Land the two real pre-passes as canonical *derived annotations* (pure
functions of the materialized Score + profile, recomputed on
materialization, never serialized into canonical Score bytes), exposed via
`derive_annotations`:

- Spelling: a Temperley-style line-of-fifths centre-of-gravity preference
  rule (key-free, deterministic), preserving authored CMN letters and only
  inferring spelling for chromatic/integer input. `resolve_spelling`
  layers authored overrides above the inferred default (the RespellPitch
  precedence rule). `spell` now takes `&Pitch` and delegates to
  `simplest_spelling`.
- Decomposition: metric greedy-aligned splitting on a 1/4096 integer grid
  (barline + dyadic-boundary ties), with exact sounding->notated tuplet
  conversion before gridding. Components reconstruct the event duration
  (invariant 15).
- A per-event-kind eligibility `TaxonomyReport` so "ineligible" is always
  explicit and counted, never silently absent.

Test infrastructure (Agent F): a 29-fixture representative corpus +
taxonomy harness (corpus.rs), the H spelling/decomposition merge gate
(prepass_harness.rs), a discrete `tests/prepass.rs` CI target, conformance
stage [7b], a dedicated CI job, and the Pass-12 batch tracker.

Review hardening folded in (nine findings):
- Guard `decompose_metric` against a zero-length measure (was a
  divide-by-zero panic; now reported ungriddable).
- Resolve spelling-override priority via `Reverse` instead of negation
  (was an i32::MIN overflow).
- Verify spelling *register* (octave), not just pitch class, in the gate.
- Close the decomposition under-emission gap: the unusual-outcome
  taxonomy buckets are an exact per-fixture whitelist (classify_corpus
  step 5b).
- Generalize `accidental_ids` to a glyph stack so authored extreme
  alterations (triple-sharp+) reconstruct exactly instead of being clamped.
- Per-fixture spread checks in the non-vacuity tripwire and broad-bucket
  coverage, so no single rich fixture can carry a signal (partial-stub
  resistance); added a `mixed_rhythm` fixture for margin.
- Pin the integer-grid note-value math to the canonical rational helpers
  via an exhaustive test; cross-reference comments.
- Replace the O(n^2) tuplet innermost-resolution scan with an id index.

fmt + clippy -D warnings clean; 199 tests pass; conformance suite green.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011giSRaHCFCGm1Z2SWv6JHt
2026-06-23 16:33:39 -04:00
Levi Neuwirth 0d8ec61a3c Pass 11 audit follow-up: honest LayoutObjectId status + doc/test gaps
Independent audit of b2f2e20 / a7adbdc. The canonical, document-state byte
layouts were already correct and golden-locked; this closes the one real
spec-vs-code gap (in the non-canonical layout namespace) and the smaller
doc/test gaps around it.

LayoutObjectId (item 2.6): the spec normatively stated the id "is derived ...
with MUSCLOID" and the ratification log / layout DECISIONS header called it
"pinned" -- but no code uses MUSCLOID (stable_layout_id and
manifestation_layout_id are untagged; synthesized_layout_id borrows MUSCCONF),
and MUSCLOID cannot even be constructed: DomainTag::from_bytes accepts only
built-ins or MUSCS-prefixed tags, so wiring it requires changing the frozen
determinism crate (out of scope for a spec pass, and the spec itself says
MUSCLOID is not a canonical system tag). Kept MUSCLOID as the pinned Track-A
target and made every artifact honest that the v0 code is provisional:
  - spec: "is derived" -> "MUST be derived" (forward contract) + a note that
    the prototype mints provisional ids; changelog "pinned" -> "specified ...
    as the Track-A target".
  - records: ratification-log line 2.6 and layout DECISIONS header/body now
    state spec-pinned-but-code-provisional; stale "Pass 11 candidate 3"
    pointer now cites the ratified requirement.
  - provenance.rs comments name the MUSCLOID target and label the current
    derivation provisional.

Other fixes:
  - epiphany-core/DECISIONS.md: the Tuplet bullet still claimed degenerate
    ratios are caught by runtime invariant 16 "since a Tuplet is a plain
    struct" -- stale after the construction-time TupletRatio change. Rewritten.
  - codec.rs: added degenerate_tuplet_ratio_is_rejected_on_decode, guarding
    the TupletRatio::dec re-validation branch that no test exercised (the
    constructor was tested, the decode path was not).
  - spec: integrity-anomaly snippet kind.canonical_bytes() ->
    to_canonical_bytes() (the actual method).
  - ids.rs / reduce.rs: clarifying comments (ManifestId's intentional,
    golden-locked document_id/generation duplication; compute_promotions
    bucketing by voice == (staff_instance, original_voice) via Invariant 5).

Verification: cargo test --workspace (434 pass, +1), clippy --all-targets clean
(0 warnings), fmt clean; spec rebuilds (lualatex, 0 undefined refs, 254pp).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-22 10:02:05 -04:00
Levi Neuwirth b2f2e204a7 Pass 11: ratify provisional byte choices into normative spec text
Spec-revision pass (architecture unchanged) converting the v0
implementation's provisional, golden-locked choices into ratified
core_spec.tex text, so durable byte layouts are fixed before the
next-phase build-outs. Worklist: spec/PASS11_WORKLIST.md; per-item
dispositions: spec/PASS11_RATIFICATION_LOG.md.

Adopt-and-pin (bytes): TypedObjectId 16-bit BE discriminant table
0..=27 (added the 5 variants the code carried); promoted-voice
(MUSCSVCE), synthetic-pitch (MUSCSPCH, tuning always in identity),
and integrity-anomaly (MUSCSANM, now a reserved built-in tag)
derivations; ChunkKind/ProfileId/CompressionAlgorithm discriminants;
ManifestId preimage (manifest_id excluded); RationalTime/scalar
layouts + the codec convention baseline the Binary Format companion
inherits.

Decide-and-pin: tempo Linear interpolates speed (not bpm);
StructuralFieldCollision tags the winner Conflicted; lifted the
>2-way / partial-overlap voice-promotion rule to normative; pinned
TransactionCategory and ObjectKind core vocabularies; added
ResolutionAction::Dismiss so the Dismissed state is reachable by an
authored op; pinned the (non-canonical) LayoutObjectId derivation
(MUSCLOID).

Fixes: blob hashing is bare MUSCBLOB||payload (deleted the
contradictory "identically to chunks" phrasing); equal-generation
superblock rule (DivergentSameGeneration); defined ProfileConstraints
with the required RetentionPolicy + first-declared precedence; made
the DVV zero-based floor normative; reconciled the invariant count to
19 and named the three construction-time MUSTs — TupletRatio now
rejects degenerate ratios at construction (zero term or
actual==notated), enforced by a checked constructor + codec decode
validation.

Code changes carry regression tests; byte-layout golden tests now
cite their ratified requirements. Workspace green: cargo test, clippy
-D warnings, fmt; spec builds (lualatex, 253pp). Per-crate DECISIONS
files annotated with the ratification status.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011giSRaHCFCGm1Z2SWv6JHt
2026-06-21 22:30:06 -04:00
Levi Neuwirth 306871ea29 Finish Agent B (item 5): tolerance/overflow, region-overlap honesty, id lock-down
Closes the three remaining item-5 sub-parts found in the audit.

② Typed tolerance + overflow (tempo.rs, invariants.rs):
- Replace the ad-hoc `f64::EPSILON` speed-degeneracy guards with a named
  TempoIntegration `Tolerance` (relative, non-finite-safe), per Appendix D
  "no ad-hoc epsilons"; aligns code with the module's own claim.
- Guard the continued-fraction convergent recurrence with checked i128 ops
  (break on overflow) and bound the residual-fraction stop by 1/max_den
  instead of f64::EPSILON, so a pathological input can't silently wrap.
- Endpoints::of: wall-clock event end uses checked_add -> Endpoints::Unknown
  on overflow, not saturating_add (which could mask an ordering violation).
- Regression tests: equal-endpoint linear segment uses the constant limit;
  extreme inversion inputs don't overflow.

① Region-overlap honesty (invariants.rs):
- Unresolvable region-overlap checks (symbolic anchors + shared staff extent)
  were silently treated as valid. Add DeferredCheck + deferred_checks() to
  surface them explicitly; check_invariants stays sound (no false positives).
- Test proves an undecidable overlap is reported as deferred, not passed, and
  that a wall-clock-resolvable disjoint pair is neither violation nor deferred.

③ Identifier-derivation lock-down (graph.rs, pitch.rs, ids.rs):
- Golden-bytes tests pin derive_promoted_voice_id (MUSCSVCE 64-byte preimage),
  derive_system_pitch_id (MUSCSPCH input layout), and the TypedObjectId
  discriminant table + Registered layout, so an accidental layout change is
  caught (the derivations were concrete but unlocked).
- canonical_pitch_bytes NFC-normalizes strings at the derivation boundary,
  making the documented NFC guarantee explicit (no-op for the already-NFC
  catalog ids).
- DECISIONS P11-1/3/6 updated to record the pinned-and-locked layouts.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-21 18:48:03 -04:00
Levi Neuwirth f5aaa96b11 Land whole-score codec (item 5) and flip the M3 full-Score gate green
Implements a total, reversible canonical byte form for the entire
epiphany_core::Score graph, unblocking the byte-level full-Score serialization
gate that M3 had to defer.

epiphany-core/src/codec.rs:
- Score::canonical_bytes() / Score::decode_canonical() with a validating
  ScoreDecodeError and a forward-only Reader cursor.
- A local Codec trait with generic combinators (Option/Vec/BTreeSet/BTreeMap/
  tuple) and macros (struct_codec!/cstyle_enum_codec!/unit_codec!/
  catalog_id_codec!) so encode and decode stay symmetric across ~110 types
  spanning graph.rs, event.rs, pitch.rs, time.rs, tempo.rs.
- Uniform form: LE integers, one discriminant byte per tagged union, u32
  counts/length-prefixes, every variable-width leaf length-prefixed, raw UTF-8
  for free text (so decode(encode(x)) == x for any valid score; catalog ids are
  already NFC). EventArena round-trips via iter_canonical + insert.
- Two pub(crate) accessors added for the codec: EventOrderingDAG::edges_ref,
  SpellingPrecedence::order_ref.
- Tests: generator-score corpus (valid_score + valid_score_rich), exotic
  event/pitch variants the generators omit, distinctness, and decoder
  rejection of trailing/truncated/empty bytes.

epiphany-testkit:
- roundtrip::assert_score_serialization_stable: encode the real Score, store it
  as a bundle Snapshot, reopen + hash-verify, decode to an equal Score, and
  assert a byte-identical re-encode.
- convergence::materialized_score builds a real ~50-bar reduce_onto
  materialization for the gate.
- criterion_4_full_score_byte_roundtrip flips from #[ignore] to a live gate;
  wired into the conformance suite. Docs (lib.rs, README, core DECISIONS P11-4)
  updated to reflect the landed codec.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-21 18:15:07 -04:00
Levi Neuwirth e9c4bad7a6 Land M1 + M2 (Agent C): framework edge fixes and real-Score graph integration
M1 — fix Agent C framework defects, tests-first:
- causal ordering: topologically order DVV edges instead of assuming HLC
  alone implies causal order (false for adversarial remote envelopes);
  HLC only breaks ties among ready operations.
- anomaly cutoff: quarantine from the earliest counter participating in
  any violating HLC pair (suffix-minima), e.g. [100,200,50] quarantines
  from counter 0, not counter 1.
- pending detection: DVV contiguous ranges use the zero-based per-replica
  counter floor; first absent id in any asserted range holds the dependent
  pending (vector coverage, not only dots).
- transaction snapshots: rollback removes member-generated conflicts.
- edge tests in concurrent_reduction.rs for all six audited cases.

M2 — reduce onto Agent B's real score graph:
- OperationSet::reduce_onto(&Score) -> GraphMaterialization { state, score }
  mutates the real arena, voices, regions, tombstones, indexes, and
  cross-cutting structures; base-free reduce() retained.
- VoiceOrigin::SystemPromoted now carries { winning_operation,
  losing_operation, original_voice }; spec and Invariant 18 updated.
- graph-aware migration, forward undo, system breaks, promotion pre-pass.
- tests/graph_reduction.rs: 11 tests asserting check_invariants is clean,
  plus a 64-seed order-independence sweep.

Pass-11 spec decisions resolved (blocking subset): DVV floor (P11-C7),
HLC-vs-causality, promoted-voice derivation inputs (P11-C4 / core P11-3).
Payload/Score canonical encoding remain deferred to the companion docs.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-21 16:37:51 -04:00
Levi Neuwirth a2e9ec32f6 A B C D F 2026-06-19 12:42:31 -04:00