Skip to content

Commit d367f2c

Browse files
authored
Merge pull request #195 from AdaWorldAPI/claude/ogar-doc-ir-spider-convergence
docs: doc-layer amendment (A1-A5) + doc-IR × spider-rs convergence plan
2 parents 172d0cd + 003bc6c commit d367f2c

3 files changed

Lines changed: 295 additions & 0 deletions

File tree

docs/DISCOVERY-MAP.md

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1298,3 +1298,25 @@ isolation. The map's job is to keep them visible.
12981298
Charter: `docs/OGAR-DOC-LAYER-PROPOSAL.md` (merged #191). Grade [S] until the
12991299
5+3 council + a probe promote it; the canon mints (0x080A/0x080B) land WITH
13001300
the council-verified build, never ahead of it.
1301+
1302+
- **D-DOC-IR-SECOND-RETINA** (2026-07-13; [S] — plan, council gates W1+):
1303+
`doc.v1` is promoted from OCR output format to the substrate's **perceptual
1304+
IR** (`ogar-doc-ir`, serde-only neutral tissue), with TWO sanctioned
1305+
producers: tesseract-rs (pixels) and spider-rs (`AdaWorldAPI/spider` fork,
1306+
DOM — HTML5 `<header>/<main>/<footer>/<table>` self-labels the regions OCR
1307+
infers). The code-side pattern replayed on perception: N retinas → one
1308+
closed doc IR → one awareness subtree, with `ruff_spo_triplet` discipline
1309+
verbatim (closed region-kind vocab, hard-fail load gate, version marker).
1310+
Spatial address = u8×u8 unit-square rail (the `X:Y` facet rail; a page IS a
1311+
256×256 tile — the "2D spatial focus of attention", zero-value-decode
1312+
region attention). Provenance lane keeps OCR confidence and crawl trust as
1313+
separate quantities; subtree identity = content sha256 (scan and HTML of
1314+
the same document converge on ONE `0x080B` subtree). Operator rulings
1315+
A1–A5 amend the doc-layer charter (one `ogar-doc` crate — split axis is
1316+
STATE not direction; `DocRenderer` trait with runtime-bound tesseract /
1317+
Spire.Doc / askama adapters — the one-leg rule; document template =
1318+
ClassView × WideFieldMask, same brick as Klickwege — no new DSL). Killer
1319+
falsifier P-XRETINA: same invoice via both retinas ⇒ same typed-field
1320+
facts + same subtree identity, run BEFORE anything persists. Plan:
1321+
`docs/DOC-IR-SPIDER-CONVERGENCE-PLAN.md`; amendment:
1322+
`docs/OGAR-DOC-LAYER-PROPOSAL.md` §AMENDMENT. Depends: D-OGAR-DOC-LAYER.
Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
1+
# DOC-IR × spider-rs Convergence — Integration Plan v1 (2026-07-13)
2+
3+
> **Status:** PLAN — companion to `OGAR-DOC-LAYER-PROPOSAL.md` (see its
4+
> 2026-07-13 AMENDMENT A1–A5, which this plan sequences). The doc-layer
5+
> 5+3 council gates W1+; W0 is verification-only and runs now.
6+
>
7+
> **Ask (operator, 2026-07-13):** combine recognition and
8+
> processing/representation of knowledge **whether it comes from
9+
> tesseract-rs or spider-rs** (`AdaWorldAPI/spider`, fork of
10+
> `spider-rs/spider`) — "using the JSON-like structuring as a reusable
11+
> input awareness (2D-'spatial' focus of attention)."
12+
>
13+
> **One sentence:** the `doc.v1` structure is promoted from "OCR output"
14+
> to the substrate's **perceptual IR** (`ogar-doc-ir`), with tesseract-rs
15+
> (pixels) and spider-rs (DOM) as its two sanctioned producers — the
16+
> code-side pattern (N language frontends → one closed ndjson → one
17+
> ModelGraph) replayed on perception, so everything upstream (ogar-doc
18+
> persistence, DeepNSM, lance-graph discovery, MedCare-rs as abstract
19+
> document store) consumes ONE shape regardless of retina.
20+
21+
## P0. The convergence thesis (why one IR, stated once)
22+
23+
| code side (shipped) | perception side (this plan) |
24+
|---|---|
25+
| Roslyn / ruff_python / ruff_ruby frontends | tesseract-rs (scan) / spider-rs (web) retinas |
26+
| closed 62-predicate ndjson, `from_ndjson` hard-fail gate | closed region-kind doc IR, `from_json` hard-fail gate |
27+
| `ruff_spo_triplet::ModelGraph` | `ogar-doc-ir` region tree |
28+
| `CompiledClass` in the graph | `document 0x080B` awareness subtree |
29+
30+
spider-rs is an unusually good second retina because **HTML5 already
31+
declares its regions**: `<header>/<main>/<footer>/<table>` are the literal
32+
Kopfzeile/Fußzeile/main positions the amendment's A3 template projects —
33+
the web *self-labels* what OCR must *infer*. Same regions, two
34+
acquisition modes, one IR.
35+
36+
## P1. Access preflight (blocking facts to verify, first spider-enabled session)
37+
38+
`AdaWorldAPI/spider` was NOT readable from this session (repo-access gate).
39+
Before W3 is scoped in detail, a session with spider access verifies:
40+
41+
- **PF-1** fork exists, default branch, divergence from upstream
42+
`spider-rs/spider`.
43+
- **PF-2** page output surface (assumed from upstream: `Website` crawl →
44+
per-page HTML string + URL + headers; a headless-chrome feature exists
45+
for rendered layout). Verify names/features before writing the seam.
46+
- **PF-3** whether rendered layout coordinates are obtainable (headless
47+
feature) or whether W3 ships DOM-order pseudo-geometry first (see W3
48+
fallback — the plan works either way).
49+
- **PF-4** workspace layout: where a harvest crate lands in the fork
50+
(sibling crate, mirroring how `ruff_*_spo` crates live in the ruff fork).
51+
52+
## P2. Wave plan
53+
54+
### W0 — council gate (no code)
55+
56+
The doc-layer 5+3 council verifies the AMENDED proposal: mints
57+
`typed_field 0x080A` + `document 0x080B`; one-crate `ogar-doc`;
58+
`ogar-doc-ir` as neutral tissue; the A2 one-leg runtime-binding rule; the
59+
A3 ClassView × WideFieldMask template. **The council verifies the
60+
source-agnostic boundary — a spec that only a tesseract producer could
61+
satisfy is a numbered factual error.**
62+
63+
### W1 — `ogar-doc-ir` (the IR crate; gates everything downstream)
64+
65+
- Types: region tree (page / region / table+cells / figure / header /
66+
footer), typed fields, quality.
67+
- **Closed region-kind vocabulary**; `from_json` HARD-FAILS on unknown
68+
kinds; explicit `doc.v1` version marker (v2 = a new marker, never a
69+
silent reshape).
70+
- **Spatial rails:** every bbox quantized to u8 × u8 unit square (the
71+
`X:Y` rail; the page IS a 256×256 tile on the existing centroid/Morton
72+
machinery). Raw coordinates = optional provenance, never the address.
73+
- **Provenance lane:** source enum (`ocr` / `dom`) + per-source confidence
74+
semantics (recognition confidence ≠ crawl trust; no shared float).
75+
- **Identity:** content sha256 as the subtree dedup key.
76+
- Deps: serde only. Tests: vocab closure, gate hard-fail on unknown kind,
77+
rail quantization round-trip, version-marker refusal.
78+
79+
### W2 — tesseract-rs producer migration (byte-parity gated)
80+
81+
`structured::{DocPage, render_json_with_regions, …}` emits `ogar-doc-ir`
82+
types; the **existing doc.v1 JSON output is the committed golden** and the
83+
migration must reproduce it byte-for-byte (same discipline as the sono
84+
parity witness: the shipped artifact gates its own refactor). tesseract-rs
85+
gains a dep on `ogar-doc-ir`; `ogar-doc-ir` never depends back.
86+
87+
### W3 — spider-fork producer (`spider_doc_ir` harvest crate, in the fork)
88+
89+
DOM → doc IR: HTML5 landmarks → region kinds; DOM order → reading order;
90+
`<table>` → cell grids; microdata/schema.org → typed fields; rendered
91+
layout coords → rails when PF-3 confirms the headless path, else
92+
**DOM-order pseudo-geometry** (top-to-bottom rail assignment) as the
93+
honest v1 — provenance lane marks which geometry mode produced the rails.
94+
Fixture-driven tests on committed HTML files; no live crawling in CI.
95+
Lives in the spider fork (PF-4), mirroring `ruff_*_spo`-in-ruff; depends
96+
on `ogar-doc-ir` via git dep floating on main (D-NEVER-PIN-BUMP).
97+
98+
### W4 — `ogar-doc` (persistence + template + renderer trait)
99+
100+
Per the amended proposal: `persist_document` / `read_document` /
101+
`reconstruct_document` facts; `DocTemplate` = ClassView × WideFieldMask
102+
(A3); `trait DocRenderer` with tesseract / Spire.Doc / askama adapters
103+
bound at runtime (A2). First consumer: MedCare-rs `routes/dms.rs` upload
104+
`recognize_document``persist_document` (raw-ref = encrypted
105+
`file_filelist` key) — sonography, histology, invoices as the abstract
106+
document store.
107+
108+
### W5 — upstream foresight seams (small, deliberate, no redesign)
109+
110+
- **DeepNSM** (stays 0-dep): entry point accepts
111+
`(text_span, region_kind, spatial_rail)` tuples in reading order — the
112+
tuple IS the contract; no doc-schema dep enters the crate. Gives the
113+
FSM region priors (a table cell is not a sentence), the temporal stream
114+
its reading order (per the temporal-stream ruling), and spatial
115+
adjacency (caption-near-figure).
116+
- **lance-graph discovery arm:** `document 0x080B` registered as a
117+
discoverable concept; sha256 as the convergence key. Typed fields are
118+
already SPO facts + rails — "all invoices from X with IBAN Y" is a
119+
graph query + rail scan, no new machinery.
120+
121+
## P3. Probes (falsifiable; graded [H] until run)
122+
123+
- **P-XRETINA (the killer witness):** the same invoice through both
124+
retinas (scan → tesseract; HTML → spider) must converge to the same
125+
typed-field facts and the same sha-keyed subtree identity. Diverse
126+
redundancy applied to perception — the MySQL-oracle pattern. GREEN
127+
promotes the whole IR from [S] to [G]; RED means the IR is
128+
tesseract-shaped-with-a-second-door and W1 gets corrected before more
129+
producers land.
130+
- **P-DOM-GROUNDTRUTH:** spider + headless render yields (pixels,
131+
DOM-labeled regions) pairs at zero annotation cost — a calibration
132+
corpus for tesseract's region classifier. The web trains the eye that
133+
reads paper.
134+
- **P-2D-MARKOV:** does spatial-neighborhood attention (Morton rail
135+
adjacency) beat pure reading-order for field harvest? Slots into the
136+
existing temporal-stream probe queue; not a W-gate.
137+
138+
## P4. Non-goals (v1 of this plan)
139+
140+
- No live crawling in any CI path (fixtures only).
141+
- No spider-side scheduling/politeness/auth policy — the fork's own
142+
concern; this plan touches only the page → doc-IR seam.
143+
- No multi-language OCR slot, no streaming payloads, no storage-backend
144+
choice (all inherited deferrals from the doc-layer proposal).
145+
- No DeepNSM redesign — W5's tuple signature is the entire ask.
146+
147+
## P5. Sequencing + gates
148+
149+
`W0 (council) → W1 (IR) → {W2, W3} in parallel → P-XRETINA → W4 → W5`.
150+
W2/W3 are independent once W1 lands; **P-XRETINA runs the moment both
151+
producers exist and BEFORE W4 persists anything** — persisting a
152+
tesseract-shaped subtree and discovering the divergence later would bake
153+
the bias into stored data. Merge-order discipline per house rule:
154+
OGAR-side crates first, fork-side producers second, in lockstep.

docs/OGAR-DOC-LAYER-PROPOSAL.md

Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,3 +145,122 @@ Append `D-OGAR-DOC-LAYER` to `docs/DISCOVERY-MAP.md`: `ogar-doc` persists `doc.v
145145
as a raw-ref (KV) + an awareness subtree (SoA graph), reconstructs it via a
146146
`reconstruct_document` ActionDef; triggers the v2-deferred `typed_field` mint +
147147
a `document` mint. Grade `[S]` (spec) until the council + a probe promote it.
148+
149+
---
150+
151+
# AMENDMENT — operator rulings, 2026-07-13 (pre-council; the council verifies THIS boundary)
152+
153+
> Supersedes the body above where they conflict. Four rulings from the
154+
> 2026-07-13 session, each recorded with its reasoning so the 5+3 council
155+
> verifies rather than re-litigates. Companion integration plan (the
156+
> spider-rs convergence + wave sequencing): `docs/DOC-IR-SPIDER-CONVERGENCE-PLAN.md`.
157+
158+
## A1. ONE `ogar-doc` crate; the split axis is STATE, not data direction
159+
160+
The considered-and-rejected topology was `ogar-ocr (inbound)` /
161+
`ogar-doc (outbound)`. Rejected because "render" names two different things:
162+
163+
- `render_searchable_pdf` / `render_text` / `render_tsv` / `render_hocr`
164+
(ocr_actions rows 5–8) are the **OCR round-trip** — serialize *this scan's*
165+
recognition back onto the pixels it came from. Stateless tesseract-rs
166+
compute; they STAY in the OCR surface (already shipped, unchanged).
167+
- `reconstruct_document` never sees pixels — it walks **stored graph
168+
knowledge** and lays it out. Stateful; it belongs to `ogar-doc` *because it
169+
reads the graph*, not because it is "outbound."
170+
171+
So: `ogar-ocr` (the existing ocr_actions surface) = **perception**, stateless,
172+
pixels ↔ structure ↔ bytes. `ogar-doc` = **memory + lifecycle**
173+
(`persist_document` / `read_document` / `reconstruct_document` + the template),
174+
one crate, in and out. Creating Word/PDF documents from graph knowledge is NOT
175+
a tesseract-rs concern, even though tesseract-rs serves delicate PDF features
176+
`ogar-doc` composes.
177+
178+
## A2. `DocRenderer` is a TRAIT; tesseract-rs is one adapter (the one-leg rule)
179+
180+
tesseract-rs rendering capabilities become **explicitly reusable** behind a
181+
renderer trait owned by `ogar-doc`:
182+
183+
```text
184+
ogar-doc: DocTemplate (ClassView × WideFieldMask) ──▶ trait DocRenderer
185+
├─ tesseract adapter (raster + text-layer PDF)
186+
├─ Spire.Doc adapter (Word, C#-side)
187+
└─ askama adapter (data-only PDF/HTML)
188+
```
189+
190+
**The one boundary the council must hold:** the tesseract adapter binds at
191+
RUNTIME (ActionInvocation / hot-plug, same fuse pattern as `tesseract-ogar`),
192+
never as a compile-time `use` — otherwise `ogar-doc` drags the tesseract
193+
render brick into its compile graph and quietly recreates the second leg the
194+
topology avoids. One tesseract-rs leg total, at the executor layer, serving
195+
both recognition and rendering.
196+
197+
## A3. The document template IS ClassView × WideFieldMask (no new DSL)
198+
199+
A document layout — Kopfzeile / main / Fußzeile — is not a new template
200+
vocabulary. It is the SAME machinery as the Klickwege structure surface:
201+
202+
- **ClassView** projects the document class's ordered region set (header
203+
positions, body/table, footer positions) exactly as it projects a class's
204+
field set — and §D2 already has the ClassView projecting the 4+12 facet
205+
register on the *inbound* side.
206+
- **WideFieldMask** gates which regions are present in this instance —
207+
the same `from_universe_present` brick that gates screens in the
208+
Klickwege menu-quad.
209+
- Header/footer/main are **positions in the ordered set**, structurally
210+
identical to screen-surface regions.
211+
212+
Consequence: ClassView projects `doc.v1 → facets` going in and
213+
`facets → laid-out document` going out; WideFieldMask gates presence both
214+
ways; navigation surfaces and documents render through ONE mechanism. This
215+
SHARPENS D8's "reuse ogar-render-askama" — the template contract is
216+
ClassView × WideFieldMask; askama is merely one `DocRenderer` adapter's
217+
serialization. Spire.Doc reuses the same positional projection for Word.
218+
219+
## A4. `ogar-doc-ir` — the doc IR is SOURCE-AGNOSTIC neutral tissue (the second-retina rule)
220+
221+
The `doc.v1` structure is not an OCR output format — it is the **perceptual
222+
IR**, and it is about to gain a second producer: **spider-rs**
223+
(`AdaWorldAPI/spider` fork) harvesting web pages, where HTML5 sectioning
224+
(`<header>/<main>/<footer>/<table>`) *self-labels* the same regions OCR must
225+
infer. This is the code-side pattern replayed on perception: N language
226+
frontends → one closed ndjson → one ModelGraph becomes N perception
227+
frontends (retinas) → one closed doc IR → one awareness subtree.
228+
229+
Therefore the IR types move OUT of tesseract-rs ownership into a new
230+
**`ogar-doc-ir`** crate (near-zero-dep: serde only), with the
231+
`ruff_spo_triplet` discipline applied verbatim:
232+
233+
1. **Closed region-kind vocabulary** + a `from_json` load gate that
234+
HARD-FAILS on unknown kinds; explicit version marker (`doc.v1``doc.v2`).
235+
2. **Canonical spatial address = u8-quantized unit square per axis** — the
236+
bbox IS the `X:Y` rail of the 4+12 facet; the page/viewport becomes a
237+
256×256 tile on the existing centroid/Morton machinery. Raw pixel/viewport
238+
coordinates are optional provenance, never the address. This is the
239+
"2D spatial focus of attention": a consumer attends to regions across
240+
documents from keys alone, zero value decode.
241+
3. **Provenance lane**: source enum (`ocr` / `dom` / …) with PER-SOURCE
242+
confidence semantics — OCR recognition confidence and crawl/boilerplate
243+
trust are different quantities and must never alias in one float
244+
(I-LEGACY-API-FEATURE-GATED applied prospectively).
245+
4. **Subtree identity = content sha256** — the same document arriving as
246+
scan and as HTML converges on ONE `document 0x080B` subtree. This is the
247+
dedup pin arm-discovery needs.
248+
249+
Producers (tesseract-rs's `structured::render_json*` arm; the spider fork's
250+
future harvest crate) depend on `ogar-doc-ir` — never the reverse, and never
251+
on each other. The existing tesseract doc.v1 JSON becomes the byte-parity
252+
golden for the migration (no silent reshape).
253+
254+
## A5. Net crate topology (what the council ratifies)
255+
256+
| crate | owns | deps |
257+
|---|---|---|
258+
| `ogar-doc-ir` | doc IR types, closed vocab, load gate, rails, provenance, sha256 identity | serde only |
259+
| `ogar-doc` | `persist` / `read` / `reconstruct` ActionDefs' vocab side + `DocTemplate` (ClassView × WideFieldMask) + `trait DocRenderer` | ogar-vocab, ogar-doc-ir |
260+
| ocr surface (existing) | rows 1–14 incl. render primitives | unchanged |
261+
| producers | tesseract-rs `structured` arm; spider-fork harvest crate | → ogar-doc-ir |
262+
| renderer adapters | tesseract PDF / Spire.Doc / askama | runtime-bound (A2) |
263+
264+
Mints unchanged from D3 (`typed_field 0x080A`, `document 0x080B`); the three
265+
ActionDefs unchanged from D4. D8's "no template DSL" is KEPT and sharpened
266+
(A3); D8's "no storage backend chosen" is KEPT.

0 commit comments

Comments
 (0)