Skip to content

Rust rewrite: full parity port of overlay (Linux GTK reader + portable core/FFI) - #1

Merged
glendonjklassen merged 41 commits into
mainfrom
rust-rewrite
Jul 10, 2026
Merged

Rust rewrite: full parity port of overlay (Linux GTK reader + portable core/FFI)#1
glendonjklassen merged 41 commits into
mainfrom
rust-rewrite

Conversation

@glendonjklassen

Copy link
Copy Markdown
Owner

Adopts the Rust rewrite as main: the pure domain core, layout engine,
feature-gated R&D tier, the single C ABI, the hydrate CLI, and the GTK4/libadwaita
Linux reader — at feature parity with the overlay backlog.

Highlights

  • Portable core (core/layout/rnd/ffi/hydrate): dependency-light pure
    Rust, cross-platform file I/O (atomic temp→fsync→rename, per-OS dirs).
  • R&D tier (feature-gated): etymology bridge, concept embeddings + SIF verse
    similarity, morphology, keyness/leitwort (Poisson scan + BH-FDR), text-witness.
  • GTK reader: warm-paper KJV reader, weave chord map, radial concept map,
    session restore, gzipped corpus cache (0.63s warm release launch).
  • Study panel polish (this final push): English-first concept lists learned
    from actual KJV renderings, sectioned analytics with headers, humanised wording.
  • ARM64 Windows: C ABI now cross-builds for aarch64-pc-windows-msvc in CI.

Verification

  • Portable crates: 87 tests · R&D features: 23 · desktop markup: 2 — all green.
  • FFI bindings in sync (C header + C# P/Invoke regenerated, no drift).
  • Portable stack type-checks for aarch64-pc-windows-msvc locally; CI links the
    ARM64 + x86_64 Windows .dll.

🤖 Generated with Claude Code

…test

Ground-up port of the overlay study logic into a pure Rust workspace:

- crates/core: canon (66 books, frozen tok stamp), VRef + refKey, the
  tokenized KJV corpus (JSONL loader + canonical-order validation +
  chapter index), Strong's dict + occurrence index + proper-noun
  heuristic, four-tier search (exact/variant/lemma/typo + phrase + ref +
  bare-Strong's), and the weave graph (canonical links, BFS components,
  union-merge, v2 JSON). 28 tests.
- crates/layout: reader layout + per-word hit-testing as a platform-
  agnostic algorithm over injected text measurement (Measure trait), so
  hit regions always match what the native UI paints. 3 tests.
- crates/rnd: feature-gated R&D capability flags (off by default).
- crates/ffi: C ABI stub (version probe) for future UniFFI/csbindgen.
- apps/desktop: headless core->layout smoke test (GTK next).

Verified against overlay's real data: 31,102 verses load, John 3 lays
out to 801 boxes, John 3:16 per-word Strong's resolve. Patches/rules
dropped by decision.

Refs PLAN.md. 33 tests pass, no warnings.
The first native UI (decision: GTK4 on Linux first). A thin shell over
pure-core + pure-layout:

- Header nav: book dropdown, chapter spinner, prev/next, live title.
- Scripture canvas measures + paints with one cairo context (so per-word
  hit regions match the glyphs exactly), driving pure-layout's display
  list: gold verse numbers, gold underline on Strong's-tagged words,
  italic-gray KJV-supplied words, ¶ paragraph breaks.
- Click a word -> pure-layout hit-test -> Strong's entry (lemma,
  translit, pronunciation, def, KJV renderings) in the study side panel.
- gtk4 0.11 / libadwaita 0.9; warm-paper theme.

Verified visually against overlay's real 31,102-verse data (John 3).

PROGRESS.md records the landing point and next steps (Windows/WinUI +
Android/Compose shells, both pending a one-time rustup + NDK/mingw
install). 33 tests pass, no warnings.
…B Garamond

Three arcs on the rust-rewrite branch.

pure-ffi — the one C ABI both native shells consume (was a stub):
- opaque PureEngine/PureDisplayList handles, callback-based Measure (layout
  stays in Rust, measured by the platform), stable camelCase-JSON payloads,
  panic-safe (catch_unwind) boundaries, explicit ownership/free.
