diff --git a/.gitignore b/.gitignore index 87e6ee1..ecebafe 100644 --- a/.gitignore +++ b/.gitignore @@ -22,3 +22,4 @@ spec/*.fls spec/*.log spec/*.out spec/*.toc +spec/*.xdv diff --git a/crates/epiphany-engrave/DECISIONS.md b/crates/epiphany-engrave/DECISIONS.md index 30460ab..706f9a8 100644 --- a/crates/epiphany-engrave/DECISIONS.md +++ b/crates/epiphany-engrave/DECISIONS.md @@ -116,9 +116,11 @@ inputs the solver cannot measure. schema major. **Schema major 1 now defines the type** (`CanvasLayoutDefaults { page_size: CanvasSize, margins: CanvasMargins }`, staff spaces, A4/8mm default) and ratifies its wire form (core spec + Binary Format 0.3.0, - Phase A); the **code graph home lands in Phase C** (`Canvas` gains the - field) and the engraver reads it in Phase C′. Until then the engraver takes - the geometry as a constructor parameter. Default arithmetic (1 staff space = staff height / 4 = 2.0 mm at + Phase A); the **code graph home landed in Phase C** (`Canvas` gained the + field). Wiring the engraver to *read* it (Phase C′) is a byte-neutral + follow-up **deferred** until a custom-geometry producer exists, so the + engraver still takes the geometry as a constructor parameter (every score's + `layout_defaults` is the A4 default today). Default arithmetic (1 staff space = staff height / 4 = 2.0 mm at an 8 mm staff): A4 210 × 297 mm → **105 × 148.5** staff spaces; 15 mm margins → **7.5** staff spaces; content area 180 × 267 mm → **90 × 133.5** staff spaces. 90 staff spaces wraps the ten-measure hand-off fixture @@ -390,3 +392,14 @@ testkit's reference-suite harness. floor). The alternative — a duration-proportional (optical) redefinition — needs the pipeline's deferred duration-aware preferred widths and stays the catalog's open question. + +## Break-constraint satisfaction predicate (Pass 12 P12-I8, ratified) + +The break-constraint satisfaction predicate — a `SystemBreakAt`/`PageBreakAt` at +`slot` is satisfied iff the final `ResolvedLayoutIR` starts a system/page at that +slot (a region-first slot trivially) — was ratified into the core spec by the +schema-major-1 track's Phase F (2026-07-06; core spec +`req:layoutir:break-satisfaction`; `spec/PASS12_RATIFICATION_LOG.md`, +schema-major-1 tranche). Satisfaction is a predicate on the output layout, not +the solver's spring state; casting-off evaluates the declared hard break +constraints as part of its tier claim. diff --git a/crates/epiphany-layout-ir/DECISIONS.md b/crates/epiphany-layout-ir/DECISIONS.md index cc925be..9edd388 100644 --- a/crates/epiphany-layout-ir/DECISIONS.md +++ b/crates/epiphany-layout-ir/DECISIONS.md @@ -445,3 +445,23 @@ all-worst `unmeasured()` vector, which a transcription test pins as excluded by the Minimal column ("measuring is part of the Minimal claim"). The catalog also blesses the existing `TieBreakingWeights::default()` (all 1.0) as the normative defaults — pinned by test rather than re-declared. + +## Break-origin attribution and system-continuation synthesis (Pass 12 P12-I9/I10, ratified) + +Two long-standing layout-ir dispositions were ratified into the core spec by the +schema-major-1 track's Phase F (2026-07-06; `spec/PASS12_RATIFICATION_LOG.md`, +schema-major-1 tranche): + +- **P12-I9 — break-override attribution via a sidecar.** Honouring a user break + carries `DecisionSource::UserOverride(id)`, but a normalized break *constraint* + (`SystemBreakAt`/`PageBreakAt`) carries no override identity. Attribution is + threaded through a `ConstrainedLayoutIR.break_origins` sidecar populated by + `to_constrained`; the normalized constraint record is deliberately **not** + widened (attribution is a projection concern, not a solver input). Ratified as + core spec `req:layoutir:break-origin-attribution`. +- **P12-I10 — system-continuation synthesis.** A stroke spanning a system + boundary is split; the post-first segments are synthesized under + `SynthesisKind::Registered(SYSTEM_CONTINUATION_SYNTHESIS)` with a + `(original, ordinal)` `stable_semantic_instance_key`. Since `LayoutObjectId`s + are non-canonical and re-derived per layout, the key need only be stable within + a layout. Ratified as core spec `req:layoutir:continuation-synthesis`. diff --git a/spec/PASS12_BATCH.md b/spec/PASS12_BATCH.md index eea278b..0298441 100644 --- a/spec/PASS12_BATCH.md +++ b/spec/PASS12_BATCH.md @@ -48,7 +48,7 @@ code instead is the failure mode this batch exists to prevent. | 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-K7~~ **RATIFIED (schema-major-1 track, 2026-07-06; see PASS12_RATIFICATION_LOG)** | `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) | @@ -62,10 +62,11 @@ code instead is the failure mode this batch exists to prevent. | 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 **(IN PROGRESS — schema-major-1 track)** | `epiphany-engrave` I | Page geometry had no graph home: the spec named `Canvas.layout_defaults` ("paper size, margins") but defined 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). **Phase A of the schema-major-1 bump defines the type** (`CanvasLayoutDefaults { page_size: CanvasSize, margins: CanvasMargins }` in staff spaces, A4/8mm default) and ratifies its v1 wire form (Binary Format 0.3.0); the **graph home lands in code in Phase C** (`Canvas` gains the field), after which the engraver reads it (Phase C′) — until fully landed, 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-K12 | `epiphany-ops` K | Cross-region slur spanning permission: `Region.permits_spanning_slurs` (schema major 1, P12-K7) gates the CreateCrossCutting(Slur) advisory, but which region governs a slur whose endpoints lie in *different* regions is under-specified. Implemented as conservative **AND** (a boundary is permeable only when both endpoint regions permit); "the start region governs" or "either side" are equally defensible. The advisory is authoring-only and never alters reduction, so the choice is not byte-affecting. Ratify one reading. | G / Pass 12 (validation) | +| ~~P12-I7~~ **RATIFIED (schema-major-1 track, 2026-07-06; see PASS12_RATIFICATION_LOG)** | `epiphany-engrave` I | Page geometry had no graph home: the spec named `Canvas.layout_defaults` ("paper size, margins") but defined 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). **Phase A of the schema-major-1 bump defines the type** (`CanvasLayoutDefaults { page_size: CanvasSize, margins: CanvasMargins }` in staff spaces, A4/8mm default) and ratifies its v1 wire form (Binary Format 0.3.0); the **graph home lands in code in Phase C** (`Canvas` gains the field), after which the engraver reads it (Phase C′) — until fully landed, solvers MAY default. | G (graph model, schema-major) | +| ~~P12-I8~~ **RATIFIED (schema-major-1 track, 2026-07-06; core_spec `req:layoutir:break-satisfaction`)** | `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~~ **RATIFIED (schema-major-1 track, 2026-07-06; core_spec `req:layoutir:break-origin-attribution`)** | `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~~ **RATIFIED (schema-major-1 track, 2026-07-06; core_spec `req:layoutir:continuation-synthesis`)** | `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~~ **RESOLVED (QMC 0.2.0: rhythmic-column spacing)** | `epiphany-engrave` I | The Standard-tier spacing floor warned on short healthy scores: 3–8-column entries with a wide clef/key lead measured spacing CV 0.36–0.41 > the 0.32 Standard floor (a spurious *diagnostic* — the scores all passed Minimal). **Resolved by the lead-aware refinement (Quality Metric Catalog 0.1.0 → 0.2.0):** `spacing_distortion` is now scoped to the system's **rhythmic columns** (slots bearing a notehead or rest), excluding the clef / key-signature / time-signature lead and treating barlines transparently (a note-to-note advance spans them) — so the furniture-width lead gap no longer inflates the CV. The three entries drop to 0.2188 / 0.0819 / 0.0856 (all below the 0.32 floor), and the axis stays honest on real irregularity (RS-3 keeps 0.2188 from a mid-line accidental). Anchor, orientation, range, thresholds, and the eight other axes unchanged; no layout/golden change (measurement-only, `ENGRAVER_VERSION` untouched). The **duration-aware optical-spacing** open question (deviation from duration-proportional spacing) stays open — it needs the pipeline's deferred duration-proportional preferred widths. | ✅ done | diff --git a/spec/PASS12_RATIFICATION_LOG.md b/spec/PASS12_RATIFICATION_LOG.md index b760acc..fdbb943 100644 --- a/spec/PASS12_RATIFICATION_LOG.md +++ b/spec/PASS12_RATIFICATION_LOG.md @@ -74,3 +74,32 @@ change**: the defect was in the metric's own definition, not the engraver. (`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). + +## Schema-major-1 tranche (2026-07-06) — data-model growth + engrave ratify-only + +The first binary-format schema-major bump (v0 → v1, `binary_format` 0.3.0), +built machinery-first on a small payload, landed the two data-model rows the +batch parked behind the frozen-layout rule (**P12-I7**, **P12-K7**) and ratifies +the three engrave/layout-ir dispositions the implementation already made +(**P12-I8/I9/I10**). Delivered as the schema-major-1 Phase A–F commit series +(from `f4a2f1f`); this tranche records Phase F. + +| Item | Disposition | Spec locus | Authority followed | +|---|---|---|---| +| P12-I7 page-geometry graph home | **landed (schema-major-1)** — `Canvas` gained `layout_defaults: CanvasLayoutDefaults { page_size: CanvasSize, margins: CanvasMargins }` (staff spaces, A4/8 mm default), defined in core spec (Phase A) and added to the graph + canonical wire form at major 1 (Phase C, byte-for-byte v0→v1 migrate-on-read, zero golden churn). The engraver still defaults to the same geometry; wiring it to *read* the graph field (C′) is a byte-neutral follow-up deferred until a custom-geometry producer exists | core_spec Ch5 §The Canvas (`CanvasLayoutDefaults`); binary_format §Schema Major 1 | `epiphany-core` (`graph.rs`, `codec.rs::decode_v0_score`) | +| P12-K7 advisory-precondition catalog | **landed (schema-major-1) + adopt** — the two graph-model gaps the advisory catalog named are filled: `Instrument.range: Option` and `Region.permits_spanning_slurs: bool` (major 1, Phases D1/D2), so `epiphany-ops` now enforces the InsertEvent pitch-in-range advisory (frame-guarded; "if any"/indeterminate → vacuous pass) and the CreateCrossCutting(Slur) region-spanning advisory. ModifyEvent's duration-boundary bucket is stated explicitly (it carries the full replacement value). Cross-region slur permission is read as **both** endpoint regions must permit (conservative AND) — see the open item below | core_spec Ch5 §Instruments / §Regions; Ch6 §6.10 advisory buckets; `PitchRange` | `epiphany-core` (`pitch.rs::PitchRange`, `graph.rs`); `epiphany-ops` (`validate.rs`) | +| P12-I8 break-constraint satisfaction | **adopt** — Ch7 gains a normative predicate (Requirement `req:layoutir:break-satisfaction`): a `SystemBreakAt`/`PageBreakAt` at `slot` is satisfied iff the final `ResolvedLayoutIR` starts a system/page at that slot; a region-first slot is trivially satisfied; satisfaction is a predicate on the output, not the solver's spring state | core_spec Ch7 §ConstrainedLayoutIR (`req:layoutir:break-satisfaction`) | `epiphany-engrave` casting-off (evaluates hard break constraints for its tier claim) | +| P12-I9 break-override attribution | **adopt (decline widening)** — Ch7 gains Requirement `req:layoutir:break-origin-attribution`: honouring a user break carries `DecisionSource::UserOverride(id)`, threaded through a `ConstrainedLayoutIR.break_origins` sidecar populated by the logical-stage projection. The normalized constraint record is deliberately **not** widened to carry override identity — attribution is a projection concern, not a solver input | core_spec Ch7 §Engraving Overrides (`req:layoutir:break-origin-attribution`) | `epiphany-layout-ir` (`constrained.rs::break_origins`, `to_constrained`) | +| P12-I10 continuation synthesis | **adopt (bless registered id)** — Ch7 gains Requirement `req:layoutir:continuation-synthesis`: a system-spanning stroke's post-first segments are synthesized under `SynthesisKind::Registered(SYSTEM_CONTINUATION_SYNTHESIS)`, with `stable_semantic_instance_key = (original, ordinal)`; because `LayoutObjectId`s are non-canonical and re-derived per layout, the key need only be stable within a layout | core_spec Ch7 §Provenance (`req:layoutir:continuation-synthesis`) | `epiphany-layout-ir` (`provenance.rs`; `SYSTEM_CONTINUATION_SYNTHESIS`) | + +**Version movements.** Binary Format companion 0.2.0 → 0.3.0 (schema major 1 +wire form + migration; Phase A). Core spec: `CanvasLayoutDefaults` / `PitchRange` +/ `Region.permits_spanning_slurs` data-model additions (Phase A) and the three +engrave requirements above (Phase F); revision-history row appended. + +**Open item (flagged, not resolved).** Which region governs a *cross-region* +slur's spanning permission is under-specified. The implementation chose the +conservative **AND** (a boundary is permeable only when both endpoint regions set +`permits_spanning_slurs`); a "the start region governs" or "either side" reading +is equally defensible. Tracked for ratification; the advisory is authoring-only +and never alters reduction, so the choice is not byte-affecting. diff --git a/spec/core_spec.pdf b/spec/core_spec.pdf index 1947860..eda38be 100644 Binary files a/spec/core_spec.pdf and b/spec/core_spec.pdf differ diff --git a/spec/core_spec.tex b/spec/core_spec.tex index 528d66c..a813422 100644 --- a/spec/core_spec.tex +++ b/spec/core_spec.tex @@ -8041,6 +8041,22 @@ pub struct LayoutObjectId(pub u128); whose change should invalidate this layout object. \end{requirement} +\begin{requirement} + \label{req:layoutir:continuation-synthesis} + \textbf{System-spanning continuation.} A line primitive (stroke) that spans a + system boundary is split into per-system segments; the segments after the + first are engraver-synthesized and \MUST{} declare a \texttt{synthesis} kind. + The reserved registered kind + \texttt{SynthesisKind::Registered(SYSTEM\_CONTINUATION\_SYNTHESIS)} names this + continuation. Its \texttt{stable\_semantic\_instance\_key} (per + Requirement~\ref{req:layoutir:object-id-derivation}) is the pair + \texttt{(original,\,ordinal)} --- the pre-split stroke's object and the + segment's order within the split --- which is stable for a fixed set of system + breaks. Because \texttt{LayoutObjectId}s are non-canonical and re-derived per + layout, this key need only be stable within a layout, not across relayouts + that move the breaks. +\end{requirement} + \begin{requirement} \label{req:layoutir:object-id-derivation} A \texttt{LayoutObjectId} \MUST{} be stable across re-layouts whose @@ -8540,6 +8556,21 @@ pub enum OverrideOrigin { overrides without explicit user action. \end{requirement} +\begin{requirement} + \label{req:layoutir:break-origin-attribution} + \textbf{Break-override attribution.} When the engraver honours a user break + override, the resulting decision \MUST{} carry + \texttt{DecisionSource::UserOverride(id)} naming the override. Because a + normalized break \emph{constraint} (\texttt{SystemBreakAt} / + \texttt{PageBreakAt}, Section~\ref{sec:layoutir:constrained}) carries no + override identity, this attribution is threaded through the projection: the + \texttt{ConstrainedLayoutIR} carries a \texttt{break\_origins} sidecar, + populated when the logical stage projects the break, mapping each user-anchored + break slot to its override id. The normalized constraint record is + deliberately \emph{not} widened to carry override identity --- attribution is a + projection concern, not a constraint-solver input. +\end{requirement} + \section{ConstrainedLayoutIR} \label{sec:layoutir:constrained} @@ -8704,6 +8735,20 @@ pub enum BreakKind { } \end{lstlisting} +\begin{requirement} + \label{req:layoutir:break-satisfaction} + \textbf{Break-constraint satisfaction.} A \texttt{SystemBreakAt} at + \texttt{slot} is \emph{satisfied} iff the final resolved layout starts a + system at that slot; a \texttt{PageBreakAt} iff the final layout starts a page + there. A slot that already begins a system (respectively page) --- in + particular a region's first slot --- is trivially satisfied. Satisfaction is a + predicate on the output \texttt{ResolvedLayoutIR}, evaluable by any consumer, + not on the solver's internal spring state. A solver's tier claim + (Section~\ref{sec:layoutir:resolved}) reports which \texttt{Hard} break + constraints its layout satisfies; a \texttt{Soft} break is advisory and MAY be + left unsatisfied. +\end{requirement} + \section{ResolvedLayoutIR} \label{sec:layoutir:resolved} @@ -14682,6 +14727,23 @@ layouts they own versus inherit: byte-for-byte v0${\to}$v1 migration are ratified in the Binary Format companion (0.2.0 $\rightarrow$ 0.3.0). \\ + \today & Schema major 1 Phase F (engrave ratify-only) & + Ratifies three engrave/layout-ir dispositions the implementation already made + (Pass 12 batch I8/I9/I10, now struck), with no byte-layout or architecture + change: the \emph{break-constraint satisfaction} predicate + (Requirement~\ref{req:layoutir:break-satisfaction} --- a \texttt{SystemBreakAt} + / \texttt{PageBreakAt} is satisfied iff the final \texttt{ResolvedLayoutIR} + starts a system/page at that slot, a region-first slot trivially); \emph{break-override + attribution} threaded through a \texttt{ConstrainedLayoutIR.break\_origins} + sidecar, declining to widen the normalized constraint record + (Requirement~\ref{req:layoutir:break-origin-attribution}); and the + \emph{system-continuation} synthesis kind + \texttt{Registered(SYSTEM\_CONTINUATION\_SYNTHESIS)} with an + \texttt{(original,\,ordinal)} instance key + (Requirement~\ref{req:layoutir:continuation-synthesis}). Flags one open item: + which region governs a cross-region slur's spanning permission (implemented as + conservative AND, P12-K12). + \\ \bottomrule \end{longtable}