Skip to content

Commit e1cbf04

Browse files
mchwangclaude
andauthored
F1: runner lifecycle and state-holder contract (#49)
* Add F1 runner lifecycle and state-holder contract Proposed contract for review before F1 implementation: attempt states and legal transitions, holder ownership and settlement, guarded retry, shutdown order, startup recovery, planning API for G4 and feedback events for J. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Record approved F1 lifecycle decisions Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Update F1 contract baseline for merged D4 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Fix sentence break in F1 baseline note Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Address F1 contract review findings - Free a slot only after the terminal write succeeds; keep an unresolved marker until startup recovery otherwise. - Task time budget records the first reason and waits for settlement. - Mark the coordinator shutdown barrier as new; today an admitted request can start a question after shutdown begins. - Write task-closed with the confirmed merge outcome and reconcile missing events at startup. - Separate F attempt kinds from D's closed Phase union. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Address F1 contract review round 2 - Split the task state version (ordering, user CAS) from the context generation captured in InvocationContext, so an attempt's own transitions never make it stale. - Admission reserves the in-memory slot synchronously before the Store transaction and releases it on refusal. - A second process exits before opening the Store instead of serving a review screen that writes. - Suggestion cancel covers ready requests via Store.cancelSuggestions. - Scope the feedback-event unique key by plan and task. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Define slot release for attempts that end before launch A pending attempt has no settled promise. Add the launch table: stop or launch error frees the slot after the terminal write; a failed pending-to-running write keeps an unresolved marker. Record D4's throw-only-after-cleanup start shape as part of D's contract. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Address F1 contract review round 3 follow-ups - Make proven settlement a merge prerequisite for F1: D4 retries cleanup every second without a limit, so shutdown can wait forever today. - Identify tasks by full PlanIdentity (plan key); feedbackEvents and user actions are scoped by the configured identity, never a bare taskId. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Address F1 contract review round 5 - Terminal guards enforce first-reason precedence. - Retry checks the unresolved marker and every current-context field. - Shutdown cancels and settles pending (preparing) attempts too. - Recovery separates unclean leftovers from clean shutdown, lists both for I3 requeue, and reconciles task-closed only for confirmed merges. - Feedback events carry an actionId; uniqueness is (plan_key, kind, action_id) so superseding events are never rejected. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Address F1 contract review round 6 - Preparation gets an abort signal, awaits its own subprocesses and counts against the attempt deadline. - Shutdown releases the runner lock last. - Add a D recovery API (recoverLeftovers) as a second merge prerequisite. - Recovery finalizes leftovers by first reason; only rows with none become failed; requeue only shutdown-cancelled or interrupted attempts. - Schema: attempts.id primary key, foreign keys, bounded result column. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Address F1 contract review round 7 - Add a preparation-failure path to the launch table. - Retry only running or queued tasks; closed and human-gated tasks need their own user action. - Add rejected as a closed status and exclude it from requeue. - Store assignment and referenced-code hash durably; every Store method that changes a context field bumps context_generation atomically. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Scope D leftover recovery to one database Recovery by generic io.codeboost labels could remove another database's live resources. Require a per-database runner owner token, labelled on every D resource type, and recovery that removes only matching resources. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Address F1 contract review round 9 - Launch check: a synchronous current-context check right before D start; pending guards and launch errors follow first-reason precedence. - The job keeps the first reason in memory; the terminal write stores it. - Distinct time-limit reason that ends in needs human, also on recovery. - Shutdown keeps existing reasons; the server rechecks stopping before every mutating dispatch. - Partial-output and interrupted-rebase ownership before I3 rebuild. - Runner token read after the Store opens under the lock; copies get a new token. - Merge, task status and task-closed share one transaction. - Composite current-attempt foreign key; context changes bump both counters. - State the D prerequisites plainly in the implementation premise. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Address F1 contract review round 10 - Irreversible actions also re-read review_version after the final await. - Writing GETs (/api/review history, /api/merge observations) check stopping before writing. - Unowned legacy D resources fail closed until explicitly removed. - UI-generated actionId idempotency keys make replays exact. - v5 to v6 backfill of task rows. - Lock path from the canonical database path plus file identity check. - GET /api/runner exposes the unresolved marker. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Store every user action once for exact idempotent replay Add a user_actions table keyed by (plan_key, action_id) with the request hash and saved response. It covers retry and run-again; a reused action ID with a different request is refused. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Address F1 contract review round 12 - Task budget during preparation and at launch records time-limit; an expired attempt deadline fails without calling D. - Time-limit never changes a closed task. - Store write gate closed at shutdown, covering every request path, including direct-merge reconciliation after a GitHub await. - Separate cancel attempt from cancel task; only merge and cancel task close a task. Reject with feedback requeues it, following design step 8. - Record refused outcomes for exact replay; name idempotency-only actions. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Address F1 contract review round 13 - Every admission requires task status running or queued. - Coordinators' settlement and close paths hold the Store write-gate capability, so questions and suggestions can settle during shutdown. - Refuse hard-linked databases; define the lock-first bootstrap for a new database and write file identity into the lock afterwards. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Address F1 contract review round 14 - Preparation subprocesses run in their own process group with SIGTERM, then SIGKILL escalation, and an awaited close. - Cancel task is refused while a merge attempt is submitting or queued. - Merge attempts are excluded from F's generic retry; MergeCoordinator keeps requiresFreshReview. - Update the lock through the step-1 descriptor instead of a rename. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Address F1 contract review round 15 - Cancel task during an active attempt stops it first and closes the task in the attempt's terminal transaction; completion requires an open task with no pending cancel. - The shutdown gate raises ShuttingDownError, mapped to 503 with no view. - Split D-owned agent resources from F-owned preparation processes. - A fixed attempt directory makes preparation files recoverable after a crash; recovery captures and removes them with ownership checks. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Address F1 contract review round 16 - Publication CAS also requires an open task with no pending cancel. - Partial output uses a D-provided bounded export before removeTaskFilesystems (prerequisite for F2). - Saved preparation process group; recovery kills and awaits it first. - Merge initiation goes through user_actions for exact replay. - Bootstrap path safety: owner-only parent directory, O_NOFOLLOW create/open. - The status response exposes stopRequested. - Abortable async clone helper is a D prerequisite. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Address F1 contract review round 17 - Preparation-starting marker; an unknown child fails closed until the user releases the attempt. - A pending cancel task beats a time-limit settlement. - The startup recovery transaction fails closed and exits. - Narrow the lock claim: node:sqlite opens by path, so same-user swaps are detected afterwards, not prevented. - Planning endpoints use the user-action protocol. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Address F1 contract review round 18 - Attempt IDs are Store-generated UUID v4, validated before path use. - Explicit same-state transition for recording a first reason. - Merge status and queue catches rethrow ShuttingDownError first. - D recovery keeps task volumes for export; startup stops if it rejects. - Recovery maps a no-reason, non-current attempt to stale. - Enumerate feedback-producing actions; everything else is idempotency-only. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Address F1 contract review round 19 - pending to running requires no first reason; failed transitions require a current context; the settlement table puts a non-current context before D stop reasons; a D stop that came before shutdown wins. - Path-safe runner token format. - runnerOwner on every pre-invocation allocator; authenticated recovered storage handles from D. - Explicit fail-closed step for unowned preparation before admission. - Persist task budget and attempt deadlines for recovery. - Hard-link check before SQLite opens the database. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Address F1 contract review round 20 - Bind recovered task storage to its attempt (attempt label plus attempts.allocation_id); mismatches are kept and reported. - Check the parent directory before any lock file operation. - Recovery checks a non-current context before the deadline fallbacks. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Split task-storage ownership from D's container ownership Task storage outlives settlement: F holds the capability and removes it after the partial-output export and before the terminal write. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Make task-storage release order consistent Export, then the terminal write storing diagnostic_ref, then removeTaskFilesystems, then the slot is freed. This applies to every writable attempt, including completed ones. Recovery exports before finalizing and removes storage before admission. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Address F1 contract review round 23 - Both preparation helpers (clone and task storage) need async abortable D variants; premise lists every D prerequisite. - Shutdown step 5 follows the storage release order. - Suggestion cancel uses retained SuggestionHandles. - Validate actionId format and size before any transaction. - Decision 1 lock is now an OS lock (SQLite exclusive locking on a dedicated lock file): no stale-lock takeover. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Address F1 contract review round 24 - Durable requeue claim: recovery sets requeue_pending; retry is refused until I3 or an explicit Resume claims it by compare-and-swap. - The OS lock cannot name its holder; drop the process-ID diagnostic. - The clean-restart regression keeps the lock file and releases the OS lock. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Address F1 contract review round 25 - Durable rebase marker (tasks.rebase_in_progress) with CAS set and clear. - Complete the v5 backfill; the budget starts at the first move to running, and a null deadline means not started. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Address F1 contract review round 26 - Releasing an unknown preparation requires a verified no-open-files check, not quiescence. - D start must return at once and run Docker setup asynchronously (new prerequisite). - F2 extracts a completed attempt's work before the terminal write and storage removal. - Suggestion cancel after a restart relies on D recovery stopping the provider. - The task budget starts at the first attempt's admission, so it covers preparation. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Address F1 contract review round 27 - Machine-wide shared/exclusive lock proves no live runner before legacy cleanup; running legacy containers also block it. - F2 records the ledger inside the publication transaction after the guard; nothing is written to the Store before it. - State that this contract governs task closure until design L1 is reconciled by its owner. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Address F1 contract review round 28 - codeboost never removes unowned legacy resources itself: it lists them with manual removal commands, and admission stays closed. The machine-wide lock is dropped. - Recovery applies D-reason precedence when stop_reason is saved; state the limit when D's reason is lost with the process. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Address F1 contract review round 29 - The completion guard says 'not closed' explicitly instead of an undefined 'open' status. - D recovery keeps task storage whole (volumes and keeper container) until F exports and removes it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Address F1 contract review round 30 - Launch: a refused pending-to-running write caused by a first reason cancels and settles normally; only other write failures leave a marker. - F reserves the allocation ID on the attempt row before async allocation. - Split recovery into an export phase (fixed-name files, no DB) and one finalization transaction. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Update F1 contract baseline for merged D5; link D prerequisites (#51) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Allow running-to-failed when D stopped before shutdown The round-19 precedence rule (D's earlier stop reason beats shutdown) needs a matching transition guard. Found while implementing F1a. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Address F1 contract review round 32 - Recovery stops leftover preparation process groups before D recovery and before touching storage. - The runner lock is keyed by the database file's device and inode, so a renamed database meets the same lock. - The partial-output export has a 60-second abortable deadline; failure records a diagnostic and continues. - The recovery time-limit mapping keeps the closed-task and pending-cancel precedence. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Address F1 contract review round 33 - Startup order is explicit: lock, open Store and token, stop preparation, D recovery, handle rejection. - Publication is skipped when the job holds an unsaved first reason. - Diagnostics retention never leaves a dangling diagnostic_ref. - Lock files live in ~/.codeboost/locks, keyed by device and inode, so moves between directories keep the same lock. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Fix step reference after startup reorder Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Export partial output only for stopped writable attempts Read-only attempts also get task storage; recovery removes every recovered handle but exports only non-completed writable attempts. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Freeze task status while an attempt is active; completion requires running Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Keep task storage until the terminal write on pre-launch paths Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
1 parent af8f3c2 commit e1cbf04

1 file changed

Lines changed: 565 additions & 0 deletions

File tree

0 commit comments

Comments
 (0)