Skip to content

Promote develop to main: Record a Per-Fetch Token in hub.owned - #2545

Merged
ptr727 merged 2 commits into
mainfrom
develop
Oct 8, 2026
Merged

ptr727 merged 2 commits into
mainfrom
develop

Conversation

@ptr727

@ptr727 ptr727 commented Oct 8, 2026

Copy link
Copy Markdown
Owner

Summary

Promotes one change from develop.

  • Record a Per-Fetch Token in hub.owned So a Menu Removes Only the Hub It Fetched #2542: menu.ps1 and menu.sh each write a token unique to the fetch into the shared hub.owned marker. The exit cleanup, holding the hub lock, removes the cached hub only when the marker still holds the session's own token. A session that fetched earlier no longer deletes a tree another session sharing the cache directory fetched since, a -Keep / --keep session's included. In menu.sh the token is read before the fetch changes anything, and a failed read fails the fetch, since errexit is suspended there.

Closes #1093.

Verification

🤖 Generated with Claude Code

…It Fetched (#2542)

## Summary

Refs #1093.

`menu.ps1` and `menu.sh` share a hub cache, `$DIR/hub`, marked by
`$DIR/hub.owned`. A session's exit cleanup removed that tree whenever
its own process-local `HUB_FETCHED` was true and the marker existed. A
session that fetched earlier could therefore delete a tree another
session sharing the directory fetched since, a `-Keep` / `--keep`
session's included.

- Each fetch now writes a token unique to that fetch into the marker: a
GUID in `menu.ps1` and 16 bytes of `/dev/urandom` as hex in `menu.sh`.
- The exit cleanup, once it holds the hub lock, removes the tree only
when the marker still holds this session's own token
(`Test-HubFetchedHere` / `hub_fetched_here`). A session that has no
token, or finds an empty marker, removes nothing.
- The issue says `menu.sh` lacks this shape. It does not: it has the
same marker and the same cleanup gate, and both menus can share one
`--dir`, so both are fixed here.

## Known limit

An older copy of either menu, one fetched before this lands, still
deletes whenever any marker exists. Until it is replaced, it can remove
a tree a new session fetched. Nothing here can close that, since an old
copy never reads the token.

## Verification (Windows host)

- New `TestMenuHubCleanup` (bash, run under Git Bash with `flock`
stubbed) and `TestPowerShellMenuHubCleanup` (pwsh, under the real lock)
share one set of cases. Two of them run a real fetch with `git` stubbed:
a session's own fetch is removed at exit, and a fetch by another session
made since survives the first session's exit.
- Mutation-checked in both menus. Disabling the token gate fails 3 cases
per menu, and writing an empty marker fails the own-fetch case per menu.
- Full suite under Git Bash: 2270 tests, OK, 100 skipped.
- ruff, mypy, the prose gate and the EOL gate pass, and so do
shellcheck, shfmt and PSScriptAnalyzer through `scripts/docker_lint.py`.
- Two local strict-review passes. The first raised one finding, a test
name claiming a cross-menu match that cannot occur, which is fixed in
e921ba5. The second raised none.
- Not run on Linux locally. CI's Linux run covers `menu.sh` under real
bash and `menu.ps1` under Linux pwsh.

The review also found one pre-existing defect, filed as #2541: the
freshness check ignores `--ref`.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Copilot AI lite review requested due to automatic review settings October 8, 2026 15:44
@coderabbitai

coderabbitai Bot commented Oct 8, 2026 •

Copy link
Copy Markdown

Important

  • 🔍 Trigger review

This repository does not receive automatic reviews because it has fewer than 10 stars.

⚙️ Run configuration
  • Configuration used: Repository: ptr727/ProjectTemplate/.coderabbit.yaml
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 6976ad92-605b-4659-9b00-c3d63320fb01
  • Autopilot · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@codecov

codecov Bot commented Oct 8, 2026 •

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 58.40%. Comparing base (382c0cc) to head (80b5f01).
⚠️ Report is 330 commits behind head on main.

Additional details and impacted files
@@           Coverage Diff           @@
##             main    #2545   +/-   ##
=======================================
  Coverage   58.40%   58.40%           
=======================================
  Files          16       16           
  Lines        8090     8090           
=======================================
  Hits         4725     4725           
  Misses       3365     3365           
Flag Coverage Δ
python-3.13 58.40% <ø> (ø)

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🔵 Needs a closer look

menu.sh can ignore marker-write failures and leave fetched trees behind.

0 open findings

What changed in this PR

Promotes the per-fetch hub ownership token changes from develop to main, preventing stale sessions from deleting another session’s cache.

Changes:

  • Adds ownership tokens to Bash and PowerShell hub cleanup.
  • Adds cross-menu cleanup and failure-handling tests.
  • menu.sh must still handle marker-write failures before proceeding.
File Summary
tests/​test_bootstrap.py Adds cross-menu cleanup coverage.
host-setup/​menu.sh Adds token generation and guarded cleanup; marker-write failure handling remains unresolved.
host-setup/​menu.ps1 Adds GUID-based ownership validation and guarded cleanup.

🧠 Review effort: Lite


Give feedback about Copilot approvals in this survey to enter a drawing for a $150 gift card.

@ptr727

ptr727 commented Oct 8, 2026

Copy link
Copy Markdown
Owner Author

Copilot's round on 9d8937b opened no thread, but its headline named one finding: menu.sh can ignore marker-write failures and leave fetched trees behind. It is real, and it is being fixed in #2548 together with its siblings in both menus' fetch paths. Once that merges into develop, this PR's head moves and a new round is due. The reader gap that lets this headline shape pass the digest is #2544.

… Its Token Only Once Written (#2548)

## Summary

Answers the Copilot finding on promotion PR #2545: "`menu.sh` can ignore
marker-write failures and leave fetched trees behind". It also fixes
that finding's siblings in the same fetch functions of both menus. Refs
#1093.

- **Marker write.** `menu.sh`'s `fetch_hub_locked` runs with errexit
suspended (`fetch_hub_locked || rc=$?`), so a failed write to
`hub.owned` let the clone go ahead unmarked. Cleanup then skipped that
tree, and every later fetch refused it as a tree this run did not
create. The write now fails the fetch before the clone. In `menu.ps1`, a
`Set-Content` failure threw past the task. It now fails the task, the
same way #2537 made a lock that cannot be taken fail it.
- **Old-tree removal.** A file held under the old tree made `menu.ps1`'s
`Remove-Item` throw past the task and end the menu session. In `menu.sh`
it made the clone run into the surviving tree, and the clone-failure
path then dropped the marker. Both now fail the fetch and leave the tree
and its marker as they were, so the owning session's exit cleanup can
still remove them.
- **When the token becomes the session's.** Each fetch builds its token
in a local variable and assigns it to the session only once the marker
holds it. Before this, a fetch that failed after generating its token
replaced the session's own token, and the session's exit cleanup no
longer matched the tree its earlier fetch had marked.

## Verification (Windows host)

- New failure cases, one per path per menu: token read in bash, old-tree
removal, and marker write. Each stubs or provokes the failure, then
asserts the task fails, nothing is cloned, the marker is kept where it
should be, and the session's token is unchanged. The `menu.ps1` stubs
shadow the cmdlet in the harness body, so each case reaches its `catch`.
- Mutation-checked against the code before each fix. The menus from
`develop` fail both write cases. The removal guards' parent fails both
removal cases. The early token assignment fails 4 cases.
- Full suite under Git Bash: 2275 tests, OK, 100 skipped. ruff, mypy,
the prose gate and the EOL gate pass, and so do shellcheck, shfmt and
PSScriptAnalyzer through `scripts/docker_lint.py`.
- Three local strict-review passes. The second raised one finding, the
early token assignment, which is fixed in 31a69ad. The third raised
none.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟢 Approval recommended

No unresolved review issues were identified.

0 open findings

🧠 Review effort: Lite


Give feedback about Copilot approvals in this survey to enter a drawing for a $150 gift card.

@ptr727
ptr727 merged commit ce0285d into main Oct 8, 2026
13 checks passed
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.

menu.ps1: hub-cache cleanup marker does not identify which session fetched it

2 participants