Skip to content

Realm production A2a: Set bucket contract, array element storage, realm-diff gate - #13793

Merged
proggeramlug merged 8 commits into
mainfrom
wrt3p
Nov 2, 2026
Merged

proggeramlug merged 8 commits into
mainfrom
wrt3p

Conversation

@proggeramlug

@proggeramlug proggeramlug commented Nov 2, 2026 •

Copy link
Copy Markdown
Contributor

Part of the realm production switch (DESIGN §3.2). This PR (A2a) carries items 2, 3 (storage half) and 4's gate script, references and test-only
input. Items 1 (owners), 3 (member order), the R-restricted mode and the CI step follow in A2b (its design is
settled; the build phases run on the same branch and open their own PR).

Item 1: every native cell has exactly one owner

Placeholder: the WRT3p-A2-design phase settles the owner facts (every owner declared at the birth; the 20
unresolved .default namespaces root-caused) and the test definition. The owners test currently in this branch
(perry-runtime-manifest/src/realm_owners.rs) passes on the present facts and is rewritten by that phase.

Item 2: one Set index sizing (perry_abi::OwnedSetIndex::from_insertions)

  • OwnedSetIndex::from_insertions(hashes) is the one place that sizes and fills a Set index: None until the
    insertion that crosses SMALL_SET_SCAN_MAX, then the index built from the insertions in order.
  • The runtime's threshold crossing (set/index.rs::insert_value) builds through it over the live elements; the
    realm image's Set emitter (realm_image/sets.rs) and the runtime build script call the same function.
    Compaction (rebuild_index) is unchanged.
  • Test every_image_set_index_equals_the_runtime_add_path: for every Set declaration with Set storage in the
    manifest, an empty Set filled through js_set_add equals from_insertions bucket for bucket, live and
    occupied counts included; a Set of at most 8 has no index. Sabotage (post-crossing slot + 1 in
    from_insertions) fails it: node:process.allowedNodeEnvironmentFlags: buckets.

Item 3 (storage): static array elements are array storage

  • RealmStorageFacts::Array { elements } (kind = "array"). The producer writes the elements of every static
    array birth there: the three elements_source arrays (node:http.METHODS, node:module.builtinModules,
    node:module.Module.wrapper) and the 44 util.inspect.colors pairs. The holder keeps length and its named
    properties; its own_key_order lists those (index keys come first by the array own-keys rule).
  • The array emitter (ArrayParts::from_cell) reads elements only from storage; an index key among the holder's
    properties is an error (a second home). Integrity stays in the header, as before.
  • Manifest delta, main 61f513a vs this branch: 47 declarations change, every one only by moving its index
    properties into array storage with the same values in the same order (checked by script over the full
    manifest); no declaration added or removed.

Item 3 (member order)

Placeholder: the WRT3p-A2-design phase decides the one home of native namespace member order (the
declaration; module_keys tables derived from it where the runtime reads them) and corrects DESIGN §3.2 item 7.

Item 4: the realm-diff gate in CI

  • PERRY_REALM_REACH_NAMES=<names.json>: a test-only compiler-driver input, read once in run_pipeline.rs
    where reach is computed, inert when unset. It sets R to exactly the file's names, top dropped
    (RealmReach::restrict_to), then closes it under the birth relation, and prints
    [realm-reach-names] <path> <n>.
  • scripts/realm_diff_gate.py: R-restricted mode for hello, lad-04-classes, lad-07-json
    (realm-dumps/programs/): the witness's R must equal the checked-in <p>.names.json; the dumper
    (scripts/realm_dump.ts) is compiled with the input and the gate asserts it took effect (the printed line names
    this file and count, and the dumper's R has no top reason and is exactly those names), so a dumper built
    without it fails by construction. Given a realm-dump.names file, the dumper walks only the roots in R; its
    dump restricted to the names must equal <p>.jsonl (main's full walk restricted to the same names). Full
    mode: the dumper compiled plainly (R is top) must equal full.jsonl. Every dump runs as
    /tmp/perry-realm-diff/realm-dump in a fixed environment (execPath, argv and module paths are realm values).
    --self-test feeds the plain dumper's compile log to the restricted check, which must refuse it.
  • PERRY_REALM_REACH_NAMES is keyed in compile_env (by path); the gate compiles with PERRY_NO_CACHE=1.
  • References are main's dumps (main populates every cell), regenerated only by
    PERRY_RUNTIME_DIR=<main>/target/release python3 scripts/realm_diff_gate.py --perry <main perry> --regenerate.
  • Open: the R-restricted mode does not pass yet, so the CI step is not in this branch (kept as
    /root/WRT/tmp/a2/ci-step.patch: "Realm diff (full and R-restricted, test-only PERRY_REALM_REACH_NAMES)" in
    test.yml, Linux, after "Realm link graph"). The dumper compiled with hello's R aborts at startup:
    Perry internal error: runtime layout EVENT_EMITTER_PROTOTYPE is born, but the program's realm does not reach it.
    Its own static imports (57 node:* namespaces) and intrinsic seeds need cells outside the witness's R. DESIGN
    §3.2 says R = the file's names united with the dumper's own named builtins, but a top program's scan is
    closed to the whole catalog before the knob runs, so its own names are gone (RealmReach::close). Decision
    pending (see the report). Ruling (coordinator): (a). The compiler keeps a top program's own pre-closure
    names; the test-only input unites the file's names with them before closure; the gate asserts that the dumper's R
    is exactly that union, that no cell outside the union is born, and that the dump restricted to the file's names
    equals the reference. It lands in A2b together with the CI step, before the owner changes it must guard.
  • The agreement check between the declared list and the table stays as it is on main; the design phase decides
    its one home.

Verification

Check Result
perry-runtime-manifest lib (producer, owners, storage) 90 passed / 0 failed (main 61f513a: 85/3)
codegen --features target-wasi realm_image + realm_plan 36 / 0
HIR realm_reach 15 / 0 (incl. restricting_drops_top_and_closes_the_given_names)
runtime Set tests (set::, every_image_set, manifest_set), debug, 1 thread 125 / 0
perry compile_env (env audit) 3 / 0
Python scripts/realm_*_tests.py 84 OK
Manifest delta vs main 47 declarations, all index properties moved to array storage, same values and order
realm-diff gate full mode, candidate vs main reference equal, 3069 cells, byte-identical; main reproduces its own reference
realm-diff gate --self-test plain dumper refused
realm-diff gate R-restricted (hello, lad-04, lad-07) FAIL: dumper aborts (open, above)
rustfmt --check on touched files clean
warnings (cargo check of the 6 touched crates) 0 Rust warnings
lint/inventory gates A/B (94 commands, base 61f513a) 0 rc differences; 7 output differences: env-parser count +1 (PERRY_REALM_REACH_NAMES), head SHA, set.rs line numbers of main's findings, test timings, a UDP-peer test timing out identically in both
startup gate, fixed inputs, exact Ir (hello / lad-01 / lad-04 / lad-07) 821,184 / 875,987 / 16,726,578 / 16,661,323 on both arms: delta 0, 0 functions changed
startup gate, plain inputs hello and lad-01 delta 0; lad-04 and lad-07 nondeterministic on main itself (RandomState / AHash inserts), no comparison
.text / binary .text +896 bytes (runtime Set threshold crossing through from_insertions), binary -80 to -88 bytes; link padding converged
git merge-tree --write-tree origin/main wrt3p (b585330) clean

Failures that were main's

Ralph Küpper added 7 commits November 2, 2026 22:23
None until the insertion that crosses SMALL_SET_SCAN_MAX, then the index built from the insertions in order. The runtime's threshold crossing and the realm image's Set emitter both call it.
…ertions

The generated test every_image_set_index_equals_the_runtime_add_path fills an empty Set through js_set_add for every Set declaration with Set storage and compares it with from_insertions bucket for bucket, live and occupied counts included. Compaction keeps its own sizing.
The emitter no longer sizes a Set index itself.
Fails by name on a cell with no owner or with two.
The producer writes the elements of every static array birth (the elements_source arrays and the util.inspect.colors pairs) as storage of kind array; the holder keeps length and its named properties. The array emitter reads elements only from storage, and an index key among the holder's properties is an error.
Since #13666 a null [[Prototype]] is the shape's identity, not header bit 0x40; the derivation emits no such bit and three producer tests still pinned it. They now assert the birth facts: null_prototype and the absent prototype with the header word of the ordinary birth of the same members, callable as the layout's header bit, the frozen word from the ABI constants. The GcHeader bit table lists bit 6 as free.
PERRY_REALM_REACH_NAMES is a test-only compiler-driver input (keyed by path in compile_env): R becomes the file's names with top dropped, closed under the birth relation, and the driver prints the file it used. scripts/realm_diff_gate.py compares the realm dumper with main's checked-in dumps in realm-dumps/, byte for byte: plainly built (full) and restricted to the reach of hello, lad-04-classes and lad-07-json, asserting the input took effect. A names file next to the dumper limits the roots it walks. References change only through --regenerate on main. The restricted mode does not pass yet: the dumper's own imports birth layouts outside the witness R, so it is not wired into CI in this commit.
@coderabbitai

coderabbitai Bot commented Nov 2, 2026 •

Copy link
Copy Markdown

Review in Change Stack →

Caution

Review failed

The pull request is closed.

  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

Share

@proggeramlug
proggeramlug marked this pull request as ready for review November 2, 2026 22:36
@proggeramlug
proggeramlug merged commit 558327e into main Nov 2, 2026
89 of 90 checks passed
@proggeramlug
proggeramlug deleted the wrt3p branch November 2, 2026 22:37
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