Problem
Another invocation can delete a still-active run bundle while its consumer cleanup hook is running. Terminal metadata is written before cleanup; retention consults the live lease only when metadata status is running. The documented lifetime protection therefore ends too early.
Verified evidence
Reviewed on 2026-09-17 at 2d67cd24e8d704386f2be7d3a41addc06fb81e17 (local checkout matched GitHub main). Reproduced in isolated macOS environments with Python 3.14.6. Framework default probe environment: Click 8.5.0 and Typer 0.27.2. Demo probes used released base-cli 0.4.3 unless noted.
A public-API two-process probe used the same application/cache namespace and RetentionPolicy(max_bundles=1). The first command wrote a temporary marker and registered an on_cleanup hook. That hook confirmed the marker existed, launched a second ordinary invocation, then checked it again:
first invocation exit: 0
metadata status during cleanup: ok
marker before second invocation: present
second invocation exit: 0
marker after second invocation: absent
first run root after second invocation: absent
The first process still held its lease. _finish_run_recorder() precedes context.cleanup(), and both retention discovery and destructive revalidation skip the lease check for ok/error/aborted records. No malicious filesystem mutation is required.
Sources:
Acceptance criteria
- Protect a held live lease regardless of whether run.json is running or terminal; retain unknown liveness safely under the documented policy.
- Revalidate liveness before deletion and preserve protection through cleanup hooks, telemetry teardown, and logger/resource close.
- Add a deterministic two-process regression with terminal metadata and a blocked cleanup hook; cover native and attached lifecycles.
- After the owner releases its lease, prove normal count/age/byte retention still removes eligible finished bundles.
Related work
Follow-up to closed #266 and #62. Distinct from open #341: this loses files across processes, rather than handlers in nested same-process runs.
Project fields
- Status: Backlog
- Priority: P1
- Area: Runtime
- Initiative: v1.0 Readiness
- Size: M
- Assignee: @codeforester
- Milestone: v1.0.0
- Target date: unscheduled
Problem
Another invocation can delete a still-active run bundle while its consumer cleanup hook is running. Terminal metadata is written before cleanup; retention consults the live lease only when metadata status is running. The documented lifetime protection therefore ends too early.
Verified evidence
Reviewed on 2026-09-17 at
2d67cd24e8d704386f2be7d3a41addc06fb81e17(local checkout matched GitHub main). Reproduced in isolated macOS environments with Python 3.14.6. Framework default probe environment: Click 8.5.0 and Typer 0.27.2. Demo probes used released base-cli 0.4.3 unless noted.A public-API two-process probe used the same application/cache namespace and
RetentionPolicy(max_bundles=1). The first command wrote a temporary marker and registered anon_cleanuphook. That hook confirmed the marker existed, launched a second ordinary invocation, then checked it again:The first process still held its lease.
_finish_run_recorder()precedescontext.cleanup(), and both retention discovery and destructive revalidation skip the lease check for ok/error/aborted records. No malicious filesystem mutation is required.Sources:
Acceptance criteria
Related work
Follow-up to closed #266 and #62. Distinct from open #341: this loses files across processes, rather than handlers in nested same-process runs.
Project fields