Skip to content

[Phase 16] S6 — Invocation-owned resources: temp state, atomic writes, worker lifetime #892

Open

Description

@cemililik

Roadmap · Phase 16, step S6 · size M · 4 unit(s) · planned in docs/roadmap/phase-16-trust-surface-hardening.md:449-479

Summary

A resource whose lifetime belongs to one invocation is named or owned globally. export_model derives <model_path>_merged_for_export by string concatenation, adopts any pre-existing directory at that path, overwrites it and then rmtrees it while returning success=True. The try/finally opens after the merge, so when the merge raises there is no cleanup at all and a user directory has already been partly clobbered; two concurrent exports of the same model collide on the same path.

Units

Unit Tracked by (October 2026 review)
C33-EXPORT-TEMP-OWNERSHIP (= CLI-01 + GAP-01) #567 · #705
F-W20260729-TRUST-10 #551
F-W20260729-CLI-19 #691 · #706
F-W20260729-CLI-08 #567 · #691 · #705

Plan

  • One discipline throughout: allocate uniquely, bind cleanup to the handle returned at creation, and release it in finally.
  • Promote the atomic-write primitive local to forgelm/wizard/_state.py to a shared utility.
  • Keep the scratch directory in the model's parent, not the system temp dir — a merged 70B fp16 checkpoint would trade a data-loss bug for an ENOSPC bug.

Exit criteria

  • A pre-existing scratch directory containing a sentinel survives byte-identical on export success and on merge failure; two sequential exports use different scratch directories.
  • shutil.rmtree(..., ignore_errors=True) is replaced by a logged OSError.
  • The 32-concurrent-writer ingest stress pattern from tests/test_pipeline_orchestrator.py is ported and leaves no orphan temp files.
  • A mid-write exception leaves the previous deploy / quickstart destination bytes unchanged.
  • A timed-out chat streamer terminates its worker within a bounded time.

How to deliver

  • One root-cause family, committed on its own; then an Opus review round and a Sonnet review round, each with verified findings fixed and committed before the next step begins.
  • A reproducer that is red before the fix and green after; the full gauntlet from CLAUDE.md passes under ./.venv/bin/python.
  • Every English documentation edit ships with its Turkish mirror in the same commit; a new or renamed audit event gets its EN and TR catalog rows in the same PR.
  • A step that grows a deferred module carries its budget_history justification in the same diff; a widened guard rolls out non-strict first, then flips.
  • Commit bodies cite Absorbs F-W20260729-…; the CHANGELOG [Unreleased] section gets an entry only for a change a user or library consumer can observe (decision C-20).

Planned in docs/roadmap/phase-16-trust-surface-hardening.md (read at f94595f). Unit IDs (F-W20260729-…) come from the 2026-07-29/30 full-project review; the issue numbers next to them are the October 2026 review's records of the same defects.

Metadata

Metadata

Assignees

No one assigned

    Labels

    blockedWaits for another issue (see Blocked by); set and removed automatically, never by handphase: 16Roadmap Phase 16: trust surface hardening (docs/roadmap/phase-16-trust-surface-hardening.md)source: roadmapPlanned or deferred work recorded in docs/roadmap/

    Type

    No type

    Projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions