# BSB + MSB Hybrid USFM Merge

Merges the Berean Standard Bible (BSB, critical text) and Majority Standard
Bible (MSB, Byzantine majority text) into a single hybrid USFM per book. The
text reads as one Bible; where the two editions differ, the differing words are
broken out into back-to-back `\zv [BSB]` / `\zv [MSB]` blocks, and redundant
inherited punctuation is wrapped in `\zp` for lighter styling.

## Files

- `merge_usfm.py`  — core merge logic for one book (also importable as a module)
- `merge_all.py`   — batch driver: merges a whole Bible, prints a validation table
- `validate.py`    — standalone validator for a single merged Matthew (dev aid)

## Running

### One book
```
python3 merge_usfm.py BSB_book.usfm MSB_book.usfm out.usfm
```

### Whole Bible
Place `merge_all.py` and `merge_usfm.py` together in the directory that contains
your `BSB/` and `MSB/` source sub-directories, then:
```
python3 merge_all.py            # uses ./BSB, ./MSB, writes ./BSB+MSB
python3 merge_all.py BSB MSB BSB+MSB   # explicit dirs
```

Files are paired by the book code on their `\id` line, **not** by filename, so
`BSB/MAT.usfm` and `MSB/MSB_MAT.usfm` pair correctly. Each output file takes the
**BSB** source filename and is written to `BSB+MSB/`.

The run prints a per-book table and flags any book that fails:
- `MARKER`  — unbalanced `\wj`, `\f`, or `\zp` on some line
- `BSB-RT`  — stripping the `[MSB]` blocks does not reproduce the original BSB
- `MSB-RT`  — swapping in the `[MSB]` blocks does not reproduce the MSB words
- `N-UNANCHORED` — N MSB-only verses could not be placed

## How differences are encoded

**Word-level variant** (e.g. Matthew 5:11):
```
\p \v 11 \wj Blessed are you when people insult you, persecute you, and falsely say\wj*
\p \zv [BSB]\zv* \wj all kinds of evil\wj*
\p \zv [MSB]\zv* \wj every evil thing\wj*
\p \wj against you because of Me. ...
```

**One side adds a phrase** — only the *added* words are bracketed; the shared
word stays in the main flow and the ending punctuation that is redundant for the
continuing reading is wrapped in `\zp` so it can be styled lighter. This works
in both directions:

MSB adds (Matthew 6:6 — BSB ends "you.", MSB continues "you openly."):
```
\p ...will reward you\zp .\zp*\wj*
\p \zv [MSB]\zv* openly.
```

BSB adds (Matthew 3:11 — MSB ends "Spirit.", BSB continues "Spirit and with fire."):
```
\p ...baptize you with the Holy Spirit\zp .\zp*\wj*
\p \zv [BSB]\zv* and with fire.
```

In each case the `\zp` punctuation belongs to the reading that stops there and
is "in the way" of the reading that continues; lightening it is what keeps the
merged line readable for both.

**Whole verse only in MSB** (Matthew 17:21, 18:11, 23:14): inserted as an
`[MSB]`-only block carrying its own verse number.

## PTXPrint setup — required custom markers

Define these character styles (custom.sty, or via the Styles tab). They were
worked out earlier in the project:

```
\Marker zv
\Endmarker zv*
\Name zv - variant label (styled as verse number)
\StyleType Character
\TextType VerseText
\FontSize 10.8          # = 0.90 factor x 12; matches verse-number size
\Superscript
\Color x5E5C64

\Marker zp
\Endmarker zp*
\Name zp - redundant inherited punctuation
\StyleType Character
\TextType VerseText
\Color x999999          # lighten to taste; this is the whole point of \zp
```

`\zv` reproduces the verse-number look for the `[BSB]`/`[MSB]` labels. `\zp`
lightens the redundant punctuation; pick whatever grey / opacity reads best.
Both are nested inside `\wj` in the output, so confirm they inherit or override
the red-letter colour the way you want.

## Notes / caveats

- The merge **combines** BSB and MSB footnotes. BSB notes are kept as the base;
  MSB notes are added, except an MSB note is dropped when BSB already carries an
  identical one at the same verse (compared on note body, ignoring the verse
  reference and markup). Each MSB note is anchored where its word sits in the
  merged text: notes on shared words go in the main flow, and notes on
  MSB-variant words travel into the `[MSB]` block with their word. When a note's
  word is a shared anchor duplicated into both readings (the verse-boundary
  case), the note is kept only on the BSB-reading copy so it is not shown twice.
