Skip to content

session: tasks stuck in working on restart, stopped status mapped to failed, and reader handoff #1554

Open

Description

@santoshkumarradha

Summary

Task frontier state recovery leaves queued tasks hung after restart, stopped tasks are improperly reported as failures, and chat reader subtasks do not fall back cleanly.

Items & Observed Behavior

  1. Tasks hung in working state across restart: A task queued or waiting on machine capacity remains in working status in the database after codeaf engine --stop and restart, but is never re-admitted to the execution frontier.
  2. Stopped tasks mapped to failure: Cancelling a task via x or /stop sets the crew line to failed and outputs /redo stronger... instead of marking it cleanly as stopped.
  3. Chat reader subtask handoff failure: When an inline chat reader subtask fails to hand off, it prints ◆ reading for the chat · stopped and leaves a stopped card in the chat before running inline.

Expected Behavior

  • Engine startup must reconcile persisted task state and re-queue uncompleted tasks onto the frontier.
  • Explicit cancellation (x, /stop) must record status as stopped and omit retry suggestions.
  • Reader subtask handoff failures should fall back to inline reading without polluting the chat stream with stopped task cards.

Root Cause / Location

  • internal/session/cancel.go and internal/session/task_frontier.go: Startup frontier reconciliation and cancellation status mapping.
  • internal/session/read_handoff.go: Silent fallback handling when subtask delegation cannot be completed.

—
Drafted with CodeAF · reviewed and owned by the author

Activity

  1. added
    bugSomething the code does that it should not
    area:sessionThe engine — turns, tasks, the toolbelt, checkpoints
    sev:seriousWrong or missing behaviour a person meets in ordinary use
    on Sep 27, 2026
  2. santoshkumarradha commented on Sep 27, 2026

    @santoshkumarradha
    MemberAuthor

    New evidence from dev 837b2b0, found by the docs lanes while writing the public docs. Replication for every item below starts from a clean install:

    1. Build dev 837b2b0 (git checkout 837b2b0 && make build, binary bin/codeaf), or install the dev build with curl -fsSL https://agentfield.ai/get/devaf | bash.
    2. Use an isolated profile: export HOME=$(mktemp -d), export OPENROUTER_API_KEY, and keep the default model (~deepseek/deepseek-v4-flash-latest, crew on auto).
    3. On a busy machine set task.max_load to 0 (/settings, Tasks) so the busy-machine gate does not hold tasks.

    1. Task stuck working after an engine restart (B08)

    • What happened: a task waiting · machine busy; codeaf engine --stop and a relaunch; the task then showed working for 10+ minutes with no worker process and no model call in codeaf logs --tail. codeaf do on the same config finished in 4 s.
    • Replication: force the hold with a tiny task.max_load (for example 0.01), /task add a README.md with one line, codeaf engine --stop, set task.max_load to 0, relaunch codeaf.

    2. A stopped task's crew line says failed (B30, two lanes)

    • Screen: after x → stop it, the card reads stopped · it had changed nothing but the crew line reads task 5 crew · failed, /redo stronger runs it again on a stronger crew (a long dash written as a comma). Also for a task that /stop ended before it did anything (task 1 crew · failed …).
    • Replication: /task Run the shell command sleep 120, then list the files; alt+t, x, stop it. This may also teach the router wrongly.

    3. Reader subtask handoff shows as a stopped task (B31)

    • Screen: ◆ reading for the chat · stopped with stopped before it started: read handoff failed; running inline; the chats list shows 2 stopped children. The turn went on inline and answered. Seen in two conversations.
    • Code at 837b2b0: internal/session/readhandoff.go:192-196 (a.cancelTask(id, "read handoff failed; running inline")).

    Acceptance (e2e)

    • After the restart above, the task is admitted and lands (or reads waiting with its reason), never working with no worker.
    • A stopped task's crew line says stopped, with no /redo stronger offer.
    • A failed read hand-off leaves no stopped card or stopped child in the chats list.

    Found while writing the public docs; manual text differences are in #1545.

    🤖 Generated with Claude Code

  3. added 2 commits that reference this issue on Sep 27, 2026
    88db9fc
    153eb04
  4. santoshkumarradha commented on Sep 28, 2026

    @santoshkumarradha
    MemberAuthor

    Independent review of automatic task recovery selected from #1619 found a related restart defect: the accepted task-specific crew was not saved in the durable run row. Pending and admitted recovery could construct a run without it, silently replacing task pins/fallback policy with conversation or profile settings.

    The bounded correction now saves accepted seats, original send IDs, fallback and failed-route history, and accumulated task/checker/model spending. Restored runs use that policy without routing again. A missing legacy policy or model call interrupted before its cost was saved remains truthfully interrupted instead of executing under guessed settings or a reset budget. The manual describes this limitation.

    Reproduction at a73ed558d: reopen a held task whose accepted worker/planner/checker differ from the conversation model; TestHeldRecoveryRetainsTheAcceptedCrew fails with held restart lost its accepted crew before the fix. On the candidate, the test invokes all three restored completers and checks the actual models. Admitted recovery also verifies saved fallback/failed-route state and rejection at an already-exhausted task cap. Additional checks cover missing/in-flight policy refusal and synchronous before-call/after-settlement persistence.

    The targeted regression set passed three repetitions on the exact committed candidate. This correction is pending integration into #1632; final combined gate and real-workflow acceptance remain pending. It does not close every behavior described in this issue.

  5. santoshkumarradha commented on Sep 28, 2026

    @santoshkumarradha
    MemberAuthor

    Follow-up during current-dev integration: the newer shared-ledger day initializes its date on first read. Restoring a saved crew spend before that initialization caused the first read to replace the saved amount with a lagging ledger value (deterministic regression: got1, expected5).

    The repair refreshes the day under its existing lock before applying saved same-day floors. Checkpoint snapshots now also refresh and include observed shared spending; yesterday's values cannot be saved as today's. Real ledger-backed tests verify refusal at an exhausted restored daily cap, preserved last-call pricing, visibility of newer ledger spending, and next-day expiry.

    The exact candidate passed all structural laws and ten repetitions of the targeted recovery/spending checks. The helper extraction leaves complexity limits unchanged and retains discarded-response charging. Final aggregate validation remains separate.

  6. santoshkumarradha commented on Sep 28, 2026

    @santoshkumarradha
    MemberAuthor

    The remaining pending-program recovery test now records the explicit accepted unrouted crew policy, matching production admission. Missing or unsettled policy still refuses recovery. Test-only commit 1b4f35db21d00fe065b5fc955f7a5f26dffe5022 reproduces the original own-driver failure on the baseline; the corrected fixture and refusal controls pass 50 repetitions (30.631s). Independent source review approved. This is part of #1632; final combined validation remains pending.

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

Metadata

Metadata

Labels

area:sessionThe engine — turns, tasks, the toolbelt, checkpointsbugSomething the code does that it should notsev:seriousWrong or missing behaviour a person meets in ordinary use

Type

No type

Projects

No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions