Skip to content

fix(git): make Git subprocess and byte-exact fixture boundaries portable on Windows - #953

Merged
ScriptedAlchemy merged 13 commits into
codex/tracedecay-total-redesign-plan-reopenedfrom
cursor/windows-git-boundaries-d09f
Sep 7, 2026
Merged

fix(git): make Git subprocess and byte-exact fixture boundaries portable on Windows#953
ScriptedAlchemy merged 13 commits into
codex/tracedecay-total-redesign-plan-reopenedfrom
cursor/windows-git-boundaries-d09f

Conversation

@ScriptedAlchemy

@ScriptedAlchemy ScriptedAlchemy commented Sep 6, 2026

Copy link
Copy Markdown
Owner

Summary

  • Adds tracedecay_runtime_core::git::git_path_argument, a spelling boundary that drops only the \\?\ verbatim prefix when a native path is handed to Git as an argument (\\?\D:\xD:\x, \\?\UNC\s\v\x\\s\v\x), leaving every other component (long, spaced, non-ASCII) byte-identical. Used at the -C repository selector and the PR-autotrack worktree add/remove arguments. Callers keep the canonical path as the root identity they key on.
  • Fixes the Windows-only fixture boundaries from the feat: TraceDecay V2 delivery (PR8–PR13) + daemon performance, memory, and reliability overhaul #707 CI baseline: host-admission worktree add and gitfile spelling, core.longpaths for the 32-level nested-tree fixture, and core.autocrlf=false for the byte-exact scheduler corpus.
  • Scopes the CLI branch add end-to-end journey test to Unix, matching the daemon's #[cfg(not(unix))] arm in branch_add_response.
  • Also repairs a pre-existing base-branch break in the slice-tests (hotpath on) lane: 128fa8fa2 deleted two functions in global-db triggers.rs but left their #[hotpath::measure] attributes above mod tests, which only fails to compile with the hotpath feature on.

Motivation

Fixes #923 (Git-boundary child of #903). Baseline run 34039753429, head 9d17537b4. This is a Git adapter / fixture construction fix, not a semantic freshness workaround.

Root causes confirmed from the archived junit reports:

Test Failure on Windows Fix
host_admission_tests::add_branch_at_replay_rejects_stale_branch_after_switch, ..._stale_root_after_adversarial_replace, ..._restart_replay_rejects_common_dir_drift git worktree add "\\?\D:\a\_temp\tmp\.tmpX-admission-wt"fatal: could not create leading directories of '//?/D:/...': Invalid argument fixture roots come from the canonical temp root (verbatim on Windows); linked_worktree_on and the gitfile write now use the Git spelling while the verbatim PathBuf stays the payload/assertion identity
git_repository_authority::authority_bounds_nested_tree_inventory_before_rename_diff git commit: Filename too long at level-0/.../level-25 -c core.longpaths=true on the fixture's Git; tree depth unchanged
code_index_scheduler::tests::real_rebase_reconcile_matches_clean_scan snapshot_content_identity digests differ (bb77f439… vs 707d16e0…); log shows LF will be replaced by CRLF for src/lib.rs, src/feature.rs, src/main_only.rs first differing inputs: the incremental reconcile reads worktree bytes that git rebase rewrote as CRLF under the runner's global core.autocrlf=true, while the clean scan captures HEAD's blobs (find_blob) which are LF. Pinned core.autocrlf=false in the fixture repo (inherited by template copies). Rebase reconciliation is unchanged. Reproduced on Linux: with GIT_CONFIG_GLOBAL set to core.autocrlf=true, the unpinned fixture fails with exactly the same two digests as the Windows job; with the pin it passes.
cli_non_interactive_test::branch_add_seals_the_single_store_branch_and_remove_retires_its_exact_artifacts code_index_scheduler_unavailable: code-index scheduler authority is unavailable for branch activation this is the daemon's #[cfg(not(unix))] arm in branch_add.rs, not a Git boundary: the manual branch activation journey is not compiled on Windows. The test is gated #[cfg(unix)] with a comment naming that arm. Enabling the journey on Windows is a separate feature.
slice-tests (hotpath on) lane: tracedecay-global-db error: expected fn at triggers.rs:1718 mod tests pre-existing on the base branch; orphaned #[hotpath::measure] attributes over mod tests left by 128fa8fa2 removed the two dangling attributes

