Repository navigation
fix: close P1 C0 gaps and queue concurrent writers - #19
Merged
Merged
Conversation
Every write transaction now begins IMMEDIATE, so concurrent writer processes wait under busy_timeout. Before, a DEFERRED read-then-write transaction failed at once with SQLITE_BUSY (GKS-IDN-005, GKS-STO-001). The migration runner re-checks each migration under the write lock. Tool errors now carry only gks_* codes on the wire; any other code is sent as gks_backend_unavailable (GKS-API-005). The lost-response replay harness SIGKILLs a real server after the durable commit and replays the request against a fresh process. This covers legacy promote, pipeline submit and graph receipt, so C0.4-LOST-RESPONSE-REPLAY moves to PASS (manifest: PASS 23, NOT_RUN 1). The baseline lock can now be run as a check (GKS-MIG-001, GKS-API-001). scripts/check-baseline-lock.mjs locks the hashes of the lockfile, the workflow, each migration and the tool registry. A new CI c0-gate slice runs check:c0 and check:baseline. Adds C0 acceptance tests for SCP-002, ING-001/002/004/005, SYS-003, IDN-004/005, PIP-001/003/008, API-002/005 and SEC-002, and extracts the GenesisRAG17 fixtures into tests/fixtures/genesisrag17.mjs. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The six-process identity race timed out at vitest's 5 s default on the Node 22 CI runner. Spawning and migrating several server processes is slower on a shared runner than locally. The race and the fresh-store migration test now allow 30 s; their assertions are unchanged. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
This PR is P1 from the SRS blueprint gap analysis. It turns C0 obligations that were implemented but never demonstrated into executable evidence. Along the way it fixes a real C0 defect in concurrent writes.
Full report:
docs/reports/2026-09-27-p1-c0-closure.md. It supersedes the G0 baseline lock pinned atbe97c93.Defect fixed: concurrent writers got
SQLITE_BUSY(GKS-IDN-005, GKS-STO-001, GKS-API-005)A new multi-process test showed two problems when several processes write to the same store:
database is locked, even withbusy_timeoutset.SQLITE_BUSYstraight away.busy_timeoutdoes not apply in that case.IMMEDIATE(writeTransaction()inpackages/gks-persistence).SQLITE_BUSYcode reached the caller.createJsonRpcToolErrorResponsenow emits onlygks_*codes; anything else becomesgks_backend_unavailableand keeps its message.The migration runner also re-checks each migration under the write lock, so processes opening a fresh store together apply each migration exactly once.
Cost: idempotent replays now also take the write lock, so writers are serialized. This is acceptable for the single-writer profile and is noted in the report.
Lost-response replay (C0.4-LOST-RESPONSE-REPLAY: NOT_RUN → PASS)
tests/integration/lost-response-replay.test.mjsexercises three operations against a real stdio server:For each one, it kills the server with SIGKILL after the write is durable and before any response is read, then replays the request against a fresh process. Each replay returns the committed result with
idempotent: true, and the store holds exactly one row for it. Sending a changed payload under the same key returnsgks_conflict.The C0.4 manifest is now PASS 23 / NOT_RUN 1. The case still NOT_RUN is the Tier-4 physical readback, which is outside the GKS boundary.
productionReadyanddeploymentAuthorizedstayfalse.Baseline lock you can run (GKS-MIG-001, GKS-API-001)
npm run check:baseline(scripts/check-baseline-lock.mjs+tests/fixtures/baseline-lock.json) fails when any of these drift:Line endings are folded to LF before hashing, so Windows and Linux runs agree.
--writerecords<HEAD>+working-treewhenever a hashed input is uncommitted, so the lock never claims a commit it was not taken from. A new CI slice,c0-gate, runscheck:c0andcheck:baselineon Node 22 and 24.C0 acceptance evidence
New tests cover:
fetchand socket connect trapped.The GenesisRAG17 fixtures are extracted to
tests/fixtures/genesisrag17.mjsso the tests can share them.Not in this PR (the report lists these as needing an owner decision)
Each of these would change accepted C0 behaviour:
jsonrpc: "2.0";Test plan
npm test: vitest 262 passed, 2 skipped (the MSP integration suites needMSP_REPO_ROOT); security 12/12.tests/unit9/9.npm run check:c0: PASS=23 NOT_RUN=1.npm run check:baselineholds.c0-gateslice and process tests running on Linux)🤖 Generated with Claude Code