PES · R56

Personal Edition Suite — Master Spec

Contents (16 sections)

Personal Edition Suite (PES) — Master Spec

Round: R56 · Status: PLAN (approved-for-build planning round; product code untouched this round) · Owner standard: zero bugs Scope: Composed Text View (CTV) · Study Bible View (SBV) · Print myGNT (PM) — the #1 ranked product gap and #1 opportunity from download/COMPETITOR-ANALYSIS-BIBLEMAKER-R55.md. Zero-fabrication: every number below is frozen ground truth from the shipped corpus (data/manifest.json, R54-verified) or the real record shape in src/services/mygnt/mygntDecisions.ts. Nothing is invented; open items are marked OPEN. Enhancement loop: this spec is maintained by a scheduled 15-minute QA agent (§13). It edits ONLY this file (by section ID) and keeps the default page in sync.


0. How to read this spec

Normative language (RFC-2119): MUST / MUST NOT / SHOULD / MAY.

Granularity ladder — every requirement lives at exactly one level:

Level Meaning Example
L0 Epic A shippable capability Print myGNT
L1 Capability A user-reachable function Footnote engine
L2 Behavior A deterministic input→output rule PM-07: marker set resets per verse
L3 Interaction A concrete UI gesture → response Enter on focused word opens popover
L4 Micro-state A visual/edge state of one element ghost dash while no decision exists
L5 Edge case Named, numbered, testable E-CTV-03 overlapping reorder units

ID scheme: CTV-nn behaviors · SBV-nn · PM-nn · X-nn cross-cutting · E-<view>-nn edge cases · D-nn decisions-still-OPEN. The QA agent references these IDs surgically in §14 changelog entries.

Priority: P0 = block for release · P1 = release quality · P2 = post-release polish.


1. Thesis and the four firsts

Positioning sentence (from R55): "Every Greek NT tool shows you an edition. Bible Maker is the first workbench that lets you build one — decide all 11,644 variant points, record why, and keep a documented, exportable, auditable edition of your own."

PES turns that thesis into three surfaces:

  1. CTV — Composed Text View: read YOUR edition as continuous Greek text (not a decision ledger — the resulting text).
  2. SBV — Study Bible View: your edition wrapped in your personal apparatus — every note is your unit decision + reasoning.
  3. PM — Print myGNT: a printed/PDF critical edition of your own with personal apparatus and a reasons appendix.

The four firsts (unique in the market per R55 census):

# First Why nobody has it
F-1 A personal apparatus that exists at all (per-unit user decisions) No Tier-A competitor; apparatus is vendor-authored everywhere
F-2 Screen==print note parity (WYSIWYG apparatus numbering) No product renders user apparatus on screen or paper
F-3 A reproducible personal-edition hash in the colophon No product versions a user's edition
F-4 Honesty design carried to paper (decided vs default visibly distinct in print) No product distinguishes them because it has neither

2. Ground truth (frozen numbers this spec is built on)

Quantity Value Source
Apparatus units (decision points) 11,644 = 3,852 substitution + 6,042 add_omit + 1,750 word-order data/manifest.json (E-01 re-derived R54)
Verses carrying units 4,720 qa12
NA28-bracketed units 408 qa12
NA28 double-bracket passages 5 (Mk short ending, Mk 16:9–20, Pericope Adulterae, Lk 22:43–44, Lk 23:34a) na-brackets lib
Witness-only verses 44 (PA 12, Mark LE 12, Act.8.37, …) qa12
Total CE decision space 11,649 points = 11,644 units + 5 passage decisions derived (D-01 CLOSED: passage decisions counted)
SRGNT / TAGNT streams 137,361 words / 7,914 verses · 142,096 words / 7,958 verses manifest (R54)
Witnesses 188 · 42,482 witness-verse pairs · 717,890 reading rows manifest
Witness-additions layer 4,753 groups = 4,572 enriched + 181 honest-empty qa10
SR–TAGNT alignment 6,558 diff records / 141,581 ops manifest (E-01)
Lexicon TBESG 9,362 · LSJ/TFLSJ 9,361 entries manifest
Base editions (decision defaults) 9 (NA28, NA27, SBLGNT, Tyndale, WH, Tregelles, TR, Byz, SRGNT) BibleMakerView
Omission split (add_omit detail) 2,791 content + 3,009 function qa12
Phase-A model hash gate 51d49df3 — PES is a DERIVED VIEW; MUST NOT move it qa13
Record shape MygntDecision { id, book, vuKey, ref, reading, edition, attended, reasoning, decisionType?, passageId?, createdAt, updatedAt } src/services/mygnt/mygntDecisions.ts

Real reading-value vocabulary (must be honored by every consumer): "Ἰησοῦν" (surface) · "(omit)" · "@order:»3" (word-order move) · "include"|"omit"|"undecided" (passage only).


3. Domain core: the Composed Edition (CE)

3.1 Deterministic resolver

CE(word w, verse v):
  P = passage(v) exists AND passageDecision(P) == "omit"  → render omitted-passage treatment, stop
  u = unitAt(w, v)                       # 0 or 1 unit anchors a word position
  r = decision(u)  if decision(u).attended        # user decided
      else editionDefault(u)             # 9-edition edition-following default (R50)
      else baseFallback(u)               # SRGNT stream value
  apply r:
    substitution  → surface = r
    "(omit)"      → render ghost-dash (L4), text excluded from continuous string
    "@order:»k"   → word placed at rank k in the verse sequence
    no unit       → surface = base stream word

Precedence table (L2, normative):

Rank Source Wins when
1 passage decision (decisionType:"passage") verse inside a bracketed passage
2 unit decision (attended:true) any
3 edition default (attended:false or absent, edition set) any
4 base fallback (SRGNT) no record at all

Invariant: exactly ONE decision record per vuKey — enforced today by id = ${book}:${vuKey} primary key. Two tabs writing concurrently: last-write-wins on updatedAt; CE hash recomputed after each write (see E-CTV-12).

3.2 CE revision & hash (reproducibility — first F-3)

  • CE.rev — monotonic integer, +1 on every decision mutation batch (not per keystroke; per commit of the decision dialog).
  • CE.hash — sha256(canonical(decisionSet)) where canonical = records sorted by vuKey, fields {vuKey, reading, edition, attended} JSON-serialized, newline-joined, UTF-8. MUST be stable across browser sessions and machines.
  • Colophon (§6.5) embeds CE.hash + CE.rev + base default edition + decision counts → a printed edition is byte-reproducible from the ledger.
  • Staleness: if Phase-A modelHash ≠ 51d49df3, views MUST show a "pipeline changed — re-derive" banner and MUST NOT silently render (integrity posture inherited from /method).

3.3 Bracketed passages & witness-only verses policy

  • The 5 passages: per-passage include|omit|undecided decisions already persist via vuKey "passage:{id}" (5-b layer, shipped). CE renders them per decision; undecided renders the NA28 default treatment (bracketed, grey — current behavior).
  • 44 witness-only verses: NEVER in CE main text (they are additions-layer evidence, not edition text). MAY appear in SBV as collapsible "witness-only" cards and MAY appear in PM as an optional appendix toggle X-07.

3.4 What CE is NOT (claims boundary — extends the claims dialog)

  • CE is NOT the autograph, NOT NA28-equivalent, NOT exhaustive (only 11,644 of all conceivable points), NOT a theological authority. Printed colophon MUST carry the abridged MAY/MUST-NOT block (§6.5). D-02 CLOSED: claims dialog copy is normative for the colophon, single source in one TS constant shared by dialog and print stylesheet generation.

4. F1 — Composed Text View (CTV)

4.1 User story

As the editor of my own Greek NT, I open Mark and read continuous text that already reflects my 1,207 decisions — not a grid, not a ledger. Words I changed feel like my words; I can tap any word to see what I decided and why. I can flip to compare against NA28 in one keystroke.

4.2 Wireframes

Desktop ≥1280 (M1 paragraph mode):

┌────────────────────────────────────────────────────────────────────────────┐
│ ◀ Mark ▸ ch.1        [M1|M2|M3|M4]  vs:NA28▾   ◉ 1,207/11,644   ⎙ Print    │  header 56px
├──────────┬─────────────────────────────────────────────────────┬──────────┤
│ density  │  1 Ἀρχὴ τοῦ εὐαγγελίου Ἰησοῦ Χριστοῦ [υἱοῦ θεοῦ].   │ word     │
│ ribbon   │  2 καθὼς γέγραπται ἐν τοῖς προφήταις·               │ popover  │
│ (verse   │    …              (text pane, max 62ch measure)      │ (on tap) │
│  heat    │  8 … κηρύσσων βάπτισμα μετανοίας …                   │          │
│  strip)  │  ────────────────────────────────────────────────    │ lexicon  │
│ 44px     │  ‸ markers row: ◉3 ◉8 ◉12 … jump-to-unit            │ TBESG/LSJ│
├──────────┴─────────────────────────────────────────────────────┴──────────┤
│ status bar: CE rev 412 · hash c3f9… · base SRGNT · 96% covered · ⎙         │
└────────────────────────────────────────────────────────────────────────────┘

Mobile ≤390: header collapses to [☰][Mark 1][◉12%][⎙]; ribbon hidden (dots row instead); popover becomes bottom sheet (max-h-[70dvh], overflow-y-auto).

4.3 Reading modes

Mode Name Layout Note
M1 Paragraph flow verses in paragraphs, verse numbers superscript default
M2 Verse-per-line one verse per line, unit markers aligned left apparatus-oriented reading
M3 Split compare left CE · right chosen reference edition, synchronized scroll reference = any of the 9
M4 Heat read M1 + ribbon; tap ribbon segment → jump density = units/verse

Mode is per-book sticky (localStorage pes.ctv.mode.{book}); switching book keeps mode.

4.4 Visual grammar of marks (normative — same grammar in print, F-4)

Mark Meaning Screen Print
solid underline + ● marker YOUR decision deviates from default underline, marker superscript superscript marker + footnote
dotted underline edition default silently in effect only when "show defaults" ON (default OFF) never printed
ghost dash — (R35 design) unit omitted by decision or base-missing dash + tappable panel footnote explains omission; text simply absent
{…} braces addition by decision braces + marker braces dropped in print; marker + footnote
⇄ corner glyph word-order unit touched tiny corner triangle footnote records @order:»k
grey italic inside included bracketed passage italic grey italic
[text] in square brackets NA28 double-bracket, undecided square brackets square brackets
◧ ghost verse (E-02 style) witness-only verse (appendix only) ghost slot appendix only

4.5 Word popover anatomy (tap any word)

┌──────────────────────────────────────┐
│ λόγος  ·  G3056 · noun, masc sg nom  │  TBESG gloss (9,362 entries)
│ LSJ: (senses 1–3, collapsed)         │  LSJ/TFLSJ 9,361 — expandable
├──────────────────────────────────────┤
│ UNIT u#4812 · substitution           │  if word anchors a unit
│ base: λόγος   default(NA28): λόγος   │
│ YOURS: ἔργον  ● decided 12 Jan 2026  │  or "default in effect — decide?"
│ reason: "Byz A C D read ἔργον;       │
│          ὁ λόγος is editorial smooth"│
│ [Edit decision] [Witnesses (14)]     │  deep-links back to Bible Maker
├──────────────────────────────────────┤
│ (word not in any unit → lexicon only)│
└──────────────────────────────────────┘

4.6 State machine (view level)

        ┌─────────┐  select book/ch   ┌─────────┐  shards ready  ┌────────┐
boot ──▶│ LOADING │──────────────────▶│ READY   │───────────────▶│ READING│
        └─────────┘                   └─────────┘                └───┬────┘
             │ stale modelHash            │ 0 decisions               │ tap word
             ▼                            ▼                           ▼
        ┌─────────┐                   ┌──────────┐              ┌──────────┐
        │ BLOCKED │                   │ EMPTY-CE │──decide─────▶│ POPOVER  │
        │ banner  │                   │ banner   │              └────┬─────┘
        └─────────┘                   └──────────┘                   │ edit
                                          ▲                          ▼
                     CE.rev++ / hash recompute ← decision saved ──┘ (all views re-derive)

Transitions: LOADING→READY only when chapter shard + decisions slice both resolve; any fetch failure → ERROR state with retry (no infinite spinner — zero-bug rule).

4.7 Completeness meter

coverage = decided / 11,649 where decided = records with attended:true (units + 5 passages, counting passage:"undecided" as NOT decided). Header shows book-scope meter; status bar shows global. Per-book breakdown table lives on SBV settings sheet. Meter MUST be aria-live="polite" (X-09).

4.8 Behavior register

