v1.0.129
Hotfix bundling 2 critical fixes — ship together as single release.
What broke
CI breakage from v1.0.128 — EXCLUSIVE pragma scope
v1.0.128 shipped db.pragma("locking_mode = EXCLUSIVE") inside applyWALPragmas(), which is called by EVERY DB type — both single-writer SessionDB (per-project) AND multi-writer ContentStore (FTS5 shared knowledge base across sessions). ContentStore is multi-writer by design (multiple Claude Code sessions concurrently search/index the same content store). Applying EXCLUSIVE there deadlocked the second instance — broke 4 ContentStore concurrency tests with 90s timeouts:
two ContentStore instances can write to the same DB fileindexPlainText is protected by withRetryindexJSON is protected by withRetrysearch and searchTrigram work under concurrent writes
CI on next + main both failed.
Fix architecture (commits f6c6153 + 77b6c15 + 24ab4fa):
- Removed
locking_mode = EXCLUSIVEfromapplyWALPragmas— base function now applies only WAL + synchronous + mmap_size (multi-writer-safe) - Added EXCLUSIVE in
SQLiteBasector only — both single-writer (lockfile + EXCLUSIVE) layers gated by tmpdir skip - Critical: tmpdir skip-gate matches lockfile's gate. Tests open SessionDB twice on same tmpdir path to exercise multi-writer recovery; if EXCLUSIVE fires when lockfile didn't, the second open hits SQLITE_BUSY on its FIRST pragma call. Single source of truth:
skipExclusive = dbPath.startsWith(tmpdir())matchesacquireDbLockhelper's check. - Architectural separation now correct:
SessionDB(per-project, single-writer) → lockfile + EXCLUSIVEContentStore(shared, multi-writer by design) → no lockfile, no EXCLUSIVE, withRetry handles SQLITE_BUSY
#561 — Pi bridge identification env leakage (algorithmic 15-adapter fix)
@ishabana on Windows 11, v1.0.127. Pi runs npm:context-mode as package extension; mcp-bridge.ts spawns server.bundle.mjs as child process. v1.0.124 #545 fix scrubbed WORKSPACE-role env vars but PRESERVED IDENTIFICATION-role vars (CLAUDE_CODE_ENTRYPOINT, CLAUDE_PLUGIN_ROOT). When Pi runs alongside Claude Code, child inherits these → detectPlatform() returns claude-code (FIRST in PLATFORM_ENV_VARS registry, identification vars hijack detection) → Pi data lands in ~/.claude/context-mode/ instead of ~/.pi/context-mode/.
This was the ROOT cause of #560 (WAL contention) — Pi server + Claude Code MCP server BOTH writing to ~/.claude/context-mode/content/*.db simultaneously, WAL grows unbounded, queries hang. Reporter's verification: ~/.pi/context-mode/sessions/ exists but ~/.pi/context-mode/content/ does NOT — confirming content lands in wrong dir.
Fix architecture (commits 8172c29 + 4ef1c78 + 554ef81):
- New algorithmic helper
foreignIdentificationEnv(platform)insrc/adapters/detect.ts— mirrors existingforeignWorkspaceEnvpattern. ReturnsSet<string>of identification-role var names from all OTHER platforms inPLATFORM_ENV_VARS. Algorithmic — registry-driven, MUST-3 compliant. - Pi bridge scrub extended in
src/adapters/pi/mcp-bridge.ts— added second loop iteratingforeignIdentificationEnv("pi")alongside existing workspace scrub. Comment cites #561 + JSDoc updated to clarify identification vars are foreign-noise when spawning under different host. - 15-adapter leak matrix extended in
tests/util/project-dir-matrix.test.ts— for each (host, foreign) pair, asserts foreign IDENTIFICATION vars are scrubbed when host = pi. Adapter #16 inherits both filters automatically. - 3-OS uniform —
process.envsemantics same on macOS/Linux/Windows once vars are materialized. No platform-conditional code.
Architectural lesson — past mistake caught
Test 7951357 in v1.0.124 era already KNEW identification vars leak into JetBrains projectRoot test. We patched the SYMPTOM in test setup (manual scrub) instead of the PRODUCTION ROOT (mcp-bridge scrub). v1.0.129 fixes the production root. Future contributors won't repeat this — the matrix test now enforces the invariant.
Composes with v1.0.128 #559 + #560 fixes
Once #561 is fixed:
- Pi writes to
~/.pi/context-mode/(correct partition) - No multi-writer WAL contention with Claude Code's MCP server (different DB path)
- v1.0.128 lockfile still protects against same-DB multi-instance (e.g. user double-registers)
- v1.0.128 sibling kill on
/ctx-upgradestill cleans accumulated zombies
Three issues (#559 + #560 + #561) all closed by v1.0.128 → v1.0.129 progression.
Tests
3242 pass · 8 pre-existing OpenCode baseline failures (unchanged from v1.0.122 baseline).
Full test suite run BEFORE push (per Mert's CI breakage prevention directive). Total 3280 tests / 28 skipped / 10 failed (8 OpenCode + 2 timing-sensitive — within baseline noise tolerance for repeated runs).
New tests added in EXISTING files (CONTRIBUTING L275 — zero new test files):
tests/store.test.ts: 4 ContentStore concurrent tests now PASS (regression confirmed fixed)tests/util/db-base-platform-gate.test.ts: regression guard for SQLiteBase EXCLUSIVE lockingtests/adapters/detect.test.ts:foreignIdentificationEnvhelper assertionstests/adapters/pi-mcp-bridge-env-scrub.test.ts: identification env scrub at spawn sitetests/util/project-dir-matrix.test.ts: 15-adapter leak matrix extended with identification ban invariant
Compatibility
15 adapters / 3 OS. Zero observable behavior change for healthy installs. Pi bridge fix is single-file (only Pi spawns context-mode child via in-repo bridge — other 14 adapters use host MCP runtime). EXCLUSIVE scope correction restores ContentStore multi-writer behavior that v1.0.128 broke.
| Adapter | Effect of v1.0.129 |
|---|---|
| Pi | #561 fixed — Pi data now correctly partitioned to ~/.pi/context-mode/
|
| Claude Code | No change — already host-spawned with correct env |
| All 15 (universal) | ContentStore multi-writer restored. SessionDB single-writer enforcement preserved (lockfile + EXCLUSIVE on production paths only). |
Upgrade
npm install -g context-mode@latest
# inside Claude Code:
/ctx-upgrade
# fully restart Claude Code (Cmd+Q + reopen)If you were on v1.0.128 and saw concurrency tests timing out, v1.0.129 is the fix.
If you run Pi alongside Claude Code, verify after upgrade: ~/.pi/context-mode/content/ should now be created on first Pi ctx_* invocation. Pi sessions and content land in ~/.pi/, Claude Code's land in ~/.claude/ — no cross-pollution, no WAL contention.
Thanks
@ishabana for #561 — staff-grade diagnosis traced through bridge env handling to detection cascade, with two concrete fix proposals (Option A scrub + Option B Pi-marker). We shipped Option A as algorithmic generalization (foreignIdentificationEnv helper). Your data on Pi+Claude coexistence broke open the architectural class — without it, this would have stayed silent until next user hit it harder.