Skip to content

Commit 8954e53

Browse files
AdaWorldAPIclaude
andauthored
Knowledge: layout-bridge assessment, OGAR Machine plan, hydrate dependency note (#6)
* Core vertical slice: docs/abi.md contract, native/lgj-abi, Java facade Ships the fully verified core of the Panama x ndarray::simd x Valhalla vertical slice (Phases A-E of the mission plan): - docs/abi.md: the normative Rust<->Java ABI contract, written before either side was implemented so both could be checked against one frozen doc instead of each other. - Five new ndarray::simd primitives (eq_u32_to_mask, gt_i32_to_mask, mask_and/mask_or(_assign), masked_sum_i32), added under ndarray's own W1a consumer contract. - native/lgj-abi: the Rust ABI crate. Generation-checked handle registry, generic SoA fixture, bulk kernels routed exclusively through ndarray::simd, 14-symbol extern "C" surface. 72/72 tests green, clippy/fmt clean, and the registry's core safety check was disable-verified (short-circuited, confirmed exactly the two guarding tests go red, restored). - java/: the Panama membrane (internal/ffm, never exposed publicly) and the public semantic facade (NativePattern/View/Predicate/ Pattern/Mask). 132/132 checks green across 8 suites, including a reflection-enforced ApiSurfaceTest that mechanically proves zero FFM types ever reach a public signature, and a LazinessTest that empirically proves the thesis: building a chain costs zero crossings, evaluating it costs exactly one, independent of row count up to 1,000,000. - .claude/: a 6-agent ensemble, 6 knowledge docs, and a full board (LATEST_STATE/STATUS_BOARD/AGENT_LOG/EPIPHANIES/TECH_DEBT/ISSUES/ PR_ARC_INVENTORY/INTEGRATION_PLANS/CODEX_REVIEW_CHECKLIST), all scoped to this repo's actual seams. A mechanical audit (D-LGJ-AUDIT) found and fixed the one real rule violation before this commit: kernels.rs::simd_popcount was calling the internal ndarray::hpc::bitwise path instead of the sanctioned ndarray::simd re-export. Deliberately NOT included: the Valhalla lab (valhalla-lab/) and the Vector API benchmark harness (bench/) — still in flight, tracked as open STATUS_BOARD.md rows, to land in a follow-up PR once reviewed with the same rigor as this slice. Generated by [Claude Code](https://claude.ai/code) * Valhalla lab: three-truths method, causal isolation, 3 real reproducers Completes D-LGJ-F. One experiment source (src/shared/), compiled twice against real JDKs -- stable JDK 26 GA (record) and the official JEP 401 early-access binary (value record) -- via a self-verifying run.sh that mechanically diffs the two Vocab.java files modulo the 'value' keyword before trusting the A/B is honest. Experiments: IdentityExperiment (semantic truth -- is identity actually unobservable), FootprintExperiment (real per-object/array/field bytes via allocation-delta + JOL where available), FfmAddressingExperiment (is the wrapper free where it touches native memory), ThesisExperiment (the mandatory headline: 65,536 rows as one native lane vs hydrated Java objects, on both platforms). Causal isolation via three additional run.sh passes: escape analysis off, and UseArrayFlattening/UseFieldFlattening toggled independently -- isolates which flag actually drives the measured difference rather than inferring it. Three real Valhalla limitations reproduced and filed under reproducers/, none of which changed the production API: - R1: @NullRestricted field on an identity class is a VerifyError (javac's fault -- no source form expresses the required strict-field init order relative to super()) - R2: array flattening has a hard 8-byte payload cliff, confirmed via -XX:+PrintFlatArrayLayout. LaneId/Ordinal/MaskId (<=8B) flatten; RowRange/Row (16B) do not. This turns "Valhalla helps descriptors, not entities" from a hand-wave into a measured VM cutoff -- and RowRange landing on the wrong side is flagged as the one place the expectation was too optimistic. - R3: the densest null-restricted array form is jdk.internal-only and generics erase flattening entirely; Foo! null-restricted type syntax confirmed not to parse, matching the earlier archaeology finding. One real defect found and fixed before landing: IdentityExperiment and the stable Platform called Class::isValue() directly on four vocabulary types with a comment incorrectly claiming it was "final API on JDK 26" -- it does not exist there at all, confirmed by a real javac failure. Fixed by routing every query through Platform.isValueClass(Class<?>), answered honestly per platform. Generated by [Claude Code](https://claude.ai/code) * Vector API bench: real JMH, cross-checked; the crossing does not always win Completes D-LGJ-G, the mission's mandated "where does execution belong" comparison -- measured, not assumed to favor the Rust crossing. Real JMH 1.37 (fork+warmup+compiler-blackholes confirmed in the log, not a hand-rolled loop -- that lives in valhalla-lab and is labelled as such there). Four components, cost kept strictly separate per the mission brief: A_DowncallOverhead (bare crossing, no work), B_SegmentAccess (raw native-memory read throughput), C_ExecutionBoundary (native fused plan vs Java Vector API vs Java scalar, swept 64 to 4,194,304 rows), E_FusionAndPlanning (fused vs unfused vs the scalar reference kernel vs plan-construction-only, swept 1-8 predicates). 50/50 rows, 0 failures. Data.crossCheck() runs in @setup and throws if the three kernels disagree on count or sum, so a faster-but-wrong Vector kernel could not have won the comparison undetected. The headline complicates the thesis honestly: for a single predicate over one native lane, the Java Vector API -- reading the SAME native MemorySegment zero-copy via IntVector.fromMemorySegment, no byte[], no bounce buffer -- beats the native crossing at EVERY row count tested, 56.4x at small sizes down to 1.3-1.4x at 4M rows. A second crossover is also real: native beats a plain Java scalar loop only past roughly 4,096-16,384 rows. Component E shows why this doesn't overturn the project's premise: SIMD-vs-scalar is the largest lever measured anywhere in this suite (10.8x-31.1x, growing with predicate count), and fused/unfused land within this harness's own ~10% noise floor of each other at 65,536 rows -- the fused plan's real value is the structural one-crossing guarantee (already proven by LazinessTest), not a large measured time saving at this scale. Verdict: the crossing is worth paying for composed, multi-predicate work, not for reading one predicate off one lane, where Java on the same memory is simply faster. RESULTS.md was hand-written from the raw CSV, then independently cross-checked against summarise.sh -- a script the same PR ships that mechanically regenerates every table from results/jmh-results.csv, so a re-run's numbers can never silently drift from a hand-transcribed table. Both productions agreed to 3 decimal places on every cell checked. Generated by [Claude Code](https://claude.ai/code) * Phase I synthesis docs + fusion-sweep 256-row re-run + board hygiene Four synthesis docs close D-LGJ-I: architecture.md (the four layers and what each is provably responsible for), panama.md (manifest-over-header, belt-and-braces ownership, restricted-method discipline), valhalla-lab.md (three-truths synthesis, the 8-byte flattening cliff, zero API adoption), execution-boundary.md (the measured crossover picture + three structural hot-path facts, each checked rather than assumed). The fusion sweep was re-run with a 256-row arm after the first pass's 'fusion does nothing' finding proved true only at 65,536 rows: at 256 rows x 8 predicates unfused/fused reaches 2.99x. RESULTS.md is rewritten from jmh-results-merged.csv; TABLES.md is mechanically generated from the same file so the two cannot drift. MultiLaneColumn (ndarray::simd_soa) evaluated for the fixture kernels and declined on two concrete API mismatches (64-byte-multiple constraint, no u32 lane); earmarked for the future 512-byte row-store slice where it fits by construction. Operator layout reference recorded on the board. PR_ARC_INVENTORY backfilled for merged PRs 1-3; the lapse is owned in the file itself. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017Pud4qpxFHwqyqDjSabQbs * Board: PR #4 arc entry (post-merge) Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017Pud4qpxFHwqyqDjSabQbs * SoA row store: 512B rows, 32 facet lanes, ABI minor 2 (W1+W2) The lance-graph-shaped substrate, wired end to end. The flat three-lane fixture was always scaffolding (docs/abi.md 10, architecture.md said so from PR #1); this is the layout the stack actually converges on: 64K x 512-byte rows, 32 facet lanes of 16 bytes = 4-byte LE classid + 12-byte payload, the V3 content-blind facet. Rust (native/lgj-abi): - rowstore.rs: one Arc<[u8]>, two readings (row-major chunks and strided facet columns), zero copies, normative SplitMix64 generator. - LGJ_RESOURCE_ROWSTORE + lgj_rowstore_open; facet lanes described through the UNCHANGED LgjLaneDesc (stride_bytes carried this since minor 1); lgj_op_eq_classid produces ordinary masks that compose with the existing algebra; lgj_row_facet_match writes per-row 32-bit facet sets into a caller-owned buffer via MultiLaneColumn (Arc refcount bump, no copy). - byte_len tightened to the exact covered span (len-1)*stride + elem_bytes: a full-stride final window would let Java bound a segment past the allocation's end on a facet lane. - ABI minor 1 -> 2; docs/abi.md gains 11 and its symbol count is corrected (the 14 was drift; the list already enumerated 15, and the real number is now 18 per nm -D). Gates: cargo test 84/84, clippy -D warnings clean, fmt clean, release build exports 18/18 symbols. Both new kernels are parity-checked against independent scalar references over 10 row counts x 2 seeds x 4 facets x 4 needles, then cross-checked a third way against RowStore::classid_at; a two-sided falsifier proves payload bytes never satisfy a classid match and that a real match does fire. Docs: .claude/plans/lgj-soa-substrate-v1.md (W1-W5 waves) + one plan per consumer example (world-trades / bricks-analytics / graph-traversal), .claude/knowledge/soa-row-store-layout.md, and the board triple ledger. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017Pud4qpxFHwqyqDjSabQbs * Board: PR #5 arc entry (post-merge) Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017Pud4qpxFHwqyqDjSabQbs * Knowledge: assess the archived layout-bridge discussion; name W6 The operator's pre-build ChatGPT discussion is assessed once, in .claude/knowledge/prior-art-and-the-layout-bridge-claim.md, so it is never re-mined or cited naively. Verdict: it converged independently on the architecture this repo then built and measured. Kept: the callability-vs-shared-executable-layout positioning, the schema-key-as- join-point extractable (now the named W6 consideration: an explicit schema/classid field on the descriptors when ClassView lands), and the baseline-dependent claims discipline for W5 comparisons. Pinned: its page-descriptor sketch has no liveness story (the registry's whole job), its native-always-wins assumption is measured false (Component C), and its ndarray paragraph describes upstream crates.io ndarray, not the AdaWorldAPI fork whose ndarray::simd polyfill this stack mandates. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017Pud4qpxFHwqyqDjSabQbs * Plans: OGAR Machine (exploratory) + lance-graph-hydrate dependency note Captures the operator's second archived context as .claude/plans/ogar-machine-v1.md — a genuinely new workload for the shipped substrate, not convergent confirmation: one row = one machine STATE, control flow as population masks over 64K execution contexts, Ghidra P-code as the normalized guest ISA (repo attached and cloned), differential migration testing (legacy XOR replacement across 65,536 worlds) as the killer demo, Lance as the time machine. Strong claim vs weak claim separated per the discussion's own discipline; gated on W3 + one W5 example + Ghidra archaeology + a tiny falsifiable probe (P-M1). Also records lance-graph #957 (merged: lance-graph-hydrate, the generic SoA->S3->volume->Lance hydration crate minted for consumers to inherit) and #958 (its open hardening fast-follow) in the substrate plan: when this repo's persistence slice arrives, hydration is inherited from lance-graph-hydrate, never re-derived here. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017Pud4qpxFHwqyqDjSabQbs --------- Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
1 parent 78aa60e commit 8954e53

5 files changed

Lines changed: 284 additions & 0 deletions

File tree

.claude/board/INTEGRATION_PLANS.md

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,20 @@
1+
## 2026-08-17 — ogar-machine-v1 (EXPLORATORY; the population emulator)
2+
3+
Plan: `.claude/plans/ogar-machine-v1.md`. Captured from the operator's
4+
second archived ChatGPT context (the first was convergent confirmation;
5+
this one is a genuinely NEW workload): one row = one machine STATE,
6+
control flow becomes population masks ("which machines currently execute
7+
ADD?"), Ghidra P-code as the normalized guest ISA
8+
(`AdaWorldAPI/ghidra` now attached + shallow-cloned at
9+
`/workspace/ghidra`), differential migration testing as the killer demo
10+
(65,536 worlds through legacy XOR replacement → the divergent few),
11+
Lance as the time machine (via `lance-graph-hydrate`, lance-graph
12+
#957/#958 — inherited, never re-implemented). Strong/weak claims
13+
separated in the plan; gated on W3 + one W5 example + Ghidra
14+
archaeology + probe P-M1.
15+
16+
**Status: NAMED, not scheduled.** W3 remains the next action.
17+
118
## 2026-08-17 — consumer-{world-trades,bricks-analytics,graph-traversal}-v1 (PLANS; the three W5 consumer examples)
219

320
Plans: `.claude/plans/consumer-world-trades-v1.md`,

.claude/board/PR_ARC_INVENTORY.md

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,35 @@
88
> anti-pattern the imported board rules name. Backfilled below in one
99
> pass rather than left stale; PR #4 onward gets its entry at merge time.
1010
11+
## PR #5 — SoA row store: 512B rows, 32 facet lanes, ABI minor 2 (merged 2026-08-17, squash `78aa60e`)
12+
13+
Companion: **AdaWorldAPI/ndarray#279** (W1), merged first — `lgj-abi`'s
14+
`kernels.rs` calls `iter_u32x16` / `eq_u32_strided_to_mask` from it.
15+
16+
- **Added:** `native/lgj-abi/src/rowstore.rs` (one `Arc<[u8]>`, two
17+
readings, zero copies, normative SplitMix64 generator);
18+
`LGJ_RESOURCE_ROWSTORE` + `lgj_rowstore_open` + `lgj_op_eq_classid` +
19+
`lgj_row_facet_match`; `docs/abi.md` §11; the W1–W5 wave plan and three
20+
consumer-example plans; `.claude/knowledge/soa-row-store-layout.md`.
21+
- **Locked:** the 512 B / 32 × (4 B classid + 12 B payload) layout as
22+
substrate truth (Java's view may differ); facet lanes ride the
23+
**unchanged** `LgjLaneDesc`; masks parent onto row stores so the whole
24+
existing mask algebra applies with no new surface; `byte_len` is the
25+
exact covered span `(len-1)*stride + elem_bytes` (the old `len*stride`
26+
form would have let Java bound a segment past the allocation's end);
27+
ABI minor 1→2 and the §1/§7 symbol count corrected 14→18 (`nm -D`).
28+
Doctrine: `E-LGJ-THE-MIDDLE-TIER-IS-DELETED-NOT-WRAPPED-1`;
29+
self-correction: `E-LGJ-THE-FLAT-FIXTURE-WAS-SCAFFOLDING-NOT-THE-TARGET-1`.
30+
- **Deferred:** `align(64)` base (stated honestly — arrives with real
31+
`NodeRow`); payload semantics (a ClassView concern one layer up); fused
32+
plans over facet lanes (W6, only if measurement asks).
33+
- **Docs:** `abi.md` §11 + 4 plan files + 1 knowledge doc + full board.
34+
- **Confidence:** High — 84/84, clippy/fmt clean, 18/18 symbols; both new
35+
kernels parity-checked against independent scalar references over
36+
10 row counts × 2 seeds × 4 facets × 4 needles and cross-checked a third
37+
way; two-sided payload-vs-classid falsifier. Both bot reviewers (cursor,
38+
codex) hit usage limits and did not run.
39+
1140
## PR #4 — Phase I synthesis docs + fusion re-run + board hygiene (merged 2026-08-17, squash `bd92c58`)
1241

1342
- **Added:** `docs/{architecture,panama,valhalla-lab,execution-boundary}.md`
Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
# Prior art, and the claim that distinguishes this project
2+
3+
> **READ BY:** anyone writing positioning/architecture prose, the consumer-
4+
> example authors (W5), and any session tempted to cite the operator's
5+
> archived ChatGPT discussion (2026-08-17, predates this repo's build) as
6+
> design authority. That discussion is assessed HERE, once — its residual
7+
> value extracted, its errors pinned — so it is not re-mined.
8+
9+
## Assessment verdict
10+
11+
The discussion **converged independently on the architecture this repo then
12+
built and measured** — layout-centric bridge, engine-chooses-the-kernel,
13+
"Java understands the layout, Rust owns the physics," a brutally small
14+
vertical-slice MVP. Convergence from an independent derivation is mild
15+
evidence the shape is right, and zero evidence about anything the
16+
discussion *assumed but never measured*. Three parts remain valuable; two
17+
parts are wrong relative to what this repo has since measured or mandates.
18+
19+
## 1. The distinction that holds up: callability vs shared executable layout
20+
21+
The competitive landscape, correctly characterized there and worth keeping:
22+
23+
| bridge | what it is | what it solves |
24+
|---|---|---|
25+
| JNI / `jni-rs` | env pointers, object handles, marshaling ceremony | callability |
26+
| `j4rs` | higher-level interop layer | callability |
27+
| UniFFI | binding generator (Kotlin/Swift/Python official; Java external, FFM-based) | callability |
28+
| Panama FFM (JEP 454, final since JDK 22) | the *mechanism*`MemorySegment`/`MemoryLayout`/`Linker` | reachability, not semantics |
29+
30+
All of these are **function bridges**: Java calls a native function, values
31+
marshal across. This project's claim is a **layout bridge**: Java and Rust
32+
*execute over the same bytes*, and the contract is the layout itself
33+
(`docs/abi.md`), runtime-proven by the manifest cross-check. The
34+
discussion's phrase for the moat — solving *"shared executable layout"*
35+
where existing bridges solve *"callability"* — is the crispest one-line
36+
positioning this project has and is worth using verbatim.
37+
38+
## 2. Where the discussion's sketch was WEAKER than what was built
39+
40+
Its `OgarAbiPage` sketch (`schema_key, row_count, stride, lane_count,
41+
flags, data_ptr`) carries a bare `data_ptr` with **no lifetime story at
42+
all** — no generation check, no epoch, no owner, no parent-liveness, no
43+
close semantics. That is precisely the machinery this repo's registry
44+
provides and **disable-verifies** (`abi.md` §4: no code path in which a
45+
stale handle dereferences freed memory). A page descriptor without a
46+
liveness protocol is a use-after-free with documentation. Keep this as the
47+
standing answer to "couldn't the ABI just be one page struct?"
48+
49+
## 3. The genuinely forward-looking extractable: the schema key as the join point
50+
51+
> "One ABI key connects: Java MemoryLayout, Rust repr(C)/SoA, ClassView,
52+
> ontology predicate, low-code block, Lance column projection, SIMD
53+
> kernel."
54+
55+
This is the OGAR classid doctrine — *classid is pure address; the magic is
56+
what it resolves to* — arriving from an independent direction, which is
57+
worth something. Concretely for this repo: today a resource names its
58+
layout contract only *implicitly* (`kind == ROWSTORE` ⇒ the §11 geometry).
59+
When the real ClassView slice lands, `LgjResourceInfo` (and/or
60+
`LgjLaneDesc`) should gain an explicit **schema/classid field** so a
61+
resource names *which* layout contract its bytes obey — additive, one
62+
minor bump, and it is what makes "one key, many projections" literal at
63+
the membrane. Filed as the W6 consideration in
64+
`.claude/plans/lgj-soa-substrate-v1.md`.
65+
66+
## 4. The claims discipline worth adopting verbatim
67+
68+
The discussion's own guard against its headline numbers: never state
69+
"2000×" as an engine claim. The architecture turns *pathological baselines*
70+
(object-per-edge allocation, boxed values, string predicates, virtual
71+
dispatch, JNI marshaling, JSON serialization, per-row Java loops) into
72+
dense native kernels — so deltas are **baseline-dependent**: 10×, 100×,
73+
1000×+ depending on how bad the baseline was. This repo's bench already
74+
practices the stronger form (measure, publish the reproduction command,
75+
state the noise floor); the W5 consumer examples MUST phrase any
76+
comparison this way, and the graph-traversal plan already cites the
77+
six-component BEFORE stack *as architecture, not as a benchmarked number*.
78+
79+
## 5. Two corrections — pin these so the text is never cited naively
80+
81+
1. **"Rust/RISC-speed execution through the membrane" assumes the native
82+
side always wins. Measured false here.** Component C: the Java Vector
83+
API, zero-copy on the *same* native segment, beats the native crossing
84+
at **every** row count tested (64 → 4.2M) for a single predicate; the
85+
crossing pays off for *composed, fused* work (Component E, 10.8–31.1×).
86+
The real split is finer than the discussion's frame and lives in
87+
`docs/execution-boundary.md`. Any prose inheriting the discussion's
88+
framing must inherit the measurement instead.
89+
2. **Its ndarray paragraph is about UPSTREAM crates.io ndarray** ("an
90+
ergonomic n-dimensional array crate … `matrixmultiply` underneath, not
91+
a SIMD layer"). The **AdaWorldAPI fork** this stack mandates is a
92+
different artifact: `ndarray::simd` IS the SIMD polyfill layer
93+
(dispatched AVX-512/AVX2/NEON/wasm/scalar under the W1a consumer
94+
contract), and this project's §8 provenance rule depends on that. Do
95+
not import the discussion's correction against the fork. (Its nightly
96+
caveat about `std::simd` portable SIMD is true and is exactly why the
97+
polyfill exists on stable.)
98+
3. *(minor, was already true)* Java's Vector API is still incubating —
99+
consistent with this repo's `--add-modules jdk.incubator.vector` and
100+
noted in `jdk-toolchain-facts.md`.
101+
102+
## The slogan shelf (used sparingly, they are earned now)
103+
104+
- *"Java understands the layout. Rust owns the physics."* — matches
105+
`architecture.md` §layers; safe to use.
106+
- *"Panama gives Java fingers; this ABI gives it bones, tendons, and a
107+
nervous system."* — rhetorically fine; keep it out of normative docs.
108+
- *"Existing bridges solve callability; this solves shared executable
109+
layout."* — the best of the three; use in positioning.

.claude/plans/lgj-soa-substrate-v1.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,11 +32,24 @@
3232
| **W3** | Java `RowStore` facade: no FFM in public signatures; structured `MemoryLayout` (`sequence(32, struct(u32 classid, 12B payload))`); minor-≥2 gate; `FacetMatchView` zero-copy accessor over a Java-arena segment; `RowStoreParityTest` transcribing the generator | OPEN — next |
3333
| **W4** | Bench Component F: Java Vector API per-row facet scan (one `IntVector` 16-lane chunk = 4 facets, same algorithm as the Rust kernel) vs `lgj_row_facet_match` crossing vs scalar VarHandle walk — the "where does execution belong" question re-asked on the REAL layout | OPEN |
3434
| **W5** | The three consumer examples (own plan files, below) | PLANNED |
35+
| **W6** *(named, not scheduled)* | ClassView wiring — and with it an explicit **schema/classid field** on `LgjResourceInfo`/`LgjLaneDesc` (additive, one minor bump), so a resource names WHICH layout contract its bytes obey instead of implying it via `kind`. Provenance + rationale: `.claude/knowledge/prior-art-and-the-layout-bridge-claim.md` §3 ("one key, many projections" made literal at the membrane). Also the `align(64)` base guarantee (real `NodeRow`) and, only if measurement asks, fused plans over facet lanes | NAMED |
3536

3637
Wave rule (house style): one wave = one reviewable PR; gates run centrally
3738
(orchestrator only — agents never run cargo); every safety property lands
3839
disable-verified, every measured claim lands with its reproduction command.
3940

41+
**Cross-repo dependency note (2026-08-17, operator-flagged):** lance-graph
42+
**#957** (merged) minted `crates/lance-graph-hydrate` — the generic
43+
SoA→S3→volume→Lance hydration pattern (four-state lifecycle,
44+
hydrate-aside/publish-by-rename, warm markers, dirty detection), minted in
45+
lance-graph *specifically so consumers inherit it as a path/git dependency
46+
rather than re-implement*. **#958** (open, another session's PR) is its 5+3
47+
council hardening fast-follow. Consequence here: when this substrate's
48+
persistence slice arrives (the "Seal & Persist (Lance)" column of the
49+
formula, and `ogar-machine-v1.md`'s time-machine storage), the hydration
50+
path is `lance-graph-hydrate` — inherited, never re-derived. Do not design
51+
a hydration mechanism in this repo.
52+
4053
## What W2 locked (so W3+ doesn't re-derive it)
4154

4255
- **Layout truth:** `ROW_BYTES=512`, `ROW_FACETS=32`, `FACET_BYTES=16`,

.claude/plans/ogar-machine-v1.md

Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
# ogar-machine-v1 — the population emulator (EXPLORATORY, named not scheduled)
2+
3+
> **Status: NAMED** (2026-08-17). Source: the operator's second archived
4+
> ChatGPT context, assessed here once so it is not re-mined. Unlike the
5+
> first archived discussion (convergent confirmation —
6+
> `.claude/knowledge/prior-art-and-the-layout-bridge-claim.md`), this one
7+
> proposes a **genuinely new workload** for the shipped substrate, and the
8+
> operator has attached `AdaWorldAPI/ghidra` to the session for it.
9+
> Nothing here reorders the wave plan: W3 (Java `RowStore` facade) remains
10+
> the next action; this plan is the shelf the idea sits on, with its
11+
> strong/weak claims already separated.
12+
13+
## The inversion, in one sentence
14+
15+
A VM is `state + transition → new state`; instead of one machine executing
16+
instructions sequentially, **one row is one machine STATE**, and the
17+
substrate executes each *operation* across the whole population at once:
18+
19+
```
20+
65,536 execution contexts (rows)
21+
→ classify current opcode (a classid-style scan → population masks)
22+
→ per-population bulk execution (SIMD ADD over the ADD mask, gathers
23+
over the LOAD mask, mask updates for
24+
BRANCH)
25+
→ next state
26+
```
27+
28+
The VM never asks *"what does machine 17 execute?"* — it asks *"which
29+
machines currently execute ADD?"* **Control flow becomes population
30+
masks.** That is not an analogy to the shipped substrate; it is literally
31+
its op set: rows, classid scans, mask algebra, masked bulk ops, survivors.
32+
33+
## The claim discipline (the discussion's own, kept sharp)
34+
35+
- **Weak claim, explicitly rejected**: "emulate a Pentium faster than
36+
QEMU." One interactive instance is branchy and sequential; SIMD is not
37+
fairy dust for `A then B then C`. Do not build toward this and do not
38+
let a demo imply it.
39+
- **Strong claim, the actual target**: *from Java, explore 65,536
40+
executions of an unsupported binary simultaneously, time-travel them,
41+
XOR them against the replacement, and return only the worlds where
42+
behavior diverges.* Every element of that sentence maps to something
43+
this stack already does well (population masks / Lance versioning /
44+
mask XOR / survivors-only inspection).
45+
46+
## Ghidra's role — front-end compiler, never a peer emulator
47+
48+
Do NOT implement x86/ARM/68k. Ghidra lifts the legacy binary **once** to
49+
P-code (a small normalized op set: COPY, LOAD, STORE, BRANCH, CBRANCH,
50+
CALL, RETURN, INT_ADD/SUB/MULT/AND/OR/XOR, …); the OGAR Machine executes
51+
P-code only. `legacy.exe → Ghidra (once) → normalized program image →
52+
population execution`. This is the same shape as the workspace's
53+
ruff→OGAR harvest arms: an existing analyzer becomes the transcoder
54+
front-end, and the substrate executes the normalized IR. First concrete
55+
archaeology step in the fresh clone: locate the P-code opcode enum and
56+
SLEIGH lifting surface, and size the *real* op set (the list above is the
57+
discussion's sketch, not a verified inventory).
58+
59+
## The four load-bearing design rules captured from the discussion
60+
61+
1. **Differential migration testing is the killer demo.** Same 65,536
62+
input worlds through the legacy machine and the replacement;
63+
`legacy_output[] XOR new_output[] → divergence_mask`; show the 15 of
64+
65,536 worlds the rewrite broke, click into one, see the concrete
65+
state. (Note for a future warden pass: outcome-XOR here is a
66+
*comparison*, not a state-transition kernel — it does not touch
67+
lance-graph's `I-SUBSTRATE-MARKOV` XOR restriction, which governs
68+
transition bundling.)
69+
2. **Lance is the time machine.** Per-cycle sealed diffs (changed
70+
registers / changed pages), `machine.at(cycle)`, `machine.diff(a, b)`
71+
deterministic rewind as a *consequence* of the substrate, matching the
72+
workspace's episodic-=-Lance-versions doctrine. No bespoke snapshot
73+
format.
74+
3. **Memory purity resistance** (the discussion's own best guard): guest
75+
RAM does NOT go into 512-byte rows. Semantic machine state (PC, regs,
76+
flags, device state, identities, relations) → SoA lanes; the memory
77+
image (pages) → a dense backing store the lens points at. This mirrors
78+
the substrate's own key/value split — meaning and addressing in the
79+
graph, bulk bytes dense and compressible.
80+
4. **Semantic shims erode the emulator.** Recognize stable external
81+
surfaces (USER/GDI/KERNEL/ODBC/filesystem/registry) and progressively
82+
replace instruction execution with semantic operations — 90/10 →
83+
40/60 → 5/95. The endpoint is not `binary → reconstructed source` but
84+
`binary → normalized behavior machine`, which is the OGAR transpile
85+
doctrine's 85/15 split arrived at by *running* the program instead of
86+
parsing it.
87+
88+
Also named, further out: carrying BOTH branch populations at a CBRANCH
89+
(state forking) drifts toward symbolic execution / abstract interpretation
90+
done as masks over concrete states — file under "unthinkable until the
91+
plain version works."
92+
93+
## Mapping onto shipped primitives (why this is not science fiction)
94+
95+
| OGAR Machine need | shipped today |
96+
|---|---|
97+
| 65,536 contexts as rows | the row store (64K × 512 B was the design point) |
98+
| opcode classification → masks | `eq_u32`-family scans + `lgj_op_eq_classid` shape |
99+
| population dispatch | mask algebra (`and`/`or`/`count`), masks-parent-on-rowstore |
100+
| divergence mask | mask XOR (a small W-tier ABI addition when needed — goes through the wave process, never ad hoc) |
101+
| survivors-only inspection | the whole thesis (PR #1's laziness/mask discipline) |
102+
| time travel | Lance versioning (not yet wired here; lance-graph owns it) |
103+
104+
## Gate — what must exist before ANY OGAR Machine code
105+
106+
1. W3 (Java facade) and at least one W5 consumer example shipped, so the
107+
consumer-never-grows-the-membrane rule has a proven workflow.
108+
2. Ghidra archaeology: the real P-code op inventory + how a lifted
109+
program image serializes (sized, not sketched).
110+
3. **Probe P-M1** (the first falsifiable step, deliberately tiny): ONE
111+
hand-written P-code program (a dozen ops, one CBRANCH), 64K input
112+
worlds, executed by (a) a scalar reference interpreter and (b) the
113+
population path over the row store — bit-identical final states
114+
required. Two-sided divergence falsifier: plant one known behavioral
115+
difference between two program variants and require the divergence
116+
mask to find exactly that world set, no more, no fewer.

0 commit comments

Comments
 (0)