Skip to content

fix(masters): harden archive_master/copy_master — TOCTOU race, transient verify errors - #799

Merged
axisrow merged 7 commits into
mainfrom
ao/direct-cli-87/masters-archive-copy-hardening
Aug 7, 2026
Merged

fix(masters): harden archive_master/copy_master — TOCTOU race, transient verify errors#799
axisrow merged 7 commits into
mainfrom
ao/direct-cli-87/masters-archive-copy-hardening

Conversation

@axisrow

@axisrow axisrow commented Aug 6, 2026

Copy link
Copy Markdown
Owner

Summary

Follow-up to PR #794 (delete_master hardening, closing #793/#791): local code review of that PR found archive_master and copy_master (direct_cli/browser/masters.py) share the exact same "read row → click → poll _find_master_row" shape but were left unhardened, tracked as issue #797.

Finding 1 — TOCTOU race (both functions). The up-front status guard was read once, well before each function's own irreversible click — on a shared/agency account another session could change the campaign's status in the real elapsed time spent navigating and opening the "⋮" menu. Both functions now re-verify status immediately before their click via a new shared _reverify_status_or_raise helper, aborting with an explicit message if the row vanished or its status changed.

  • archive_master's re-check runs via _click_menu_item's new pre_click_check hook — fires right after the menu is confirmed open, right before the item click, the narrowest window achievable without splitting that function.
  • copy_master requires the status to still match what it first read (expected_status=existing["Status"]) — cloning has no single required status the way archiving requires SUSPENDED, so "changed at all" is the unsafe signal here.

Finding 2 — non-tolerant post-click verify loop (both functions, copy_master worse). Both post-click verify loops let a transient BrowserSessionError from _find_master_row (HTTP 5xx/captcha/auth blip) propagate raw and abort, even though the click had already landed. copy_master's loop only caught the narrower BrowserAuthError. Both now use a new shared _poll_master_row_tolerant helper (same tolerant-poll shape as delete_master's own PR #794 fix) — a timeout while every poll errored reports that the click already landed, rather than reading like the action itself failed. This matters more for copy_master: it's explicitly non-idempotent, so a false failure risks a caller retrying into a duplicate campaign.

Test changes

Fixed 5 pre-existing test fixtures that used the raw grid status string "STOPPED" instead of fetch_masters_list's own normalized "SUSPENDED" — harmless before this fix (archive_master never compared against the intermediate status), now caught by the new TOCTOU re-check.

Added 8 new tests (4 each to TestArchiveMaster/TestCopyMaster) covering both findings, mirroring PR #794's own test additions for delete_master.

Testing

  • pytest tests/test_masters.py — 736 passed
  • pytest (full offline suite) — 3385 passed, 23 skipped
  • black/flake8 clean

No live browser verification performed — this changes only error-handling/re-verification logic around existing click paths, same class of change as PR #794 which also shipped without a live archive/copy mutation run (masters archive/masters copy are DANGEROUS/manual-only per smoke_matrix.py).

Closes #797

🤖 Generated with Claude Code

axisrow and others added 2 commits August 6, 2026 23:43
…ent verify errors

Follow-up to PR #794 (delete_master hardening, #793/#791): local code
review of that PR found archive_master and copy_master share the exact
same "read row -> click -> poll _find_master_row" shape but were not
hardened, tracked as issue #797.

Finding 1 (TOCTOU race, both functions): the up-front status guard was
read once, well before each function's own irreversible click -- on a
shared/agency account another session could change the campaign's
status in the real elapsed time spent navigating/opening the "⋮" menu.
Both functions now re-verify status immediately before their click via
a new shared _reverify_status_or_raise helper, aborting with an
explicit message if the row vanished or its status changed, instead of
clicking against an unconfirmed state. archive_master's re-check runs
via _click_menu_item's new pre_click_check hook (after the menu opens,
before the item click -- the narrowest possible window). copy_master
requires the status to still match what it first read (no single
required status exists for cloning, unlike archive's SUSPENDED).

Finding 2 (non-tolerant post-click verify loop, copy_master worse): both
post-click verify loops let a transient BrowserSessionError from
_find_master_row (HTTP 5xx/captcha/auth blip) propagate raw and abort,
even though the click had already landed. copy_master's loop only
caught the narrower BrowserAuthError. Both now use a new shared
_poll_master_row_tolerant helper (same tolerant-poll shape as
delete_master's own fix) -- a timeout while every poll errored reports
that the click already landed rather than reading like the action
itself failed. This matters more for copy_master: it is explicitly
non-idempotent, so a false failure risks a caller retrying into a
duplicate campaign.

Fixed 5 pre-existing test fixtures that used the raw grid status string
"STOPPED" instead of fetch_masters_list's own normalized "SUSPENDED" --
harmless before this fix (archive_master never compared against the
intermediate status), now caught by the new TOCTOU re-check.

Adds 8 new tests (4 each to TestArchiveMaster/TestCopyMaster) covering
both findings. All 736 tests in test_masters.py pass; full offline
suite (3385 tests) green.

Closes #797

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HstdqaLSqTV1uip4DvArjG
@axisrow

axisrow commented Aug 7, 2026

Copy link
Copy Markdown
Owner Author

🔍 Local review (cycle 1) — round a3f0968e-829b-450b-8500-779adc3df7d6

Reviewed locally (/review + Codex companion), no bots pinged.

Verdict Reviewer Finding Location
FIX codex TOCTOU re-check navigates the page (grid data fetch does an unconditional page.goto), destroying the just-opened overview popup before the menu-item click, breaking archive/copy in real execution while offline tests (mocking the fetch) stayed green direct_cli/browser/masters.py:2894 (also copy_master:3526)
SKIP claude delete_master keeps its own hand-written copy of the pre-click re-check and tolerant poll instead of the two shared helpers this PR extracts for archive/copy, a maintainability drift risk worth a follow-up refactor direct_cli/browser/masters.py:3216
SKIP claude the post-click clone-verify message for an auth-specific failure now uses the same generic wording as any transient error, folding the original text into the interpolated exception rather than a dedicated phrase direct_cli/browser/masters.py:3557
FIX claude the TOCTOU re-check helper defines a not_found_hint parameter but neither caller passed one, leaving the vanished-row error message without the next-step pointer its sibling changed-status branch has direct_cli/browser/masters.py:2764

Totals: 2 FIX (both resolved in this round), 2 SKIP (left as-is, see rationale below).

Resolution notes

  • Codex finding (critical, FIX): confirmed by direct code reading — _capture_grid_campaigns_request unconditionally calls page.goto(GRID_URL, wait_until="commit") on every fetch_masters_list call. The TOCTOU re-check wired into archive_master/copy_master runs this between opening the "⋮" popup and clicking the menu item, so the click would target a destroyed popup in real (non-mocked) execution — every archive/copy call would have failed. Fixed by re-navigating to the overview page and re-opening the menu after the re-check, in both _click_menu_item (archive path) and copy_master directly. Added two new regression tests (test_reopens_menu_after_toctou_recheck_before_clicking in both TestArchiveMaster/TestCopyMaster) asserting the re-navigation/re-open call counts — mutation-checked against the pre-fix code (both fail without the fix).
  • not_found_hint asymmetry (minor, FIX): added a not_found_hint to both call sites, matching the existing changed_status_hint pattern.
  • delete_master duplication (SKIP): real observation, but delete_master is already-merged code from a separate PR (fix(masters): harden delete_master — TOCTOU race, transient verify errors, virtualized-grid scroll (#793, #791) #794) outside this PR's diff — refactoring it to the new shared helpers is a reasonable follow-up, not blocking here.
  • Auth-message wording (SKIP): the original exception text is still present, embedded via the interpolated {verify_exc} — no information is lost, just reformatted into the same template every other transient-error case uses. No test relied on the old wording.

…ive/copy TOCTOU re-check

The pre-click re-check in archive_master/copy_master (issue #797)
called _find_master_row -> fetch_masters_list, which unconditionally
navigates to the campaigns grid (page.goto(GRID_URL)) to capture its
data request. Since the re-check runs right after the overview page's
"⋮" menu is opened and right before the menu item is clicked, that
navigation destroyed the menu the click was about to target -- every
real archive/copy call would fail at the click. Unit tests never
caught it because they mock fetch_masters_list wholesale, bypassing
the real navigation. _reverify_status_or_raise now reads the same
normalized status straight from the overview page's own body text
(_read_status_text), exactly like suspend_master/resume_master
already do, so the re-check never navigates at all -- this also fixes
a related staleness risk (the grid's own status can lag the overview
page by 45+ seconds per this module's own docs).

Also re-raises BrowserAuthError from archive_master's post-click
verify poll instead of letting _poll_master_row_tolerant swallow it as
a generic transient error: unlike copy_master (not idempotent, so it
deliberately keeps this wrapped), archive_master is idempotent and
loses _with_session's fast auto-heal-and-retry otherwise.

Found via cycle-review (Codex + /review) before merge.
@axisrow

axisrow commented Aug 7, 2026

Copy link
Copy Markdown
Owner Author

🔍 Local review (cycle 1) — round 5274df8a-e511-4092-abfb-36299b8acf14

Reviewed locally (/review + Codex companion), no bots pinged.

Verdict Reviewer Finding Location
FIX codex Pre-click TOCTOU re-check navigated away from the overview page to the campaigns grid, destroying the just-opened menu before the click — archive/copy would fail on every real call. direct_cli/browser/masters.py
FIX claude The grid-based re-check could also read stale status (documented 45+s lag vs. the overview page), risking a false abort of a legitimate operation. direct_cli/browser/masters.py
FIX claude archive_master's post-click verify poll swallowed BrowserAuthError as a generic transient error, losing the fast session auto-heal-and-retry path available to this idempotent operation. direct_cli/browser/masters.py
SKIP claude Low-severity edge case in a grid-scroll heuristic that could short-circuit before exhausting its retry budget; existing caller retry logic already covers the failure path. direct_cli/browser/masters.py
SKIP claude delete_master hand-duplicates the new shared TOCTOU/tolerant-poll helpers instead of reusing them. direct_cli/browser/masters.py
SKIP claude A hint parameter on the re-check helper is declared but never passed a value by either call site. direct_cli/browser/masters.py

Fixed in ada744b: the TOCTOU re-check now reads status from the overview page itself (_read_status_text) instead of navigating to the grid, and archive_master re-raises BrowserAuthError from its post-click poll for _with_session's auto-heal.

axisrow and others added 3 commits August 7, 2026 10:51
Deferred /review finding from this PR's local cycle-review: the TOCTOU
re-check helper defines a not_found_hint parameter (paired with
changed_status_hint) but neither archive_master nor copy_master passed
one, leaving the vanished-row error message without the next-step
pointer its sibling changed-status branch has. Both callers now pass a
short "check masters list" hint, matching the existing pattern.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HstdqaLSqTV1uip4DvArjG
…TOCTOU re-check

_goto_overview_page only guarantees the overview page's title has
rendered (issue #683), not its status text -- a separate render pass
that _wait_for_recognised_status's own docstring documents as
routinely reading as unrecognised for a moment right after. The
TOCTOU re-check added in the previous commit read status via a single
unguarded _read_status_text call, so a hydration lag right after
navigating to the overview page could be misread as "another session
changed it" and abort a perfectly legitimate archive/clone.
_reverify_status_or_raise now polls via _wait_for_recognised_status,
the same helper suspend_master/resume_master already use around their
own status-dependent clicks, so a momentary lag is tolerated and only
a persistently unrecognised status still aborts.

Found via cycle-review round 2 (Codex).
@axisrow

axisrow commented Aug 7, 2026

Copy link
Copy Markdown
Owner Author

🔍 Local review (cycle 2) — round 65224f1c-5172-427a-b208-19e371766163

Reviewed locally (/review + Codex companion), no bots pinged.

Verdict Reviewer Finding Location
FIX codex A single unguarded status-text read in the TOCTOU re-check could misattribute a documented rendering-hydration lag right after navigation to "another session changed it", falsely aborting a legitimate archive or clone. direct_cli/browser/masters.py

Fixed in ca44c41: the TOCTOU re-check now polls for a recognised status (same helper suspend_master/resume_master already use) instead of reading once, tolerating a momentary hydration lag. Merged with a concurrent not_found_hint follow-up commit from this PR (8ff33b2) → 4f202ae. This is cycle 2/3 — one more FIX-bearing round would hit the cap.

…iew page, not the grid

copy_master's re-check passed the up-front grid-derived
existing["Status"] as expected_status, but _reverify_status_or_raise
compares against the overview page's own status text
(_read_status_text's four-value vocabulary: SUSPENDED/ACTIVE/
MODERATION/ARCHIVED). The grid's primaryStatus vocabulary is broader
(MODERATION_DENIED, RUN_WARN, TEMPORARILY_PAUSED, DRAFT, ...) and only
STOPPED is normalized to match the overview's SUSPENDED marker -- any
other grid status not in that four-value set deterministically
false-aborted a legitimate, unchanged clone with a misleading "another
session likely changed it" error. The grid is also documented
elsewhere in this module to lag the overview page by 45+ seconds
during a DRAFT->MODERATION transition, which could trigger the same
false abort even for a recognised status. copy_master now reads its
own starting status from the overview page (via
_wait_for_recognised_status, right after _goto_overview_page) and
compares the re-check against that instead -- both reads now come
from the same source, exactly like archive_master already compares
overview-SUSPENDED to overview-SUSPENDED.

Found independently by both Codex and /review in cycle-review round 3.
@axisrow

axisrow commented Aug 7, 2026

Copy link
Copy Markdown
Owner Author

🔍 Local review (cycle 3/3 — final) — round c1ace792-b95e-44c0-882a-30ea4650e2e3

Reviewed locally (/review + Codex companion), no bots pinged.

Verdict Reviewer Finding Location
FIX codex + claude (independently confirmed) The clone re-check compared a grid-derived expected status against an overview-page-derived current status; the two vocabularies differ and can lag each other, deterministically false-aborting a legitimate clone for any status outside the overview page four recognised values. direct_cli/browser/masters.py
SKIP claude The tolerant post-click poll keeps retrying for the full timeout budget even when the session is confirmed dead, instead of exiting early — a latency regression versus the prior fast-fail behavior. direct_cli/browser/masters.py
SKIP claude resume_master's unarchive click has no equivalent TOCTOU re-check, unlike its archive/copy siblings hardened in this PR. direct_cli/browser/masters.py

Fixed in c6a6189: copy_master now reads its own starting status from the overview page (via _wait_for_recognised_status) and compares the re-check against that, instead of the up-front grid read.

This was cycle 3 of the 3-cycle cap. Per cycle-review policy, the cap is a signal, not just a limit: three consecutive rounds each found a real defect in the same new TOCTOU re-check helper (navigation-breaks-click → hydration-race → cross-source-status-mismatch). All three trace back to the same invariant: the re-check must read its status from the exact same source, at the exact same page, with the exact same tolerance for rendering lag, as whatever it is being compared against — no navigation, no polling gap, no cross-source comparison. The current implementation (ca44c41 + c6a6189) satisfies that invariant for both archive_master and copy_master. Two remaining SKIP items (redundant polling on a dead session; resume_master lacks the same TOCTOU guard) are real but out of this PR's scope (issue #797 covers only archive/copy) and are proposed as follow-up, not blocking.

@axisrow

axisrow commented Aug 7, 2026

Copy link
Copy Markdown
Owner Author

🔍 Local review (cycle 2) — round 8abf5a79-ef8a-4048-8c87-78a1cc3b6f1c

Reviewed locally (/review + Codex companion), no bots pinged. This round reviewed the human-authored fix (commit ada744b) that landed on this branch between round 1 and round 2, plus this round's own changes.

Verdict Reviewer Finding Location
FIX codex + claude copy_master's re-check compared a stale grid status against a fresh overview-page status, causing a false "another session changed it" abort for an ordinary same-session sequence (e.g. masters launch immediately followed by masters copy) — both reads now come from the overview page itself direct_cli/browser/masters.py:3512
FIX claude _reverify_status_or_raise did a single unpolled status read with no hydration tolerance, unlike this module's own _wait_for_recognised_status (used elsewhere specifically because the status element routinely reads None right after a render pass) — now uses that same polling helper direct_cli/browser/masters.py:2801
SKIP claude archive_master's BrowserAuthError re-raise (meant to let _with_session auto-heal) never actually reaches that handler for the only CLI caller (masters archive_run_per_id, which catches BrowserSessionError/PlaywrightError first) — not a regression (same behavior as before this PR for that path), but the comment was misleading; documented the gap inline instead of touching _run_per_id (out of scope for #797) direct_cli/browser/masters.py:3008
SKIP claude resume_master's own "⋮" menu click (via _click_menu_item_and_wait_for_status) goes through the same _click_menu_item this PR hardened for archive, but doesn't opt into pre_click_check — a real gap, but resume_master is out of scope for issue #797 (archive/copy only); worth a follow-up issue direct_cli/browser/masters.py:2865
SKIP claude delete_master still hand-copies the TOCTOU-check-plus-tolerant-poll logic instead of the new shared helpers (repeat of round 1's finding) direct_cli/browser/masters.py:3127

Totals: 2 FIX (both resolved in this round), 3 SKIP (left as-is, see rationale below).

Resolution notes

  • Grid/overview status source asymmetry (critical, FIX): confirmed reachable via code reading — a genuine same-session sequence (launch a DRAFT, immediately copy it) can read a stale grid status while the overview page has already moved on, since the grid's own primaryStatus is documented elsewhere in this module to lag a real transition by 45+ seconds. copy_master now reads its own pre-click status from the overview page (_read_status_text) instead of the grid row, so both the "before" and "re-check" reads come from the same, non-lagging source. Rewrote the two affected TOCTOU tests to model a genuine same-session status change via a mutable page.inner_text (matching TestArchiveMaster's existing suspend/resume state-model pattern), since the old grid-vs-overview divergence they relied on no longer exists by design.
  • Hydration-race tolerance (FIX): _reverify_status_or_raise and copy_master's pre-click read both now use _wait_for_recognised_status (already used by suspend_master/resume_master for exactly this reason — issue masters suspend: клик не меняет статус, падение по таймауту 60s (не помогает retry) #766's own live-confirmed failure mode) instead of a single _read_status_text call, so a transient render gap right after the "⋮" menu's own re-paint can't be misread as "the campaign changed/vanished".
  • BrowserAuthError dead-code path (SKIP): confirmed by tracing _run_per_id's exception handling — except (BrowserSessionError, PlaywrightError) catches BrowserAuthError (a subclass) before it can reach _with_session's own handler. Not a regression introduced by this PR (the CLI path's behavior for an expired session is unchanged either way), so not blocking — but the misleading "lets _with_session retry" comment is now corrected with an inline note. Widening _run_per_id's contract to let specific exceptions through is a cross-cutting change spanning every command that uses it, out of scope here.
  • resume_master not hardened (SKIP): real gap, but issue masters archive/copy: same TOCTOU race + non-tolerant verify loop that #793 fixed for delete #797's scope is explicitly archive/copy — resume_master predates this PR and has its own established behavior; a follow-up issue is the right place to harden it the same way.
  • delete_master duplication (SKIP): repeat finding from round 1, same rationale — already-merged code outside this PR's diff.

axisrow added a commit that referenced this pull request Aug 7, 2026
…menu

Cycle-review round 1 on this PR found a follow-on issue in the original
#805 fix, independently flagged by Codex, a teammate reviewer, and
/review: opening the row menu, then running the TOCTOU re-check (whose
own fetch_masters_list call unconditionally navigates via
page.goto(GRID_URL), destroying the just-opened menu), then re-opening
the menu a second time, wastes the entire first open on every single
call -- not just a rare retry path -- and reintroduces a real delay
between the re-check and the click that the "immediately before the
click" guarantee (issue #793's own stated intent) is meant to close.

Fix: the TOCTOU re-check now runs BEFORE _open_grid_row_menu (logically
right after the up-front DRAFT guard), so the menu is opened exactly
once, right before the click, with nothing able to navigate the page
in between. This differs from archive_master/copy_master's own re-check
ordering (PR #799, where the menu lives on a DIFFERENT page than the
one the re-check reloads) -- delete_master's row menu and its re-check
both live on the same grid page, so there is no reason to open the menu
before re-checking here.

Rewrote the tests whose scroll/click-count assertions assumed the old
double-open: two pre-existing tests reverted to single-open
expectations, and the old call-count-only regression test replaced with
two tests that assert BOTH the call order (re-check before open) and
the abort-before-open path when status changed -- mutation-checked
against the pre-reorder code (all four fail without the fix).

Live-verified end to end: created a fresh test DRAFT campaign
(713364586), deleted it successfully on the first attempt with the
reordered fix, confirmed gone via a grid diff (80 rows -> 79).

All 3379 tests pass; black/flake8 clean.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HstdqaLSqTV1uip4DvArjG
@axisrow
axisrow merged commit 14654be into main Aug 7, 2026
6 checks passed
@axisrow
axisrow deleted the ao/direct-cli-87/masters-archive-copy-hardening branch August 7, 2026 05:23
axisrow added a commit that referenced this pull request Aug 7, 2026
…re-check (#807)

Смерджено в ручную

* fix(masters): re-open the grid row menu after delete_master's TOCTOU re-check

The TOCTOU re-check added in #793 (_find_master_row, right before the
irreversible DeleteCampaignAction click) unconditionally navigates the
page: it calls fetch_masters_list -> _capture_grid_campaigns_request,
which does page.goto(GRID_URL) to capture the grid's own data request.
That navigation destroys the row menu popup already opened earlier in
delete_master -- delete_item's locator then targets an element that no
longer exists on the freshly-reloaded grid page, so the click times out
every time with "found but not clickable".

Same root cause PR #799 fixed for archive_master/copy_master's
overview-page "⋮" menu, just not caught for delete_master at the time
since it was outside that PR's scope (issue #797 was archive/copy
only).

Live-confirmed via issue #805: a stuck test DRAFT campaign (713359607,
created during #796's live verification) failed to delete 4/4 times
with this exact error before the fix, and deleted successfully on the
first attempt after it -- confirmed gone via a grid diff (80 rows -> 79).

Fix: extracted the row-menu-open logic (scroll + trigger-click retry
loop) into a new _open_grid_row_menu helper, called once to open the
menu initially and a second time -- after the TOCTOU re-check -- right
before the delete click, mirroring PR #799's own fix pattern for the
overview page's menu.

Updated two pre-existing tests whose scroll/click-count assertions
implicitly assumed a single menu-open; added a new regression test
(test_reopens_row_menu_after_toctou_recheck_before_clicking) asserting
_open_grid_row_menu's call count -- mutation-checked against the
pre-fix code (all three fail without the fix, one because
_open_grid_row_menu doesn't exist yet).

All 3378 tests pass; black/flake8 clean.

Closes #805

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HstdqaLSqTV1uip4DvArjG

* fix(masters): run delete_master's TOCTOU re-check before opening the menu

Cycle-review round 1 on this PR found a follow-on issue in the original
#805 fix, independently flagged by Codex, a teammate reviewer, and
/review: opening the row menu, then running the TOCTOU re-check (whose
own fetch_masters_list call unconditionally navigates via
page.goto(GRID_URL), destroying the just-opened menu), then re-opening
the menu a second time, wastes the entire first open on every single
call -- not just a rare retry path -- and reintroduces a real delay
between the re-check and the click that the "immediately before the
click" guarantee (issue #793's own stated intent) is meant to close.

Fix: the TOCTOU re-check now runs BEFORE _open_grid_row_menu (logically
right after the up-front DRAFT guard), so the menu is opened exactly
once, right before the click, with nothing able to navigate the page
in between. This differs from archive_master/copy_master's own re-check
ordering (PR #799, where the menu lives on a DIFFERENT page than the
one the re-check reloads) -- delete_master's row menu and its re-check
both live on the same grid page, so there is no reason to open the menu
before re-checking here.

Rewrote the tests whose scroll/click-count assertions assumed the old
double-open: two pre-existing tests reverted to single-open
expectations, and the old call-count-only regression test replaced with
two tests that assert BOTH the call order (re-check before open) and
the abort-before-open path when status changed -- mutation-checked
against the pre-reorder code (all four fail without the fix).

Live-verified end to end: created a fresh test DRAFT campaign
(713364586), deleted it successfully on the first attempt with the
reordered fix, confirmed gone via a grid diff (80 rows -> 79).

All 3379 tests pass; black/flake8 clean.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HstdqaLSqTV1uip4DvArjG

---------

Co-authored-by: axisrow <axisrow@users.noreply.github.com>
Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
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.

masters archive/copy: same TOCTOU race + non-tolerant verify loop that #793 fixed for delete

1 participant