- open / open_from_bytes, toc, chapter_count, verse/token, layout_chapter,
  hit_test, strongs (+ occurrences), search.
- generated bindings: C header (cbindgen) + C# P/Invoke (csbindgen), plus a
  hand-written idiomatic C# wrapper and a Kotlin/JNA wrapper. Regenerate with
  `cargo run -p pure-ffi --features bindgen`.
- verified: 10 Rust ABI tests, a C consumer (bindings/c/smoke.c) and a C#
  P/Invoke consumer, both driving the real 31,102-verse corpus.
- reviewed adversarially (6 lenses); fixed the surfaced wire-contract issues
  (verse key, exported flag constants, callback totality + NaN clamp, null on
  out-of-range chapter, explicit-null item fields, u32->u16 truncation).
- Windows x86_64 .dll cross-builds (mingw); host .so/.a build.

core::notes — the kjv-notes.jsonl loader (missing file -> empty, bad lines
skipped, notes grouped per verse in file order), feeding search + the reader.

desktop reader — the core's study surface, wired into GTK:
- multi-tier search box; concordance (occurrences); 1769 margin notes;
  Ctrl zoom; keyboard scroll + chapter nav.
- real typography: Pango shaping in the bundled EB Garamond (registered with
  fontconfig at startup, no system install), replacing cairo's toy font API.
- fixes: hit regions align with glyphs (was offset by the top margin -> hit
  the line below); Strong's on double-click (single click reserved); study
  panel is on-demand (hidden by default, Esc/clear-search closes it).

cargo test: 44 green across core/layout/rnd/ffi, no warnings.
Load all weaves from OVERLAY_HOME/weaves (+ suggested) at startup and precompute
a verse → partners map (both directions of each undirected link, deduped).

- Reader: verses carrying cross-references get a subtle gold gutter dot.
- Study panel: double-clicking a word now lists that verse's cross-references —
  each a clickable jump link, tagged with the weave that asserts it — alongside
  its Strong's entry, margin notes, and concordance.

Reuses core's ported weave graph + loader; the authoring / constellation /
chords UI remain later work.
Refactor the single-pane reader into N independently-navigable columns
(overlay's core reading model).

- Each pane has its own book/chapter nav strip (dropdown, chapter spin,
  prev/next), scroll position, draw, and per-word hit-test.
- Per-pane + / ✕ add and close columns (up to 3); the pane row rebuilds on
  change so handlers always hold a valid index.
- The active pane (last touched; gold top accent) is what the header search,
  cross-reference/search "go" links, and the study panel target.
- Ctrl+scroll / Ctrl+/- zoom all panes together; Page/Home/End scroll the
  focused pane; ←/→ (or [ ]) step its chapter.

Verified: John 3 + Numbers 21 render side by side; single-pane nav strip shows
book/chapter/prev/next/+ . cargo test 44 green, no warnings.
Overlay a transparent, click-through draw layer on the pane row and draw a soft
gold curve between the two endpoints of every weave link whose verses are both
currently on screen. Verse positions map into the overlay via GTK
`compute_point`, so the connectors track each pane's scroll automatically; the
layer redraws on scroll, navigation, zoom, and pane add/close.

Endpoint + gutter dots mark linked verses. Verified with Genesis 15 ∥ Romans 4:
a curve joins Gen 15:6 ↔ Rom 4:3 ("Abraham believed God … counted … for
righteousness"). cargo test 44 green, no warnings.
- Hover a Strong's-tagged word for a quick tooltip gloss (code + lemma +
  transliteration + trimmed definition), wired through GTK's query-tooltip and
  the same per-pane hit-test as double-click.
- A canon-overview strip under the panes maps the 66 books in their 8 canon
  sections (Law … Revelation) with the OT/NT divide and a pin per pane (active
  in gold); clicking a book jumps the active pane there.

Verified: strip shows the sections + John's pin under Gospels. cargo test 44
green, no warnings.
core::thread and core::tag — port overlay's Thread.hs / Tag.hs (personal study
data, one JSON file per item under home/threads and home/tags):
- Thread { name, notes, entries:[ref, span, word snapshot, note, added] };
  Tag { name, color?, members:[target(verse|concept), note?, added] }.