ID Behavior Pri
CTV-01 Render continuous CE text for any of 27 books P0
CTV-02 Apply resolver precedence (§3.1) exactly; one unit → one visual mark P0
CTV-03 Verse numbers superscript, tappable → jump to Bible Maker verse grid P0
CTV-04 Word popover: lexicon + unit status + reason + deep link P0
CTV-05 Mode switcher M1–M4, per-book sticky P1
CTV-06 Reference selector (9 editions) for M3 compare P1
CTV-07 Density ribbon (M4): per-verse unit count heat, 4 buckets P1
CTV-08 Markers row under text: ● markers in verse order, tap → popover P1
CTV-09 "Show defaults" toggle (dotted underlines) default OFF P1
CTV-10 Completeness meter (§4.7), aria-live P0
CTV-11 Empty-CE banner: "Your edition currently equals {base}. Decide your first unit →" links to Bible Maker P0
CTV-12 Stale-model banner BLOCKED state (§3.2) P0
CTV-13 Print button → PM preview of current book (entry to F3) P0
CTV-14 i18n en/id for ALL chrome; Greek never localized P0
CTV-15 Virtualized rendering: only visible chapter windows in DOM P0
CTV-16 Keyboard: ←/→ word, Enter popover, Esc close, 1–4 modes, V cycle P1
CTV-17 Deep link #/{book}/{ch} and #/{book}/{ch}:{v} restore position P1
CTV-18 Passage undecided → NA28 bracket treatment + "decide passage" chip P0
CTV-19 Passage omitted → single-line tombstone "— passage omitted by editor —" P0
CTV-20 Addition rendering with braces (screen) per §4.4 P0
CTV-21 Word-order: @order:»k applied to sequence; arrow affordance on moved word P0
CTV-22 Popover lexicon fallback: word absent from TBESG → show lemma + POS only (no fake gloss) P0
CTV-23 Book selector shows per-book decided counts next to names P2
CTV-24 Shared "Open in Bible Maker" for the focused unit P1

4.9 Edge cases

ID Case Required treatment
E-CTV-01 Word in NO unit and absent from lexicon plain word; popover shows lemma+POS only
E-CTV-02 Unit whose decision string is empty/whitespace treat as undecided-default; log to console once
E-CTV-03 Overlapping reorder units on same word position precedence by unit index (lower wins); both listed in popover; never render twice
E-CTV-04 @order:»k with k > verse word count clamp to end; popover shows warning chip
E-CTV-05 Chapter with 0 units no markers row; ribbon grey; meter unaffected
E-CTV-06 Verse that is entirely omitted by decision tombstone line, verse number kept
E-CTV-07 Decision exists for vuKey the current model no longer has (drift) record shown in SBV "orphan decisions" list; not rendered
E-CTV-08 11,649-row decisions fetch slow (>800ms) render base text immediately, reconcile marks when slice arrives (no blocking)
E-CTV-09 "(omit)" on a word that is a verse's ONLY word verse tombstone (same as E-CTV-06)
E-CTV-10 Passage decision "undecided" but passage contains decided units units render; passage keeps brackets
E-CTV-11 User renames edition (colophon name) with invalid chars sanitize [A-Za-z0-9 _-], max 64, else fallback "My Greek NT"
E-CTV-12 Two tabs write decisions concurrently last-write-wins; on window focus, re-pull slice + recompute hash
E-CTV-13 Print pressed during LOADING disabled until READY (tooltip why)
E-CTV-14 Dark mode contrast of grey-italic bracketed text contrast ≥ 4.5:1 both themes (X-02)

5. F2 — Study Bible View (SBV)

5.1 User story

As the editor, I study Mark 1 with my edition open beside MY apparatus: every note is numbered exactly as it will print, each carrying my chosen reading, my witnesses, my reasoning, and my confidence. I filter to "only my deviations" to rehearse my defense of the text.

5.2 Wireframes

Desktop three-pane:

┌──────────────┬───────────────────────────────┬───────────────────────────┐
│ TEXT (CTV M2)│ APPARATUS (verse-scoped)      │ REASONS                   │
│              │ Mrk 1:2 · 3 units             │ note b card:              │
│ 1 Ἀρχὴ…[a]   │ a  ἐν τοῖς προφήταις — add    │ ┌───────────────────────┐ │
│ 2 …[b][c]    │    ἐν Ἠσαΐᾳ (NA28) vs TR Ἠσαΐᾳ│ │ b · substitution      │ │
│ 3 …          │ b  τοῖς προφήταις ⋯ variants  │ │ chosen: Ἠσαΐᾳ         │ │
│              │ c  …                          │ │ wits: TR, Byz, A C …  │ │
│ (sync scroll │ (unit rows, R35 dash+panel    │ │ reason: …             │ │
│  to focused  │  anatomy reused verbatim)     │ │ confidence ●●○ revise │ │
│  verse)      │ [only-mine ▾][type ▾][kind ▾] │ │ ⚠ anti-fallacy #4:    │ │
│              │                               │ │ "don't count mss,     │ │
│              │                               │ │  weigh them" reminder │ │
│              │                               │ └───────────────────────┘ │
└──────────────┴───────────────────────────────┴───────────────────────────┘
Mobile: tabs [Text|Apparatus|Reasons]; note tap on Text → Apparatus tab scrolled to unit.

5.3 Personal apparatus note grammar

A NOTE = the print-facing projection of one unit decision:

note := marker + unit-ref + kind + chosen-reading + [against-default] + [witnesses] + [reason ≤280ch] + [confidence]
  • marker: a, b, c … z, aa, bb … per verse, ordered by unit index within the verse (deterministic; NEVER alphabetical-by-content).
  • kind: substitution · addition · omission · word-order (from unit type + reading value).
  • Verse header line: Mrk 1:2 · 3 units · 2 decided · witnesses cited: 14.

5.4 Note-numbering parity contract (first F-2 — NORMATIVE)

  1. SBV marker sequence for verse v == PM footnote marker sequence for verse v == marker order in the reasons appendix (§6.6), all derived from ONE function numberNotes(v) in shared lib.
  2. Test gate: for every verse with units, the three renderings produce identical marker arrays (property test over all 4,720 verses; gate runs in QA script, MUST PASS before any PES release).

5.5 Filters & study presets

  • Filter axes: only-my-deviations · kind (sub/add/omit/order) · decided-vs-default · confidence · has-reason.
  • Preset = named combination persisted in D1 (pesPresets), max 24 presets; sharing a preset exports JSON (X-06).

5.6 Reason cards & anti-fallacy hooks

  • Reason card fields: chosen reading, base default, witness citation list (from 42,482-pair table), reasoning text, confidence (none/low/med/high), timestamp.
  • The 12-item anti-fallacy catalogue (shipped) surfaces contextually: e.g. a decision citing >6 witnesses with no internal-consistency note shows the relevant catalogue reminder — NEVER blocks, only reminds (guarded-inference posture).

5.7 Behavior register

ID Behavior Pri
SBV-01 Three-pane layout ≥1024; stacked tabs <1024 P0
SBV-02 Verse sync: focusing a verse in Text scrolls Apparatus to that verse block P0
SBV-03 Notes generated by numberNotes(v) (§5.4 parity function) P0
SBV-04 Filters (§5.5) combinable; counts update live P1
SBV-05 Presets save/load/delete, max 24, en/id names P1
SBV-06 Reason card edit inline; autosave debounce 800ms; dirty indicator P0
SBV-07 Confidence selector on card; affects PM reasons appendix column P1
SBV-08 Anti-fallacy contextual reminders (§5.6) P2
SBV-09 Witness citation popover reuses existing witness panel P1
SBV-10 "Only my deviations" one-tap filter in toolbar P1
SBV-11 Orphan decisions list (E-CTV-07) with purge/re-attach P2
SBV-12 Book completeness breakdown table P1
SBV-13 Export study preset JSON P2
SBV-14 Keyboard: N next note, P previous note, F focus filter P2
SBV-15 Apparatus pane reuses R35 row anatomy (no new visual dialect) P0

5.8 Edge cases

ID Case Treatment
E-SBV-01 Verse with units but zero decided header shows "0/3 decided", notes render with default-readings greyed
E-SBV-02 Reason >280 chars hard truncation warning at 280 (PM limit); SBV allows longer but flags "will split in appendix (E-PM-05)"
E-SBV-03 Verse has >26 units (marker exhaustion into aa) aa…zz sequence; tested against census max units/verse
E-SBV-04 Filters produce empty set explicit empty state with filter reset button
E-SBV-05 Preset name collision suffix " (2)"
E-SBV-06 Decision edited while apparatus pane open pane updates in place, scroll anchor kept
E-SBV-07 Witness list >50 for one unit collapse to first 12 + "+38 more"
E-SBV-08 Book with 0 decisions full-book empty state → CTV-11 banner
E-SBV-09 Passage-scoped note (passage decisions in SBV) passage notes appear on the passage's opening verse, kind "passage"
E-SBV-10 Notes renumber after a decision edit recompute is local to verse; no cross-verse renumber (per-verse reset, §6.4)

6. F3 — Print myGNT (PM)

6.1 User story

As the editor, I press ⎙ and receive a typeset critical edition of MY text: continuous Greek with superscript markers, my apparatus as footnotes, my reasons as an appendix, and a colophon that hashes the whole thing — a real book of my own scholarship.

6.2 Product kinds

Kind Contents Audience
K1 Critical Edition CE text + apparatus footnotes + colophon self/supervisor
K2 Reader CE text only (markers hidden), no apparatus reading copy
K3 Apparatus Digest all 11,644 units as a table, per book reference
K4 Full Dossier K1 + reasons appendix + methodology statement + colophon archival

6.3 Page geometry & typography

Token Value Note
Page A4 210×297mm; Letter 8.5×11in toggle @page { size: A4; margin: 22mm 19mm 24mm 19mm } (duplex-aware: inner 24mm when duplex ON)
Greek face embedded via fontsource (same face as app — no metric drift) fallback serif chain
Body size 11pt / 15.5pt leading (A4), 12pt Letter user-tunable S/M/L → 10/11/12.5pt
Text measure single column justified; hyphenation OFF (Greek) text-align: justify; hyphens: none
Footnotes 8.5pt / 12pt leading, rule above, per-page
Verse numbers superscript, same size as body
Max lines per page derived by engine, never hand-tuned

6.4 Footnote engine (normative)

ID Rule
PM-01 Markers per verse: a…z then aa…zz (§5.4 parity)
PM-02 Marker numbering is PER VERSE (never per page) → stable across re-pagination, satisfies parity contract
PM-03 Footnote block printed at bottom of the page where the MARKER falls
PM-04 Note longer than fits → "(cont.)" continuation on next page; never silently truncated
PM-05 A verse's footnote block MUST NOT be orphaned from its marker page: if marker is last line of page, block starts same page bottom or moves marker
PM-06 >12 footnotes on one page → digest overflow note "n further notes: appendix §A.{book}.{ch}.{v}" (K4)
PM-07 Omitted words appear ONLY in footnotes; continuous text simply flows past
PM-08 Additions printed without braces in text; footnote records "addition; base lacks"
PM-09 Word-order decisions: text shows new order; footnote records @order:»k and base order
PM-10 Passage-omitted: text skips passage; tombstone line "— {passage name} omitted by editor (see appendix) —" once per passage

6.5 Colophon (every kind except K2)

Fields (fixed order): edition name (E-CTV-11 rules) · editor · date (ISO) · base-default declaration · CE rev + hash (§3.2) · Phase-A model hash · counts (decided/defaults per kind: sub/add/omit/order/passages) · license lines: "Greek base stream and apparatus data © contributors, CC BY; TBESG/LSJ gloss data per PROVENANCE §3; no restricted text served (qa15 L3)" · abridged MAY/MUST-NOT claims block (D-02) · /method URL citation.

6.6 Reasons appendix (K4)

Table per book: verse · marker · kind · chosen · against(default) · witnesses (n) · reason (wrapped) · confidence. Row keep-together; a reason >280ch splits at sentence with "(cont.)" — never mid-word.

6.7 Render path

  1. v1 (this suite): browser print — dedicated print route renders print-DOM; @media print hides app chrome; user "Save as PDF". Zero new server deps; deterministic via embedded fonts.
  2. v2 (explicitly DEFERRED, not in P0–P5): server-side PDF (typst/puppeteer on Workers is out of scope; will be its own round).

6.8 Keep-together decision table

Element Rule
heading + first verse KEEP
verse + first 2 lines of its footnote block TRY; else move whole verse (PM-05)
apparatus unit row KEEP
reason row (§6.6) KEEP; else sentence-split
colophon STARTS ON NEW PAGE, never split

6.9 Behavior register

ID Behavior Pri
PM-11 Print preview route /{view}/print/{book} renders paginated preview (CSS columns simulation) P0
PM-12 Kind selector K1–K4; K2 hides markers (F-4 honesty: a K2 copy is declared "reading copy" in colophon-lite) P0
PM-13 Duplex toggle → inner margin 24mm P1
PM-14 Book range selector: single book P0 (multi-book whole-NT is P2)
PM-15 Print stylesheet shares §4.4 grammar (same marks → same semantics) P0
PM-16 Colophon generation from ONE shared constants module (D-02) P0
PM-17 Reasons appendix numbering == SBV markers (parity function) P0
PM-18 Preview shows page count + estimated pages before printing P1
PM-19 "Open print dialog" button → window.print() on print-DOM only P0
PM-20 i18n: ALL front-matter/appendix labels en+id; Greek text untouched P0
PM-21 Page-break audit gate: script asserts zero orphaned footnote blocks on a census sample (Mt, Mk, Jhn, Rom) P0
PM-22 K3 digest sorted by unit index; includes undecided-default rows greyed P1

6.10 Edge cases

ID Case Treatment
E-PM-01 Book where user decided 0 units K1 prints with apparatus "no editorial decisions recorded in {book}" + colophon; NOT blocked
E-PM-02 Footnote block taller than page continuation chain (PM-04); >1 full page → appendix overflow (PM-06)
E-PM-03 Marker sequence exceeds zz (verse with >702 units) impossible per census (max units/verse ≪ 702); assertion in engine anyway
E-PM-04 Print while decision autosave in flight (SBV-06 debounce) print button waits for flush; indicator
E-PM-05 Reason exactly at 280ch boundary no split marker unless actually split
E-PM-06 Greek line overflow (very long word + justified) allow emergency ragged-right on that line only
E-PM-07 User prints K2 but has deviations from declared base K2 colophon-lite states "reading copy; 1,207 editorial deviations recorded in apparatus edition"
E-PM-08 Browser print scaling ≠100% preview banner "set scale 100%"
E-PM-09 Duplex with odd-page-only content blank-page insertion rule; stated in preview
E-PM-10 Passage included but individual units omitted inside units omitted individually; passage tombstone NOT printed
E-PM-11 Edition name with RTL-lookalike chars sanitize per E-CTV-11
E-PM-12 Page count > 900 (whole NT K4) hard warning + per-part split suggestion; not blocked

7. Cross-cutting

ID Requirement
X-01 i18n: all new strings under CTV.* / SBV.* / PM.*, en + id parity test; default id (existing posture)
X-02 WCAG 2.1 AA: 4.5:1 text contrast both themes; focus-visible everywhere; all marks have non-color redundancy (F-4 grammar is shape+text, not hue)
X-03 Keyboard map: §4.6/§5.7/§6.9; no keyboard traps; Esc closes any layer
X-04 Perf budgets: CTV chapter first paint ≤300ms local · popover open ≤50ms (prefetched shards) · SBV 3-pane interactive ≤500ms · PM preview layout ≤1s/book-chapter · no layout thrash on scroll (rAF-batched)
X-05 Privacy: no telemetry; decisions never leave user's store except explicit export (existing posture)
X-06 Export/import: CE ledger JSON already exportable via /api/export — PES adds preset + colophon metadata; import validates against schema §8
X-07 Witness-only verses appendix toggle (PM) — default OFF
X-08 Integrity: PES is a derived view — MUST NOT move Phase-A modelHash 51d49df3; qa13 --check MUST PASS on every code round touching PES
X-09 aria-live regions: completeness meter, autosave state, page count
X-10 Licensing: printed colophon carries CC BY + PROVENANCE §3 lines verbatim (single constants source)
X-11 Non-goals: no verse re-ordering beyond recorded @order; no free-typing Greek text (text comes only from the pipeline); no collaborative editing; no server PDF (v2); no mobile app

8. Data contracts

// CE manifest (derived; produced by resolver, consumed by CTV/SBV/PM)
{
  "ceRev": 412,
  "ceHash": "c3f9…64",            // §3.2 canonical hash
  "baseDefault": "SRGNT",
  "modelHash": "51d49df3",        // staleness guard (X-08)
  "counts": { "decided": 1207, "defaults": 10437, "passagesDecided": 3, "passagesUndecided": 2 },
  "perKind": { "substitution": 511, "add_omit": 566, "wordOrder": 130 }
}

// resolution record (per rendered unit; internal)
{ "vuKey": "Mrk.1.2:4", "kind": "add_omit", "chosen": "Ἠσαΐᾳ", "source": "decision|default|fallback", "note": 2 }

// print spec (input to print route)
{ "kind": "K1", "book": "mrk", "duplex": false, "pageSize": "A4", "bodySize": "M",
  "includeWitnessOnlyAppendix": false, "ceRev": 412, "ceHash": "c3f9…64" }