Changes

  • crates/tracedecay-runtime-core/src/git.rsgit_path_argument (Windows impl via Component/Prefix; refuses to respell paths containing literal ./.. or \\?\Volume{...} prefixes), applied in git_command_at; unit tests including a Windows-only spelling table and a cross-platform "spelled path canonicalizes back to the same directory" check.
  • crates/tracedecay/src/daemon/pr_autotrack.rs — worktree add/remove arguments go through the boundary.
  • crates/tracedecay/src/mcp/server/writer_test_support.rs, host_admission_tests.rsgit_path_argument wrapper; worktree add arg and common-dir gitfile pointer.
  • crates/tracedecay-runtime-core/tests/git_repository_authority.rscore.longpaths=true.
  • crates/tracedecay-code-index-runtime/src/code_index_scheduler/tests.rscore.autocrlf=false in GitFixture::build_fresh.
  • crates/tracedecay-cli/tests/core_cli_suite/cli_non_interactive_test.rs#[cfg(unix)] on the branch-add journey test and its only-here import.
  • crates/tracedecay-global-db/src/schema_contract/invariants/triggers.rs — drop the orphaned hotpath::measure attributes.

Not changed: traversal/authentication checks, rebase reconciliation, the checked-in evaluator object pack, labels or historical commits.

Test plan

  • cargo test -p tracedecay-runtime-core --lib git:: — 13 passed (incl. the new spelling tests)
  • cargo test -p tracedecay-runtime-core --test git_repository_authority — 15 passed
  • cargo test -p tracedecay-code-index-runtime --lib code_index_scheduler::tests::real_rebase_reconcile_matches_clean_scan — passes with default config and with GIT_CONFIG_GLOBALcore.autocrlf=true; fails without the pin under that config (negative control)
  • cargo test -p tracedecay --lib mcp::server::host_admission_tests — 24 passed
  • cargo test -p tracedecay --lib daemon::pr_autotrack — 24 passed
  • cargo test -p tracedecay-cli --test core_cli_suite branch_add_seals — passes on Linux
  • The CI slice-tests (hotpath on) command verbatim: HOTPATH_METRICS_SERVER_OFF=1 cargo test -p tracedecay-rusqlite-runtime -p tracedecay-global-db --locked --features tracedecay-rusqlite-runtime/hotpath,tracedecay-global-db/hotpath,tracedecay-global-db/test-helpers — compiles and passes
  • cargo clippy --tests on tracedecay-runtime-core, tracedecay-code-index-runtime, tracedecay, tracedecay-cli — no warnings
  • cargo fmt --all -- --check, npm run lint:commit — clean
  • Windows lanes on this PR's CI (the failing rows above) — the verbatim-path and long-path behaviour can only be observed there

Checklist

  • CHANGELOG.md updated (test/CI-only fix plus an internal helper; no user-facing change)
  • No secrets, credentials, or .env files included
  • Breaking changes documented (none)

Targets codex/tracedecay-total-redesign-plan-reopened (#707). #707 stays draft; nothing here undrafts or merges it.

Open in Web Open in Cursor 

cursoragent and others added 5 commits September 6, 2026 20:14
fs::canonicalize returns the \\?\ verbatim form on Windows. Win32 file
APIs and Command::current_dir accept it, but Git for Windows rewrites a
path *argument* to //?/D:/... and then fails ("could not create leading
directories" from git worktree add). Add git_path_argument, which drops
only the verbatim prefix at the Git argument boundary and passes every
other component through unchanged, and use it for the -C repository
selector and the PR-autotrack worktree add/remove arguments. Callers keep
the canonical path as the root identity they key on.

Refs #923

Co-authored-by: Zack Jackson <ScriptedAlchemy@users.noreply.github.com>
The host-admission fixtures build under the canonical temp root, which
on Windows is verbatim, and then handed that spelling to git worktree add
and wrote it into a gitfile. Route both through the Git argument spelling
while the fixture keeps the verbatim root as the identity in the payload.

Refs #923

Co-authored-by: Zack Jackson <ScriptedAlchemy@users.noreply.github.com>
The 32-level nested-tree fixture exceeds MAX_PATH on Windows and git
commit failed with 'Filename too long'. Pass core.longpaths=true to the
fixture's Git so the tree-depth condition under test is unchanged.

Refs #923

Co-authored-by: Zack Jackson <ScriptedAlchemy@users.noreply.github.com>
real_rebase_reconcile_matches_clean_scan compares an incremental
reconcile, which reads the worktree files git rebase rewrote, against a
clean scan that captures HEAD's blobs. Under the Windows runner's global
core.autocrlf=true the rewritten files came back CRLF, so the corpora
differed at src/feature.rs and src/main_only.rs. Set core.autocrlf=false
in the fixture repository so both read the same bytes.

Refs #923

Co-authored-by: Zack Jackson <ScriptedAlchemy@users.noreply.github.com>
branch_add_response only compiles the activation journey under
cfg(unix) and answers code_index_scheduler_unavailable elsewhere, so the
end-to-end CLI journey cannot pass on Windows by construction.

Refs #923

Co-authored-by: Zack Jackson <ScriptedAlchemy@users.noreply.github.com>
@changeset-bot

changeset-bot Bot commented Sep 6, 2026

Copy link
Copy Markdown

⚠️ No Changeset found

Latest commit: 9fd1d0b

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@ScriptedAlchemy

Copy link
Copy Markdown
Owner Author

This branch no longer merges cleanly with codex/tracedecay-total-redesign-plan-reopened (tip 5808a75). Conflicting files when merging the base in: crates/tracedecay-runtime-core/src/git.rs crates/tracedecay-runtime-core/tests/git_repository_authority.rs. Needs a rebase or base merge by the author; I left the branch untouched. The peer-landed work most likely behind the conflict: 5808a75 (registrar keyed by store authority), 2cc9808 (capability digest), b098810 (git argument paths on Windows), 6504d0c (private DACL), d265aa4 (host fixture paths).

cursoragent and others added 5 commits September 6, 2026 22:44
128fa8f deleted suspend/restore_immutability but left their
#[hotpath::measure] attributes above the tests module. The attribute is
inert without the feature, so only the hotpath slice lane saw the macro
reject a module ('expected fn') and fail to compile tracedecay-global-db.

Co-authored-by: Zack Jackson <ScriptedAlchemy@users.noreply.github.com>
# Conflicts:
#	crates/tracedecay-runtime-core/src/git.rs
#	crates/tracedecay-runtime-core/tests/git_repository_authority.rs

@ScriptedAlchemy ScriptedAlchemy left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review — keep the Git argument boundary; HOLD for coverage and conflicts

Reviewed ea537d2584eae6bf0f0cb871881dcff2da6722f1; source review only. GitHub reports conflicts; no PR workflow run was returned for this exact head.

The narrow git_path_argument helper is the correct direction: respell only when crossing into Git argv, retaining the admitted native path for identity and authorization. Preserve OsStr/non-UTF-8 data, component boundaries and unchanged handling of device/volume paths. Require native Windows drive and UNC paths with spaces/non-ASCII/long components, plus a filesystem check that the argv spelling still addresses the same directory. Do not use this helper as a project-identity normalizer.

P1 coverage: scoping the positive branch_add_seals... journey to Unix is only honest if the Windows contract is explicitly unsupported. Add a Windows test of the named unsupported response and prove no branch/store artifacts are created. Record the platform limitation in the support/acceptance inventory. Removing the sole Windows test is not a completed cross-platform feature fix; enabling that feature is separate work, not necessary in this PR.

Pinning core.autocrlf=false is appropriate for the byte-exact fixture. Keep a separate ordinary Windows/CRLF behavior test where the product claims it, so fixture normalization does not mask a production source-binding defect. Keep the checked-in evaluator pack/labels unchanged.

Resolve overlap with #959's path producers and #949's identical orphaned-hotpath deletion once. Run affected Git/host-admission/rebase tests on the resolved Windows merge tree before integration into #707. No timeout or freshness relaxation, and no #707 state change.

@github-actions

github-actions Bot commented Sep 7, 2026

Copy link
Copy Markdown
Contributor

Performance Comparison codex/tracedecay-total-redesign-plan-reopenedcursor/windows-git-boundaries-d09f

Total Elapsed Time: 5.25s → 4.78s (-8.9%)
CPU Baseline: 89.16µs → 90.12µs (+1.1%)
Benchmark ID: index-bench-timing

timing - Execution duration of functions.

+------------------------------------------+----------------------------+---------------------------------+---------------------------------+----------------------------------+------------------------------+
| Function                                 | Calls                      | Avg                             | P95                             | Total                            | % Total                      |
+------------------------------------------+----------------------------+---------------------------------+---------------------------------+----------------------------------+------------------------------+
| tracedecay-index-bench                   | 1 → 1 (+0.0%)              | 5.25s → 4.78s (-9.0%)           | 5.26s → 4.79s (-8.9%)           | 5.25s → 4.78s (-9.0%)            | 100.00% → 100.00% (+0.0%)    |
+------------------------------------------+----------------------------+---------------------------------+---------------------------------+----------------------------------+------------------------------+
| query.artifact.append_pages              | 13 → 13 (+0.0%)            | 190.05ms → 175.14ms (-7.8%)     | 262.93ms → 236.85ms (-9.9%)     | 2.47s → 2.28s (-7.7%)            | 47.04% → 47.61% (+1.2%)      |
+------------------------------------------+----------------------------+---------------------------------+---------------------------------+----------------------------------+------------------------------+
| query.artifact.batch.sqlite              | 13 → 13 (+0.0%)            | 120.09ms → 119.17ms (-0.8%)     | 161.48ms → 160.56ms (-0.6%)     | 1.56s → 1.55s (-0.6%)            | 29.73% → 32.39% (+8.9%)      |
+------------------------------------------+----------------------------+---------------------------------+---------------------------------+----------------------------------+------------------------------+
| query.artifact.batch.postings            | 13 → 13 (+0.0%)            | 107.03ms → 106.38ms (-0.6%)     | 145.49ms → 144.31ms (-0.8%)     | 1.39s → 1.38s (-0.7%)            | 26.49% → 28.92% (+9.2%)      |
+------------------------------------------+----------------------------+---------------------------------+---------------------------------+----------------------------------+------------------------------+
| code_index.workers.install               | 83 → 83 (+0.0%)            | 19.20ms → 14.30ms (-25.5%) 🚀   | 66.22ms → 48.33ms (-27.0%) 🚀   | 1.59s → 1.19s (-25.2%) 🚀        | 30.34% → 24.82% (-18.2%)     |
+------------------------------------------+----------------------------+---------------------------------+---------------------------------+----------------------------------+------------------------------+
| code_index.build.and_publish             | 2 → 2 (+0.0%)              | 588.74ms → 499.16ms (-15.2%)    | 611.84ms → 501.74ms (-18.0%)    | 1.18s → 998.33ms (-15.4%)        | 22.42% → 20.87% (-6.9%)      |
+------------------------------------------+----------------------------+---------------------------------+---------------------------------+----------------------------------+------------------------------+
| domain.canonical.sha256                  | 114526 → 114526 (+0.0%)    | 10.33µs → 8.44µs (-18.3%)       | 13.97µs → 13.99µs (+0.1%)       | 1.18s → 966.50ms (-18.1%)        | 22.52% → 20.21% (-10.3%)     |
+------------------------------------------+----------------------------+---------------------------------+---------------------------------+----------------------------------+------------------------------+
| query.artifact.prepare_pages             | 13 → 13 (+0.0%)            | 56.85ms → 43.81ms (-22.9%) 🚀   | 83.76ms → 63.18ms (-24.6%) 🚀   | 739.05ms → 569.55ms (-22.9%) 🚀  | 14.07% → 11.91% (-15.4%)     |
+------------------------------------------+----------------------------+---------------------------------+---------------------------------+----------------------------------+------------------------------+
| code_index.chunk.index_file              | 276 → 276 (+0.0%)          | 2.31ms → 2.01ms (-13.0%)        | 5.26ms → 2.97ms (-43.5%) 🚀     | 636.60ms → 555.79ms (-12.7%)     | 12.12% → 11.62% (-4.1%)      |
+------------------------------------------+----------------------------+---------------------------------+---------------------------------+----------------------------------+------------------------------+
| query.artifact.finalization.advance_wake | 14 → 14 (+0.0%)            | 41.09ms → 39.60ms (-3.6%)       | 261.75ms → 256.25ms (-2.1%)     | 575.30ms → 554.47ms (-3.6%)      | 10.95% → 11.59% (+5.8%)      |
+------------------------------------------+----------------------------+---------------------------------+---------------------------------+----------------------------------+------------------------------+
| code_index.extract.parser_artifact       | 276 → 276 (+0.0%)          | 2.12ms → 1.88ms (-11.3%)        | 4.78ms → 2.81ms (-41.2%) 🚀     | 585.08ms → 518.51ms (-11.4%)     | 11.14% → 10.84% (-2.7%)      |
+------------------------------------------+----------------------------+---------------------------------+---------------------------------+----------------------------------+------------------------------+
| query.artifact.batch.parallel_prepare    | 13 → 13 (+0.0%)            | 47.01ms → 34.20ms (-27.2%) 🚀   | 71.30ms → 49.25ms (-30.9%) 🚀   | 611.17ms → 444.54ms (-27.3%) 🚀  | 11.64% → 9.29% (-20.2%) 🚀   |
+------------------------------------------+----------------------------+---------------------------------+---------------------------------+----------------------------------+------------------------------+
| code_index.build.assemble                | 2 → 2 (+0.0%)              | 207.65ms → 185.97ms (-10.4%)    | 210.63ms → 198.97ms (-5.5%)     | 415.29ms → 371.93ms (-10.4%)     | 7.91% → 7.78% (-1.6%)        |
+------------------------------------------+----------------------------+---------------------------------+---------------------------------+----------------------------------+------------------------------+
| code_index.chunk.build                   | 276 → 276 (+0.0%)          | 1.43ms → 1.23ms (-14.0%)        | 3.93ms → 1.78ms (-54.7%) 🚀     | 395.68ms → 339.60ms (-14.2%)     | 7.53% → 7.10% (-5.7%)        |
+------------------------------------------+----------------------------+---------------------------------+---------------------------------+----------------------------------+------------------------------+
| 🆕 code_index.chunk.identify             | 0 → 276 (+100.0%) ⚠️       | 0.00ns → 1.21ms (+100.0%) ⚠️    | 0.00ns → 1.77ms (+100.0%) ⚠️    | 0.00ns → 335.13ms (+100.0%) ⚠️   | 0.00% → 7.01% (+100.0%) ⚠️   |
+------------------------------------------+----------------------------+---------------------------------+---------------------------------+----------------------------------+------------------------------+
| 🗑️ code_index.chunk.map_ordered          | 780 → 0 (-100.0%) 🚀       | 511.54µs → 0.00ns (-100.0%) 🚀  | 630.27µs → 0.00ns (-100.0%) 🚀  | 399.00ms → 0.00ns (-100.0%) 🚀   | 7.60% → 0.00% (-100.0%) 🚀   |
+------------------------------------------+----------------------------+---------------------------------+---------------------------------+----------------------------------+------------------------------+

Generated with hotpath-rs

@ScriptedAlchemy

Copy link
Copy Markdown
Owner Author

Resolved against the current redesign base and pushed as 2d614b35f (0 commits behind 7b67254c2 at verification).

Conflict decisions:

  • Kept central b0988105a / current shared plain_git_args + plain_host_path authority, central host-admission runner conversion, and central long-path/config fixture fixes. Dropped this branch's duplicate git_path_argument, explicit pr-autotrack/fixture conversions, and duplicate core.longpaths change.
  • Retained the two behaviors central lacked: repository-local core.autocrlf=false for byte-exact scheduler fixtures, and Unix scope for the branch-add journey that the daemon only implements on Unix.
  • Preserved the concurrent ea537d258 remote-head build fix through normal merge history; its tree change is now also in the base.

Verification on the integrated tree: the rebase-vs-clean-scan test passed both normally and with simulated global core.autocrlf=true (1/1 each); the branch-add journey passed (1/1); scoped clippy reported 0 warnings; actionlint and rustfmt passed. An optional all-features probe separately exposed an existing base too_many_arguments lint in tracedecay-query; it is outside this diff and the required scoped clippy is clean. Issue #923 remains open pending real Windows CI acceptance.

@ScriptedAlchemy
ScriptedAlchemy marked this pull request as ready for review September 7, 2026 03:33
@ScriptedAlchemy
ScriptedAlchemy merged commit 320173d into codex/tracedecay-total-redesign-plan-reopened Sep 7, 2026
7 checks passed
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Sep 7, 2026

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review Completed 2026-09-07T03:35:10.896522Z 9fd1d0b Draft marked ready
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

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