Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
546b17a
Core vertical slice: docs/abi.md contract, native/lgj-abi, Java facade
AdaWorldAPI Aug 17, 2026
a1e65cc
Merge main (bootstrap commit) into dev branch to establish shared his…
AdaWorldAPI Aug 17, 2026
bdd40b2
Valhalla lab: three-truths method, causal isolation, 3 real reproducers
AdaWorldAPI Aug 17, 2026
317ee83
Merge main (squash of PR #1) to fix history divergence for PR #2
AdaWorldAPI Aug 17, 2026
ea4753c
Merge main (squash of PR #2) to keep dev branch history aligned
AdaWorldAPI Aug 17, 2026
4ab0da8
Vector API bench: real JMH, cross-checked; the crossing does not alwa…
AdaWorldAPI Aug 17, 2026
96eccff
Merge main (squash of PR #3) to keep dev branch history aligned
AdaWorldAPI Aug 17, 2026
cd7782b
Phase I synthesis docs + fusion-sweep 256-row re-run + board hygiene
AdaWorldAPI Aug 17, 2026
ddeaecb
Merge main (squash of PR #4) to keep dev branch history aligned
AdaWorldAPI Aug 17, 2026
e4463cb
Board: PR #4 arc entry (post-merge)
AdaWorldAPI Aug 17, 2026
e8b6dc2
SoA row store: 512B rows, 32 facet lanes, ABI minor 2 (W1+W2)
AdaWorldAPI Aug 17, 2026
aff72f3
Merge main (squash of PR #5) to keep dev branch history aligned
AdaWorldAPI Aug 17, 2026
8fceaca
Board: PR #5 arc entry (post-merge)
AdaWorldAPI Aug 17, 2026
91e22f3
Knowledge: assess the archived layout-bridge discussion; name W6
AdaWorldAPI Aug 17, 2026
6927961
Plans: OGAR Machine (exploratory) + lance-graph-hydrate dependency note
AdaWorldAPI Aug 17, 2026
7e218ed
Merge main (squash of PR #6) to keep dev branch history aligned
AdaWorldAPI Aug 17, 2026
9cc85ad
Board: PR #6 arc entry (post-merge)
AdaWorldAPI Aug 17, 2026
f3bbab7
Waves calcified: dispatch maps for every plan; Ghidra plan from real …
AdaWorldAPI Aug 17, 2026
dac0f0b
Merge main (squash of PR #7) to keep dev branch history aligned
AdaWorldAPI Aug 17, 2026
57a7e48
Board: PR #7 arc entry (post-merge)
AdaWorldAPI Aug 17, 2026
83b8994
Plan: lance-graph #958 merged (was open at last check)
AdaWorldAPI Aug 17, 2026
572f865
Java RowStore facade: W3 shipped (185/185, one bug found+fixed)
AdaWorldAPI Aug 17, 2026
b138382
Merge main (squash of PR #8) to keep dev branch history aligned
AdaWorldAPI Aug 17, 2026
bc6f91a
Board: PR #8 arc entry (post-merge)
AdaWorldAPI Aug 17, 2026
619b3de
Plan: r2sleigh recorded as third lift path + decompiler candidate
AdaWorldAPI Aug 17, 2026
84e73ca
Bench Component F: the boundary re-asked on the real row-store layout…
AdaWorldAPI Aug 17, 2026
897fd92
Merge main (squash of PR #9) to keep dev branch history aligned
AdaWorldAPI Aug 17, 2026
201a626
Board: PR #9 arc entry (post-merge)
AdaWorldAPI Aug 17, 2026
ed4fb7c
Parity: the third independent read path (ROW_LAYOUT segment reads)
AdaWorldAPI Aug 17, 2026
6c4afe4
Merge main (squash of PR #10) to keep dev branch history aligned
AdaWorldAPI Aug 17, 2026
9717cda
Board: PR #10 arc entry (post-merge)
AdaWorldAPI Aug 17, 2026
8eecb3b
Consumer example: World/Trades — the zero-object fluent domain API (W5a)
AdaWorldAPI Aug 17, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions .claude/board/PR_ARC_INVENTORY.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,25 @@
> anti-pattern the imported board rules name. Backfilled below in one
> pass rather than left stale; PR #4 onward gets its entry at merge time.

## PR #10 — third parity read path + R2IL handoff boundary (merged 2026-08-17, squash `4114c4e`)

- **Added:** `RowStoreParityTest` section reading all 32,000 classids of a
1000-row store DIRECTLY from the raw lane-0 segment through
`Layouts.ROW_LAYOUT.byteOffset(...)` — proving the LAYOUT's carving
against the generator, and giving `ROW_LAYOUT` its first real consumer
(it had been defined and size-checked but read by nothing). AllTests
185 → 188.
- **Locked:** three independent routes to the same numbers (native
kernels / generator transcription / structured segment read); the raw
lane's own description pinned (n*512 bytes, contiguous). The R2IL
handoff boundary recorded in `ghidra-integration-v1.md`: r2sleigh/ruff
integration arrives from ANOTHER session — lift-candidate C and the
r2dec direction are FROZEN here until it lands.
- **Deferred:** everything the handoff covers, deliberately.
- **Docs:** the plan's handoff section IS the record.
- **Confidence:** High — closes a gap the W3 worker itself flagged rather
than one discovered by accident. Bot reviewers at usage limits.

## PR #9 — bench Component F: the boundary on the real layout (merged 2026-08-17, squash `b28bd34`)

- **Added:** `F_RowStoreFacetScan` + `RowStoreData` + two `Kernels`
Expand Down
2 changes: 1 addition & 1 deletion .claude/board/STATUS_BOARD.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,4 +40,4 @@ layout wired end to end. Doctrine: `E-LGJ-THE-MIDDLE-TIER-IS-DELETED-NOT-WRAPPED
| D-LGJ-W2 | lgj-abi row store: `rowstore.rs`, `LGJ_RESOURCE_ROWSTORE`, `lgj_rowstore_open`, strided facet lanes through the unchanged `LgjLaneDesc`, `lgj_op_eq_classid`, `lgj_row_facet_match`, ABI minor 1→2, `docs/abi.md` §11 | **DONE 2026-08-17** — `cargo test` **84/84**, clippy/fmt clean, release build exports **18/18** symbols (`nm -D`). Parity: both kernels vs independent scalar references over 10 row counts × 2 seeds × 4 facets × 4 needles, cross-checked a THIRD way against `RowStore::classid_at`. Two-sided payload-vs-classid falsifier. End-to-end membrane test covers describe → predicate → mask algebra → count → facet-match → lifecycle |
| D-LGJ-W3 | Java `RowStore` facade: structured `MemoryLayout`, minor-≥2 gate, `FacetMatchView`, parity test transcribing the generator | **DONE 2026-08-17** — dispatched per `.claude/waves/wave-substrate-w3-w4.md` (3 Sonnet workers, disjoint scopes: FFM membrane extension / public facade / tests), orchestrator-integrated. `javac -Xlint:all` clean (same 7 pre-existing `[restricted]` warnings, zero new). `AllTests` **185/185** (was 132; +53 new checks: 29 parity + 24 lifetime). **One real bug caught by the suite and fixed**: `FacetMatchView.rowCount()` was missing the closed-store guard `matchesOf`/`cardinality` both had — a stale row count was readable after the owning store closed. Fixed, re-verified. Both mandated disable-runs ran red-then-green: (1) `Abi.requireMinor` inflated by 1 → exactly `RowStoreParityTest`+`RowStoreLifetimeTest` failed, all 8 other suites stayed green; (2) the pure-Java generator's a/b draw order swapped in `RowStoreParityTest` → exactly that suite broke (17/29), `RowStoreLifetimeTest` (generator-independent) stayed green — confirming the parity test is a real falsifier, not decorative. `Mask.source()` retyped `NativePattern → NativeResource` (new interface) so a `Mask` can parent onto either a `NativePattern` or a `RowStore` — zero call-site breakage (verified: no existing caller bound the narrower type) |
| D-LGJ-W4 | Bench Component F: Vector API facet scan vs the crossing, on the REAL layout | **DONE 2026-08-17** — 1 Sonnet worker (F_RowStoreFacetScan + RowStoreData + Kernels facet-match arms, cross-check-in-@Setup discipline), orchestrator-run JMH: 9/9 combos, cross-checks green at every row count. **Finding: Component C's direction survives, its margin collapses** — Vector API wins the 32-facet strided scan at every row count but by 2.51×/1.92×/1.14× (4K/65K/1M rows) vs C's 56×; at 512 MiB traversed all three arms converge on memory bandwidth. Native arm's per-call allocation asymmetry disclosed in §F with a named follow-up (`facetMatchesInto`), not hidden. summarise.sh extended with the F table (and the old 'E/F' section retitled 'E' — a real naming collision); tables regenerated from the merged CSV |
| D-LGJ-W5 | Three consumer examples (trades / bricks / graph) — one plan file each | Planned, gated on W3 |
| D-LGJ-W5 | Three consumer examples (trades / bricks / graph) — one plan file each | **trades DONE 2026-08-17** — `consumers/trades/` (own compile unit, core consumed as a third-party would): `Trade` (schema-not-entity: zero public ctors, zero instance fields, reflection-forced construction still throws), `World.open` → the existing lazy `View` under domain names, zero new membrane surface. TradesParityTest 12/12 (chain vs transcribed-generator recomputation at 1K+64K rows; 0 crossings composing / 1 at terminal THROUGH the domain vocabulary; reflection guard). TradesAllocationTest 3/3 — **the poster's number, measured: 240 bytes/query, IDENTICAL at 64K and 1M rows** (row-count independence is the thesis assertion; 64 KiB absolute backstop). Disable-run: VENUE pointed at the wrong lane → the membrane's own LANE_KIND_MISMATCH rejected it (the binding is checked, not trusted); restored green. bricks + graph still shelved |
114 changes: 114 additions & 0 deletions consumers/trades/src/main/java/com/adaworldapi/trades/Trade.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
package com.adaworldapi.trades;

import com.adaworldapi.lancegraph.Field;
import com.adaworldapi.lancegraph.I32Field;
import com.adaworldapi.lancegraph.LaneId;
import com.adaworldapi.lancegraph.Ordinal;
import com.adaworldapi.lancegraph.Pattern;
import com.adaworldapi.lancegraph.U32Field;

import java.util.List;

/**
* The domain schema for the "One Billion Objects. Zero Objects." poster.
*
* <h2>This is a schema, not an entity</h2>
*
* <p>There is no such thing as a {@code Trade} instance, on purpose, and the constructor enforces
* that rather than merely discouraging it (see below). The thesis this consumer example exists to
* demonstrate: <strong>a million logical trades are one native lane set, not a million Java
* objects.</strong> {@code Trade} is the vocabulary a fluent query is written against —
* {@code Trade.VENUE.eq(Trade.XETRA)} — never a bag of fields a row gets copied into.
*
* <p>This class is written the same generated shape as {@link Pattern}: constants only, no logic,
* names taken from the schema, lane indices stated once. It is a domain-named sibling of
* {@code Pattern}, not a replacement for it — see the field notes below for exactly how the two
* relate.
*
* <pre>{@code
* try (var world = World.open(1_000_000, World.DEFAULT_SEED).source()) {
* long xetraCount = world.view()
* .where(Trade.VENUE.eq(Trade.XETRA))
* .where(Trade.PRICE.gt(100))
* .count();
* }
* }</pre>
*
* <h2>Field mapping — honest about what the fixture actually offers</h2>
*
* <p>The generated fixture ({@link com.adaworldapi.lancegraph.NativePattern}) has exactly three
* lanes: an id, an unsigned 32-bit class tag ({@code 0..15}), and a signed 32-bit value
* ({@code -150..361}). This schema binds the domain names a trading example would actually use
* onto those same two data lanes — {@link #VENUE} is the class lane, {@link #PRICE} is the value
* lane — rather than inventing a fourth lane the substrate does not have.
*
* <ul>
* <li>{@link #VENUE} — {@link Pattern#CLASS}'s lane ({@code lane 1}), read as a trading venue
* identifier. The fixture generates 16 distinct values ({@code 0..15}); {@link #XETRA} and
* {@link #NASDAQ} are two of them, chosen so a demo predicate selects a measured, known
* fraction of the rows rather than an arbitrary one.
* <li>{@link #PRICE} — {@link Pattern#VALUE}'s lane ({@code lane 2}), read as a price tick. The
* fixture's signed range ({@code -150..361}) does not correspond to a real price in any
* currency; the demo's fiction is that these are cents-scale ticks, deliberately unrealistic
* (a real price is never negative) so that a signed-comparison bug shows up rather than
* agreeing with an unsigned one by accident — see {@link I32Field#gt(int)}.
* </ul>
*
* <h2>QUANTITY is deliberately absent</h2>
*
* <p>The poster's domain fiction has a third field, quantity. It is <strong>not fabricated
* here</strong>: the current flat three-lane fixture has no third numeric lane to bind it to, and
* inventing one would mean this schema quietly grows its own private data rather than projecting
* the real substrate. A quantity field arrives with the multi-lane {@code ClassView} facet slice
* (32 facets, {@code W6} in the substrate plan) — at that point {@code Trade} gains a
* {@code QUANTITY} constant bound to a real lane, and this class's shape does not otherwise change.
* Until then, honesty about what exists beats completeness of the poster.
*
* <h2>Binds onto the flat pattern, not the row store</h2>
*
* <p>{@link World#open} opens a {@link com.adaworldapi.lancegraph.NativePattern} and returns its
* {@link com.adaworldapi.lancegraph.View} — the flat, three-lane substrate {@link Pattern} already
* uses, not the 32-facet {@code RowStore} the substrate wave shipped alongside it. That is where
* the {@code gt}/{@code eq} lazy {@code View} machinery lives today. A facet-row binding (one
* {@code Trade} row addressed as a lane slice of a {@code RowStore} facet, via a future
* {@code ClassView}) is future work, not a gap in this example — see the {@code QUANTITY} note
* above for the same boundary from the data side.
*/
public final class Trade {

/**
* Never constructed. A {@code Trade} instance would be exactly the per-entity object this
* example exists to prove unnecessary — a million of them is the anti-thesis, not a
* convenience. Thrown even through reflection with {@code setAccessible(true)}, so the
* guarantee is "impossible," not merely "discouraged by visibility."
*/
private Trade() {
throw new AssertionError(
"a Trade is never materialized — 1,000,000 logical trades are one native lane set,"
+ " not 1,000,000 objects. There is no Trade instance to construct.");
}

/** Venue identifier — {@link Pattern#CLASS}'s lane, read under a domain name. */
public static final U32Field VENUE =
new U32Field("venue", LaneId.of(1), Ordinal.of(0));

/** Price tick — {@link Pattern#VALUE}'s lane, read under a domain name. See the class doc for
* why this is a signed, fictional cents-scale tick rather than a real currency amount. */
public static final I32Field PRICE =
new I32Field("price", LaneId.of(2), Ordinal.of(1));

/**
* A venue id used throughout this example's predicates. {@code 7} is the fixture class the
* rest of this repo's test corpus already exercises, so {@code Trade.VENUE.eq(Trade.XETRA)}
* selects the same, already-measured ~6% (1-in-16) fraction of rows as {@code
* Pattern.CLASS.eq(7)} does elsewhere.
*/
public static final int XETRA = 7;

/** A second, distinct venue id, for predicates that need two venues to compare or exclude. */
public static final int NASDAQ = 3;

/** Every field this schema defines, in schema order. See the class doc for why there is no
* {@code QUANTITY} entry yet. */
public static final List<Field> FIELDS = List.of(VENUE, PRICE);
}
84 changes: 84 additions & 0 deletions consumers/trades/src/main/java/com/adaworldapi/trades/World.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
package com.adaworldapi.trades;

import com.adaworldapi.lancegraph.NativePattern;
import com.adaworldapi.lancegraph.View;

/**
* The entry point for the "One Billion Objects. Zero Objects." poster example.
*
* <h2>The claim</h2>
*
* <p>A million (or a billion, given enough rows in the fixture) logical trades never become that
* many Java objects. {@link #open} opens one native lane set and hands back one lazy {@link View}
* — the same fluent {@code where}/{@code count}/{@code sumOf} machinery {@link
* com.adaworldapi.lancegraph.NativePattern} already provides, addressed through domain names
* ({@link Trade#VENUE}, {@link Trade#PRICE}) instead of schema-generic ones ({@code
* Pattern.CLASS}, {@code Pattern.VALUE}).
*
* <pre>{@code
* try (var pattern = NativePattern.open(1_000_000, World.DEFAULT_SEED)) {
* long n = World.viewOf(pattern)
* .where(Trade.VENUE.eq(Trade.XETRA))
* .where(Trade.PRICE.gt(100))
* .count();
* }
* }</pre>
*
* <h2>Zero membrane growth — the iron rule</h2>
*
* <p>This class adds no ABI symbol, no native call, no query engine. It consumes {@code
* com.adaworldapi.lancegraph} exactly as a third-party developer would: {@link NativePattern#open}
* to obtain rows, {@link NativePattern#view()} to obtain the lazy description, {@link View#where}
* to narrow it. If a future domain example needs a capability the public API does not expose, the
* fix is a change to the substrate plan, never a shortcut taken here.
*
* <h2>Lifetime, stated honestly</h2>
*
* <p>A {@link View} does not own the rows it describes — its parent {@link NativePattern} does,
* and the parent must outlive every view (and every terminal operation) derived from it, exactly
* as {@link NativePattern}'s own class documentation specifies. {@link View#source()} is how a
* caller gets back to the resource that must eventually be closed.
*
* <p>{@link #open(long, long)} returns a {@code View} rather than the {@code NativePattern}
* itself, matching the wave's domain-facade shape ("returns the existing lazy {@code View}
* machinery under domain names") — but that means the resource is reachable only through {@link
* View#source()}, which is why every example in this class's Javadoc closes via {@code
* World.open(...).source().close()} (or, more idiomatically, by holding the pattern in the
* try-with-resources and deriving the view from it, as shown above). A caller who wants the
* cleaner try-with-resources shape should open the {@link NativePattern} directly and call {@link
* NativePattern#view()} — {@link #open} exists for the one-line poster snippet, not to hide the
* resource.
*/
public final class World {

private World() {}

/** The default seed, re-exported from {@link NativePattern#DEFAULT_SEED} so a caller need not
* import the core package just to name it. */
public static final long DEFAULT_SEED = NativePattern.DEFAULT_SEED;

/**
* Open {@code nRows} trades generated deterministically from {@link #DEFAULT_SEED} and return
* their lazy view.
*
* <p>See the class documentation for the lifetime note: the returned view's underlying
* resource is reachable, and must eventually be closed, via {@link View#source()}.
*/
public static View open(long nRows) {
return open(nRows, DEFAULT_SEED);
}

/**
* Open {@code nRows} trades generated deterministically from {@code seed} and return their
* lazy view.
*
* <p>Building and narrowing the returned view crosses the native membrane zero times, exactly
* as {@link View}'s own documentation specifies — only a terminal operation ({@code count()},
* {@code sumOf(...)}, {@code select()}) executes.
*
* @throws IllegalArgumentException if {@code nRows} is negative
*/
public static View open(long nRows, long seed) {
return NativePattern.open(nRows, seed).view();
}
}
Loading