feat: sync portable fixes from upstream colby v1.5.0 - #173
Merged
Conversation
Run cargo metadata from the workspace root so its argv is exactly 'metadata --locked --no-deps --format-version 1' with no --manifest-path, while still accepting any caller cwd. Make the EXIT trap treat a deleted/unreadable Cargo.lock as changed so it deterministically exits 90 under set -e. Commit the Scenario B exclude fix and add argv-exactness and trap mutation/deletion regressions. Correct the evidence ledger transcript.
Add the initial black-box behavioral Red for Batch M: `codegraph init` must build the index in the isolated sibling `.codegraph-v2` namespace, never the fixed legacy `.codegraph` root. The test uses only the shipped public CLI surface and filesystem artifacts and imports no proposed Green API. On the v0.40.4 base it fails behaviorally because init still writes the legacy namespace. Record the pre-Red provenance/base gates, exact command/exit status, and failing assertion in the evidence ledger.
Introduce codegraph-core::IndexPaths as the single path authority for the isolated v2 index namespace (frozen plan Batch M, lines 236-338). It resolves, for a project and optional CODEGRAPH_DIR override: - the physical projectIdentity (full lowercase SHA-256 of a versioned binary payload: st_dev/st_ino on Unix, volume serial + 128-bit FileIdInfo on Windows), failing closed on unsupported filesystems with no lexical fallback; - the normalized legacy-root set (fixed .codegraph plus the configured old CLI root) that new binaries never open; - the isolated current root (.codegraph-v2 by default; a <name>-v2-<identity> sibling of a configured legacy root), plus every current-root artifact path (db, permanent lock, two fixed state slots, tombstone, config.toml, codegraph.json, daemon pid/log/socket). Path identity is physical: canonicalize the project and legacy roots, anchor a not-yet-created root on its nearest existing ancestor, and fail closed on empty/root/dot/parent aliases, symlink/reparse components below that ancestor, legacy equality, and ancestor/descendant overlap. Two distinct projects sharing a configured root receive distinct identity-suffixed current roots. Also adds infallible transitional helpers (current_root_lenient, current_db_lenient) and is_reserved_index_dir for the data-plane wiring in the next slice. This commit is the path layer only; the state-slot/lease/Store open protocol that consumes these paths lands in a later Batch M task.
…Paths Move the default index storage root that public `codegraph init` writes from the fixed legacy <project>/.codegraph to the isolated sibling <project>/.codegraph-v2, turning the initial Batch M black-box Red init_writes_isolated_v2_namespace_not_legacy_codegraph green. Data-plane consumers routed through the codegraph-core::IndexPaths authority (current_root_lenient / current_db_lenient) so no code reconstructs the .codegraph-v2 literal and the read/write sites all agree: - codegraph-cli main.rs codegraph_dir/db_path (central helper for init, index, sync, status, unlock, open_store, is_initialized, remove_db_files, spill); - codegraph-mcp CodeGraphEngine::open + roots::db_path_for, so the stdio/HTTP/daemon MCP request path reads the same namespace init writes; - codegraph-watch sync::default_db_path for watcher/catch-up sync; - codegraph-extract scan_dir now skips the whole .codegraph/.codegraph-* family via IndexPaths::is_reserved_index_dir, so a project never scans its own v2 index storage back into the graph. Directly-affected staging/read tests move the DB (and CLI-owned lock/uninit root) from .codegraph to .codegraph-v2. Daemon rendezvous paths (daemon.pid/sock/log) and the MCP must-not-self-index assertions stay on .codegraph; Config::discover, the codegraph.json ancestor walkers, and the benchmark oracle are deliberately unchanged and recorded as remaining Batch M consumers for the next integration task.
Close the transitional configured-root bypass rejected in verification and
tighten the Batch M path authority:
- Delete current_root_lenient/current_db_lenient. CLI codegraph_dir/db_path,
codegraph-mcp CodeGraphEngine::open, and codegraph-watch default_db_path now
resolve through fail-closed IndexPaths::resolve, honoring the configured
CODEGRAPH_DIR identity-suffixed sibling. CODEGRAPH_DIR=. / .. / root / overlap
/ symlink aliases now error before any root or DB creation and never mutate
the legacy namespace; two projects sharing one configured root get distinct
identity roots. Existence-probes that must stay infallible (CLI is_initialized
and status, mcp roots::db_path_for) degrade to the safe default and never open
a reconstructed configured-root path; the authoritative rejection is in
CodeGraphEngine::open.
- Replace the over-broad is_reserved_index_dir(".codegraph-" prefix) with
IndexPaths::reserved_child_dir_names, the exact resolved root set matched only
as direct children of the project root, so a user .codegraph-sources/ stays
scannable while .codegraph and .codegraph-v2 are excluded.
- Detect Windows junctions/reparse points via FILE_ATTRIBUTE_REPARSE_POINT in
addition to FileType::is_symlink.
- Capture GetFileInformationByHandleEx's OS error before CloseHandle so the
diagnostic is not masked.
- Remove the state_slot(usize) modulo-alias API; state_slots() is the exact
0/1 contract for this slice.
- Create the .codegraph rendezvous parent before opening daemon.log in the
parent-side detached-spawn redirect, since the current namespace is the
sibling .codegraph-v2 and .codegraph may not exist yet.
Adds real public-surface CLI regressions (configured relative/absolute root
sibling, two-project collision, CODEGRAPH_DIR=. fails closed byte-nonmutating)
and a scanner regression proving .codegraph-sources is indexed. The initial
black-box Red stays green; cargo test --workspace --locked passes.
…via MCP Correction #3 for Batch M IndexPaths verification. Two claims of 7652267 were overclaims and are superseded here (no amend; prior commits preserved). Byte-proof snapshots: the CLI nonmutation oracle captured (path, byte LENGTH), so an equal-length in-place write was invisible. tree_snapshot now captures the COMPLETE bytes per file via symlink_metadata, comparison moved into assert_tree_bytes_unchanged (reports only changed paths), and a harness self-test flips one byte at constant length to prove the assertion fails. Reachable invalid-config state: db_exists_for collapsed unsafe-configured-root and absent-DB into one bool that both MCP front-ends consumed before CodeGraphEngine::open, so CODEGRAPH_DIR=. emitted the generic "No indexed project" and the actionable IndexPaths diagnostic was unreachable. roots.rs now carries typed RootStatus/ProjectArg states discriminated by error VARIANT (never by parsing rendered strings), with one shared resolve_project_arg both front-ends delegate to; candidate order is unchanged and an indexed candidate still wins over an earlier invalid one. New public-surface regressions stage a trap DB at the default .codegraph-v2 namespace under a refused CODEGRAPH_DIR=. and prove both the hand-rolled and the shipped rmcp tool call fail closed with the stable reason, serve no trap symbol, and mutate zero project bytes. Test env mutation is now panic-safe via an RAII EnvGuard holding the serializing lock. No dependency, schema, node-id, or golden change; Cargo.lock byte-identical.
The nonmutation oracle added in 7d95634 stat'd entries with symlink_metadata but read them with fs::read, which follows the link, so the "never follows links" claim was false. It also converted I/O errors into false "unchanged" results (read_dir early-return, entry filter_map(Result::ok), read().unwrap_or_default()) and recorded only files, hiding empty-directory mutations. Both oracles now build typed entries: an OS-native relative PathBuf plus Directory | RegularFile(complete bytes) | Symlink(read_link target). Every I/O step panics with a path-naming message instead of skipping or defaulting, and an entry kind without a deterministic exact representation panics rather than being omitted. Failure messages stay bounded, naming paths and kind labels but never file bytes. New cfg(unix)-gated self-tests prove the properties mechanically: empty-directory creation/removal is detected, a symlink retarget is detected while an out-of-tree write to its target is not (proving no follow), and a special entry kind makes the snapshot panic. Also removes the stale documentation left by the previous correction: roots::db_path_for and McpServer::engine_for no longer claim CodeGraphEngine::open surfaces the authoritative invalid-config error, which the shared typed resolver now raises before any engine is opened, and the MCP test module doc describes both server front-ends. Test-only plus comments; no production behavior, dependency, schema, node-id, or golden change.
…gate evidence The Batch M classifier validation evidence was appended after the last oxfmt pass, so the committed ledger was not formatter-clean and the next `make ci` failed at `fmt-check` before any test ran. Reformat the ledger with oxfmt and append a dated correction that keeps both historical daemon_single_watcher_fires_once attempts as history, records the doc-format failure observed after 224e762, and states the authoritative post-format gate result. Documentation only: no Rust, manifest, schema, golden, or Cargo.lock change.
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
Ports every portable fix from upstream
colby/codegraphv1.5.0 (86-commit range), plus the correctness defects found while verifying them.Upstream ports — 15 behavioral landings across four batches:
find_pathenqueue-once, andnode <symbol> --filereturning the pinned overload's source.end_line, MyBatis dialect + qualified refids.Release integrity — deterministic
SHA256SUMSpublished with every release and fail-closed verification in both installers; a drift guard asserting the asset-name contract across the workflow and both installers;KNOWN_DIFFS.mdwired into the equivalence oracle as a fail-closed executable allowlist; and aCI Successgate that now requires every job to concludesuccessrather than merely notfailure.Correctness fixes found during verification:
Path::display()lossily replaced non-UTF-8 bytes, so a hard-killed daemon's committed WAL went undetected and a stale index was served asCurrent.Verification
make ci CARGO='cargo --locked'green at default parallelism, run repeatedly.reference/golden/changes confined tocpp/and purely additive, with every pre-existing node ID preserved object-for-object.Cargo.lockunchanged (750ee84b…); no hand-bumped versions.Known limitations
ETXTBSYtest flake (stub written then immediately exec'd) remains unfixed; it has not reproduced recently.