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:
- CTV — Composed Text View: read YOUR edition as continuous Greek text (not a decision ledger — the resulting text).
- SBV — Study Bible View: your edition wrapped in your personal apparatus — every note is your unit decision + reasoning.
- 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 byvuKey, 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|undecideddecisions already persist viavuKey "passage:{id}"(5-b layer, shipped). CE renders them per decision;undecidedrenders 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 | |
|---|---|---|---|
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)
- 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. - 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
- v1 (this suite): browser print — dedicated print route renders print-DOM;
@media printhides app chrome; user "Save as PDF". Zero new server deps; deterministic via embedded fonts. - 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
--checkPASS (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.