Scope retained materializations with git-cas acquisitions - #756
Conversation
|
@codex Self-Code Review complete.
Reviewed Residual risks are explicit: callers must eventually invoke |
📝 WalkthroughWalkthroughThe PR replaces exact materialization lookups with lifecycle-managed acquisitions, adds coordinate-first live resolution for retained and replayed materializations, updates cleanup and snapshot-publication behavior, upgrades ChangesLive materialization acquisition
Estimated code review effort: 4 (Complex) | ~45 minutes Sequence Diagram(s)sequenceDiagram
participant Caller
participant MaterializeController
participant MaterializeLiveStrategy
participant MaterializationStore
participant GitCasMaterializationStoreAdapter
Caller->>MaterializeController: resolveLiveMaterialization()
MaterializeController->>MaterializeLiveStrategy: resolveMaterialization()
MaterializeLiveStrategy->>MaterializationStore: acquireExact(coordinate)
MaterializationStore->>GitCasMaterializationStoreAdapter: acquireExact(coordinate)
GitCasMaterializationStoreAdapter-->>MaterializeLiveStrategy: acquisition or miss
MaterializeLiveStrategy-->>MaterializeController: resolution with release()
MaterializeController-->>Caller: live materialization resolution
Possibly related issues
Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches📝 Generate docstrings
Comment |
There was a problem hiding this comment.
Actionable comments posted: 3
🤖 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/services/controllers/MaterializeController.ts`:
- Around line 376-380: Update the acquisition lifecycle in _buildResult() so the
success-path acquisition.release() runs after the catch that handles operation
failures, preventing a release rejection from being passed to
releaseAcquisitionAfterFailure() and retried. Preserve the existing result
return and failure cleanup behavior.
In `@src/domain/services/controllers/MaterializeLiveStrategy.ts`:
- Around line 355-364: Update materializedResolution to validate the complete
acquired handle: retain the existing bundle comparison and also compare the
handle’s coordinate and stateHash against result.materialization. Throw the same
resolution error when any identifying field differs, ensuring the returned
acquisition represents the reported materialization.
In `@src/domain/services/controllers/MaterializeStrategyRuntime.ts`:
- Around line 28-33: Replace the structural LiveMaterializationResolution type
with a frozen runtime-backed class or factory that validates construction,
especially the allowed source values and their corresponding
materialization/release requirements. Preserve the existing materialization,
source, replayedPatchCount, and release API while ensuring every created
resolution is immutable and cannot represent an invalid combination.
🪄 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: 02dc1ff5-7ff3-4d34-966a-3b97eb8e593c
⛔ Files ignored due to path filters (1)
package-lock.jsonis excluded by!**/package-lock.json
📒 Files selected for processing (17)
docs/topics/cas-first-memoized-materialization.mdpackage.jsonsrc/domain/services/controllers/MaterializationWorkspaceCleanup.tssrc/domain/services/controllers/MaterializeController.tssrc/domain/services/controllers/MaterializeLiveStrategy.tssrc/domain/services/controllers/MaterializeStrategyRuntime.tssrc/infrastructure/adapters/GitCasMaterializationStoreAdapter.tssrc/ports/MaterializationStorePort.tstest/helpers/InMemoryGitCasFacade.tstest/helpers/InMemoryMaterializationStore.tstest/integration/api/materialization.retainedResume.test.tstest/integration/infrastructure/adapters/GitCasMaterializationStoreAdapter.integration.test.tstest/unit/domain/services/controllers/MaterializationWorkspaceCleanup.test.tstest/unit/domain/services/controllers/MaterializeController.stateSession.test.tstest/unit/infrastructure/adapters/GitCasMaterializationStoreAdapter.test.tstest/unit/infrastructure/adapters/GitCasMaterializationWorkspace.test.tstest/unit/scripts/v18-v17-public-read-legacy-reading-builder.test.ts
📜 Review details
⏰ Context from checks skipped due to timeout. (3)
- GitHub Check: coverage-threshold
- GitHub Check: test-node (22)
- GitHub Check: preflight
🧰 Additional context used
📓 Path-based instructions (5)
**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (AGENTS.md)
**/*.{ts,tsx,js,jsx}: Do not use direct imports fromsrc/infrastructure/**insrc/domain/**orsrc/ports/**; depend on a port instead.
Do not use direct Node built-ins insrc/domain/**orsrc/ports/**; use a port instead.
Files:
test/unit/infrastructure/adapters/GitCasMaterializationWorkspace.test.tstest/unit/domain/services/controllers/MaterializationWorkspaceCleanup.test.tstest/integration/api/materialization.retainedResume.test.tssrc/ports/MaterializationStorePort.tssrc/domain/services/controllers/MaterializationWorkspaceCleanup.tstest/unit/scripts/v18-v17-public-read-legacy-reading-builder.test.tstest/unit/domain/services/controllers/MaterializeController.stateSession.test.tstest/helpers/InMemoryMaterializationStore.tstest/integration/infrastructure/adapters/GitCasMaterializationStoreAdapter.integration.test.tssrc/domain/services/controllers/MaterializeController.tssrc/infrastructure/adapters/GitCasMaterializationStoreAdapter.tstest/helpers/InMemoryGitCasFacade.tssrc/domain/services/controllers/MaterializeStrategyRuntime.tssrc/domain/services/controllers/MaterializeLiveStrategy.tstest/unit/infrastructure/adapters/GitCasMaterializationStoreAdapter.test.ts
src/**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (AGENTS.md)
src/**/*.{ts,tsx,js,jsx}: Do not introduceany,as any,as unknown as,unknown(outside adapters),Record<string, unknown>(outside adapters),*Likeplaceholder types,JSON.parse/JSON.stringify(outside adapters),fetch(outside adapters),process.env(outside adapters),@ts-ignore, orz.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 createutils.ts,helpers.ts,misc.ts, orcommon.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 asUint8Array;Bufferbelongs in infrastructure adapters.
Files:
src/ports/MaterializationStorePort.tssrc/domain/services/controllers/MaterializationWorkspaceCleanup.tssrc/domain/services/controllers/MaterializeController.tssrc/infrastructure/adapters/GitCasMaterializationStoreAdapter.tssrc/domain/services/controllers/MaterializeStrategyRuntime.tssrc/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 orsrc/infrastructure/**; ports must stay abstract and depend only on boundary-safe types.
Files:
src/ports/MaterializationStorePort.ts
src/domain/**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (AGENTS.md)
src/domain/**/*.{ts,tsx,js,jsx}: Insrc/domain/**, do not useDate.now(),new Date(),Date(),performance.now(),Math.random(),crypto.randomUUID(),crypto.getRandomValues(),setTimeout,setInterval, rawnew 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 extendWarpError.
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/MaterializationWorkspaceCleanup.tssrc/domain/services/controllers/MaterializeController.tssrc/domain/services/controllers/MaterializeStrategyRuntime.tssrc/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, andinstanceofdispatch; domain objects should be runtime-backed nouns, not ad hoc shape bags.
Files:
src/domain/services/controllers/MaterializationWorkspaceCleanup.tssrc/domain/services/controllers/MaterializeController.tssrc/domain/services/controllers/MaterializeStrategyRuntime.tssrc/domain/services/controllers/MaterializeLiveStrategy.ts
🧠 Learnings (1)
📚 Learning: 2026-03-04T12:08:30.347Z
Learnt from: flyingrobots
Repo: git-stunts/git-warp PR: 63
File: package.json:126-126
Timestamp: 2026-03-04T12:08:30.347Z
Learning: Vitest 4 removes vite-node as a dependency and rewrites its pool system. Do not flag the absence of vite-node in package.json or lockfiles as an error for Vitest 4 projects. Use this as a general guideline: if a project uses Vitest 4, missing vite-node is expected and correct; only flag issues if there is evidence the project is not using Vitest 4 or if vite-node is explicitly required by the project.
Applied to files:
package.json
🪛 ast-grep (0.44.1)
test/integration/infrastructure/adapters/GitCasMaterializationStoreAdapter.integration.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)
[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 (17)
src/domain/services/controllers/MaterializeStrategyRuntime.ts (1)
22-26: LGTM!src/ports/MaterializationStorePort.ts (1)
8-12: LGTM!Also applies to: 22-24
package.json (1)
120-120: LGTM!src/infrastructure/adapters/GitCasMaterializationStoreAdapter.ts (1)
5-5: LGTM!Also applies to: 26-26, 47-47, 163-211, 245-266
test/helpers/InMemoryGitCasFacade.ts (1)
17-17: LGTM!Also applies to: 52-54, 63-68, 114-116, 304-344
test/helpers/InMemoryMaterializationStore.ts (1)
8-8: LGTM!Also applies to: 48-67, 103-114
test/integration/infrastructure/adapters/GitCasMaterializationStoreAdapter.integration.test.ts (1)
59-63: LGTM!Also applies to: 87-132, 259-264, 285-301, 413-415
test/unit/infrastructure/adapters/GitCasMaterializationStoreAdapter.test.ts (1)
4-4: LGTM!Also applies to: 41-48, 65-84, 104-104, 148-148, 166-166, 227-231, 266-266, 286-286, 366-366, 375-375, 386-386, 397-397, 410-410, 449-449, 478-491, 542-542
test/unit/infrastructure/adapters/GitCasMaterializationWorkspace.test.ts (1)
439-439: LGTM!src/domain/services/controllers/MaterializationWorkspaceCleanup.ts (1)
2-2: LGTM!Also applies to: 17-40
src/domain/services/controllers/MaterializeController.ts (1)
1-1: LGTM!Also applies to: 59-62, 182-184, 345-375
src/domain/services/controllers/MaterializeLiveStrategy.ts (1)
3-10: LGTM!Also applies to: 24-24, 40-40, 55-101, 193-195, 246-257, 330-353, 365-386
test/integration/api/materialization.retainedResume.test.ts (1)
7-7: LGTM!Also applies to: 104-112
test/unit/domain/services/controllers/MaterializationWorkspaceCleanup.test.ts (1)
2-5: LGTM!Also applies to: 39-53
test/unit/domain/services/controllers/MaterializeController.stateSession.test.ts (1)
21-21: LGTM!Also applies to: 472-580
docs/topics/cas-first-memoized-materialization.md (1)
16-35: LGTM!Also applies to: 166-167
test/unit/scripts/v18-v17-public-read-legacy-reading-builder.test.ts (1)
49-52: LGTM!
Release Preflight
If this PR is from a |
Release Preflight
If this PR is from a |
|
@codex Final Self-Code Review at
The three original CodeRabbit findings are resolved: success-path release failures are not retried, cold reacquisition validates coordinate/state hash/bundle, and live resolutions are frozen runtime-validated domain objects. The independent Code Lawyer found one low-severity ambiguity in the compatibility state-cache diagram; Evidence: clean fetched worktree, Graft reports no breaking export changes, all review threads are resolved, documentation gates pass, and the final pre-push firewall passed all static gates plus 7,020 tests (2 skipped). GitHub CI is running on this exact head. Please confirm that no unresolved correctness or contract issue remains. |
Release Preflight
If this PR is from a |
Summary
@git-stunts/git-casto 6.3.0.findExact()reads with a storage-neutralacquireExact()/release()lifecycle.Issue
Refs #738.
Refs #734.
Provides downstream adoption evidence for git-cas #69.
This does not complete #738.
RuntimeHostand checkpoint creation still consume the full-state compatibility result. The next slice migrates those consumers to the new handle-first contract.Test plan
05ff83981: all static gates and 7,020 unit tests passed; 2 skipped.git prune --expire=nowkeeps generation A readable while acquired; after release, A is prunable while generation B remains retained.npm run lint, typechecks, surface validation, Markdown/docs gates, policy gates, and quarantine-graduate checks pass.05ff83981resolves it and all documentation gates pass.Storage invariants
A retained handle is decoded while its git-cas cache acquisition is active. The acquisition pins the observed generation across concurrent replacement or eviction until the caller releases it. Failure cleanup is best-effort and cannot replace the primary materialization error; release failure after a successful operation remains visible.
Cold materialization must reacquire the retained generation and match its coordinate, state hash, and bundle before returning it. Any mismatch fails closed and releases the mismatched acquisition exactly once.
Compatibility note
git-cas stamps its package version into asset manifests. The dependency bump therefore intentionally advances one v17 migration golden asset handle without changing the represented payload.
ADR checks