Files
agent-radar 2ed3415fb7
Publish Claude Code Binaries / Stage and publish binaries (push) Canceled after 0s
Publish Tutti App Runtime / Build darwin-arm64 (push) Canceled after 0s
Publish Tutti App Runtime / Build darwin-amd64 (push) Canceled after 0s
Publish Tutti App Runtime / Build linux-amd64 (push) Canceled after 0s
Publish Tutti App Runtime / Build windows-amd64 (push) Canceled after 0s
Sync Tutti Agent Skills / sync (push) Canceled after 0s
Windows Agent Adapters / Test Windows agent adapters (push) Canceled after 0s
Windows Daemon Adapters / Test Windows daemon adapters (push) Canceled after 0s
Publish Tutti App Runtime / Publish runtime catalog (push) Canceled after 0s
源码快照 @ 2026-09-01 (source-only, 剔除非源码素材)
2026-09-01 20:17:27 +08:00

14 KiB

Issue execution

Managed task deletion is reported as a stale checkpoint

When a source Agent reports that a canceled task could not be removed because the current checkpoint rejects graph changes, inspect the two mutation attempts separately. tutti issue task delete must return tutti_issue_managed for a Tutti-owned graph; that is the expected ownership guard. The authorized path is tutti plan issue mutate with the active checkpoint and graph revision.

If the mutate call reports that its caller, checkpoint, revision, or operation set is not current, first confirm the execution row, active checkpoint, graph revision, and source Session. When those fences still match, inspect --operations-json: operation objects use kind, not op, and a rework embeds its replacement under task, not replacement. Go's permissive JSON decoder otherwise ignores the alias, leaves the required field empty, and the service rejects the malformed operation before it evaluates the durable checkpoint.

The CLI must reject that malformed shape with an actionable kind validation, and the durable wake prompt must include exact supersede and rework examples. Validate both aliases in the CLI provider tests and the task-canceled wake-prompt test. Do not weaken the generic Issue ownership guard or physically delete task/Run audit history; supersede and rework preserve that history.

Reworked task scheduling is reported as a stale checkpoint

After a failed or canceled task is reworked, the mutation can succeed but scheduling its replacement may still be rejected. Run tutti plan issue get --issue-id <id> --json once to separate fence state from task eligibility. Compare its active checkpoint and graph revision with the successful mutation result, then use each task's blockerReason. Stable reasons such as stale_graph_revision, missing_agent_target, and dependency_unsatisfied identify which correction is required instead of collapsing every failure into a generic schedule rejection.

A replacement submitted with only a new task ID, title, and content is a sparse rework, not a request to clear launch configuration. The mutation layer must inherit omitted Agent target, compatible model selection, permission mode, reasoning effort, execution directory, and dependencies from the superseded task. Explicit replacement values override those defaults. It must also redirect dependencies for active not_started tasks in the same transaction, preserve the old task and Run as superseded history, and reject the transaction if an affected dependent has already started.

Do not query or modify the backing SQLite database to recover or bypass the rejected command. The daemon and CLI are the supported control plane, and guessing a production database path while the runtime is in development mode produces unrelated evidence. If the authoritative CLI snapshot and documented recovery commands still cannot resolve the failure, retain and report the exact CLI error.

The checkpoint wake prompt must describe sparse rework inheritance, dependency redirects, and scheduling with the graph revision returned by the successful mutation. The injected CLI skill must also define the checkpoint/action matrix and bound fence or schema recovery to one refresh and one retry. Validate both failed and canceled terminal-run paths, sparse rework, inherited launch settings, dependency redirect, and replacement scheduling in the execution conformance suite.

Final rework passes review but Tutti never reaches Goal Review

If the last replacement Run is complete and its evidence passes review, but plan issue acknowledge returns inactive_checkpoint even after one refresh, inspect the ordered checkpoint backlog rather than weakening the caller or revision fence. The characteristic state is an active final task_settled checkpoint with no running Run and no later pending checkpoint, plus an older all_tasks_terminal row in superseded state.

This state occurs when the previous final Run queued the deterministic all_tasks_terminal checkpoint, then the source Agent reworked that Run before the terminal checkpoint was promoted. The graph mutation correctly supersedes the stale terminal boundary. When the replacement Run later settles, terminal checkpoint creation must rearm that superseded singleton with the current graph revision and a sequence after the replacement settlement. Treating any existing terminal checkpoint ID as current strands the replacement in pending_acceptance: acknowledge has neither active work nor a later checkpoint to justify advancing, so the execution never reaches Goal Review.

Validate the complete chain in the execution conformance suite: settle the original final Run, rework while its terminal checkpoint is pending, schedule and settle the replacement, acknowledge its settlement, and assert that the rearmed terminal checkpoint becomes the active pending_goal_review boundary. Do not bypass the failure with a generic Issue task update or by relaxing the checkpoint/revision fence.

For an execution already persisted in this state, run the normal settlement recovery path (or restart a daemon that invokes it). Recovery only rearms a superseded terminal singleton when the execution is awaiting_main, a terminal task checkpoint is active, every active task is terminal, and every terminal Run already has a settlement checkpoint.

Tutti composer stays busy after every task Turn settles

The Tutti composer deliberately shows Stop while its managed Issue still has nonterminal tasks. When every Agent Turn is terminal but the composer remains busy, compare the execution graph revision with the active checkpoint revision and inspect the ordered checkpoint backlog. An awaiting_main execution whose active settlement checkpoint has an older revision cannot pass the source Agent's schedule or acknowledge fence.

This mismatch can occur when parallel Runs append settlement checkpoints at one graph revision, the source Agent mutates the graph while reviewing the first checkpoint, and a later checkpoint is promoted without being rebound to the new revision. Promotion through both schedule and acknowledge must set the checkpoint's revision to the current execution revision in the same transaction. The watchdog repair path must also rebind already-active stale settlement or watchdog checkpoints, advance their retry deadline, and issue the next deterministic wake without rewriting task or Run history.

Validate this class with a conformance scenario that mutates the graph before both schedule-driven and acknowledge-driven backlog promotion. Also validate watchdog recovery from a pre-existing active checkpoint whose revision trails the execution revision. Do not change the composer to ignore nonterminal Issue tasks; that would hide the durable orchestration deadlock while work remains unreviewed.

When a rework succeeds but the current Issue board shows both the original and replacement tasks, compare the board with the Issue's active task projection. Rework deliberately retains the superseded task row and Run history for audit, but current-task lists, progress counts, and scheduling must exclude tasks whose supersededAtUnix is set. Do not delete the superseded history to make the counts agree.

Settled checkpoint keeps reopening the source Session

A terminal Agent Turn does not resolve its Tutti execution checkpoint. When the checkpoint remains active after that Turn settles, the inactivity watchdog deliberately creates another deterministic wake after five minutes. Each wake is a new Agent Turn, so Desktop may show a new generic Turn-completion notification even though no task Run restarted.

First group the wake records by Issue, checkpoint, and wake sequence. Multiple Issues may legitimately target the same source Session and therefore share the same conversation title. If an older Issue was replaced by a new plan but was never archived, both active checkpoints will continue to wake that Session. Do not suppress watchdog delivery or mark a Turn terminal as proof that the Issue is terminal; either action loses durable work.

The source Agent must have an explicit terminal path when it decides an Issue should not continue. tutti plan issue stop derives source authority from the invoking Session, fences against the active checkpoint and graph revision, and reuses the recoverable archive flow to cancel Runs and close open wakes. The durable wake prompt must advertise that command. Validate the source, checkpoint, and revision fences, plus idempotent replay after the first stop has already canceled the active checkpoint.

Paused Tutti Issue keeps reopening and reports no resume command

A stopped task cascade may leave the Tutti-owned Issue nonterminal with dispatchPaused=true. The source conversation should then stay quiet. If it reopens every five minutes, correlate the daemon's client_submit_id=tutti-execution-wake:<checkpoint>:wake:main:<sequence> with the Issue pause fact and the wake rows for that checkpoint. A sequence that keeps increasing while the Issue is paused proves the watchdog delivery path did not consume the same durable gate as task scheduling.

Do not resolve or delete the checkpoint and do not archive an Issue the user may resume. Apply the pause at every main-wake boundary: due watchdog materialization, dispatchable listing, durable claim, and final dispatch CAS. Retain the prepared or settled wake history so clearing the pause continues from the same checkpoint and graph revision.

If pause races after Agent Host has already accepted the wake Turn but before the final dispatch CAS, cancel that Turn before making the wake retryable. An accepted clientSubmitId cannot execute again, so atomically cancel the leased wake and prepare the next sequence with a fresh identity under the same active checkpoint. Keep the replacement hidden while paused. If canonical Turn cancellation fails, retain the lease until expiry to prevent overlapping orchestrator Turns.

Run tutti plan issue get --issue-id <id> --json. A paused snapshot must expose dispatchPaused=true, omit plan issue schedule from allowedActions, and advertise plan issue resume. Only the original source Session may execute that resume. For an older Session whose immutable command snapshot lacks the new capability, the exact compatibility request tutti issue update --issue-id <id> --dispatch-paused=false --json must route to the same source-scoped control; mixed field updates and other generic managed-Issue mutations remain rejected.

Validate paused list/claim/finalize races, fresh wake identity after a canceled accepted Turn, lease retention when cancellation fails, deferred watchdog sequence creation, idempotent source-scoped resume, the paused execution snapshot, and both CLI entry points. Restarting Desktop is not a resume operation and must not create another wake.

Stop remains pending while the Agent Turn is already canceled

Check the durable Issue, Run, Agent Turn, runtime operation, and Agent outbox facts separately. A paused Issue with a running Run and a terminal Agent Turn usually indicates that synchronous Agent settlement re-entered Issue mutation while the stop caller still held the same per-Issue mutex.

The invariant is:

Never call Agent Host, git worktree operations, or another re-entrant module while holding the Issue mutation lock.

Cancellation should persist dispatchPaused=true and snapshot running Runs under the lock, release it, then cancel Agent Sessions and idempotently settle Runs from exact canonical Turn facts. A regression test should use a canceller that publishes settlement synchronously before returning; a passive recorder cannot reproduce this deadlock class. A second barrier test should pause while launch is in flight and verify Stop returns immediately while the non-blocking launch gate still requests exact-Turn compensation after launch.

Do not fix this symptom by treating the UI test as flaky, adding a timeout, or introducing another pause flag. Those changes hide the blocked command without repairing the callback cycle.

For the ownership and data-flow contract, see Issue Execution Coordination.

Stopping a Tutti source Turn leaves automation recoverable

First compare the canonical source Turn, activity inbox, execution, archive operation, workflow operation, Run launch intent, wake, and Goal Review rows. A canceled source Turn followed by awaiting_main, pending_goal_review, or a new wake after restart means Stop affected the Agent runtime but did not cross a durable product boundary. A scan of running Runs is not sufficient: one source conversation may own several executions, including executions with no current Run, and bounded workspace scans can omit older Issues.

The source-session Stop path must request archive for every nonterminal execution belonging to the exact workspace/source Session. The archive transaction pauses dispatch and cancels checkpoints, wakes, reviews, prepared or leased launch intents, and workflow recovery before external cancellation. Archive recovery then cancels exact Run, main-wake, and reviewer Turns. If Stop wins before a Run has a canonical Turn, settle that unlaunched Run as canceled; if delivery is already in flight, the launch gate performs exact-Turn compensation.

The canonical canceled Turn and its workspace_tutti_source_activity_inbox marker are atomic. Draining the marker must create the same archive operations, must not count the canceled Turn as watchdog activity, and must happen before reviewer or main-wake dispatch. Create-Issue startup recovery must also reject an accepted workflow while that canceled-source marker remains undrained. This is why closing and reopening the app cannot legitimately resume the old automation.

Validate this class with the source-session archive conformance scenarios, canceled-source inbox recovery, main-wake and reviewer dispatch-race compensation, a prepared Run with no canonical Turn, and workflow recovery fenced before inbox drain. Keep the generic Issue ownership guard intact; source Stop is a Tutti execution lifecycle operation, not a generic Issue mutation.