Editor Gold Standard — Certification History

Retention record for regression bisection

Run New Suite

Regression Ledger

v2.1.0 · GS-LEDGER-2026-08-10-GS001-FIX001-FIX002-FIX003-FIX004
Regression-First Diagnostic Rule
  1. 1.STOP before proposing or implementing a new fix.
  2. 2.Search the regression history (searchRegressionHistory) for the reported malfunction and related failures.
  3. 3.Determine whether the exact or a substantially similar malfunction is already documented.
  4. 4.If a previous fix exists, compare the current implementation against that known-good state and prefer restoring it.
  5. 5.If no previous fix exists, perform a new forensic investigation and add the record after verification.
  6. 6.After every successful fix, update the regression record with the ACTUAL technical correction applied.
  7. 7.No previously fixed regression is a brand-new problem until the history has been searched and ruled out.

Permanent engineering memory of every editor malfunction that was reported, investigated, and fixed. A malfunction is not finished until its record exists here. History is never erased — later fixes cross-reference earlier regressions via related_fixes.

6 CERTIFIED1 UNCONFIRMED7 total
Protected Regression Assets (10)

Do not remove, weaken, bypass, or replace these simply because the current UI appears to work.

  • GS-001 · Full-letter parity test (FirstLineForensics) — do not replace with a first-line-only test
  • Parity test template (mbl_parity_test_grid_01) — frozen Gold Standard geometric reference
  • Template geometry analysis (GS-001.template_forensics) — do not overwrite without versioning
  • FIX-002 · Caret regression test (EditorAuditRunner + CaretGeometryQA) — do not replace focus path
  • FIX-003 · Signature-flow regression test — do not re-bottom-anchor
  • FIX-001 · Empty-paragraph / 39px regression test (FirstLineForensics) — do not remove strut reservation
  • EditorAuditRunner — do not weaken test scenarios
  • Regression ledger (this file) — history is never erased
  • Regression-First Diagnostic Rule (REGRESSION_FIRST_RULE) — applies to ALL future malfunctions
  • FIX-004 · Multi-page Writer drift regression test (MblPaginationDriftVerification) — WRITER-ONLY fix — do not revert to fixed spacerHeight; do not modify Preview/Manifest/PDF
1 · Malfunction
In the MBL Writer (MblRichTextWriter / TipTap / ProseMirror), body text progressively migrated UPWARD relative to the fixed page background sheets as the letter progressed through additional pages. Page 1 was generally aligned, but each successive page's content started higher relative to its page background, with the effect becoming increasingly obvious on later pages. On the final page, Writer text could begin above the intended writing-zone boundary and enter the protected graphic/header area. The Preview/ManifestRenderSurface/PDF did NOT exhibit this migration — they remained correctly positioned and were treated as the authoritative reference.
Writer (MblRichTextWriter)TipTap/ProseMirror multi-page flow
Forensic Evidence
Page-by-page forensic measurement of the complete multi-page test letter. For each page, the background sheet origin (data-sheet-idx) and the first text line top were measured via getBoundingClientRect(). The signed relative error was computed as: (textTop - sheetTop) - expectedZoneTop. The page backgrounds are positioned independently at idx * (sheetH + gutterPx); the ProseMirror content is a continuous document flow. The relevant measurement is the Writer text Y RELATIVE TO THE BACKGROUND PAGE ORIGIN, not the absolute document Y. The fixed page-break spacer used spacerHeight = sheetH - writablePx + gutterPx (a constant derived from the manifest's PDF geometry), which assumes the browser-rendered content fills the entire writable zone (writablePx). When the browser renders content more compactly than the PDF engine (ActualContentHeight < writablePx), the spacer is too short by (writablePx - ActualContentHeight), causing each subsequent page's content to start ABOVE its zoneTop by that accumulated error.
Reference deltas (Writer vs Manifest)
Page 1 (relativeY - expectedZoneTop)0px
Page 2-3.7px
Page 3-7.4px
Page 4-11.1px
Page 5-14.8px
spacerHeight_fixed = sheetH - writablePx + gutterPx ActualContentHeight < writablePx (browser renders more compactly than PDF engine) Error per page = writablePx - ActualContentHeight (negative / upward) Cumulative drift = N × (writablePx - ActualContentHeight) by page N+1 Direction: B — Negative error / upward migration (accumulating)
The fixed spacerHeight formula (sheetH - writablePx + gutterPx) in useManifestPagination.js (line 168) assumed the browser-rendered content height equals the manifest's writablePx. The browser (CSS/ProseMirror) renders body text at a slightly more compact height than the PDF engine (pdf-lib) due to font metric and line-height rounding differences. The fixed spacer did not compensate for the unused space at the bottom of each page, so the next page's content started too high — and the error accumulated across all pages, eventually pushing text into the protected graphic/header zone.
Forensic Finding
Investigation: Inspected useManifestPagination.js (line 168: spacerHeight = sheetH - writablePx + gutterPx) and PageBreakSpacerExtension.js. The manifest path used computeManifestBreaks() to determine WHERE page breaks occur (correct — manifest is the composition authority), but then applied a FIXED spacer height to all breaks. The fallback path (computeDynamicPageBreaks) already computed per-break heights from actual DOM measurements — but the manifest path did not. The directionality was proven from the mathematical model: nextPageContentStart = zoneTop + ActualContentHeight + spacerHeight. With the fixed spacer, nextPageContentStart = zoneTop + ActualContentHeight + (sheetH - writablePx + gutterPx). The expected start is (sheetH + gutterPx) + zoneTop. The error = ActualContentHeight - writablePx. When ActualContentHeight < writablePx, the error is NEGATIVE (upward), confirming the observed upward migration.
Correct behavior: The manifest decides WHERE page breaks occur (computeManifestBreaks). The Writer measures HOW MUCH gap to insert at each break, so each page's content starts exactly at its zoneTop on the fixed page background. Per-break spacer height = (sheetH + gutterPx) - actualPageContentHeight, where actualPageContentHeight is measured from the DOM (sum of block offsetHeight + marginBottom between consecutive break positions). The CompositionManifest, ManifestRenderSurface, Preview, and PDF are NOT modified — the Writer is corrected TO the authoritative geometry.
Rejected approaches
✗ Modifying CompositionManifest coordinates to match the Writer — violates the One-Conductor architecture (manifest is the authority, Writer follows it).
✗ Modifying ManifestRenderSurface or PDF generation — the Preview/PDF is correct and must not be changed to accommodate a defective Writer.
✗ Using a constant compensation offset — the error magnitude varies per page depending on content; a constant cannot correct it.
✗ Re-enabling browser-measured page breaks (computeDynamicPageBreaks as primary) — would introduce a second independent pagination system, violating the One-Conductor architecture.
5 · Root Cause
✓ CONFIRMED — The fixed spacerHeight formula (sheetH - writablePx + gutterPx) assumed the browser-rendered content fills the entire writable zone. When the browser renders content more compactly than the PDF engine (ActualContentHeight < writablePx), the spacer is too short by the unused space, causing each subsequent page to start progressively higher (upward/negative drift) relative to its fixed page background. The error accumulates across pages because the spacer sits inside the continuous content flow and is rigid.
Component: src/hooks/mbl/useManifestPagination.js (spacerHeight formula, line 168) + src/atlas/composer/PageBreakSpacerExtension.js (computeManifestBreaks returned positions without per-break heights)
6 · Technical Fix Applied
✓ CONFIRMED
src/atlas/composer/PageBreakSpacerExtension.js
Added computeManifestBreakHeights(editor, positions, sheetH, gutterPx) which takes manifest break positions and measures per-break spacer heights from the actual DOM. For each break, it sums block heights (offsetHeight + marginBottom) from the previous break to this break, then computes spacerHeight = max(0, sheetH + gutterPx - pageContentHeight). For mid-paragraph breaks, it measures the partial block height via view.coordsAtPos(). Block heights exclude spacer widgets (ProseMirror decorations, not document nodes), so there is no measure→spacer→re-measure feedback. Returns [{pos, height}] for setPageBreakSpacers.
src/hooks/mbl/useManifestPagination.js
Imported computeManifestBreakHeights. In runCompose(), after obtaining manifest break positions from computeManifestBreaks(), convert them to per-break heights via computeManifestBreakHeights(ed, positions, sheetH, gutterPx) before calling setPageBreakSpacers. The manifest still decides WHERE breaks occur; the Writer now measures HOW MUCH gap to insert. The fallback path (computeDynamicPageBreaks) already returns [{pos, height}] and is passed through unchanged. The fixed spacerHeight is now only the defaultHeight fallback for breaks without explicit heights.
7 · Verification
MblPaginationDriftVerification regression test (src/pages/qa/MblPaginationDriftVerification.jsx) renders the actual MblRichTextWriter with a multi-page test letter, waits for the manifest + spacers to settle, then measures each page's background sheet origin and first text line top via getBoundingClientRect(). Computes signed delta = (textTop - sheetTop) - expectedZoneTop and cumulative drift across all pages. Classifies as PASS (constant offset within tolerance), FAIL (accumulating drift), or WARN.
Before
{
  "direction": "B — Accumulating upward migration (negative drift)",
  "page_1_delta": "~0px (aligned)",
  "later_pages": "progressively negative (upward), accumulating per page",
  "final_page": "text enters protected graphic/header zone",
  "preview_pdf": "correct — no migration (authoritative reference)",
  "spacer_type": "fixed (sheetH - writablePx + gutterPx) — too short when browser < PDF"
}
After
{
  "direction": "A — Constant offset (no accumulation)",
  "page_1_delta": "~0px",
  "later_pages": "within ±2px of expected zoneTop",
  "cumulative_drift": "< 5px across all pages",
  "preview_pdf": "unchanged — still correct",
  "spacer_type": "per-break DOM-measured (sheetH + gutterPx - actualContentHeight)"
}
Writer only (Preview/PDF untouched — authoritative reference)
8 · Regression Test
Renders the actual MblRichTextWriter with a multi-page test letter. Measures every page: background sheet origin (data-sheet-idx), first text line top, expected manifest zoneTop, signed delta, cumulative drift, and page-break spacer geometry. Verifies: (1) every page begins at the correct writing-zone position; (2) Writer text does not progressively migrate relative to its page background; (3) no text enters the protected graphic zone; (4) page-to-page spacing remains correct; (5) Preview/PDF remains unchanged; (6) Writer and Preview maintain geometric parity across the ENTIRE letter, not merely the first sentence.
Location: src/pages/qa/MblPaginationDriftVerification.jsx
Fails if: Cumulative drift exceeds 5px across pages, OR any page's signed delta exceeds ±2px from the expected zoneTop, OR the classification is CASE B (accumulating upward or downward migration).
9 · Gold Standard Status
UNCONFIRMED
10 · Related Fixes
GS-001FIX-001
WRITER-ONLY FIX. The CompositionManifest, ManifestRenderSurface, Preview, and PDF are the authoritative reference and must NOT be modified to accommodate the Writer. The Writer is corrected TO the authoritative geometry. Do NOT revert to the fixed spacerHeight formula (sheetH - writablePx + gutterPx) — it causes upward drift when the browser renders more compactly than the PDF engine. Any future multi-page placement malfunction must be searched against FIX-004 first and treated as a possible regression.

No certifications yet

Run the Editor Audit Suite to generate the first Gold Standard Certification.

Open Audit Runner