Skip to content

test(hook-augment): pin worktree payload-cwd resolution - #1768

Merged
DeusData merged 3 commits into
DeusData:mainfrom
bmcnaboe:fix/hook-augment-worktree-tests
Sep 25, 2026
Merged

DeusData merged 3 commits into
DeusData:mainfrom
bmcnaboe:fix/hook-augment-worktree-tests

Conversation

@bmcnaboe

Copy link
Copy Markdown
Contributor

Regression tests for the hook augment payload-cwd -> project resolution across a linked git worktree, on a real worktree fixture:

  • payload cwd inside an indexed linked worktree (and a subdir) resolves to that worktree own project, never a sibling checkout or nothing;
  • an unindexed worktree gets a deliberate "no indexed graph project matched" notice, never a silent 0 bytes;
  • main-checkout resolution is unchanged.

Current main already resolves worktrees correctly; this adds the coverage that was missing so it cannot regress. Opened as a draft.

Fixes #1752

@github-actions

Copy link
Copy Markdown

Thanks for opening this — it has been seen, and it is queued.

This note is automated, but it is not a brush-off: it exists so you know where your PR stands instead of having to guess from silence.

Current review status: working through a backlog. 0.9.1-rc.1 is out, so the release freeze that held reviews is over — but it left a large queue of open pull requests behind it, and we are reading through them oldest-first. The background is in discussion #1144.

What that means for this PR, concretely:

  • It will not be closed for inactivity. No stale bot touches pull requests here.
  • It may still sit a while before a human reads it. That is on us, not on you.
  • Older PRs are read first, so a recent one is not being skipped — it is behind a queue.

Things that will genuinely speed it up whenever review does happen:

  • Keep it rebased on main — the tree is moving quickly right now, and a conflicting branch cannot be reviewed as the diff you intended.
  • Get CI green, or say which failures you believe are pre-existing.
  • Keep the change to one claim. Bundled features and refactors get split before they get merged, which costs you a round trip.
  • Every commit needs a sign-off (git commit -s) — CI enforces DCO.

If this fixes a bug, a reproduction we can run is worth more than a description of the symptom.

Thanks for contributing, and sorry in advance for the wait.

@bmcnaboe
bmcnaboe marked this pull request as ready for review August 24, 2026 19:54
@bmcnaboe
bmcnaboe requested a review from DeusData as a code owner August 24, 2026 19:54
@DeusData DeusData added maintainer-notes Internal observations and improvement notes editor/integration Editor compatibility and CLI integration priority/normal Standard review queue; useful PR with ordinary maintainer urgency. labels Sep 1, 2026
@DeusData

DeusData commented Sep 1, 2026

Copy link
Copy Markdown
Owner

Thank you for adding deterministic linked-worktree coverage while leaving current production behavior unchanged. The positive, unindexed, and main-checkout controls give this a clear maintenance boundary. The contribution queue is quite full, so review may take a little time, but we will come back with feedback as soon as possible.

@DeusData

DeusData commented Sep 6, 2026

Copy link
Copy Markdown
Owner

Picking this back up, with thanks for the patience: the branch now conflicts with main (test_cli.c moved a lot underneath it in the last two weeks), so it cannot be evaluated as-is. Could you rebase onto current main and keep the sign-off? Once it applies cleanly I will take the host-side clearance for the four system() sites in the test (they are the same shape as the fourteen existing ones in the suite) and give it a proper review straight away.

The hook resolves a payload cwd inside a linked git worktree to that
worktree own indexed project (and a subdir of it), never a sibling
checkout or nothing, and an unindexed worktree gets a deliberate
"no indexed graph project matched" notice rather than a silent 0 bytes.
Main-checkout resolution is unchanged. These regression tests use a real
linked worktree and lock the payload-cwd -> project invariant.

Fixes DeusData#1752

Signed-off-by: Brian McNaboe <bmcnaboe@gmail.com>
@bmcnaboe
bmcnaboe force-pushed the fix/hook-augment-worktree-tests branch from d47f098 to e8dcb28 Compare September 8, 2026 18:14
@bmcnaboe

bmcnaboe commented Sep 8, 2026

Copy link
Copy Markdown
Contributor Author

Rebased onto current main (b5185d1), sign-off kept. Same two tests, one fewer hunk: the forward declaration of cbm_project_name_from_path is gone since pipeline.h already provides it. cli suite passes locally (311). The earlier test-windows-guards failure was the guard's own fixture ("ASCII baseline did not index"), not these tests, which are compiled out on Windows.

timothybrush pushed a commit to timothybrush/codebase-memory-mcp that referenced this pull request Sep 24, 2026
…ure on Windows

Several processes first-starting together against a runtime directory
that does not exist yet -- test-windows-guards' section_cold_storm, or a
host that launches more than one MCP server on its very first run -- all
observe the final path component absent. One CreateDirectoryW wins; the
others get ERROR_ALREADY_EXISTS. win_private_directory_tree_secure()
treated that as a failure and recorded no validation detail, so every
loser exited with a bare

    secure CLI coordination could not be created (endpoint)

The function called right after the walk, win_runtime_directory_secure(),
has always tolerated ERROR_ALREADY_EXISTS for the same directory, and the
POSIX walk tolerates EEXIST at the same point; only the Windows walk in
front of them did not.

Seen four times on 2026-09-21 on unrelated PRs (DeusData#1768 three attempts in
a row, DeusData#2140, DeusData#1999, DeusData#808). The racy lines date from July; the guard
began exercising them on 2026-09-03, when each guard section was given
its own empty CBM_RUNTIME_DIR, so the final component is now absent at
storm time on every run.

The walk now treats ERROR_ALREADY_EXISTS from its own CreateDirectoryW as
"the directory I wanted exists". Nothing is trusted because of that: an
ancestor still goes through win_directory_component_secure(), and the
final component through win_runtime_directory_secure(), which refuses a
non-directory or reparse point and enforces owner and DACL.

Every refusal on this path now names its component and its rule. The
walk reports the Windows error when it can neither create nor inspect a
component, and win_runtime_directory_secure() says whether the path
could not be created, cannot be inspected, exists but is not a directory,
or is a reparse point. One helper owns the wide-to-UTF-8 conversion for
these messages and the existing ancestor message now uses it too, so
src/daemon/ipc.c stays at its memory-core baseline.

Deterministic reproduction, no threads and no timing: a test seam fires
in the walk between "component observed absent" and CreateDirectoryW,
and the test plays the process that wins the creation.

  daemon_ipc_windows_private_directory_survives_lost_creation_race
  daemon_ipc_windows_private_directory_refuses_and_names_a_planted_file

Verification. macOS arm64 (ASan+UBSan): build clean, daemon_ipc 53 passed
(2 Windows-only skips), daemon_bootstrap 28 passed, lint-memory-core
unchanged (ipc.c stays at 146 raw sites). The two new tests are Windows-only
and have NOT been run locally: the Windows VM was down when this was written,
so the RED run on the seam-only tree and the GREEN run with this fix are
delegated to CI's windows-latest legs (test-windows shards, test-windows-guards)
by an explicit maintainer decision. If the guard suite's cold storm still
fails with this in place, the attribution above is wrong and this reverts.

Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
@DeusData
DeusData merged commit a5550e1 into DeusData:main Sep 25, 2026
33 checks passed
@DeusData

Copy link
Copy Markdown
Owner

Merged — thank you, and sorry for the long wait after you had the last word.

Verified on the merge result with the current main: the cli suite passes, including both of your new tests, and main has not touched tests/test_cli.c in a way that overlaps them. The shape is right for what they pin: each fixture works in its own mkdtemp directory, cleans up before its assertions, and carries a control on a plain main checkout, so a failure points at the behaviour rather than at the fixture.

One small follow-up worth knowing, not a blocker: the fixtures' git commit inherits the user's global git configuration, so on a machine with commit.gpgsign=true they would fail rather than skip. Passing -c commit.gpgsign=false (or setting it in the fixture repository's local config) would make them independent of whoever runs them. Happy to take that in a tiny follow-up if you prefer not to.

daidaiJ pushed a commit to daidaiJ/codebase-memory-mcp that referenced this pull request Sep 29, 2026
…ure on Windows

Several processes first-starting together against a runtime directory
that does not exist yet -- test-windows-guards' section_cold_storm, or a
host that launches more than one MCP server on its very first run -- all
observe the final path component absent. One CreateDirectoryW wins; the
others get ERROR_ALREADY_EXISTS. win_private_directory_tree_secure()
treated that as a failure and recorded no validation detail, so every
loser exited with a bare

    secure CLI coordination could not be created (endpoint)

The function called right after the walk, win_runtime_directory_secure(),
has always tolerated ERROR_ALREADY_EXISTS for the same directory, and the
POSIX walk tolerates EEXIST at the same point; only the Windows walk in
front of them did not.

Seen four times on 2026-09-21 on unrelated PRs (DeusData#1768 three attempts in
a row, DeusData#2140, DeusData#1999, DeusData#808). The racy lines date from July; the guard
began exercising them on 2026-09-03, when each guard section was given
its own empty CBM_RUNTIME_DIR, so the final component is now absent at
storm time on every run.

The walk now treats ERROR_ALREADY_EXISTS from its own CreateDirectoryW as
"the directory I wanted exists". Nothing is trusted because of that: an
ancestor still goes through win_directory_component_secure(), and the
final component through win_runtime_directory_secure(), which refuses a
non-directory or reparse point and enforces owner and DACL.

Every refusal on this path now names its component and its rule. The
walk reports the Windows error when it can neither create nor inspect a
component, and win_runtime_directory_secure() says whether the path
could not be created, cannot be inspected, exists but is not a directory,
or is a reparse point. One helper owns the wide-to-UTF-8 conversion for
these messages and the existing ancestor message now uses it too, so
src/daemon/ipc.c stays at its memory-core baseline.

Deterministic reproduction, no threads and no timing: a test seam fires
in the walk between "component observed absent" and CreateDirectoryW,
and the test plays the process that wins the creation.

  daemon_ipc_windows_private_directory_survives_lost_creation_race
  daemon_ipc_windows_private_directory_refuses_and_names_a_planted_file

Verification. macOS arm64 (ASan+UBSan): build clean, daemon_ipc 53 passed
(2 Windows-only skips), daemon_bootstrap 28 passed, lint-memory-core
unchanged (ipc.c stays at 146 raw sites). The two new tests are Windows-only
and have NOT been run locally: the Windows VM was down when this was written,
so the RED run on the seam-only tree and the GREEN run with this fix are
delegated to CI's windows-latest legs (test-windows shards, test-windows-guards)
by an explicit maintainer decision. If the guard suite's cold storm still
fails with this in place, the attribution above is wrong and this reverts.

Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
daidaiJ pushed a commit to daidaiJ/codebase-memory-mcp that referenced this pull request Sep 29, 2026
…ure on Windows

Several processes first-starting together against a runtime directory
that does not exist yet -- test-windows-guards' section_cold_storm, or a
host that launches more than one MCP server on its very first run -- all
observe the final path component absent. One CreateDirectoryW wins; the
others get ERROR_ALREADY_EXISTS. win_private_directory_tree_secure()
treated that as a failure and recorded no validation detail, so every
loser exited with a bare

    secure CLI coordination could not be created (endpoint)

The function called right after the walk, win_runtime_directory_secure(),
has always tolerated ERROR_ALREADY_EXISTS for the same directory, and the
POSIX walk tolerates EEXIST at the same point; only the Windows walk in
front of them did not.

Seen four times on 2026-09-21 on unrelated PRs (DeusData#1768 three attempts in
a row, DeusData#2140, DeusData#1999, DeusData#808). The racy lines date from July; the guard
began exercising them on 2026-09-03, when each guard section was given
its own empty CBM_RUNTIME_DIR, so the final component is now absent at
storm time on every run.

The walk now treats ERROR_ALREADY_EXISTS from its own CreateDirectoryW as
"the directory I wanted exists". Nothing is trusted because of that: an
ancestor still goes through win_directory_component_secure(), and the
final component through win_runtime_directory_secure(), which refuses a
non-directory or reparse point and enforces owner and DACL.

Every refusal on this path now names its component and its rule. The
walk reports the Windows error when it can neither create nor inspect a
component, and win_runtime_directory_secure() says whether the path
could not be created, cannot be inspected, exists but is not a directory,
or is a reparse point. One helper owns the wide-to-UTF-8 conversion for
these messages and the existing ancestor message now uses it too, so
src/daemon/ipc.c stays at its memory-core baseline.

Deterministic reproduction, no threads and no timing: a test seam fires
in the walk between "component observed absent" and CreateDirectoryW,
and the test plays the process that wins the creation.

  daemon_ipc_windows_private_directory_survives_lost_creation_race
  daemon_ipc_windows_private_directory_refuses_and_names_a_planted_file

Verification. macOS arm64 (ASan+UBSan): build clean, daemon_ipc 53 passed
(2 Windows-only skips), daemon_bootstrap 28 passed, lint-memory-core
unchanged (ipc.c stays at 146 raw sites). The two new tests are Windows-only
and have NOT been run locally: the Windows VM was down when this was written,
so the RED run on the seam-only tree and the GREEN run with this fix are
delegated to CI's windows-latest legs (test-windows shards, test-windows-guards)
by an explicit maintainer decision. If the guard suite's cold storm still
fails with this in place, the attribution above is wrong and this reverts.

Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

editor/integration Editor compatibility and CLI integration maintainer-notes Internal observations and improvement notes priority/normal Standard review queue; useful PR with ordinary maintainer urgency.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

hook-augment returns 0 bytes when payload cwd is an indexed linked worktree

2 participants