- Format-checked, ref-parsing serde (custom (de)serialize keeps the frozen
  "overlay-thread-v1" / "overlay-tag-v1" wire form); dir loaders sorted by name,
  bad files reported not dropped; membership queries. +7 tests.

Desktop: "Threads" / "Tags" header buttons open a browse list in the study
panel; a thread shows its passages (snapshot preview + note) as jump links, a
tag shows its verses (jump) and concepts (concordance); a verse's tags also
appear in its word study. Verified against the Romans Road thread.

Read side only — authoring (add/tag/write) is next. cargo test 51 green.
core::store — a portable atomic writer: write to a sibling temp file, fsync,
close the handle (required on Windows), then fs::rename over the target
(replaces the destination on Unix and Windows alike). All paths built with
Path::join; a `slug` helper mirrors overlay's filename slugging.

core authoring — thread::{thread_file, write_thread, add_to_thread} and
tag::{tag_file, write_tag, add_member, remove_member}: create-or-append by
case-insensitive name, dedupe tag members, refuse to clobber an unparsed file,
caller-supplied timestamps (keeps core deterministic). +4 tests covering the
write→reload round-trip in a temp dir.

Desktop — a word study now offers "+ tag verse" and "+ add to thread" (a modal
name prompt, then create-or-append, atomic write, and reload) and "✕" to untag;
the data home is kept in State for reloads. Verified the action links render;
core write path is unit-tested end-to-end.

cargo test 55 green, no warnings.
core::weave — write_weave + add_link (find-or-create a weave by case-insensitive
name, dedupe/canonicalize via Weave::add_links, refuse to clobber an unparsed
file, caller-supplied timestamp), through the atomic cross-platform store. +1
test covering create → append → dedupe round-trip.

Desktop — single-click a word to pin its verse as a link endpoint (blue band);
when two panes are pinned the header "+ link" button enables. It prompts for a
weave name, writes the whole-verse link, reloads weaves + rebuilds the cross-ref
index and connector pairs, and the new gold connector line draws immediately.
Double-click still opens Strong's; the loaded weaves are kept in State for
find-or-create.

Read + write of the weave graph are now both in the reader. cargo test 56 green.
The C ABI was read-only; the Windows/Android shells could display study data but
not create it. Now the engine loads notes + threads + tags + weaves from its
home dir (when opened via pure_engine_open) and exposes:

read  — pure_engine_threads_json / _tags_json / _verse_xrefs_json(ref)
write — pure_engine_thread_add / _tag_add / _tag_remove / _weave_add_link
        (null on success, else an owned error string; caller supplies the UTC
        timestamp; writes go through core::store's cross-platform atomic write;
        the engine reloads its in-memory copies after each write)

An engine opened from bytes has no home and returns an error from the write
calls (study data stays read-only). A dedicated guard turns any panic in a write
into an error rather than a false success. New wire DTOs for threads/tags/xrefs;
regenerated the C header + C# P/Invoke shim.

Verified with an end-to-end ABI test: open a temp home, tag/thread/weave via the
ABI, read back, exercise the error paths. cargo test 57 green; Windows x86_64
.dll still cross-builds.
core::weave gains is_suggested / approve_weave / reject_weave: approve
marks every link approved and lands the weave in home/weaves (merging a
same-named weave there), removing the suggestion; reject deletes the
file. Both go through the cross-platform core::store atomic writer.

GTK: a "Suggested" header button opens the review queue — each proposal
under weaves/suggested with its links as jump links and approve/reject
actions that reload + re-render.

FFI: pure_engine_suggested_weaves_json lists the queue with per-item
ordinals; pure_engine_weave_approve / _weave_reject act by that ordinal
(null on success, else an owned error; needs a home). Regenerated the C
header + C# P/Invoke shim.

60 tests green (incl. an end-to-end ABI review round-trip); Windows
x86_64 .dll still cross-builds.
…/spanB

A click now pins a single word as a link endpoint; clicking another word
in the same verse grows the span from the first click's anchor (widen or
narrow without clearing). The pinned span highlights its exact words
(blue) rather than the whole verse, and make_link records each endpoint's
token span via Link::canon_span — the core already stored spanA/spanB.
Connectors and cross-references stay verse-level, so nothing else shifts.
core: thread::set_thread_notes / set_entry_note (empty clears; errors on
missing thread or out-of-range entry) and weave::set_weave_notes (marks
notesSource=hand). All via the cross-platform atomic writer.

GTK: a thread view gains "✎ notes" and a per-entry "✎ note"; a suggested
weave gains "✎ note". A new prompt_text dialog pre-fills the current text
and permits an empty submission (to clear).

FFI: pure_engine_thread_set_notes / _thread_entry_set_note /
_weave_set_notes (null on success, else an owned error; needs a home),
covered by the ABI round-trip test. Regenerated C header + C# shim.

62 tests green; Windows .dll still cross-builds.
weave_markup renders a weave's kind, notes (with ✎ note), and each link
as its two passages with the spanA/spanB words bolded (KJV-supplied words
stay italic-gray, as in the reader) and the shared label shown. Opened
from a cross-reference (the weave name is now a link) or the suggested
review list (a new "⇔ compare" action). Read-only view over the corpus;
no new on-disk format.
navigate_pane cleared the pane's display list and now polls every 8ms
(up to ~1s) until the new chapter is painted and its scroll extent has
grown to the new content height, then scrolls once. This fires as soon
as the layout is ready — usually the next frame — instead of hoping a
fixed 50ms delay lands after the paint, and can't scroll a stale chapter
or clamp short against a not-yet-updated adjustment.
core::config: a cross-platform per-user config (Windows %APPDATA%, macOS
Application Support, else XDG) holding the study mode + body size, read
and written through one code path (atomic write via core::store). Loads
default-as-first-run when absent; a damaged file loads default without
re-prompting.

GTK: first launch shows a guided chooser — Simple reader vs Full study.
Simple hides the study/authoring surface (Threads/Tags/Suggested/+link
buttons, the verse's tag+author actions, weave-note editing), leaving a
clean reader + search + Strong's; Full unlocks it. A toolbar toggle flips
modes; the choice and the live zoom size persist across launches.

65 tests green; Windows .dll still cross-builds.
core::home resolves the data directory in order: $PURE_STUDY_HOME /
$OVERLAY_HOME → the CWD if it's a working tree (has data/kjv.jsonl) →
next to the executable → the per-user data dir (XDG / %APPDATA% / macOS
Application Support). An explicit env override is honored verbatim so a
precise "hydrate here" error can surface; otherwise only a directory that
really looks like a home is used.

The desktop app uses it (no more hard OVERLAY_HOME requirement — verified
launching from a checkout with the env unset), logs the resolved home +
kind at startup, and its data-missing screen now lists every location
searched. Paths join cross-platform throughout.
A GitHub Actions workflow with three jobs:
- test: cargo test the portable crates (core/layout/rnd/ffi; the GTK
  shell needs system libs and is excluded).
- bindings: regenerate the C header + C# P/Invoke shim and fail on any
  diff — the doc-vs-wire drift class the ABI review flagged.
- windows-dll: cross-build the C ABI for x86_64-pc-windows-gnu (mingw),
  matching the local cross-build.

Verified the test and binding-drift steps pass locally (bindings in sync).
Two R&D capabilities that need no ML packs — both derived from data
already loaded — land behind the Full-study gate:

- core::crossref: parse the hydrated TSK topical cross-reference tier
  (data/cross-references.tsv, ~344k vote-ranked refs, ranges supported;
  missing file → empty, the reader runs fine). Shown labelled "study
  cross-references (TSK)" in the word study.
- rnd::bridge (feature `bridge`): the OT↔NT etymology bridge — Strong's
  own "of Hebrew origin (Hxxxx)" derivations linking Greek↔Hebrew codes.
  Surfaced as "↔ cross-testament" partners (concordance links) per word.

Wired into the desktop (Full study only) and verified against the real
corpus: Matthew 1:2 "Abraham" shows G11 ↔ H85 and 23 TSK cross-references
with verse ranges. CI now also runs the bridge-feature tests. Docs +
module map updated.

The heavier R&D (concept engine, embeddings, morphology, keyness, trust,
quotation detection) genuinely depends on the ML data-pack pipeline and
stays deferred. 72 tests green (70 default + 2 bridge).
rnd::embed (feature `embeddings`) loads the offline-trained
concept-vectors.vec (word2vec text format) with its .meta (tokenization
gate + aligned flag + alias map) and .freq sidecars — no training, pure
load. Rows are unit-normalised so cosine is a dot product; alias keys
resolve to their root's row (the split Strong's numbers the KJV tags).

