Skip to content

Read retained node liveness without whole-state materialization#757

Merged
flyingrobots merged 4 commits into
mainfrom
v19-runtime-materialization-handle
Jul 17, 2026
Merged

Read retained node liveness without whole-state materialization#757
flyingrobots merged 4 commits into
mainfrom
v19-runtime-materialization-handle

Conversation

@flyingrobots

Copy link
Copy Markdown
Member

Summary

  • add a bounded internal MaterializationReadPort and trie-backed reader for independently retained node-liveness roots
  • route RuntimeHost.hasNode() through operation-scoped retained materialization acquisitions before the explicit legacy full-state fallback
  • prove the warm exact-coordinate path survives aggressive Git pruning without replaying patches, publishing a whole state, or populating _cachedState
  • document the first handle-first compatibility read and the remaining full-materialization paths

Issue scope

This advances #738 under the #734 storage-ownership campaign. Both issues remain open: cold retained-handle misses and graph reads other than exact node liveness can still reconstruct a complete WarpState.

Invariants

  • git-warp does not create, pin, cache, or prune CAS objects directly
  • every materialization acquisition is released on success and best-effort released while preserving the primary read failure
  • bounded reads open only the retained node-liveness trie with a 256-page operation-local cache
  • absence of the bounded reader or an unavailable root selects the existing compatibility fallback explicitly
  • no application-level package export changes

Source evidence

  • bounded retained-root port: [cite: src/ports/MaterializationReadPort.ts#3-5@56ed3ce16acd36cada7446c4d3dfcd8b0d036f30]
  • operation-local trie cursor and bounded page residency: [cite: src/domain/materialization/TrieMaterializationReader.ts#10-43@56ed3ce16acd36cada7446c4d3dfcd8b0d036f30]
  • acquisition, bounded read, and release lifecycle: [cite: src/domain/services/controllers/MaterializeLiveStrategy.ts#72-86@56ed3ce16acd36cada7446c4d3dfcd8b0d036f30]
  • explicit compatibility fallback: [cite: src/domain/services/controllers/QueryReads.ts#124-132@56ed3ce16acd36cada7446c4d3dfcd8b0d036f30]
  • automatic trie-reader construction: [cite: src/domain/warp/RuntimeHostBoot.ts#357-361@56ed3ce16acd36cada7446c4d3dfcd8b0d036f30]
  • real-Git prune and warm-read proof: [cite: test/integration/api/materialization.retainedResume.test.ts#76-108@56ed3ce16acd36cada7446c4d3dfcd8b0d036f30]

Validation

  • npm run lint
  • npm run typecheck
  • npm run typecheck:policy
  • npm run typecheck:surface (0 errors, 0 warnings)
  • npm run build && npm run typecheck:consumer
  • npm run lint:semgrep
  • npm run lint:sludge
  • npm run test:local (7,031 passed, 2 skipped)
  • focused unit and real-Git integration tests
  • full IRONCLAD M9 pre-push firewall

Structural audit note

Graft reports the internal MaterializeDeps and MaterializePersistence declarations as removed and re-added because they moved to a dedicated source-size-compliant module and are re-exported from their original module. The package publication-surface validator reports zero changes, errors, or warnings.

@coderabbitai

coderabbitai Bot commented Jul 17, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

You’ve reached a temporary PR review limit under our Fair Usage Limits Policy.

Your recent review volume is higher than typical usage, so adaptive limits are currently applied.

Next review available in: 20 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 516a3009-38d0-4a08-800e-38ad39354af3

📥 Commits

Reviewing files that changed from the base of the PR and between 56ed3ce and 4a1ae43.

📒 Files selected for processing (5)
  • docs/topics/cas-first-memoized-materialization.md
  • src/domain/materialization/TrieMaterializationReader.ts
  • src/domain/warp/RuntimeHostBoot.ts
  • test/unit/domain/WarpCore.stateSessionAutoConstruct.test.ts
  • test/unit/domain/materialization/TrieMaterializationReader.test.ts
📝 Walkthrough

Walkthrough

Adds bounded trie-backed node-liveness reads for retained materialization roots, wires them through runtime and query layers, preserves fallback to full state materialization, and adds unit, controller, integration, and documentation coverage.

Changes

Retained node-liveness reads

Layer / File(s) Summary
Bounded trie reader and runtime wiring
src/ports/MaterializationReadPort.ts, src/domain/materialization/TrieMaterializationReader.ts, src/domain/warp/RuntimeHostBoot.ts, src/domain/services/controllers/MaterializeDeps.ts
Defines the read contract, performs bounded trie membership checks, and constructs the reader from trie storage.
Live presence resolution and query integration
src/domain/RuntimeHost.ts, src/domain/services/controllers/MaterializeController.ts, src/domain/services/controllers/MaterializeLiveStrategy.ts, src/domain/services/controllers/QueryReads.ts, src/domain/services/controllers/ReadGraphHost.ts
Resolves retained node roots, releases acquisitions, exposes tri-state presence, and bypasses whole-state reads when presence is available.
Validation and documentation
test/unit/domain/materialization/TrieMaterializationReader.test.ts, test/unit/domain/services/controllers/MaterializeController.liveNodeRead.test.ts, test/unit/domain/services/controllers/QueryController.test.ts, test/integration/api/materialization.retainedResume.test.ts, docs/topics/cas-first-memoized-materialization.md
Covers bounded reads, root statuses, cleanup failures, fallback behavior, retained-resume integration, and current handle-first scope.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Possibly related issues

Possibly related PRs

  • git-stunts/git-warp#751 — Provides the retained CAS materialization-root model consumed by these node-liveness reads.

Sequence Diagram(s)

sequenceDiagram
  participant QueryReads
  participant RuntimeHost
  participant MaterializeController
  participant MaterializeLiveStrategy
  participant TrieMaterializationReader
  QueryReads->>RuntimeHost: query node presence
  RuntimeHost->>MaterializeController: readLiveNodePresence(nodeId)
  MaterializeController->>MaterializeLiveStrategy: readNodePresence(nodeId)
  MaterializeLiveStrategy->>TrieMaterializationReader: hasNode(nodeAliveHandle, nodeId)
  TrieMaterializationReader-->>QueryReads: boolean or null
Loading

Poem

A rabbit hops through roots retained,
With bounded pages neatly contained.
The node says “yes,” or softly “no,”
Then handles release before we go.
Whole states wait for colder trails—
While trie-leaf whispers ride the rails.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 16.67% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly captures the main change: reading retained node liveness without whole-state materialization.
Description check ✅ Passed The description is mostly complete, covering summary, issue context, and test plan/validation, though the ADR checks section is omitted.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/domain/materialization/TrieMaterializationReader.ts`:
- Around line 18-27: Update the TrieMaterializationReader constructor to
validate options, store, codec, and optional geometry using the domain’s
established validation errors before accessing their properties, then call
Object.freeze(this) after initialization. Preserve the default
TrieGeometry.default16way() behavior and use instanceof-based dispatch where
runtime type selection is required.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 97e7550d-9194-4985-a095-5a20375f05e8

📥 Commits

Reviewing files that changed from the base of the PR and between a97d03c and 56ed3ce.

📒 Files selected for processing (14)
  • docs/topics/cas-first-memoized-materialization.md
  • src/domain/RuntimeHost.ts
  • src/domain/materialization/TrieMaterializationReader.ts
  • src/domain/services/controllers/MaterializeController.ts
  • src/domain/services/controllers/MaterializeDeps.ts
  • src/domain/services/controllers/MaterializeLiveStrategy.ts
  • src/domain/services/controllers/QueryReads.ts
  • src/domain/services/controllers/ReadGraphHost.ts
  • src/domain/warp/RuntimeHostBoot.ts
  • src/ports/MaterializationReadPort.ts
  • test/integration/api/materialization.retainedResume.test.ts
  • test/unit/domain/materialization/TrieMaterializationReader.test.ts
  • test/unit/domain/services/controllers/MaterializeController.liveNodeRead.test.ts
  • test/unit/domain/services/controllers/QueryController.test.ts
📜 Review details
⏰ Context from checks skipped due to timeout. (3)
  • GitHub Check: preflight
  • GitHub Check: test-node (22)
  • GitHub Check: coverage-threshold
🧰 Additional context used
📓 Path-based instructions (5)
src/**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (AGENTS.md)

src/**/*.{ts,tsx,js,jsx}: Do not introduce any, as any, as unknown as, unknown (outside adapters), Record<string, unknown> (outside adapters), *Like placeholder types, JSON.parse/JSON.stringify (outside adapters), fetch (outside adapters), process.env (outside adapters), @ts-ignore, or z.any() in core code; use validated boundary models and ports instead.
Use constructor-injected ports for external capabilities; do not rely on ambient dependencies for I/O, clocks, persistence, or entropy.
Do not create utils.ts, helpers.ts, misc.ts, or common.ts; name files after the actual concept they model.
Prefer one file per class, type, or object; if a file accumulates peer concepts, split it.
Keep helper corridors, fake shape trust, transitional duplication, and compile-time theater out of the codebase; runtime-honest TypeScript must reflect actual behavior.
No enum usage; prefer runtime-backed domain forms and unions.
Do not use boolean trap parameters; prefer named option objects or separate methods.
Avoid magic strings or numbers when a named constant should exist.
Keep domain bytes as Uint8Array; Buffer belongs in infrastructure adapters.

Files:

  • src/ports/MaterializationReadPort.ts
  • src/domain/services/controllers/MaterializeDeps.ts
  • src/domain/services/controllers/ReadGraphHost.ts
  • src/domain/materialization/TrieMaterializationReader.ts
  • src/domain/services/controllers/QueryReads.ts
  • src/domain/RuntimeHost.ts
  • src/domain/warp/RuntimeHostBoot.ts
  • src/domain/services/controllers/MaterializeController.ts
  • src/domain/services/controllers/MaterializeLiveStrategy.ts
src/ports/**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (AGENTS.md)

In src/ports/**, do not import Node built-ins or src/infrastructure/**; ports must stay abstract and depend only on boundary-safe types.

Files:

  • src/ports/MaterializationReadPort.ts
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{ts,tsx,js,jsx}: Do not use direct imports from src/infrastructure/** in src/domain/** or src/ports/**; depend on a port instead.
Do not use direct Node built-ins in src/domain/** or src/ports/**; use a port instead.

Files:

  • src/ports/MaterializationReadPort.ts
  • test/unit/domain/materialization/TrieMaterializationReader.test.ts
  • src/domain/services/controllers/MaterializeDeps.ts
  • src/domain/services/controllers/ReadGraphHost.ts
  • src/domain/materialization/TrieMaterializationReader.ts
  • test/unit/domain/services/controllers/QueryController.test.ts
  • src/domain/services/controllers/QueryReads.ts
  • src/domain/RuntimeHost.ts
  • test/unit/domain/services/controllers/MaterializeController.liveNodeRead.test.ts
  • test/integration/api/materialization.retainedResume.test.ts
  • src/domain/warp/RuntimeHostBoot.ts
  • src/domain/services/controllers/MaterializeController.ts
  • src/domain/services/controllers/MaterializeLiveStrategy.ts
src/domain/**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (AGENTS.md)

src/domain/**/*.{ts,tsx,js,jsx}: In src/domain/**, do not use Date.now(), new Date(), Date(), performance.now(), Math.random(), crypto.randomUUID(), crypto.getRandomValues(), setTimeout, setInterval, raw new Error(...)/new TypeError(...), or direct imports from Node built-ins; time, entropy, and external capabilities must enter through ports or parameters, and domain errors should extend WarpError.
Construct domain objects only in core when doing so establishes validated runtime truth; do not build infrastructure adapters, host APIs, persistence implementations, wall clocks, or entropy sources inside core.
Prefer discriminated unions and explicit result types instead of boolean-flag bags, and model expected failures as return values rather than exceptions.
src/domain/ must not import host APIs or Node-specific globals; hexagonal architecture boundaries are mandatory.
Domain code must not use the wall clock directly; time must enter through a port or parameter.

Files:

  • src/domain/services/controllers/MaterializeDeps.ts
  • src/domain/services/controllers/ReadGraphHost.ts
  • src/domain/materialization/TrieMaterializationReader.ts
  • src/domain/services/controllers/QueryReads.ts
  • src/domain/RuntimeHost.ts
  • src/domain/warp/RuntimeHostBoot.ts
  • src/domain/services/controllers/MaterializeController.ts
  • src/domain/services/controllers/MaterializeLiveStrategy.ts
src/domain/**/!(*.test).{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (AGENTS.md)

Use explicit domain concepts with validated constructors, Object.freeze, and instanceof dispatch; domain objects should be runtime-backed nouns, not ad hoc shape bags.

Files:

  • src/domain/services/controllers/MaterializeDeps.ts
  • src/domain/services/controllers/ReadGraphHost.ts
  • src/domain/materialization/TrieMaterializationReader.ts
  • src/domain/services/controllers/QueryReads.ts
  • src/domain/RuntimeHost.ts
  • src/domain/warp/RuntimeHostBoot.ts
  • src/domain/services/controllers/MaterializeController.ts
  • src/domain/services/controllers/MaterializeLiveStrategy.ts
🪛 ast-grep (0.44.1)
test/integration/api/materialization.retainedResume.test.ts

[warning] Importing child_process exposes a command-execution surface; ensure any command/argument built from input is validated, and prefer execFile/spawn with an argument array over exec.
Context: import { execFile } from 'node:child_process';
Note: [CWE-78] Improper Neutralization of Special Elements used in an OS Command ('OS Command Injection').

(detect-child-process-typescript)


[warning] Importing child_process exposes a command-execution surface; ensure any command/argument built from input is validated, and prefer execFile/spawn with an argument array over exec.
Context: import { execFile } from 'node:child_process';
Note: [CWE-78] Improper Neutralization of Special Elements used in an OS Command ('OS Command Injection').

(detect-child-process-typescript)


[warning] Importing child_process exposes a command-execution surface; ensure any command/argument built from input is validated, and prefer execFile/spawn with an argument array over exec.
Context: import { execFile } from 'node:child_process';
Note: [CWE-78] Improper Neutralization of Special Elements used in an OS Command ('OS Command Injection').

(detect-child-process-typescript)


[warning] Importing child_process exposes a command-execution surface; ensure any command/argument built from input is validated, and prefer execFile/spawn with an argument array over exec.
Context: import { execFile } from 'node:child_process';
Note: [CWE-78] Improper Neutralization of Special Elements used in an OS Command ('OS Command Injection').

(detect-child-process-typescript)

🔇 Additional comments (14)
src/ports/MaterializationReadPort.ts (1)

1-6: LGTM!

src/domain/materialization/TrieMaterializationReader.ts (1)

1-16: LGTM!

Also applies to: 29-45

src/domain/services/controllers/MaterializeDeps.ts (1)

1-30: LGTM!

test/unit/domain/materialization/TrieMaterializationReader.test.ts (1)

1-40: LGTM!

src/domain/services/controllers/MaterializeController.ts (1)

55-57: LGTM!

Also applies to: 79-79, 164-166

src/domain/services/controllers/MaterializeLiveStrategy.ts (1)

16-17: LGTM!

Also applies to: 72-88, 349-368

test/unit/domain/services/controllers/MaterializeController.liveNodeRead.test.ts (1)

1-260: LGTM!

src/domain/warp/RuntimeHostBoot.ts (1)

8-8: LGTM!

Also applies to: 38-38, 76-76, 340-340, 357-362, 391-393

src/domain/RuntimeHost.ts (1)

405-407: LGTM!

Also applies to: 428-431

src/domain/services/controllers/ReadGraphHost.ts (1)

31-31: LGTM!

src/domain/services/controllers/QueryReads.ts (1)

125-130: LGTM!

test/integration/api/materialization.retainedResume.test.ts (1)

1-2: LGTM!

Also applies to: 23-24, 75-119, 153-160

test/unit/domain/services/controllers/QueryController.test.ts (1)

121-121: LGTM!

Also applies to: 184-196

docs/topics/cas-first-memoized-materialization.md (1)

105-112: LGTM!

Also applies to: 174-176

Comment thread src/domain/materialization/TrieMaterializationReader.ts
@github-actions

Copy link
Copy Markdown

Release Preflight

  • package version: 18.2.1
  • prerelease: false
  • npm dist-tag on release: latest
  • npm pack dry-run: passed
  • jsr publish dry-run: passed

If this PR is from a release/* branch and merges to main, Main Push Release Branch Check will run final preflight and create v18.2.1. A maintainer who is a JSR @git-stunts scope member must then dispatch the Release workflow manually.

@flyingrobots

Copy link
Copy Markdown
Member Author

Self-Code Review

@codex please confirm the review disposition below.

Severity Count Disposition
Critical 0 None found
High 0 None found
Medium 1 Fixed in 3cdd71a91137c60c86ea323d50d4acffd226c88a
Low 0 None found
File Infraction Evidence Mitigation
src/domain/warp/RuntimeHostBoot.ts Medium: authority/encoding mismatch. An explicitly injected openStateSession could write roots using a custom store, geometry, or encoding while boot still installed the default trie reader. A subsequent bounded hasNode() could interpret those roots through the wrong contract instead of selecting the compatibility fallback. Corrected ownership boundary: [cite: src/domain/warp/RuntimeHostBoot.ts#345-363@3cdd71a91137c60c86ea323d50d4acffd226c88a]. Regression assertion: [cite: test/unit/domain/WarpCore.stateSessionAutoConstruct.test.ts#76-94@3cdd71a91137c60c86ea323d50d4acffd226c88a]. Applied prompt: “Pair TrieMaterializationReader only with the built-in state-session opener that shares its store, codec, and geometry; leave custom opener roots under custom ownership and force the explicit legacy fallback unless a matching reader is supplied.”

Review conclusion

After the correction, I found no remaining correctness, lifecycle, public-surface, or Markdown violations in origin/main...HEAD. The source-level Graft export report still models the internal MaterializeDeps relocation as remove/add, but the original import path re-exports both types and typecheck:surface reports 0 errors and 0 warnings; this is not a package API break.

Verification

  • clean worktree and fresh origin/main before review
  • focused suite: 5 files, 88 tests passed
  • npm run typecheck:src
  • npm run typecheck:test
  • npm run lint
  • post-fix IRONCLAD M9: all static gates and 7,031 stable tests passed, 2 skipped

@github-actions

Copy link
Copy Markdown

Release Preflight

  • package version: 18.2.1
  • prerelease: false
  • npm dist-tag on release: latest
  • npm pack dry-run: passed
  • jsr publish dry-run: passed

If this PR is from a release/* branch and merges to main, Main Push Release Branch Check will run final preflight and create v18.2.1. A maintainer who is a JSR @git-stunts scope member must then dispatch the Release workflow manually.

coderabbitai[bot]
coderabbitai Bot previously approved these changes Jul 17, 2026
@github-actions

Copy link
Copy Markdown

Release Preflight

  • package version: 18.2.1
  • prerelease: false
  • npm dist-tag on release: latest
  • npm pack dry-run: passed
  • jsr publish dry-run: passed

If this PR is from a release/* branch and merges to main, Main Push Release Branch Check will run final preflight and create v18.2.1. A maintainer who is a JSR @git-stunts scope member must then dispatch the Release workflow manually.

@flyingrobots

Copy link
Copy Markdown
Member Author

Independent Code Lawyer Review

@codex please confirm the independent review disposition.

Severity Count Disposition
P0 / Critical 0 None found
P1 / High 0 None found
P2 / Medium 0 None found
P3 / Low 1 Fixed in 4a1ae43e87e2e4397cd77a297fd87e8ddb493531
File Finding Mitigation
docs/topics/cas-first-memoized-materialization.md The documentation described RuntimeHost.hasNode() as consuming retained roots without qualifying that the default reader is installed only with the built-in trie-backed state session. A supported custom session opener intentionally owns its root encoding and selects compatibility fallback, so the unconditional prose overstated availability. Qualified the fast-path contract and limitation list around the built-in session/reader pair, and documented custom-opener fallback. [cite: docs/topics/cas-first-memoized-materialization.md#103-116@4a1ae43e87e2e4397cd77a297fd87e8ddb493531] [cite: docs/topics/cas-first-memoized-materialization.md#175-182@4a1ae43e87e2e4397cd77a297fd87e8ddb493531]

Residual risk

Concurrent frontier advancement during one exact membership operation and deliberately corrupted retained trie pages are not newly exercised by this slice. The operation snapshots the frontier before acquisition, and existing trie readers fail closed on malformed pages; these remain bounded follow-up test opportunities rather than merge blockers.

Verification

  • independent diff review against origin/main
  • git diff --check
  • Markdownlint and Prettier
  • docs topology and source-backed-reference gates
  • post-fix IRONCLAD M9: all static gates and 7,031 stable tests passed, 2 skipped

@github-actions

Copy link
Copy Markdown

Release Preflight

  • package version: 18.2.1
  • prerelease: false
  • npm dist-tag on release: latest
  • npm pack dry-run: passed
  • jsr publish dry-run: passed

If this PR is from a release/* branch and merges to main, Main Push Release Branch Check will run final preflight and create v18.2.1. A maintainer who is a JSR @git-stunts scope member must then dispatch the Release workflow manually.

@flyingrobots
flyingrobots merged commit 7c5e7e2 into main Jul 17, 2026
16 of 17 checks passed
@flyingrobots
flyingrobots deleted the v19-runtime-materialization-handle branch July 17, 2026 16:38
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