Skip to content

fix(storage): harden callback cleanup boundaries - #617

Merged
fishmingyu merged 1 commit into
mainfrom
agent/pr592-atomic-extract
Aug 13, 2026
Merged

fix(storage): harden callback cleanup boundaries#617
fishmingyu merged 1 commit into
mainfrom
agent/pr592-atomic-extract

Conversation

@fishmingyu

Copy link
Copy Markdown
Member

Summary

Harden callback post-validation and authenticated resource cleanup as an independent replacement for the stacked #592 change.

This PR is based directly on current main. It carries no compiler, CAS, manifest-import, or downstream artifact changes from the old storage stack.

Changes

  • run reader validity, exact ownership, child namespace, and parent authority checks after callback success, failure, or cancellation
  • preserve the first callback, postflight, or cleanup failure while retaining later failures as diagnostics
  • preconstruct POSIX and Windows cleanup plans before acquiring resources
  • drive resource owners through bounded, constant-stack cancellation retries
  • continue later independent cleanup actions when one action cannot complete
  • retain incomplete idempotent cleanup owners on the primary exception for explicit retry
  • avoid closing observably reused foreign descriptors or handles
  • document the remaining pure-Python call-entry and exact-identity ABA limits that require native ownership

Type of Change

  • Bug fix
  • New feature
  • Breaking change
  • Documentation update
  • Refactoring
  • Performance improvement
  • Tests

Testing

  • Tests pass locally
  • Added new tests for the changes
  • Python 3.10 focused atomic suite: 236 passed, 10 skipped
  • Python 3.11 expanded publication/storage suite: 492 passed, 10 skipped
  • Python 3.12 focused atomic suite: 236 passed, 10 skipped
  • local unit tier excluding two independently reproduced baseline environment failures: 4530 passed, 66 skipped
  • changed-file pre-commit hooks: passed
  • git diff --check origin/main...HEAD: passed

Checklist

  • My code follows the project's style guidelines
  • I have performed a self-review of the code
  • I have commented the code, particularly in hard-to-understand areas
  • The changes generate no new warnings
  • Any dependent changes have been merged and published

Bound cancellation retries while preserving the first failure and continuing independent cleanup actions. Retain incomplete POSIX, Windows, and publication authority owners on the primary exception so callers can retry cleanup without closing reused foreign resources.

Verified with the focused atomic-directory suite on Python 3.10, 3.11, and 3.12, the local unit tier excluding two confirmed baseline failures, and the repository pre-commit hooks for the changed files.
@github-actions github-actions Bot added type/docs Documentation type/test Test-related labels Aug 13, 2026
@fishmingyu fishmingyu added the type/bug Behavior does not match expectations label Aug 13, 2026 — with ChatGPT Codex Connector
@fishmingyu
fishmingyu marked this pull request as ready for review August 13, 2026 19:31
@fishmingyu
fishmingyu merged commit 36ee064 into main Aug 13, 2026
24 checks passed
@fishmingyu
fishmingyu deleted the agent/pr592-atomic-extract branch August 13, 2026 19:35

@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: d12a3eb362

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

) -> None:
"""Keep an incomplete idempotent cleanup owner reachable from ``failure``."""

if owner is None or _publication_cleanup_owner_is_closed(owner):

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Preserve reused-resource diagnostics during owner protection

When a context body is already failing and an owned descriptor or HANDLE has concurrently been closed and reused, protect_pending_owners() reaches this probe before cleanup. Both resource owners implement closed by silently marking identity-mismatched records released, so the subsequent close_all() skips the record and the primary exception receives no ownership-change diagnostic; the same reuse is correctly reported when the body succeeds and this pre-protection path is skipped. Retaining pending owners should not destructively reconcile mismatched records before cleanup can report them.

Useful? React with 👍 / 👎.

Comment on lines +922 to +924
deque(
iter(partial(_run_ordered_actions_trampoline_pass, state), True),
maxlen=0,

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 Do not let StopIteration terminate the cleanup trampoline

If the callback or context body leaves a tracing/profiling hook that raises StopIteration when _run_ordered_actions_trampoline_pass is entered, this callable-sentinel iterator treats that exception as normal iteration exhaustion. _run_ordered_actions() then returns without recording a primary failure or advancing the state, so a callback result can escape with every post-validation skipped; on the cleanup path, all acquired descriptors or HANDLEs can likewise remain open. The trampoline must ensure StopIteration cannot escape into the iterator protocol as its termination signal.

Useful? React with 👍 / 👎.

Comment on lines +2014 to +2019
(
(
"directory orphan post-callback ownership validation "
"also failed",
validate_after_ownership,
),

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Validate orphan reader state before recapturing ownership

When an orphan callback catches an authenticated-file failure and also changes the orphan tree, this inner wrapper runs the ownership recapture before the generic read_child wrapper checks reader._require_valid(). The ownership-drift error therefore becomes primary and the earlier suppressed authentication failure is reduced to a later note, contrary to the reader-validity-before-ownership ordering used by _run_authenticated_directory_callback and documented for callback postconditions. Add the validity check ahead of this ownership validation so the first security failure is preserved consistently.

Useful? React with 👍 / 👎.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

type/bug Behavior does not match expectations type/docs Documentation type/test Test-related

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant