E-D (layout-ir, honest solver tier): add SolverTier::Stub (a non-conformance rung
below Minimal) and have StubSolver report it instead of falsely claiming the
Minimal conformance tier; the passthrough evaluates no constraints and computes
no quality metrics.
E-C (layout-ir, constraint/reference validation): ConstrainedLayoutIR::validate()
now also checks the LayoutConstraint vector — NoCollision/Align/PositionWithin
must name glyphs in the set, SystemBreakAt/PageBreakAt must name existing slots,
PositionWithin regions must be finite/non-negative — rejecting dangling
references instead of silently accepting them.
E-B (layout-ir, content-sensitive ScoreVersion): derive ScoreVersion from the
whole score's canonical bytes (Agent B's whole-score codec) rather than the
layout projection's object identities, so a pure content edit that changes no
identifier still changes the version — required for correct incremental-layout
cache invalidation.
D-A (bundle, extension-root preservation): Bundle::commit now enforces
preservation — after the builder closure runs, every prior extension declaration
it did not re-declare (by extension_id) is carried forward verbatim, so an
extension-unaware writer cannot silently orphan an unknown extension's
preserved_chunk_roots. An extension-aware writer that re-declares its id keeps
control.
Each fix has a regression test; per-crate DECISIONS updated. (Item-6 remainder:
D-B operation-block summaries next; E-A real time-axis deferred per request.)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>