-
Notifications
You must be signed in to change notification settings - Fork 0
feat: complete AUTOPILOT milestone (v7.1.0) — Kill the Materialize Tax #7
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
Replace M1-M3-TASKS.md (all complete) and M4-M6-TASKS.md with a single ROADMAP.md that combines the ideas roadmap with unfinished milestone tasks. 52 tasks across 9 milestones (AUTOPILOT through ECHO), each with user stories, acceptance criteria, test plans, and dependency tracking. Add scripts/roadmap.js for managing task lifecycle: close (with status propagation), open, status, and show commands. The script maintains an ASCII DAG and per-task status fields in ROADMAP.md.
…nuclear ESLint Add `materialize` CLI subcommand that materializes + checkpoints all graphs (or a single --graph). Add `warp.autoMaterialize` git config support to the post-merge hook: when true, the hook runs `git warp materialize` automatically after pulls that change warp refs. Upgrade ESLint to typescript-eslint with typed linting. Key rules added: - no-floating-promises: catches unawaited Promise return values - no-misused-promises: catches Promises in boolean conditionals - await-thenable: catches await on non-Promise values - require-await: catches dead async keywords Fix missing `await` bugs in production code caught by the new rules: - QueryBuilder.run() called getNodes()/getNodeProps() without await - LogicalTraversal._prepare() used hasNode() in if-check without await - Fix incorrect JSDoc @returns on async methods (string[] vs Promise<string[]>) Fix missing `await` in test files for async query API methods.
- Remove `@typescript-eslint/no-base-to-string` disable — `remote` is
already a string at that point, so `String(remote)` was redundant.
- Remove `@typescript-eslint/require-await` disable — the outer
createServer handler never awaited; the async work lives in the
`req.on('end')` callback. Drop `async` from the outer handler.
…CKPT/3, AP/HOOK/1, AP/HOOK/2 Add comprehensive test suites proving the remaining AUTOPILOT features work end-to-end: - AP/INVAL/3: Writer.commitPatch() triggers eager re-materialize (10 tests) - AP/LAZY/2: query methods auto-materialize when state is null/dirty (46 tests) - AP/CKPT/3: materialize() auto-checkpoints when patch threshold exceeded (14 tests) - AP/HOOK/1: post-merge hook script verified and roadmap closed - AP/HOOK/2: add post-merge hook to scripts/hooks/ for npm install activation AUTOPILOT (v7.1.0) is now 10/10 tasks closed.
|
Warning Rate limit exceeded
⌛ How to resolve this issue?After the wait time has elapsed, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout. Please see our FAQ for further information. 📝 WalkthroughWalkthroughAdded extensive documentation and roadmap files; introduced Git hook management (installer, scripts, CLI commands) and auto-materialize/auto-checkpoint workflows; converted several synchronous APIs to async with Promise returns; added many unit tests and TypeScript/ESLint tooling, plus multiple small doc/JSDoc and util refactors. 📝 WalkthroughAdded extensive documentation and roadmap files; introduced Git hook management (installer, scripts, CLI commands) and auto-materialize/auto-checkpoint workflows; converted several synchronous APIs to async with Promise returns; added many unit tests and TypeScript/ESLint tooling, plus multiple small doc/JSDoc and util refactors. Changes
Sequence Diagram(s)sequenceDiagram
participant User as "User"
participant CLI as "warp-graph CLI"
participant HookInst as "HookInstaller"
participant FS as "Repo FS / Git hooks dir"
participant GitCfg as "git config"
User->>CLI: run `install-hooks` (optionally --force)
CLI->>HookInst: getHookStatus(repoPath)
HookInst->>FS: read existing hook file
FS-->>HookInst: return content / null
HookInst->>CLI: classifyExistingHook(content)
CLI->>User: prompt strategy (interactive) / decide strategy
User-->>CLI: choose strategy
CLI->>HookInst: install(repoPath, {strategy})
HookInst->>FS: write/backup/append hook file
HookInst->>FS: set executable bit
HookInst->>GitCfg: (maybe) read core.hooksPath
HookInst-->>CLI: return install result (action, hookPath, version)
CLI-->>User: renderInstallHooks(result)
sequenceDiagram
participant User as "User"
participant CLI as "warp-graph CLI"
participant Warp as "WarpGraph(materialize)"
participant Persistence as "Git Persistence"
participant Checkpoint as "CheckpointService"
User->>CLI: run `materialize` <graph>
CLI->>Warp: handleMaterialize(graph)
Warp->>Persistence: load latest checkpoint & patches since
Persistence-->>Warp: checkpoint + patches
Warp->>Warp: apply join/reduce to materialize state
Warp->>Checkpoint: maybe create checkpoint (policy)
Checkpoint-->>Persistence: write checkpoint
Warp-->>CLI: materialize result (state summary / checkpointSha)
CLI-->>User: renderMaterialize(result)
Estimated code review effort🎯 5 (Critical) | ⏱️ ~120 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches🧪 Generate unit tests (beta)
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. Comment |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
src/domain/services/StreamingBitmapIndexBuilder.js (1)
135-143:⚠️ Potential issue | 🟠 MajorAvoid breaking the public API:
registerNodenow returns sync value.This change removes the Promise return type but the JSDoc still promises
Promise<number>. It can break callers using.then(...)and changes scheduling semantics. Consider keeping the async signature for compatibility (or update all call sites + docs).✅ Minimal compatibility fix
- registerNode(sha) { - return this._getOrCreateId(sha); - } + async registerNode(sha) { + return this._getOrCreateId(sha); + }src/domain/WarpGraph.js (1)
93-129:⚠️ Potential issue | 🔴 CriticalPrevent recursive auto-checkpointing when
createCheckpoint()callsmaterialize().
materialize()auto-checkpoints when the threshold is met, butcreateCheckpoint()callsmaterialize()unconditionally (Line 698). When a checkpoint policy is enabled and the threshold is reached, this can recurse indefinitely and overflow. Add a guard flag and reuse cached state when already fresh.🛠️ Proposed fix to avoid recursion
@@ /** `@type` {{every: number}|null} */ this._checkpointPolicy = checkpointPolicy || null; + + /** `@type` {boolean} */ + this._checkpointing = false; @@ - if (this._checkpointPolicy && patchCount >= this._checkpointPolicy.every) { + if (this._checkpointPolicy && !this._checkpointing && patchCount >= this._checkpointPolicy.every) { try { await this.createCheckpoint(); this._patchesSinceCheckpoint = 0; } catch { // Checkpoint failure does not break materialize — continue silently } } @@ - const state = await this.materialize(); + let state; + const prevCheckpointing = this._checkpointing; + this._checkpointing = true; + try { + state = (this._cachedState && !this._stateDirty) + ? this._cachedState + : await this.materialize(); + } finally { + this._checkpointing = prevCheckpointing; + }Also applies to: 493-500, 680-708
🤖 Fix all issues with AI agents
In `@bin/warp-graph.js`:
- Around line 1066-1076: The execGitConfigValue function currently constructs
shell command strings using repoPath and key which allows injection and breaks
on spaces; change it to use child_process.execFileSync (or execFileSync) with an
argument array instead of a single shell string: call git as the executable and
pass ['-C', repoPath, ...] plus either ['rev-parse','--git-dir'] for the
--git-dir branch or ['config', key] for the normal branch, preserve options like
{ encoding: 'utf8' }, call .trim() on the result, and keep the existing
try/catch behavior so errors are still handled.
🧹 Nitpick comments (9)
docs/ideas/IDEA-003-DX.md (2)
48-48: Add language identifiers to fenced code blocks.markdownlint MD040 flags missing language tags; use ```bash (or appropriate).
✅ Suggested fix
-``` +```bashAlso applies to: 68-68
17-17: Reduce repeated phrasing for readability.You repeat “I need to understand…” in nearby sentences; consider rewording one instance.
tsconfig.json (1)
1-16: Consider including scripts/tests if you want them type-checked.Right now only
srcandbinare in scope; ifscripts/ortest/should be covered by TS checks, add them toinclude.💡 Optional include expansion
"include": [ "src/**/*.js", - "bin/**/*.js" + "bin/**/*.js", + "scripts/**/*.js", + "test/**/*.js" ]src/domain/services/QueryBuilder.js (2)
241-269: Avoid serialgetNodePropscalls inwherefiltering.This loop now awaits per node, which can add avoidable latency on larger working sets. Consider batching with
Promise.allto keep order but parallelize fetches.⚡️ Possible parallelization
- const filtered = []; - for (const nodeId of workingSet) { - const propsMap = (await this._graph.getNodeProps(nodeId)) || new Map(); - const edgesOut = adjacency.outgoing.get(nodeId) || []; - const edgesIn = adjacency.incoming.get(nodeId) || []; - const snapshot = createNodeSnapshot({ - id: nodeId, - propsMap, - edgesOut, - edgesIn, - }); - if (op.fn(snapshot)) { - filtered.push(nodeId); - } - } - workingSet = sortIds(filtered); + const snapshots = await Promise.all( + workingSet.map(async (nodeId) => { + const propsMap = (await this._graph.getNodeProps(nodeId)) || new Map(); + const edgesOut = adjacency.outgoing.get(nodeId) || []; + const edgesIn = adjacency.incoming.get(nodeId) || []; + return { + nodeId, + snapshot: createNodeSnapshot({ id: nodeId, propsMap, edgesOut, edgesIn }), + }; + }) + ); + const filtered = snapshots + .filter(({ snapshot }) => op.fn(snapshot)) + .map(({ nodeId }) => nodeId); + workingSet = sortIds(filtered);
299-313: Consider batchinggetNodePropsin the selection loop.The final selection now awaits one-by-one; parallelization can reduce latency without changing ordering.
⚡️ Possible parallelization
- const nodes = []; - for (const nodeId of workingSet) { - const entry = {}; - if (includeId) { - entry.id = nodeId; - } - if (includeProps) { - const propsMap = (await this._graph.getNodeProps(nodeId)) || new Map(); - const props = buildPropsSnapshot(propsMap); - if (selectFields || Object.keys(props).length > 0) { - entry.props = props; - } - } - nodes.push(entry); - } + const nodes = await Promise.all( + workingSet.map(async (nodeId) => { + const entry = {}; + if (includeId) { + entry.id = nodeId; + } + if (includeProps) { + const propsMap = (await this._graph.getNodeProps(nodeId)) || new Map(); + const props = buildPropsSnapshot(propsMap); + if (selectFields || Object.keys(props).length > 0) { + entry.props = props; + } + } + return entry; + }) + );src/domain/services/PatchBuilderV2.js (1)
271-274: Consider documenting the new callback payload.Since
onCommitSuccessnow receives{ patch, sha }, updating the constructor JSDoc (or a typedef) would help downstream implementers.ROADMAP.md (1)
203-213: Add language specifiers to fenced code blocks.The ASCII diagrams at lines 203 and 226 lack language specifiers. For ASCII art/diagrams, use
textorplaintextto satisfy linting and improve accessibility for screen readers.Proposed fix
-``` +```text AUTOPILOT ──→ GROUNDSKEEPER ──→ PULSEAnd similarly for the Task DAG block at line 226.
Also applies to: 226-252
src/domain/warp/Writer.js (1)
47-54: Add JSDoc for theonCommitSuccessparameter.The new
onCommitSuccessparameter is not documented in the JSDoc block. Consider adding:* `@param` {Function} options.getCurrentState - Function to get current materialized state + * `@param` {Function} [options.onCommitSuccess] - Callback invoked after successful commit */eslint.config.js (1)
23-31: Verify ESLint runtime compatibility forimport.meta.dirname.Line 30 relies on
import.meta.dirname, which isn’t supported in older Node runtimes. If CI/local Node isn’t guaranteed to support it, the config will fail to load. Consider deriving__dirnameviafileURLToPath(import.meta.url)for broader compatibility.♻️ Safer dirname derivation
import js from "@eslint/js"; import tseslint from "typescript-eslint"; +import { fileURLToPath } from "node:url"; +import { dirname } from "node:path"; + +const __dirname = dirname(fileURLToPath(import.meta.url)); @@ - tsconfigRootDir: import.meta.dirname, + tsconfigRootDir: __dirname,
- Prevent recursive auto-checkpointing: add _checkpointing guard flag so createCheckpoint() → materialize() doesn't re-trigger auto-checkpoint. createCheckpoint() now reuses cached state when fresh. - Fix command injection in execGitConfigValue: replace execSync shell string with execFileSync argument array. - Restore Promise return type on StreamingBitmapIndexBuilder.registerNode() to preserve public API compatibility. - Parallelize QueryBuilder where/select loops with Promise.all. - Add JSDoc for Writer.onCommitSuccess parameter. - Add language specifiers to ROADMAP.md fenced code blocks. - Use fileURLToPath-based __dirname in eslint.config.js for broader Node.js compatibility (import.meta.dirname requires Node 21.2+). - Expand tsconfig.json include to cover scripts/ and test/.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
src/domain/WarpGraph.js (1)
1669-1819:⚠️ Potential issue | 🟡 MinorUpdate examples to await async query APIs.
The docs still show sync usage (e.g., Line 1680, Line 1703, Line 1747, Line 1794, Line 1813). These methods now return Promises.✏️ Example adjustment (apply similarly elsewhere)
- if (graph.hasNode('user:alice')) { + if (await graph.hasNode('user:alice')) {
🤖 Fix all issues with AI agents
In `@src/domain/WarpGraph.js`:
- Around line 1646-1654: The _ensureFreshState method currently only throws when
there is no cached state, so if this._stateDirty is true and
this._autoMaterialize is false reads will use stale data; update
_ensureFreshState (in class WarpGraph, method _ensureFreshState) to check for a
dirty state when auto-materialize is disabled and throw an Error (e.g., "Cached
state is dirty; call materialize()") before returning, while preserving the
existing materialize path when this._autoMaterialize is true and the
no-cached-state error when _cachedState is absent.
🧹 Nitpick comments (1)
ROADMAP.md (1)
1-1892: Exceptional planning document with outstanding internal consistency.This 1892-line roadmap demonstrates remarkable attention to detail:
✅ Strengths:
- All cross-references verified accurate (task dependencies, blocking relationships, cross-milestone links)
- Arithmetic confirmed correct (task counts, hour estimates)
- Comprehensive task specifications with clear acceptance criteria
- Excellent scope management (explicit non-goals)
- Logical milestone progression from practical to theoretical
💡 Optional enhancements for navigability:
- Consider adding a table of contents for a document of this size
- Could add a "Document History" section to track roadmap evolution
- Might benefit from section anchors for deep-linking
This level of consistency and completeness in a planning document significantly reduces ambiguity and sets clear expectations for implementation.
- _ensureFreshState now throws when state is dirty and autoMaterialize is off, preventing silent reads of stale data. - Update all query method JSDoc examples to await async return values.
Replace bare Error throws in _ensureFreshState, join, runGC, and applySyncResponse with QueryError instances carrying distinct codes: - E_NO_STATE: no cached state (call materialize() first) - E_STALE_STATE: cached state is dirty (call materialize() to refresh) Update tests to assert on error type (QueryError) instead of brittle message string matching.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 2
🤖 Fix all issues with AI agents
In `@src/domain/WarpGraph.js`:
- Around line 239-248: The onCommitSuccess handler currently applies joinPatch
to this._cachedState even when this._stateDirty is true, which can materialize a
stale cache and clear the dirty flag incorrectly; update the gating so eager
re-materialization only happens when the cache is clean (i.e., !_stateDirty) and
this._cachedState, patch, and sha are present, otherwise leave this._stateDirty
true; apply the same change to the other onCommitSuccess occurrences referenced
(around lines 1569-1577 and 1622-1630) so all eager patch applications check
!_stateDirty before calling joinPatch and _setMaterializedState.
In `@test/unit/domain/WarpGraph.lazyMaterialize.test.js`:
- Around line 153-163: The mock for persistence.listRefs returns an array of
objects but discoverWriters expects an array of ref path strings; update the
test in WarpGraph.lazyMaterialize.test.js to have
persistence.listRefs.mockResolvedValue return an array of string ref paths (e.g.
'refs/warp/test/writers/writer-1') instead of objects with {ref, sha} so
discoverWriters can iterate correctly and the test accurately exercises
rematerialization behavior.
Audit and fix JSDoc in 21 files: - WarpGraph.js: document constructor options (checkpointPolicy, autoMaterialize), fix @throws to use QueryError with E_NO_STATE / E_STALE_STATE codes, document onCommitSuccess callback shape, add @throws for syncWith/serve/join/runGC/applySyncResponse - Services (10 files): add missing @param/@returns/@throws to QueryBuilder, LogicalTraversal, HookInstaller, CommitDagTraversal, BitmapIndexBuilder/Reader, Frontier, GCPolicy, HealthCheckService, WarpStateIndexBuilder - CRDT/Utils/Warp (7 files): fix ORSet serialize/deserialize types, add @throws to VersionVector, fix MinHeap param names, add WarpTypes.js typedefs, document Writer/PatchSession throws - Infrastructure (3 files): expand GraphPersistencePort abstract contract with @throws and param descriptions, complete GitGraphAdapter method docs, document CLI command handlers
CHANGELOG: document all AUTOPILOT features (auto-invalidation, auto-materialize, auto-checkpoint, post-merge hook, CLI commands), ESLint hardening, QueryError codes, and 133 new tests (1571 total). README: add autoMaterialize to Quick Start, fix missing await in query examples, document checkpointPolicy option, update querying section intro. GUIDE: add Auto-Materialize and Auto-Checkpoint section with code examples, document eager re-materialize after writes, update troubleshooting and performance tips for auto-checkpointing.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 2
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
src/infrastructure/adapters/GitGraphAdapter.js (2)
436-449:⚠️ Potential issue | 🟠 Major
nodeExistsmasks non-missing errors.Catching all errors and returning
falsesilently hides repository failures. The codebase already uses this pattern elsewhere (refExists,getConfig) to distinguish between "object doesn't exist" (exit code 1) and actual errors that should be rethrown.Suggested fix
async nodeExists(sha) { this._validateOid(sha); try { await this._executeWithRetry({ args: ['cat-file', '-e', sha] }); return true; - } catch { - return false; + } catch (err) { + const exitCode = err?.details?.code ?? err?.exitCode ?? err?.code; + if (exitCode === 1) { + return false; + } + throw err; + } }
38-55:⚠️ Potential issue | 🟡 MinorHandle missing-ref errors consistently and close the TOCTOU gap in
readRef.
refExistsonly checkserr?.details?.code === 1whileconfigGet(line 540) checkserr.exitCode === 1, indicating inconsistent error shapes from the plumbing library. Additionally,readRefhas a race condition: the ref can be deleted between therefExistscheck andrev-parseexecution, causing it to throw instead of returningnullper its contract.Fix by adding fallback error field checks in
refExistsand wrappingrev-parsein a try-catch that treats exit code 1 as a missing ref:Suggested changes
async function refExists(execute, ref) { try { await execute({ args: ['show-ref', '--verify', '--quiet', ref] }); return true; } catch (err) { - if (err?.details?.code === 1) { + const exitCode = err?.details?.code ?? err?.exitCode ?? err?.code; + if (exitCode === 1) { return false; } throw err; } }async readRef(ref) { this._validateRef(ref); const exists = await refExists(this._executeWithRetry.bind(this), ref); if (!exists) { return null; } - const oid = await this._executeWithRetry({ - args: ['rev-parse', ref] - }); - return oid.trim(); + try { + const oid = await this._executeWithRetry({ args: ['rev-parse', ref] }); + return oid.trim(); + } catch (err) { + const exitCode = err?.details?.code ?? err?.exitCode ?? err?.code; + if (exitCode === 1) { + return null; + } + throw err; + } }
🤖 Fix all issues with AI agents
In `@src/domain/services/HookInstaller.js`:
- Around line 144-153: In _upgradeInstall, when classification.appended is true
call replaceDelimitedSection(existing, stamped) and then detect if the returned
updated content is identical to existing (which indicates missing/corrupted
DELIMITER_END); if identical, fall back to writing stamped (overwrite) instead
of writing the no-op result so the upgrade isn't silently skipped. Reference
_upgradeInstall, classifyExistingHook, replaceDelimitedSection and DELIMITER_END
when making this change.
- Around line 144-183: The writes in _upgradeInstall, _appendInstall, and
_replaceInstall use this._fs.writeFileSync(...) with a mode option that only
applies on file creation, so after each writeFileSync call (the ones in
_upgradeInstall where updated or stamped are written, the one in _appendInstall
where appended is written, and the one in _replaceInstall where stamped and the
backup are written) call this._fs.chmodSync(hookPath, 0o755) (or the appropriate
backup path for the backup write) to ensure the hook file is executable; locate
the writeFileSync calls in these methods and add matching chmodSync calls
referencing hookPath (and backupPath for the backup) immediately after each
write.
🧹 Nitpick comments (2)
src/domain/types/WarpTypes.js (1)
89-133: Well-structured operation type definitions.The new JSDoc typedefs are clean, consistent with existing patterns in the file, and correctly correspond to the factory function return types.
Optional enhancement: Consider adding a union type to enable type-safe handling of any operation:
/** * Any graph operation * `@typedef` {OpNodeAdd | OpNodeTombstone | OpEdgeAdd | OpEdgeTombstone | OpPropSet} Op */This would parallel the existing
ValueRefpattern and benefit consumers that process operations polymorphically.,
src/domain/services/GCPolicy.js (1)
39-46: Avoid shared mutableDEFAULT_GC_POLICY.
Consider freezing (or returning a fresh copy) to prevent accidental mutation by consumers.Proposed change
-export const DEFAULT_GC_POLICY = { +export const DEFAULT_GC_POLICY = Object.freeze({ tombstoneRatioThreshold: 0.3, // 30% tombstones triggers GC entryCountThreshold: 50000, // 50K entries triggers GC minPatchesSinceCompaction: 1000, // Min patches between GCs maxTimeSinceCompaction: 86400000, // 24 hours max between GCs compactOnCheckpoint: true, // Auto-compact on checkpoint -}; +});
- GitGraphAdapter.nodeExists: only return false for exit code 1, rethrow real errors - GitGraphAdapter.refExists: normalize exit code check across error field shapes - GitGraphAdapter.readRef: wrap rev-parse in try-catch to close TOCTOU race - HookInstaller: detect no-op in _upgradeInstall when delimiters are corrupted, add chmodSync after writes to ensure hooks are executable - GCPolicy: freeze DEFAULT_GC_POLICY to prevent accidental mutation - WarpTypes: add Op union typedef covering all operation types
The mode option in writeFileSync only applies on file creation, not when overwriting. Add explicit chmodSync(0o755) after each write to ensure hooks are always executable, including _freshInstall and the backup write in _replaceInstall.
listRefs returns an array of ref path strings, not objects with
{ref, sha}. The mock was returning the wrong shape, preventing
discoverWriters from iterating correctly during rematerialization.
The onCommitSuccess handler was applying joinPatch to _cachedState even when _stateDirty was true, which would layer a single patch on top of stale state and then incorrectly clear the dirty flag. Now all three onCommitSuccess callbacks (createPatch, writer, createWriter) check !_stateDirty before eager application, falling through to mark dirty when the cache is already stale.
Summary
Completes all 10 tasks in the AUTOPILOT (v7.1.0) milestone, eliminating the "materialize tax" — the DX problem where developers must manually orchestrate state freshness across cached state, checkpoints, and indexes.
createPatch(),writer.commitPatch(), andPatchSession.commit()all apply patches to cached state immediately — no stale reads.autoMaterialize: trueoption onWarpGraph.open(). Query methods (hasNode,getNodeProps,neighbors,getNodes,getEdges,query().run(),traverse.*) auto-materialize when state is null or dirty.checkpointPolicy: { every: N }option. Aftermaterialize()processes N+ patches, a checkpoint is created automatically. Failures are swallowed — never breaks materialize.git pulland prints a warning (or auto-materializes ifwarp.autoMaterializegit config is set). Installed viacore.hooksPathonnpm install.ROADMAP.mdwith task tracking script (scripts/roadmap.js).git warp materializeCLI command.Test plan
WarpGraph.invalidation.test.js— dirty flag + eager re-materialize (11 tests)WarpGraph.writerInvalidation.test.js— Writer API invalidation (10 tests)WarpGraph.lazyMaterialize.test.js— auto-materialize guard (46 tests)WarpGraph.autoCheckpoint.test.js— auto-checkpoint trigger (14 tests)WarpGraph.autoMaterialize.test.js— option validation (7 tests)WarpGraph.checkpointPolicy.test.js— option validation (9 tests)WarpGraph.patchCount.test.js— patch counter tracking (7 tests)HookInstaller.test.js— hook install/upgrade/append/replace (29 tests)WarpGraph.noCoordination.test.js— multi-writer safety regression suite (3 tests)Summary by CodeRabbit
New Features
Documentation
Tests
Chores