Skip to content

feat(devmap-store): latest_symbols_for_file (recover code vendored from an unpushed commit) - #14

Merged
bharathvbcr merged 20 commits into
mainfrom
claude/friendly-lamport-60dj43
Sep 29, 2026
Merged

bharathvbcr merged 20 commits into
mainfrom
claude/friendly-lamport-60dj43

Conversation

@bharathvbcr

@bharathvbcr bharathvbcr commented Sep 28, 2026 •

Copy link
Copy Markdown
Owner

Why

GitPulse vendors DevCouncil crates into src-tauri/vendored/, and its VENDOR.json gives origin commit c55d479 for all of them. That commit was never pushed. I diffed each vendored crate's src/ against rust/<crate> on main and found exactly one difference in devmap-store:

  • FileSymbolsPage and Store::latest_symbols_for_file in src/db.rs
  • the matching re-export in src/lib.rs

GitPulse's cmd_codeintel_symbols_for_file (the codeintel::symbols_for_file path) calls this method. Without it here, re-vendoring GitPulse from DevCouncil would drop the feature. Every other vendored crate was byte-identical to main.

GitPulse is re-vendored from this PR's head (4efeecf) on its claude/friendly-lamport-60dj43 branch. There, vendor-crates.mjs --check reports all 12 crates as upstream: matches.

What

The port itself:

  • a429fde lands the vendored code, verbatim apart from cargo fmt on the lib.rs re-export list.
    • The rows and the generation's head_sha come from one pinned snapshot. None means the store has no generation. Some with empty rows means the path has no indexed symbols. Spans go through checked_span.
    • Adds rust/devmap-store/tests/symbols_for_file.rs, 5 tests: an empty store, file scoping and source order (checked against all_symbols), an unindexed path, the latest generation winning, and a corrupt span being refused.
  • fba2df5 declares that test's parse requirement, as devmap-cli's every_integration_test_is_classified_against_the_parse_feature requires.

main has been red since v1.3.5. The rest make this PR green. All but the last one are fixes that already exist on claude/zealous-faraday-56lcrv.

Lockfiles, formatting and timeouts:

  • e63f184 updates rust/gusset-engine/Cargo.lock to dc-glob 1.3.5.
  • a2c364e and c3c5f4d port b6e9673, split into two commits.
    • a2c364e pins find-msvc-tools to 0.1.14, because cc 1.2.67 does not compile against 0.1.13 on Windows.
    • c3c5f4d makes devmap-serve's 5 s reply bound cover the write, not the wait for the writer. This fixes serve_stress.
  • 92e5f8d ports the lsp.rs and dc-proc parts of e3bcb6b, which bound every wait on a language server. This fixes every_child_process_in_the_kernel_goes_through_the_runner.
  • dd7695c applies gofmt to policy/zfix_split_test.go.

Windows, cherry-picked unchanged with -x:

  • Gusset:
    • fea3992 ← 3197897, 62331b3 ← 876ace2, e88cdb3 ← f8866c7 harden the engine integration.
    • 0b389c4 ← 663b998 pins Gusset 709c2b7.
    • d5ef7eb ← f0ec3e2: Gusset is unix-only (compile_error! elsewhere), so the MinGW/gnu-target build could never pass. gussetfn and gusset-check are now build-tagged unix, and Windows skips the engine build.
  • Rust tests on Windows:
    • b30b477 ← c7563cf: safe_fs checks file identity on Windows too.
    • b031491 ← a21ee78: the last two Windows clippy errors.
    • 9a1d8d2 ← 38c4d29: native Windows path validation in MCP root resolution, a shell-free detached build, and sharing-violation retries in artifact writes and the store.
    • 58760dc ← 241b018: the last three Windows tests. After it, test (windows-latest) fell from 12 failing targets to 1.
    • f9083a7 ← ebd2a8f:
      • On Windows, write_atomic retries the whole write on a sharing violation. That fixes concurrent_emission_leaves_one_valid_bundle.
      • Read-only opens retry lost SQLite races. It also carries the gate-test fix below.
    • 975a79b ← 9248cc6: a process-wide lock covers a read-only connection's open and first read. Concurrent read-only connections could livelock on Windows setting up the WAL index (concurrent_readers_cannot_enqueue_writer_work).
    • 819944a is left out. It updates a workflow test for a rust.yml job this branch does not carry, and scripts/check-workflows.test.mjs passes 7/7 without it.

Mine, not on zealous-faraday:

  • 4efeecf extends 9248cc6's lock, renamed CONNECTION_SETUP, to read-write opens, from Connection::open through migrate.
    • At 975a79b, concurrent_v19_openers_keep_pending_work_and_one_durable_identity failed on Windows. Sixteen threads calling Store::open all got SQLITE_PROTOCOL for the whole 20 s retry deadline. It is the same livelock, between read-write connections.
    • Migration was already serialised by SQLite's write lock. Other processes still coordinate through SQLite, and nothing inside an open opens another store, so the lock cannot be re-entered.
    • zealous-faraday will want the same change.

The gate test, 485a2a6 then f9083a7:

  • runInThrowawayTree read the tree as soon as sh exited. A backgrounded write (echo hi > .env &) therefore went unrecorded, and landed during t.TempDir cleanup. That failed TestCommandVerdictIsNeverLooserThanTheWritesItPerforms on macOS.
  • 485a2a6 and ebd2a8f made the same command+"\nwait" change independently, and the file takes ebd2a8f's version with its regression test.

CI

Green on 4efeecf: every workflow, including test (windows-latest) twice and test (macos-15) twice.

Two Windows failures on earlier heads were intermittent and did not recur:

  • A capacity-step git commit that git itself failed to write (unable to create temporary file).
  • concurrent_readers_cannot_enqueue_writer_work, which 975a79b fixes.

Verification (Linux, rustc 1.98.1, go 1.26.6)

Rust:

  • cargo fmt --all --check and cargo clippy --workspace --all-targets --locked -- -D warnings: clean.
  • As an unprivileged user, every devmap-store test binary passes: migration_ladder 12/12, embedded_reader 14/14, store_hardening 53/53, symbols_for_file 5/5, and the rest. As root, the tests that rely on read-only fixtures fail, because root ignores file permissions.
  • The two concurrent-open tests pass 10/10 repeated after 4efeecf.
  • All 144 devmap-serve, devmap-query and devmap-cli test binaries pass. The wider lock deadlocks nothing.
  • serve_stress: 10/10, three runs in a row.

Gusset engine, Go and scripts:

  • rust/gusset-engine against Gusset 709c2b7: build --locked, 12/12 tests, clippy clean.
  • Go:
    • gofmt and go vet are clean.
    • go test ./gate ./gussetfn ./policy ./cmd/devcouncil ./repomap passes, and -race ./gussetfn passes.
    • GOOS=windows CGO_ENABLED=0 go build ./... and go vet pass.
  • check-release.test.mjs: 32/32. check-workflows.test.mjs: 7/7.

🤖 Generated with Claude Code

https://claude.ai/code/session_01WQJD75wFPY52ckToQTu9FS

…its generation

GitPulse's code-intel panel (cmd_codeintel_symbols_for_file) reads the
symbols a single file declares and compares the generation's head_sha with
the commit it is showing. That reader was written against an unpushed local
commit (c55d479) and vendored into GitPulse from it, so the vendored
devmap-store carried FileSymbolsPage and Store::latest_symbols_for_file
while DevCouncil did not, and GitPulse could not re-vendor without losing
the feature. This lands the same code upstream.

The rows and the head_sha are read from one pinned snapshot, like
SearchPage: a second "latest" read could describe another generation.
`None` means no generation; `Some` with no rows means the path has no
indexed symbols. Corrupt spans go through checked_span, as every other
symbol reader does.

Tests in tests/symbols_for_file.rs cover the empty store, file scoping
and source order, an unindexed path, the latest generation winning, and a
corrupt span being refused.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WQJD75wFPY52ckToQTu9FS
The v1.3.5 release bumped the workspace version, but
rust/gusset-engine/Cargo.lock (outside the workspace) still named dc-glob
0.2.3, so every job that builds the umbrella staticlib with
`cargo build --locked` failed before any test ran. Regenerated with
`cargo update -p dc-glob --offline` against the pinned gusset 7a56c3c;
gusset stays 0.0.1. The same change is on claude/zealous-faraday-56lcrv.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WQJD75wFPY52ckToQTu9FS
cc 1.2.67 does not compile against find-msvc-tools 0.1.13, which
re-exports FILE_ATTRIBUTE_TEMPORARY as i32 where std wants u32; 0.1.14
restores u32. Every Windows leg that builds the workspace failed on it,
main included. Same lockfile change as b6e9673 on
claude/zealous-faraday-56lcrv, via `cargo update -p find-msvc-tools
--precise 0.1.14`.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WQJD75wFPY52ckToQTu9FS
devmap-resolve's LSP client spawned its server with a raw
Command::new, which devmap-extract's
every_child_process_in_the_kernel_goes_through_the_runner guard rejects:
a child outside the subprocess runner has no deadline and no output cap.
That test failed on main and on every Rust leg of this PR.

This is the lsp.rs and dc-proc part of e3bcb6b from
claude/zealous-faraday-56lcrv, unchanged. Its rust.yml hunk (a
static-musl step that builds on earlier workflow commits there) is left
out.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WQJD75wFPY52ckToQTu9FS
The clients jobs run `gofmt -l .` and failed on this file, on main as
well. Byte-identical to the file on claude/zealous-faraday-56lcrv (from
f0ec3e2).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WQJD75wFPY52ckToQTu9FS
devmap-cli's every_integration_test_is_classified_against_the_parse_feature
requires each integration test to be either feature-off safe or gated on
`parse`. symbols_for_file builds its generations with extract_file and the
resolver, so it is gated like retention_churn.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WQJD75wFPY52ckToQTu9FS
The umbrella and gussetfn were a startup health check with gaps at the
boundary. This closes the ones found by auditing it end to end:

- Stale links: Go's build and test caches key a cgo package on its flag
  text, not on the archive bytes, so after a Rust rebuild `go build` linked
  the old archive and `go test` could replay a cached "ok" (demonstrated
  with a marker string: invisible without -a). rust/gusset-engine/cgo-env.sh
  always runs the incremental cargo build and folds the archive's sha256
  into CGO_CFLAGS. verify.sh (which built only when the archive was
  missing), ci-local.mjs and the setup-gusset action now use it.
- Poison: the shared handle lived in a sync.Once, so one poisoned handle
  failed every later Match for the life of the process. A poisoned handle
  is now retired and the next call opens a new one; a failed Open is
  retried instead of latched. Close() shuts the engine for servers.
- Allocator blindness: no archive declared a global allocator, so
  gusset.Stats() read zero and AdviseMemoryLimit subtracted nothing. The
  umbrella installs gusset's Counting allocator; a test pins that a Rust
  buffer is counted once.
- MatchAny made one crossing per pattern. Opcode 1 carries a whole list,
  split into frames under the 4 KiB inline limit, validating every pattern
  before matching so the answer cannot depend on order.
- The firewall was only ever proven against gusset's diagnostic engine.
  SelfTest panics inside this archive (opcode 0x7fff0001, header-only) on
  a throwaway handle and requires ErrPanic, ErrPoisoned, and a clean match
  on the shared handle. Check stays panic-free: Manvi runs it in serve.
- DrainLogs forwards gusset's Rust log ring, which nothing read.
- The lockfile named gusset 0.0.1 / dc-glob 0.2.3, so `cargo build
  --locked` failed against current gusset; the setup-gusset pin moves from
  7a56c3c to b6f5200 (gusset main, 0.0.2) to match it.

Tests: the CPython fixture through the boundary, MatchAny against Go
across frame splits, poison recovery under 64-way concurrency, 200
micro-deadlines without poison, and FuzzMatchParity. Against a checkout of
gusset at the pin (b6f5200), with the archive built by cgo-env.sh: race
detector with GOGC=1 -count=15 clean, a 90 s fuzz clean, gusset-check ok
with non-zero Rust stats. An earlier 4 min fuzz (1.94M execs) against the
pre-allocator archive also found no divergence.

Protects I2 (panic firewall), I3 (cancellation), I4 (bounded handles)
and I6 (the archive under test is the archive linked).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FUNo5WZs78gWyCSXf2nRhm
(cherry picked from commit 3197897)
…ation

An adversarial review of 3197897 found these; each fix has a test that
fails without it (reverted and run):

- Match obeyed an opcode already on the caller's context: opcode 1 decoded
  a match frame as a match-any frame, and the self-test opcode panicked
  the shared handle. Match now pins opcode 0.
  (TestMatchIgnoresAnOpcodeOnTheContext)
- A call landing on a handle a sibling had just poisoned or retired got
  ErrPoisoned or an unclassified "handle is closed" while a healthy handle
  was one call away (457 + 64 such errors in the review's probe). call()
  retries once on the replacement; a frame's own ErrPanic is never retried.
  After Close, the retry reaches engine() and answers ErrClosed, as Close
  documents. (TestPoisonUnderConcurrencyRecovers now requires every call
  to succeed and exactly one replacement per poisoning;
  TestZZCloseRacingCallsSeeErrClosed; TestOwnPanicIsNotRetried)
- Close joins workers without a bound, so wiring it into a server's exit
  would hang on a stuck engine. Shutdown(drain) runs gusset.Shutdown first
  and returns its error without joining when the drain expires.
  (TestShutdownIsBoundedAndRefusesLaterCalls, in a child process)
- MatchAny validated UTF-8 per frame, so a bad pattern in frame 2 went
  unreported when frame 1 matched. Every field is checked up front.
  (TestMatchAnyValidatesAcrossFrames)
- TestStatsCountBuffersOnce passed with the global allocator removed:
  gusset counts buffers by hand regardless. TestCountingIsTheGlobalAllocator
  asserts AllocCount grows across Matches (0 -> 0 without Counting).
- verify.sh: `eval "$(cgo-env.sh)" || fail` could never fail — eval of empty
  output succeeds — so a failed engine build linked a stale archive.
  The output is captured first.
- cgo-env.sh and ci-local hashed target/release while an inherited
  CARGO_TARGET_DIR sent the fresh archive elsewhere; both now pass
  --target-dir. Base CFLAGS come from `go env` (process env, `go env -w`,
  or default) instead of the process env alone. A path with a space is
  refused by name.
- check-release now requires rust/gusset-engine/Cargo.lock's dc-glob to
  match the product version; the next bump would otherwise break
  `cargo build --locked` of the umbrella exactly as 0.2.3-at-1.3.5 did.
- Doc: the self-test opcode is sent by SelfTest, not Check.

Race detector with GOGC=1 -count=5 clean; gusset-check ok.

Protects I2 (panic firewall), I3 (bounded shutdown), I4 (bounded
handles) and I6 (the archive under test is the one linked).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FUNo5WZs78gWyCSXf2nRhm
(cherry picked from commit 876ace2)
gussetfn.DrainLogs stopped on a short read, treating it as "ring empty".
gusset's second-pass audit (80c6468) makes gusset_drain_logs hand over
whole lines and never split a UTF-8 character, so a short read can leave
lines behind; only 0 means empty. Looping until 0 is correct under both the
pinned gusset and the new one.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FUNo5WZs78gWyCSXf2nRhm
(cherry picked from commit f8866c7)
b6f5200 -> 709c2b7: gusset's second audit fixed a use-after-free where a
waiter returned freed Rust memory as its result, a double-Wait park, drain
exit admitting unreadable work, a queue lost-wakeup, phantom ring overflow,
failure codes lost with a NULL status, unbounded engine error text and
split log drains, and added a chaos hammer. Verified against it before
pinning: umbrella cargo test, gussetfn race suite, gusset-check.

Protects I1, I2 and I4.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FUNo5WZs78gWyCSXf2nRhm
(cherry picked from commit 663b998)
A third audit found the gusset gates in DevCouncil CI could not run:

- analysis-plane's clients job stopped at its gofmt step on
  policy/zfix_split_test.go (already on main), so Set up Gusset, vet,
  go test (which includes gussetfn) and -race never ran. gofmt applied.
- A pin-only bump triggered nothing: neither workflow's path filter named
  .github/actions/setup-gusset/**, and rust.yml also omitted
  rust/gusset-engine/** and gussetfn. Added.
- The Windows components leg could never build: gusset refuses non-unix
  targets with compile_error!, yet the action built it for
  x86_64-pc-windows-gnu through MinGW, and gussetfn plus gusset-check
  imported gusset unconditionally, so the host (which dc-verify's json
  contract needs) could not build there either. gussetfn and gusset-check
  are now build-tagged unix; elsewhere gussetfn answers ErrUnsupported and
  `devcouncil gusset-check` exits 2 ("could not run", never a pass). The
  action still checks out and links the sibling on Windows (go.mod's
  replace must resolve) and skips the Rust toolchain and archive build;
  the MinGW and gnu-target steps are gone. Verified: GOOS=windows
  CGO_ENABLED=0 go build and go vet of the host and gussetfn succeed.
- TestStatsCountBuffersOnce had no downward slack on a process-wide
  counter; a concurrent free from an earlier test's cleanup could fail it.
  It allows n-n/16; double-counting still fails near 2n.

actionlint clean; check-workflows tests pass; gussetfn -race and policy
tests pass; gusset-check ok on linux.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FUNo5WZs78gWyCSXf2nRhm
(cherry picked from commit f0ec3e2)
b6e9673)

serve_stress's ten_thousand_pipelined_stdio_requests_stay_inside_the_ceiling
failed on this PR with "MCP response write exceeded 5s": the 5 s
RESPONSE_WRITE_TIMEOUT covered the wait for the writer mutex as well as
the write, so on a loaded runner a reply queued behind other in-flight
replies to a peer that was reading fine ran out of time. The bound now
covers write+flush once the writer is held.

This is the devmap-serve half of b6e9673 on
claude/zealous-faraday-56lcrv, unchanged; its find-msvc-tools lockfile
half is already here as a2c364e.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WQJD75wFPY52ckToQTu9FS
… the scan detector room

- safe_fs: check_unchanged and check_appended_only compared the held
  handle with the file now at the name by dev/ino under cfg(unix) only. On
  Windows a managed file swapped for another between open and use went
  unnoticed, and the name's metadata was computed and dropped, which is
  the unused-variable clippy error that failed the Windows leg once cc
  compiled again. same_identity compares volume serial and file index from
  the handles on Windows (windows_information, already used here), dev/ino
  on unix. Clippy is clean on linux; the Windows build is checked by CI (the
  vendored C grammars cannot be cross-built here).
- repomap: TestAnAreaIsFoundWithoutWalkingEveryIndexedFile failed on macOS
  runners at 3.4x and 7.4x against a bound of 3x for an 8x larger map,
  though AreaForPath never touches the file table. The map is now 32x
  larger and the bound 8x: the lookup passes 5/5 here, and putting the old
  per-level scan back reads 39.7x and fails.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FUNo5WZs78gWyCSXf2nRhm
(cherry picked from commit c7563cf)
Checked locally with the windows-gnu target and mingw-w64, the same
workspace set rust.yml's Windows Clippy step lints; it is clean now:

- same_identity (added in c7563cf) named a File and a Metadata `held` and
  `_held`; clippy::similar_names. Renamed to held_file / named_file.
- dc-regress owners_and_test_signal: two tests drive a /bin/sh stub
  standing in for git and returned early on non-unix, which passed without
  testing anything and is unreachable_code under -D warnings. They are
  #[cfg(unix)] now, since the mechanism cannot exist on Windows. The other
  three tests in the file still run everywhere.

Linux clippy and the file's tests (5/5) pass.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FUNo5WZs78gWyCSXf2nRhm
(cherry picked from commit a21ee78)
…aring-violation retries

The Windows leg compiled for the first time in b6e9673 and showed 28
failing tests across 12 targets. Taken by cause:

Production
- repo_path / MCP roots (devmap-serve root_resolve): the unix rule ran on
  every host, so a Windows server refused every native path ("this server
  only opens unix filesystem paths"). Validation is now the host's own:
  unix still refuses C:\... and /C:/..., Windows refuses a drive-less /...
  instead of resolving it against the current drive, and takes only
  file:///<drive>:/... URIs. Neither side reinterprets the other's
  spelling. Unit tests for both directions; the unix URI test is unix-only.
- Hook background builds (devmap-cli hook): they ran under `sh -c`, which
  Windows does not guarantee, and the lock-owner liveness check answered
  "alive" for every pid on non-unix, so a dead build's lock stood for the
  full 30-minute ceiling. On Windows the build is now spawned directly as a
  detached process, removes its own lock on exit (OwnedLock, only when the
  lock's pid file names it, so the variable cannot direct any other
  removal), and OpenProcess/GetExitCodeProcess answers liveness. The hook's
  own std handles are made non-inheritable first; otherwise the build held
  the host's pipe and the host waited on the hook until the build ended.
  unix behaviour is unchanged.
- write_atomic (devmap-query): the snapshot comparison did not retry os
  error 32 while another writer's rename was replacing the target, which
  failed concurrent artifact and `devmap claude` bundle writes. It now
  waits within a 5 s deadline, and the rename retry drops its 100-attempt
  cap (about 0.5 s) for the same deadline.
- Store::open (devmap-store): SQLITE_PROTOCOL, a WAL-index lock race lost
  after SQLite's own retries, is retried from the top for up to 20 s with
  backoff; open is re-entrant because migrate re-reads the version under
  the write lock. All eight concurrent openers of a legacy store failed on
  it.
- paths: state paths are joined per component, so doctor no longer prints
  `.\.devmap\codeintel/devmap.sqlite`.

Tests (the code was right, the fixture was not)
- Canonical paths on Windows are `\\?\` verbatim with long names where
  the temp dir used 8.3 (`RUNNER~1`). Assertions that a message names a
  path accept it as written or canonical without the prefix (`names`); the
  `paths` db_path comparison ignores the prefix on both sides.
- Root URIs were `format!("file://{}", path)`, which is `file://C:\...`
  on Windows; `file_uri` builds the platform's form.
- Host configs were JSON built by format!, so a Windows path was an
  invalid escape and the config registered nothing; now serde_json.
- A repository name containing `"` cannot exist on Windows; there the
  fixture keeps the other hostile characters.
- make_undetachable set the read-only attribute, which Windows ignores on
  directories; it now denies writes with icacls.
- A mid-session store deletion cannot happen on Windows while the server
  holds the file; the test asserts the refused delete and that the store
  still serves.
- fanout.sh runs only on unix, where its consumers (verify.sh, the memory
  probe) run; a bare `bash` on a Windows runner is the WSL launcher. The
  rusqlite half of the test still runs everywhere.

Verified: clippy -D warnings clean for x86_64-pc-windows-gnu (mingw-w64)
and linux across the rust.yml workspace set; linux tests for every
touched binary pass. Three tests that rely on permission denials fail
identically before and after this change here because the container
runs as root (claude_integration an_unwritable_output_directory...,
kernel_defects k1_..., hook an_unremovable_stale_lock...,
pinned_root_disables_discovery); CI runs them as a normal user.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FUNo5WZs78gWyCSXf2nRhm
(cherry picked from commit 38c4d29)
…ss_reach

38c4d29 took the Windows leg from 28 failures to 3, all in its own test
changes, and one file it edited after formatting failed Format on every OS
(verify.sh gates too, which runs the same check):

- pinned_root_disables_discovery: the refusal names the pinned root
  canonically (`\\?\C:\...`), and the assertion compared the raw spelling;
  it uses `names`, like the other path assertions.
- parse_roots_list_caps_at_max_and_reports_overflow built drive-less
  `file:///tmp/...` URIs, which a Windows server now correctly refuses, so
  there was nothing to cap; it builds them in the host's spelling.
- windows_file_uri_is_rejected_not_reinterpreted asserts the unix rule and
  is unix-only; its Windows twin asserts that `file:///Users/...` does not
  become a root there.

cargo fmt --all --check clean; clippy -D warnings clean for linux and
x86_64-pc-windows-gnu; mcp_repo_scope 24/24 and phase1_freshness_reach
9/9 on linux (hook_conformance's pinned-root test needs a non-root user,
as before).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FUNo5WZs78gWyCSXf2nRhm
(cherry picked from commit 241b018)
runInThrowawayTree ran `sh -c <command>` and snapshotted the tree as soon
as sh exited. For a corpus entry that backgrounds its write
(`echo hi > .env &`), sh exits first: the write landed after the
snapshot, so the test recorded `would have written []` instead of `.env`,
and on macOS it raced t.TempDir's RemoveAll, failing
TestCommandVerdictIsNeverLooserThanTheWritesItPerforms with "directory not
empty". Appending `wait` on its own line makes sh reap the job first.

main never reached this on macOS: its clients job stopped at gofmt.
Passes 30/30 with -count=30; the backgrounded entry now records [.env].

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WQJD75wFPY52ckToQTu9FS
bharathvbcr pushed a commit to bharathvbcr/GitPulse that referenced this pull request Sep 28, 2026
Re-vendored from bharathvbcr/DevCouncil#14 at 485a2a6, which now also
carries DevCouncil's Windows fixes: file identity checks on Windows in
devmap-extract's safe_fs, native path validation, and sharing-violation
retries in devmap-query's artifact writes and devmap-store. Behaviour on
unix is unchanged (safe_fs keeps the same dev/ino check behind a helper).

`vendor-crates.mjs --check` reports every DevCouncil crate local: clean,
upstream: matches. clippy -D warnings is clean, and the Rust suite passes
apart from tests this sandbox cannot run as-is (two permission tests that
root bypasses, which pass unprivileged).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WQJD75wFPY52ckToQTu9FS
…le atomic writes; test(gate): wait for backgrounded writes

The last two Windows failures at 3b58dd7, and a macOS flake at 241b018:

- concurrent_readers_cannot_enqueue_writer_work: eight threads opening one
  store read-only lost the WAL-index race (SQLITE_PROTOCOL) as the
  migrators had; only Store::open retried it. Both opens now go through
  one retrying_lost_races helper.
- concurrent_emission_leaves_one_valid_bundle: os error 32 still escaped
  write_atomic, from a step outside the comparison and the rename (a
  different bundle file each run). Every step of write_atomic is safe to
  repeat from the top, so on Windows the whole write retries a sharing
  violation within the same 5 s deadline.
- gate: runInThrowawayTree ran `sh -c command` and read the tree when sh
  exited, so `echo hi > .env &` was recorded as writing nothing and its
  write landed during t.TempDir cleanup ("directory not empty", macOS).
  The shell now waits for its background jobs. If the gate had allowed
  that command, the old harness would have missed its write.
  TestThrowawayTreeSeesABackgroundedWrite fails without the wait (run 4:
  saw [], want [.env]).

fmt --check clean; clippy -D warnings clean for linux and windows-gnu;
migration_ladder 12/12, artifacts 7/7, gate passes. embedded_reader's
a_filesystem_read_only_open... fails here identically without this change
(root ignores the read-only fixture); CI runs it as a normal user.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FUNo5WZs78gWyCSXf2nRhm
(cherry picked from commit ebd2a8f)
…in a process

concurrent_readers_cannot_enqueue_writer_work still failed on Windows at
ebd2a8f: eight threads opening one store read-only all got SQLITE_PROTOCOL
for the whole 20 s retry deadline. Retrying cannot help. Reproduced
locally under Wine with a windows-gnu build: a single reader opens fine
and creates the -wal/-shm pair, the storm is intermittent and leaves the
file healthy, and even plain opens with no further reads fail. It is
contention between read-only connections in one process setting up the
WAL index together, with no read-write connection there to finish it.

A read-only connection now opens and makes its first read, the moment it
maps the WAL index, under a process-wide lock (READ_ONLY_SETUP); reads
after that run concurrently. Under Wine the test fails 3/3 without the
lock (21-33 s) and passes 4/4 with it (about 2.7 s); the whole
embedded_reader suite passes there, 11/11. Linux: migration_ladder 12/12,
embedded_reader unchanged (its read-only-fixture test needs a non-root
user). fmt and clippy clean for linux and windows-gnu.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FUNo5WZs78gWyCSXf2nRhm
(cherry picked from commit 9248cc6)
bharathvbcr pushed a commit to bharathvbcr/GitPulse that referenced this pull request Sep 28, 2026
Re-vendored from bharathvbcr/DevCouncil#14 at 975a79b, which adds two
Windows fixes from the same upstream series:

- devmap-query: on Windows, write_atomic retries the whole write when a
  sharing violation (os error 32) escapes any step, within its 5 s
  deadline. Unchanged on unix.
- devmap-store: read-only opens retry lost SQLite races like Store::open,
  and a process-wide lock covers a read-only connection's open and first
  read, so concurrent read-only connections cannot livelock setting up
  the WAL index. Reads after that still run concurrently.

`vendor-crates.mjs --check` reports every DevCouncil crate local: clean,
upstream: matches. clippy -D warnings is clean, and the Rust suite passes
apart from the permission tests root bypasses (they pass unprivileged).
process_admission_stress's substitution test fails its own "race was
exercised" guard intermittently on this 4-CPU sandbox: in one full run
the test passed and an identical copy of it failed, every refusal being
the storm renaming the directory away, so the vendored crates are not
involved.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WQJD75wFPY52ckToQTu9FS
At 975a79b the Windows leg failed
concurrent_v19_openers_keep_pending_work_and_one_durable_identity: sixteen
threads calling Store::open on one v19 store all got SQLITE_PROTOCOL for
the whole 20 s retry deadline (the test ran 19.5 s). It is the livelock
9248cc6 fixed for read-only connections, between read-write ones:
connections in one process setting the WAL index up together, each losing
to the others, with retrying unable to help.

The process-wide lock (renamed READ_ONLY_SETUP -> CONNECTION_SETUP, since
it now covers both) is also held across open_once, from Connection::open
through enable_wal and migrate. Migration was already serialised by
SQLite's write lock, so this costs in-process openers nothing they were
not already waiting for. Other processes still coordinate through SQLite,
and everything after the open runs concurrently. Nothing inside an open
opens another store, so the lock cannot be re-entered.

Linux: fmt and clippy -D warnings clean; every devmap-store test binary
passes as an unprivileged user (migration_ladder 12/12, embedded_reader
14/14, store_hardening 53/53, ...); the two concurrent-open tests pass
10/10 repeated; all 144 devmap-serve, devmap-query and devmap-cli test
binaries pass, so the wider lock deadlocks nothing there. Not reproduced
on Windows here; the next Windows leg is the check.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WQJD75wFPY52ckToQTu9FS
bharathvbcr pushed a commit to bharathvbcr/GitPulse that referenced this pull request Sep 29, 2026
Re-vendored from bharathvbcr/DevCouncil#14 at 4efeecf. devmap-store's
process-wide setup lock (now CONNECTION_SETUP) also covers a read-write
Store::open, from Connection::open through migration, so concurrent opens
in one process cannot livelock setting up the WAL index on Windows. Reads
after an open still run concurrently.

`vendor-crates.mjs --check` reports every DevCouncil crate local: clean,
upstream: matches. clippy -D warnings is clean. The full Rust suite
(2798 passed) hits no deadlock from the wider lock. It fails only the two
permission tests root bypasses (they pass unprivileged) and
process_admission_stress's intermittent "race was exercised" guard,
which, as in 79107bb, is unrelated to the vendored crates.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WQJD75wFPY52ckToQTu9FS
@bharathvbcr
bharathvbcr merged commit e8e664c into main Sep 29, 2026
37 checks passed
@bharathvbcr
bharathvbcr deleted the claude/friendly-lamport-60dj43 branch September 29, 2026 01:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants