Skip to content

fix(windows): recover scope retention and long private archives - #1958

Merged
ScriptedAlchemy merged 8 commits into
masterfrom
codex/fix-windows-retention-handles
Sep 24, 2026
Merged

ScriptedAlchemy merged 8 commits into
masterfrom
codex/fix-windows-retention-handles

Conversation

@ScriptedAlchemy

Copy link
Copy Markdown
Owner

Problem

Native Windows CI found two distinct failures in the #919 lifecycle: scope quarantine cannot rename a directory while this process holds its child generation-lock handle (AccessDenied 5), and private archive retirement reaches a long Win32 path that fails with path-not-found 3. The first diagnostic run also proved the crash-recovery tests were retaining a handle a restarted process cannot retain.

Change

  • Drop crash-simulation handles before recovery, without dropping a real external owner.
  • After the durable scope journal is written, release only this collector’s generation locks before renaming on Windows. New lock attempts read the validated journal and defer only for the exact scope being collected; unrelated live siblings remain available.
  • Preserve extended-length local and UNC paths for Windows private-file operations so long digest-bearing archive temp files reach the OS intact.
  • Add focused coverage for the held-owner deferral/retry, exact journal fence, and long archive paths. Remove the diagnostic expectation disproved by native Windows.

Verification

  • cargo test -p tracedecay-code-index-retention --lib scope_ --locked -- --nocapture: 22 passed locally.
  • cargo check -p tracedecay-code-index-retention --tests --locked, cargo fmt --all --check, and git diff --check: passed.
  • Native Windows CI is pending at this PR head; the earlier diagnostic run established the first errors but is not proof that these fixes work. This PR does not claim all [707/P1] Make Windows quarantine and atomic retirement respect held filesystem capabilities #919 rows are resolved or close the issue automatically.

@changeset-bot

changeset-bot Bot commented Sep 23, 2026 •

Copy link
Copy Markdown

⚠️ No Changeset found

Latest commit: 9228329

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

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Sep 23, 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-23T02:58:41.356676Z 07b6ec7 PR opened
ℹ️ 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.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 07b6ec7cbc

ℹ️ 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".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +652 to +656
if wide.len() < 260
|| wide.starts_with(&[BACKSLASH, BACKSLASH, b'?' as u16, BACKSLASH])
|| wide.starts_with(&[BACKSLASH, BACKSLASH, b'.' as u16, BACKSLASH])
{
return Ok(absolute);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Use one path form for sibling replacement

When only one sibling crosses the 260-code-unit threshold, this returns an extended \\?\ path for that sibling while leaving the other in ordinary absolute form. replace_file_atomically then compares the two lexical parent paths and rejects them as non-siblings. This occurs naturally when a destination is just below the threshold but its longer temporary filename is at or above it, causing an otherwise valid Windows atomic publication to fail with InvalidInput; normalize both siblings to a consistent path form before the parent comparison.

Useful? React with 👍 / 👎.

@ScriptedAlchemy

Copy link
Copy Markdown
Owner Author

Native Windows run 35812131656 at exact head 07b6ec7 confirms a remaining blocker: code_index_generations::tests::pending_scope_journal_refuses_new_generation_locks_until_recovery fails in shard 5 at tests.rs:2604 with UnsafeState("stranded scope ... changed filesystem identity during rollback") after drop(quarantine). JUnit: https://github.com/ScriptedAlchemy/tracedecay/actions/runs/35812131656/artifacts/10732708263 . The external-owner retry, long-path atomic replacement, exact-spelling, and both crash-recovery tests passed on native Windows. Keeping this PR unmerged; the existing P1 mixed sibling path-form review also remains actionable.

@ScriptedAlchemy

Copy link
Copy Markdown
Owner Author

Read-only root-cause trace for the shard-5 journal test: the fixture captures ScopeDirectoryIdentityV1.modified_* in ScopeQuarantineAuthority::prepare, then persists the journal. The first fenced try_acquire_code_generation_store_lock calls open_lock_file(...).create(true) before scope_retention_pending; the fixture has no lock file yet, so that creates a child and changes the Windows directory mtime. Recovery correctly refuses the changed identity. A pre-open journal check appears needed in addition to the existing post-lock check (which still closes the check/acquire race); please verify with the exact Windows test. The separate P1 sibling path-form review remains open.

@ScriptedAlchemy
ScriptedAlchemy merged commit 7db00b0 into master Sep 24, 2026
27 of 33 checks passed
ScriptedAlchemy added a commit that referenced this pull request Sep 24, 2026
* test(retention): release crash handles and cover locked rename

* fix(windows): preserve long private archive paths

* fix(windows): fence exact scope during retention rename

* fix(windows): close retention and long-path races

* fix(retention): let collector use held scope fence

(cherry picked from commit 7db00b0)
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.

1 participant