- Combined footnotes are **labeled by origin** so the reader can tell which
  edition each comes from: a note unique to BSB is prefixed `[BSB]`, a note
  unique to MSB is prefixed `[MSB]`, and a note present in both editions (the
  deduplicated case) is left unlabeled. The label is plain text placed at the
  start of the note's visible text (after the first `\ft`/`\fqa`/`\xt`).
- Books present in `BSB/` but not `MSB/` are copied through unchanged. Books
  only in `MSB/` are skipped.
- **Relocated passages.** A few passages sit at different verse numbers in the
  two editions — most notably the Romans doxology (BSB 16:25-27 vs MSB
  14:24-26). The merge detects identical text appearing as a BSB-only run and an
  MSB-only run, and shows it in BOTH places as a one-sided variant block: an
  `[MSB]` block at the MSB position (Romans 14, carrying MSB's verse numbers
  24-26) and a `[BSB]` block at the BSB position (Romans 16, carrying BSB's
  numbers 25-27). Each reading reconstructs the text natively at its own verse
  keys. The validation table's `reloc` column counts these. Genuinely MSB-only
  verses with no BSB equivalent (e.g. the grace benediction at Romans 16:24) are
  still inserted normally as `[MSB]` blocks.
- **Section heading inside a box.** When a variant comprises an *entire* section
  (rare — e.g. the Romans doxology, whose whole "Doxology" section is the
  BSB-position variant), the section heading and its reference (`\s1`, `\r`,
  etc.) are pulled *inside* the variant box rather than left hanging before it.
  This also merges the box with an immediately preceding variant box: at Romans
  16 the MSB-only grace benediction (`[MSB] \v 24`) and the doxology (`[BSB] \v
  25-27`) end up in one box with `\s1 Doxology` between them, in document order.
  The heading is absorbed only when no normal verse text follows the variant
  before the next section/chapter/box boundary; an ordinary heading whose section
  contains regular text (e.g. Matthew 17's "Second Prediction") stays outside.
- **Long disputed passages.** Mark 16:9-20 and John 7:53-8:11 — present in both
  BSB and MSB but frequently bracketed in critical editions — are wrapped in
  variant boxes (category `\cat disputed\cat*`) headed by a `[BSB+MSB]` label.
  Because a single large `\Position p` sidebar with a background fill cannot
  break across pages in PTXPrint, each passage is split into several shorter
  boxes — one per natural section — separated by a hidden-period paragraph
  (`\p \zh . \zh*`) so the material can flow down the page:
    - Mark is split at its four section headings (boxes starting at 16:9, 16:12,
      16:14, 16:19), each carrying a `[BSB+MSB]` label before its heading.
    - John is split into 7:53 (its own box), then chapter 8 in two boxes —
      8:1-5 and 8:6-11. The 7:53 and 8:1-5 boxes carry `[BSB+MSB]` and use
      category `disputed`; the 8:6-11 box is a mid-section continuation carrying
      no tag and using a separate category `disputed2`
      (so they can be styled differently, e.g. without a repeated border). The
      John passage spans the 7/8 chapter boundary at 8:1, handled in two parts: a
      `\cp 8` (published chapter character, *not* `\c 8` — which would draw a
      drop-cap that misbehaves beside the sidebar) is placed outside the boxes to
      register the chapter, with its printed form suppressed in the stylesheet;
      and the chapter is shown to the reader as a bold inline `\zc 8:1\zc*` on
      verse 1 inside the box (replacing that verse's `\v` number). A `\zc` style
      entry controls the bold inline form. (Note: omitting `\c 8` means tools
      that read chapter context only from `\c`, such as running headers and
      cross-references, will not see chapter 8 here; verify those in your render.)
  Inner word-level variant boxes within a passage are un-nested (the `\esb`/
  `\esbe` wrappers dropped) while their `\zv [BSB]`/`\zv [MSB]` labels stay
  inline. The validator strips the `[BSB+MSB]` banner and the hidden-period
  separators (they carry no text) for round-tripping.
- "punct" verses are the cases where a shared word carries one edition's
  punctuation the other would place differently. This is the unavoidable cost of
  a single text stream; the `\zp` wrap is what makes it unobtrusive. No words are
  ever misplaced — only punctuation attachment differs.
- Large *block* differences (Mark 16 long ending, John 7:53–8:11, Acts 8:37,
  1 John 5:7–8) are a different shape from word-level variants. The validator
  will pass them if the text round-trips, but eyeball those passages in the
  output to confirm the layout reads the way you want.
- Re-run after any source update; the merge is deterministic.
