Problem
Think's native v19 adapter caches each opened git-warp Runtime in a module-global sessions Map. A session is released only when a caller explicitly invokes closeNativeMemory or clearWarpRuntimeCache, but the product/read handles have no owned close method and most callers and port fixtures never invoke either function.
This was latent with git-warp 19.0.2. After installing git-warp 19.1.0, whose fast path keeps bounded Git sessions resident, the missing lifecycle ownership becomes observable as leaked git update-ref --stdin subprocesses and a test process that never exits.
The defect belongs at the Think integration boundary: git-warp Runtime exposes close and Symbol.asyncDispose, and NativeMemorySession.close delegates to runtime.close. Think opens and caches the runtime but does not make closure structurally unavoidable.
Evidence
Environment:
- Think runtime checkout: /Users/james/git/think-v19-runtime
- Think commit: 3f7219a
- git-warp: 19.1.0
- git-cas resolved by git-warp: 6.5.10
- Plumbing resolved by git-warp: 3.3.0
- Node: 26.0.0
Reproduction:
-
Point the existing Think v19 runtime at the public global git-warp 19.1.0 package.
-
Run npm run test:fast.
-
Lint, runtime-truth, and hexagonal-boundary ratchets pass.
-
Early real-Git Browse/History assertions pass.
-
The port runner stops producing TAP output and remains resident for more than three minutes.
-
Process inspection shows ten child processes such as:
/Applications/Xcode.app/Contents/Developer/usr/bin/git update-ref --stdin
Each child is sleeping with stdin held open by one of the test workers.
-
Interrupting only the launched test command terminates every leaked child; no mind or repository ref was changed.
Relevant code at the witnessed commit:
- src/store/native-runtime.js keeps const sessions = new Map().
- openNativeMemory inserts NativeMemorySession instances into that map.
- closeNativeMemory is the only map eviction and Runtime.close path.
- src/store/runtime.js exposes clearWarpRuntimeCache, but no production or fixture caller owns it.
- openProductReadHandle returns a frozen read handle with no close or async-dispose method.
Operational contrast:
- codex-think --remember --json completes because the wrapper process exits; after 19.1.0 it dropped from 93.0 seconds to 4.21 seconds for the same 26 matches.
- claude-think --remember --json dropped from 19.1 seconds to 1.63 seconds for the same 50 matches.
The release is delivering its intended speedup, but process exit is not a valid resource-management strategy for MCP servers, long-lived applications, benchmarks, or test workers.
Required outcome
- Give every Think-owned runtime/read handle an explicit idempotent close and Symbol.asyncDispose path.
- Make composition roots and test fixtures own that handle with try/finally or await using.
- Define whether the module cache is reference-counted, lease-based, or process-scoped; do not leave ownership ambient.
- Ensure reopening and repair replace sessions without orphaning the previous Runtime.
- Add a regression test that opens, reads/writes, closes, and proves no git update-ref --stdin, cat-file, or other persistent Git child remains.
- Add a process-exit test whose success cannot be faked by a test-runner timeout or forced teardown.
- Run the complete port and acceptance gates against public git-warp 19.1.0.
- Preserve the measured recall speedup and do not disable persistent lower-layer sessions merely to hide the consumer leak.
Non-goals
- Do not change the Think memory data model, adopt EntityOccurrence, or start the contextual-mind migration.
- Do not weaken the port suite or add forced process.exit calls.
- Do not revert git-warp, git-cas, or Plumbing performance work as a substitute for lifecycle ownership.
Problem
Think's native v19 adapter caches each opened git-warp Runtime in a module-global sessions Map. A session is released only when a caller explicitly invokes closeNativeMemory or clearWarpRuntimeCache, but the product/read handles have no owned close method and most callers and port fixtures never invoke either function.
This was latent with git-warp 19.0.2. After installing git-warp 19.1.0, whose fast path keeps bounded Git sessions resident, the missing lifecycle ownership becomes observable as leaked git update-ref --stdin subprocesses and a test process that never exits.
The defect belongs at the Think integration boundary: git-warp Runtime exposes close and Symbol.asyncDispose, and NativeMemorySession.close delegates to runtime.close. Think opens and caches the runtime but does not make closure structurally unavoidable.
Evidence
Environment:
Reproduction:
Point the existing Think v19 runtime at the public global git-warp 19.1.0 package.
Run npm run test:fast.
Lint, runtime-truth, and hexagonal-boundary ratchets pass.
Early real-Git Browse/History assertions pass.
The port runner stops producing TAP output and remains resident for more than three minutes.
Process inspection shows ten child processes such as:
/Applications/Xcode.app/Contents/Developer/usr/bin/git update-ref --stdin
Each child is sleeping with stdin held open by one of the test workers.
Interrupting only the launched test command terminates every leaked child; no mind or repository ref was changed.
Relevant code at the witnessed commit:
Operational contrast:
The release is delivering its intended speedup, but process exit is not a valid resource-management strategy for MCP servers, long-lived applications, benchmarks, or test workers.
Required outcome
Non-goals