// note record (parity function output)
{ "verse": "Mrk.1.2", "marker": "b", "unitIndex": 4, "kind": "substitution",
  "chosen": "Ἠσαΐᾳ", "againstDefault": "ἐν Ἠσαΐᾳ", "witnesses": ["TR","Byz","A","C"],
  "reason": "…≤280…", "confidence": "med" }

9. End-to-end flows

FLOW A — decide → everywhere
  Bible Maker grid ──save──▶ MygntDecision(D1) ──▶ CE.rev++ / hash
        │                                        │
        ▼                                        ▼
  CTV text re-render (shard slice)         SBV notes renumber (verse-local, E-SBV-10)
                                                 │
                                                 ▼
                                     PM preview invalidated (hash changed)

FLOW B — print session
  ⎙ on CTV/SBV ──▶ print route (kind, book, options) ──▶ resolver → numberNotes() parity
      → paginate → preview (pages + count) ──▶ window.print() ──▶ PDF/paper + colophon hash

FLOW C — share
  Export CE ledger JSON ──▶ (other device) import validate §8 ──▶ same CE.hash ⇒ same book

10. Test matrix & QA gates

  • Matrix: {CTV, SBV, PM} × modes × {en,id} × {1440, 768, 390} × {light,dark} × CE states {empty, minimal, mixed, full-book} × kinds K1–K4.
  • Property gates: parity test §5.4 over 4,720 verses; page-break audit PM-21; i18n key parity X-01; contrast X-02.
  • Round gates (every code round): lint clean · tsc delta 0 vs 106 baseline · Phase-A --check PASS (X-08) · qa18 197/197 · browser pass 1440+390 zero console errors · ERRATUM stays at zero NEW findings (zero-bug standard).

11. Rollout

Phase Contents Acceptance
P0 CE resolver + hash + completeness (pure lib + tests) resolver golden tests; hash stable across runs; X-08 PASS
P1 CTV M1/M2 + popover + meter + empty/blocked states §4.9 edges E-CTV-01…06 pass; budgets X-04
P2 CTV M3/M4 + full visual grammar + keyboard grammar table §4.4 1:1 on screen
P3 SBV 3-pane + notes + presets + parity function parity gate §5.4 PASS
P4 PM K1/K2 print CSS + preview + colophon PM-21 audit PASS; colophon fields §6.5 complete
P5 PM K3/K4 + appendix + a11y/i18n polish + full matrix matrix §10 green; zero-bug gate

12. Risks

Risk Mitigation
11,649-row decision slice slow on low-end per-book slice fetch + base-first render (E-CTV-08)
Print metric drift across browsers embedded fonts + PM-21 audit + preview banner (E-PM-08)
Footnote overflow pathological verses PM-04/06 continuation + appendix
Concurrent-tab decision races E-CTV-12 last-write-wins + hash recompute
Scope creep into Phase A/B/C PES is VIEW-layer only; Phase gates remain owner-controlled
Hash unstable across serializations canonical serialization spec §3.2 + golden test

13. Continuous enhancement loop (scheduled QA agent, every 15 min)

Axes (each run must name the axis it served): robustness (new edge cases / tightening) · advancement (one-of-a-kind mechanisms) · effectiveness (does each behavior serve the editor's goal) · efficiency (steps, latency, tokens of effort) · uniqueness (moat deepening vs R55 census).

Rules: R1 Iron Rule git fetch && git reset --hard origin/main first · R2 edit ONLY download/PERSONAL-EDITION-SUITE-SPEC-R56.md (by section/ID) — product code untouched except page-sync fixes · R3 add a §14 changelog line per run (date · axis · IDs touched · delta) · R4 surgical edits, never wholesale rewrites · R5 commit ONLY on substantive delta (max 1 commit/run) + CANARY + tar; otherwise no-op report · R6 report EN/ID · R7 zero-bug standard applies to the spec page itself (lint + render check).

14. Spec changelog

Date (WIB) Axis IDs Delta
2026-01-30 (created) — all v1.0 initial spec born from R55 analysis + owner directive

15. Sources (repo pointers)

data/manifest.json · src/services/mygnt/mygntDecisions.ts · src/lib/na-brackets.ts · src/islands/views/BibleMakerView.tsx · scripts/qa12-external-review-scope.ts · scripts/qa13-phase-a-reconciliation.ts · ERRATUM.md · download/COMPETITOR-ANALYSIS-BIBLEMAKER-R55.md · src/pages/method.astro.