Queries: nearest_concepts (same-language distributional near-synonyms)
and cross_concepts (the cross-testament semantic bridge, live only when
the space is Procrustes-aligned). parse_embedding is split out for
file-free unit tests; verified against the real 7426-vector artifact.

Surfaced in the GTK word study (Full study only): "≈ concepts near" and
"≈ across the testaments", each a concordance link with its lemma — e.g.
G26 ἀγάπη → διακονία/ὑπομονή/γνῶσις and Hebrew neighbours. Absent
artifact → the section simply doesn't render.

Tests: 6 with --features "bridge embeddings"; no warnings.
rnd::morph (feature `morphology`) ports the consuming side of overlay's
Morph.hs: the OSHM (Hebrew/Aramaic) and Robinson (Greek) parsing-code
parsers, the study-panel renderer, and the sidecar loader over
morphology.jsonl. The offline projection that builds the sidecar stays
in Python; this only reads it. Codes parse once at load; a stale
tokenization stamp is refused; a missing file → None.

Surfaced in the GTK word study (Full study): the token's original-language
parse under the English word — e.g. Genesis 1:1 "created" → "Qal perfect,
3rd masculine singular", alongside its concept neighbours and the
cross-testament partner G2936 κτίζω.

Tests: 11 with --features "bridge embeddings morphology" (5 new: Hebrew/
Aramaic/Greek render, error-not-panic, sidecar gloss). CI runs all three.
VerseSim ports the Arora-Liang-Ma SIF recipe over the concept embedding:
weight each concept by a/(a+p(concept)) with the trainer's own frequency
table, average per verse, subtract the per-testament mean, then remove the
projection onto that testament's top principal component (power iteration,
no linalg dependency; skipped below 50 verses). similar_verses_in ranks
the same testament by cosine; similar_verses_cross the other (aligned only).

Built once at startup from the embedding + corpus, surfaced in the GTK word
study (Full study) as "verses like this" — e.g. John 3:16 → John 6:27,
3:17, 3:15, 12:25. Unit test covers the power-iteration PCA.

12 tests with the R&D features on.
data-prep/README.md records exactly which artifacts the R&D tier consumes
(concept-vectors.vec/.meta/.freq, morphology.jsonl, cross-references.tsv),
how each is produced by the existing offline Python (overlay ml/ +
pipelines/), and the key fact that it is build-once (no GPU, no foundation
model, one lightweight CPU skip-gram) → ship-the-files. Notes licensing
(concept vectors wholly owned; TSK CC-Attribution; OSHB CC-BY-4.0; domains
excluded for copyleft) and that hosting the pack is just placing the files
under <home>/data/, which core::home already resolves.

PLAN/PROGRESS module map + status updated for rnd::embed, rnd::morph,
core::crossref, and the documented pack.
New crates/hydrate CLI. `copy --from <src> --to <home>` places the pack
(core kjv/strongs/notes + R&D cross-references/concept-vectors[.meta/.freq]/
morphology) into <home>/data; `check [--home]` verifies each artifact by
loading it through the real code paths and reports what will light up
(verse/entry counts, TSK coverage, embedding dim/alignment/freq, morphology
coverage, etymology-bridge code count), exiting non-zero only when a
required core file is missing.

It places + validates, it does not train/generate (that's the offline
pipeline; see data-prep/README.md). Verified: copy from the overlay
checkout hydrates a fresh home to 31102 verses, 343556 TSK refs, 7426
aligned vectors, 31091 morph verses. Added to the workspace + CI test set.
… pack

rnd::bridge gains the fused layer over the etymology base: load_sources
reads the committed bridge/*.json witnesses (LXX / Abbott-Smith / TIPNR)
plus optional hydrated data/bridge-sources.json + quotation-pairs.json;
Priors loads source-priors.json. FusedBridge::build merges etymology +
external partners per lemma, each tagged with the witnesses that assert it
and ranked by best trust prior (etymology treated as authoritative).

pure-hydrate now copies the bridge sources + priors and reports the fused
link count. The desktop uses FusedBridge and shows cross-testament partners
with provenance — e.g. H4899 מָשִׁיחַ → G5547 (abbott-smith+lxx) = Christ,
G3323 (etymology). Verified against the real pack (5922 external links).

13 rnd tests with all features (3 bridge, incl. the fusion merge/ranking).
The engine loads the R&D artifacts at open (fused bridge from strongs +
home witnesses; concept embedding + morphology sidecars when a home is
present) and gains four read endpoints:
- pure_engine_concept_neighbours_json(code,k) — near + cross-testament
- pure_engine_bridge_partners_json(code) — fused partners w/ sources+prior
- pure_engine_morph_json(ref,tok) — parse code + rendered gloss
- pure_engine_similar_verses_json(ref,k) — SIF, model built lazily + cached

Each returns null when its artifact is absent (bytes-opened engines get
etymology-only bridge, no embedding/morph). New wire DTOs; regenerated the
C header + C# shim. pure-rnd is pure Rust so the cdylib still cross-builds
for Windows (verified). End-to-end ABI test with tiny artifacts covers all
four + the null paths. 13 FFI tests.

Now the Windows/Android shells reach the full study + R&D surface over the
one ABI, matching decision #1.
Two reader chrome bugs:
- The Paned divider was a fixed absolute 700px from the left, so on a wide
  window the study panel (end child) ballooned to fill the rest. Now the
  panel opens as a stable ~380px sidebar: on the hidden→visible transition
  show_study sets the divider to width − PANEL_WIDTH.
- The chrome (header nav, dropdowns, study panel, canon strip) followed the
  dark system theme, leaving light text on the light nav strip (illegible).
  The reader is a warm-paper light design, so force the light color scheme
  (adw StyleManager ForceLight) to match the cream scripture + gold accents.

Verified: panel opens as a sidebar (not massive) and the nav is legible
dark-on-cream.
Ports the reader-facing core of overlay's Concept.hs (feature `concept`,
pure corpus folds, no ML data): per-concept occurrence stats + book
distribution (top_books / testament_split), and the collocation graph —
co-occurrence → PPMI → mutual-kNN → label-propagation communities. Memory
is bounded by keeping only the mutual-kNN edges (the dense PPMI matrix is
dropped after filtering). The Concept engine exposes stat / top_books /
testament_split / collocates / community, which back the concept
neighbourhood diagram and the dispersion strip (viz next).

Also documents the config-window Hyprland rule work in this session:
pure-study now opens on the little Samsung (workspace 1 → HDMI-A-2).

17 rnd tests with all features (4 new: distribution, ppmi, mutual-kNN,
communities). CI feature set updated.
…ion)

The desktop builds rnd::concept at startup (feature `concept`) and, in
Full study, the word study now shows two more sections per Strong's code:
- ◦ collocation field: the code's co-occurrence community (what shares its
  verses), distinct from the distributional embedding neighbours.
- ◦ distribution: the books it concentrates in (top 5) + the OT/NT split.

Verified against the real corpus: H430 (Elohim) → Deuteronomy/Psalms/
Genesis with its Hebrew collocation field. (The radial graph + cairo
dispersion-strip visualizations remain as polish; the data is surfaced.)
rnd::burst ports Burst.hs: a Poisson scan statistic over each concept's
occurrence positions (regularized incomplete gamma / Lanczos gammaln,
Numerical Recipes §6), Bonferroni-corrected within a concept and
Benjamini–Hochberg–gated across concepts, to surface deliberately-packed
theme-words. Pure corpus statistics. The word study now shows a "leitwort"
line (span + tightness) when the clicked concept bursts.

To keep launch instant, the heavy analytics — SIF verse-sim, the concept
graph, and the leitwort sweep — are no longer built eagerly at startup;
ensure_analytics builds them once on the first Full-study word lookup and
caches them (a no-op in Simple mode). Time-to-window dropped 10.6s → 3.3s
(debug); the first deep lookup pays the one-time sweep.

10 rnd tests with the concept feature (3 new: gamma/Poisson, scan window,
Benjamini–Hochberg).
core::config gains the reading session — the open panes (book, chapter)
and the active index — folded into the same cross-platform config file
(additive fields, older configs still load). The desktop restores those
panes at launch (falling back to John 3 on a fresh install, active index
clamped into range) and saves them on window close-request via
persist_config (which now snapshots panes + mode + body size).

Verified: a config naming Romans 8 + Psalms 23 (active 1) reopens both
panes with Psalms 23 active.
A "Map" study-tool (Full mode) opens a popup arc diagram over the canon-
ordered axis: each woven book pair is a ribbon whose thickness is the link
count and colour marks OT-internal (gold), NT-internal (blue), or cross-
testament (purple). chord_arcs aggregates State.links by book-order pair;
draw_chord_map paints section bands + the OT/NT seam + heaviest-first
ribbons; click a book to jump the active pane, Esc closes. Verified against
the real weave library (cross-testament arcs dominate).
…xCache.hs)

Two startup wins:
- core::corpus caches the parsed corpus beside the source as a gzipped
  bincode snapshot (kjv.jsonl.idxcache), keyed by the source's length +
  mtime + tokenization; any mismatch re-parses. Skips the ~19 MB JSONL
  parse on unchanged data. store gains write_atomic_bytes for it.
- The desktop no longer parses the multi-MB embedding + morphology at
  launch — they load lazily in ensure_analytics with the other Full-study
  analytics, so a Simple reader never pays for them.

Time-to-window (debug) 3.3s → 2.7s warm; the cache is 6 MB gzipped (was
37 MB raw). Corpus cache round-trip/invalidation covered by a test.
rnd::witness (feature `bridge`) loads data/text-witness.json — a
lexicon-free H↔G alignment that can disbelieve bridge links — and enforces
the gate: disbelief() returns a percentile ONLY when the witness has passed
its held-out grading (witnessQualified && testimonyActionable), so an
ungraded witness structurally cannot accuse. Missing/corrupt file → silent.
The desktop loads it and marks a disbelieved cross-testament partner with a
⚠ (heb-first keying). The shipped witness is not yet qualified, so nothing
surfaces today — the path is complete for when a graded one ships.

23 rnd tests with all features (3 new witness: silent-when-unqualified,
strongest-percentile-when-qualified, missing-file).
A "▸ concept map" link in the Full-study word study opens a popup for the
clicked code (ConceptGraph.hs + ConceptMap.hs): a radial neighbourhood with
the concept at centre and labelled spokes to its distributional embedding
neighbours (gold) and its collocation community (green), over a dispersion
strip shading the 66 books by density. Esc closes. Verified with G26 ἀγάπη.
Word study double-click surfaced R&D concept lists by bare Strong's
code + original-language lemma only — illegible to an English reader,
and the six analytic tiers ran together as one undifferentiated block.

- english_gloss(): learn the recognisable English word from how the KJV
  actually renders a code (mode over sampled occurrences, translator-
  supplied words skipped), not Strong's etymological headword. Falls
  back to distilling the definition. Deterministic across panel + map.
- concept_links(): render English-first ('love ἀγάπη'), code as the link.
- Sectioned analytics: SAME ROOT ACROSS TESTAMENTS / SIMILAR CONCEPTS /
  APPEARS ALONGSIDE / WHERE IT CONCENTRATES / LEITWORT, each a spaced
  header with blank-line separation; near + cross concepts merged.
- Distribution shows counts ('Genesis ×12'), not chapter-like refs.
- Leitwort reworded ('42 of its 55 uses cluster in …', p ≈ 10⁻ⁿ) instead
  of a bare 'strength' number; witness flag worded 'disputed by usage'.
- Bridge sources humanised (lxx → Septuagint).
- Radial concept-map node labels English-first to match.
- Test: panel markup shapes validated through Pango's parser; distil_gloss.
The C ABI now cross-builds for ARM64 Windows in CI, not just x86_64 — the
target a Snapdragon/Surface Windows box uses natively. README documents the
portable-vs-GTK split and the exact pull-and-build steps on ARM Windows.
@glendonjklassen
glendonjklassen merged commit d3b8336 into main Jul 10, 2026
0 of 8 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant