Repository navigation
Commit e1cbf04
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
0 commit comments