Skip to content

Preserve cancellation signals through artifact rollback and cleanup #824

Description

@Infiland

Problem

The anchored byte-artifact transaction deliberately catches BaseException so reverse rollback can continue across every recorded mutation. Its final aggregation currently converts every rollback failure into an OSError, including KeyboardInterrupt, SystemExit, and other control-flow exceptions.

A transaction interrupted during rollback therefore reports the earlier ordinary I/O failure instead of the cancellation signal. Completed unlink cleanup can also surface a post-operation signal before the cleanup durability barrier runs.

This is reproducible on current main: trigger an ordinary failure after commit, raise KeyboardInterrupt from before_rollback, and publish_specs() escapes OSError with the interruption only mentioned in a note.

Related: #719, #774, #823

Scope

  • Continue attempting all reverse rollbacks after an individual failure.
  • Preserve and re-raise the exact first BaseException that is not an Exception, including its identity and SystemExit.code.
  • Keep an original forward control signal authoritative when rollback has only ordinary failures.
  • Attach the primary transaction error, additional rollback failures, and retained recovery paths as notes without replacing the selected control signal.
  • Complete ownership bookkeeping and the applicable durability barrier before propagating a post-unlink cleanup signal.
  • Preserve ordinary rollback aggregation and completed-with-error behavior.

Acceptance criteria

  • Ordinary forward failure plus rollback KeyboardInterrupt or SystemExit re-raises the exact rollback signal after all rollback entries are attempted.
  • Forward KeyboardInterrupt or SystemExit remains the escaping object when rollback has only ordinary failures.
  • Multiple rollback signals have deterministic first-signal precedence and retain all secondary details as notes.
  • Signals after completed replace/unlink operations record ownership correctly before propagation.
  • Cleanup performs its directory durability attempt after a completed unlink before re-raising the exact signal.
  • Tests cover publish, absent publish, restore, both rollback directions, cleanup, retained recovery, and exception identity.
  • Native Windows transaction CI, Pyright, Ruff, the full unit suite, and exact Godot 4.7.1 validation pass.

Metadata

Metadata

Assignees

No one assigned

    Labels

    architectureInternal architecture and maintainabilitybugSomething isn't workingtestingTests, fixtures, CI, validation, and coverage

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions