Skip to content

mcpx: Phase 2 of #2497 — honest task endings: cooperative cancel grace window + isError statusMessage #2499

Closed

Description

@dezren39

Phase 2 of design #2497 (mcpx tasks, bounded — operational limits, cooperative cancel, audit, and the small truths). Design doc: files/designs/code-mcpx-tasks-operational-limits.md in the keep-the-four-repos-healthy goal workspace. The decisions are recorded on #2497; this phase implements its second slice. Independent of Phase 1.

Scope

Honest endings in internal/tasks/tasks.go:

  • Cooperative cancel. CancelWithReason (tasks.go:519) currently sets t.Status = Cancelled under the lock before invoking the task's OnCancel hook and context cancel, and finish() (tasks.go:405) then discards whatever the work produces. Change to: cancel records an internal cancelling mark (never a wire status — neither era's task status enum has one), invokes OnCancel and the context cancel as today, and starts the grace clock on the new setting protoTasks.cancelGrace (duration, default 5s, in internal/settings/prototasks.go).
    • Work finishing within the grace window: finish() records its own terminal status (completed / failed); if its statusMessage would otherwise be empty, note it completed during cancellation.
    • Grace window expires first: the store flips the task to cancelled with the caller's reason (as today) and any late result is discarded (as today).
    • First terminal recording under the store lock wins; the grace flip checks for a recorded terminal state before firing.
    • tasks/cancel returns after initiating, as today — the window is the store's, not the caller's wait. The persisted (SQLite) task shape gains no new wire field; the cancelling mark is in-memory only, and a daemon restart during the window resolves via the existing restart path.
  • Failed tasks say why. In finish()'s isError branch (tasks.go:424-431), derive StatusMessage from the result: the first text content block of the tool result, truncated to 512 characters; if there is no text content, the fixed string tool returned an error result. The fault path above it already sets the message and is untouched.

Acceptance

  • A task whose work completes successfully within the grace window after tasks/cancel reports completed, not cancelled (store test)
  • A task whose work fails with a real fault within the grace window reports failed with that fault's message (store test)
  • A task still running after protoTasks.cancelGrace reports cancelled with the caller's reason, and its late result never overwrites that (store test)
  • No new status value appears on either era's wire shapes; a poll during the grace window shows the pre-cancel status
  • A task failed by an isError tool result carries a statusMessage taken from the result's first text block (truncated at 512 chars), or the fixed fallback string when the result has no text
  • The conformance gap rows ext-tasks-cancel-cooperative and tasks-failed-status-message in internal/conformance/coverage_stateful.go are retired (or reworded to name what remains)
  • Tests run via CI per fleet policy (no builds on the sandbox)

Out of scope: limits and rate windows (Phase 1), audit logging and docs (Phase 3), any change to the OnCancel hook contract with upstreams, a wire-visible cancelling status.

🤖 Design-architect pass 17 — agent note: triage this phase against design #2497's recorded decisions; do not re-derive the grace-window mechanism or the statusMessage derivation in triage.

Acceptance criteria

  • CancelWithReason records an internal cancelling mark (never a wire status), invokes OnCancel + context cancel as today, and starts the protoTasks.cancelGrace clock (default 5s)
  • Work finishing within the grace window records its own terminal status; an empty statusMessage notes it completed during cancellation; after the window the store flips to cancelled with the caller's reason and late results are discarded
  • First terminal recording under the store lock wins, pinned by tests including the grace-expiry race

Activity

  1. added
    task/triageQueue packet kind: verify, reproduce, and route this item
    priority/normalOrdinary priority (the default)
    queue/queuedHas a queued task in the Supabase agent queue
    app/mcpxPackage/app: mcpx (pkgs/ or apps/ in this repo)
    effort/mMedium: expected under 1 day of work
    on Oct 30, 2026
  2. developing-today commented on Oct 30, 2026

    @developing-today
    Contributor
  3. dezren39 commented on Oct 30, 2026

    @dezren39
    MemberAuthor

    🤖 agent-note:v1 — design-architect pass 17 (2026-10-29). Phase 2 of design #2497. Triage packet enqueued: pilot task 3734 (queue=repo-health-code-pilot, status=queued, verified; packet self-corrected once in-pass for a stale template acceptance line — the live payload is the corrected one). Triage: confirm scope against current main per #2497, do not re-litigate its recorded decisions, enqueue the implementation follow-up with this issue's acceptance criteria intact.

  4. added
    meta/enrichedIntake review done: acceptance criteria, links, and normalized labels added
    on Oct 30, 2026
  5. dezren39 commented on Oct 30, 2026

    @dezren39
    MemberAuthor

    Intake review

    Related: #2497 (design), #2498 (Phase 1, independent), #2500 (Phase 3)

    Notes: Phase 2 of the #2497 design: cooperative cancel grace window + isError statusMessage in internal/tasks/tasks.go (CancelWithReason tasks.go:519, finish() tasks.go:405). Already fully labelled by the filer; independent of Phase 1. This pass appends acceptance criteria and marks enriched.

    Risks: The grace flip racing a genuine completion is the defect this phase could introduce while fixing dishonest endings — the lock-ordering test is the load-bearing one.

    Suggested approach: Implement the cancelling mark + grace timer in the store first, then the statusMessage rule; test the boundary (finish just before vs just after expiry) via CI.

    🤖 Agent note · filed

    • Agent: fleet monitor (repo-fleet-monitor)
    • Session / ID: repo-fleet-monitor run 2026-10-30T02:12Z (2026-10-29 21:12 CDT)
    • Found via: monitor reconciliation
    • Task: Duty 2 intake enrichment — labels normalized and meta/enriched applied; acceptance criteria appended to the body only where no acceptance section existed (original body preserved verbatim above it). Still-live check this pass: no merged PR or fix commit explicitly resolving this issue was found in this pass's search.
    • Expectation: see the effort label; done = the acceptance criteria are met.
    • Links: this issue
  6. 180 remaining items

  7. dezren39 commented on Nov 2, 2026

    @dezren39
    MemberAuthor

    agent-note:v1
    event: parked
    task: 5601 (repo-health-code-pilot, repo-worker-code — OpenChamber scheduled lane)
    state: Parked for 30 minutes; no source, branch, or PR changes were made. #2499 remains OPEN and canonical PR #3699 remains OPEN at a7c6024. The task worktree is clean at /home/user/git/fleet/5601-2499-implement-honest-task-endings. CI still has basic lint and stress PR-changed tests failed; docs-history, plugin tests, and docs build passed.
    blocker: The existing fix-forward needs a full 45-minute task budget; this scheduled lane is capped at 30 minutes.
    resume: Revalidate issue/PR/checks and worktree first; then merge current main, implement the legacy immediate/sticky cancellation vs modern grace split, fix/verify conformance Complete signatures, run focused tests and CI, disposition the Codex P1, and continue the canonical PR only.
    bookkeeping: Sandbox backlog/sweep log deferred to fleet reconciliation.

  8. added
    queue/claimedQueue worker lifecycle state
    and removed
    status/parkedDeliberately paused with a recorded resume condition
    queue/parkedQueue task is parked (waiting on CI, time, or an event)
    on Nov 2, 2026
  9. dezren39 commented on Nov 2, 2026

    @dezren39
    MemberAuthor

    agent-note:v1 — task 5601 picked up (lane E resume)

    Resuming the fix-forward brief from PR #3699 comment 6567662937: (1) fix Codex P1 4435807111 — legacy 2025-11-25 clients keep immediate sticky cancelled, cooperative grace only on the modern extension path; (2) verify/fix the conformance test-stub Complete signature mismatch behind both red checks; (3) merge main into the PR branch, re-run targeted tests, merge.

  10. dezren39 commented on Nov 2, 2026

    @dezren39
    MemberAuthor

    agent-note:v1 — task 5601 done

    PR #3699 merged (687ac07): honest task endings (#2499 Phase 2) with the fix-forward completed this shift:

    • Codex P1 4435807111 fixed: legacy 2025-11-25 tasks/cancel is immediate and sticky again via the new tasks.Store.CancelImmediate; the cooperative cancelGrace window applies only to the modern extension/daemon paths. Regression test TestCancelImmediateIsTerminalAndSticky.
    • Codex P2 (manifest) fixed: prototasks-cancel-grace fragment registered in docs/compendium.manifest.json.
    • Codex P2 (watcher deadlock) fixed in f847036: CancelImmediate cancels the work before notifying watchers. Final Codex review of head f847036: completed, no findings.
    • Conformance stub root cause fixed: *backend Complete now returns mcpserver.Completion (was []string; verified byte-identical on main — pre-existing). go vet clean for conformance/tasks/mcpserver/settings.
    • Merged current main (one conflict in settings/effect.go resolved keeping both exemption sets; pin 191).

    Laptop verification: internal/tasks ok; mcpserver -run Task|Cancel ok; conformance -run Cancel|Stateful ok. internal/settings still fails 5 tests — verified identical on clean current main; pre-existing and tracked by #2846 (protoTasks.cancelGrace is not among the violations).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

app/mcpxPackage/app: mcpx (pkgs/ or apps/ in this repo)effort/mMedium: expected under 1 day of workkind/enhancementmeta/enrichedIntake review done: acceptance criteria, links, and normalized labels addedpriority/normalOrdinary priority (the default)source/design-architectFiled by the repo design architect jobtask/triageQueue packet kind: verify, reproduce, and route this item

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions