Skip to content

fix: stable task identity across sleep/wake cycles - #2230

Merged
simple-agent-manager[bot] merged 7 commits into
mainfrom
sam/implement-stable-task-identity-7pwd61
Oct 4, 2026
Merged

simple-agent-manager[bot] merged 7 commits into
mainfrom
sam/implement-stable-task-identity-7pwd61

Conversation

@simple-agent-manager

@simple-agent-manager simple-agent-manager Bot commented Oct 4, 2026 •

Copy link
Copy Markdown
Contributor

Summary

VM sleep/wake now reactivates the original task instead of creating another task row. Task hierarchy, dispatch depth, fan-out accounting, and chat ownership remain attached to one task ID.

  • Add the sleeping task status and its UI label; only VM teardown changes this status. Instant continues waking in place.
  • Reset the TaskRunner's runtime state on wake, with a persisted wake-attempt ID fencing stale RPCs, alarms, callbacks, snapshot writes, and cleanup.
  • Retain automated source/event/member authorization, explicit human follow-ups to terminal conversations, and normal/fallback recovery prompts without replaying the original task description.
  • D1 migration 0182_session_snapshot_recovery_attempt_id.sql adds a nullable column. Existing legacy claims keep their old path; no historical task rows are migrated.

Validation

  • Shared package: 774 tests passed.
  • Focused recovery/prompt/state-machine tests: 84 passed.
  • Independent real-SQL authorization/event tests: 33 passed.
  • Callback/service tests: 104 passed.
  • VM sleep lifecycle: 11 passed; Instant lifecycle: 22 passed.
  • Stable identity/admission cleanup and state-write CAS tests: 14 passed.
  • Migration tested against existing rows and fresh full migration chain.
  • Changed API files lint passed. API-local Durable Object regressions: 8 passed. API typecheck passed. Shared Sleeping badge: 12 tests passed. Updated recovery/status/storage fixtures: 314 focused tests passed. Full unit/integration CI passed on dd19473; Worker CI exposed three missing workspace-identity fixtures, corrected and all 16 tests in that Worker file passed locally. Successful CI run: https://github.com/raphaeltm/simple-agent-manager/actions/runs/37240877919.

Staging Verification Evidence

Staging deployment 37241770621 succeeded on ce4c7e2. Playwright token-login returned 200; dashboard, project chat, and ideas loaded at 1280px and 375px with no page exceptions or horizontal overflow. Sleeping sessions render on the dashboard. Task API returned 50 unique IDs in 50 rows; session API returned 20 unique IDs, including sleeping sessions. D1 confirms migration0182 recovery_attempt_id exists.

Screenshots: desktop dashboard, mobile dashboard, mobile project, mobile ideas.

UI Screenshot Evidence

Playwright screenshots of actual components with mock data, inspected on desktop and mobile.

Surface: TaskList and shared Sleeping badge

Surface: IdeaDetailPage

Data Flow Trace

session-sleep-teardown.ts:completeSleepTeardown marks VM tasks sleeping → session-recovery.ts:ensureSessionRecovery claims a snapshot with a distinct attempt ID and updates the same task → session-recovery-task.ts:startRecoveryTask preserves recovery authority and selects the resume prompt → TaskRunner.reactivate resets runtime bindings and schedules placement → session-linking.ts/agent-session-step.ts complete the matching snapshot → project-data/sessions.ts:wakeSession preserves task binding. TaskList and IdeaDetailPage consume the shared sleeping status.

Untested Gaps

A live VM sleep/wake cycle was not exercised: staging has zero active nodes and zero unexpired available sleeping VM snapshots. Used the user-authorized bounded verification above. This does not claim post-wake duplication was tested live. Automated tests exercise stable task identity, replay ownership/lineage, and real Durable Object state.

Specialist Review Evidence

Reviewer Status Outcome
cloudflare-specialist / constitution-validator / test-engineer (api_review) ADDRESSED Fixed wake authority, resume prompt, per-attempt acknowledgment, stale state/snapshot/callback/cleanup fencing; no configuration violations.
task-completion-validator / doc-sync-validator (completion_review) ADDRESSED Corrected Instant status regression, added lifecycle coverage, updated architecture docs.
security-auditor (independent completion_review) PASS Reviewed final authority, state, snapshot, admission, and legacy-owner fixes; no remaining high/critical findings.
ui-ux-specialist (ui_review) ADDRESSED Reviewed actual-component desktop/mobile screenshots; fixed Unknown Sleeping badge and mobile overflow.

CodeRabbit Review Evidence

Requested with coderabbit-review label at 2026-10-04 23:22 UTC after CI and staging passed. CodeRabbit acknowledged processing, but after 15 minutes (23:37 UTC) there were zero submitted reviews and zero inline comments; check remained pending. Proceeding under the user-authorized best-effort review gate; no received feedback is unresolved.

Post-Mortem

Wake used a replacement task row as a runtime identity, which dropped hierarchy and reset dispatch lineage. Stable task identity requires a separate per-wake identity to fence delayed work. Regression tests now cover repeated wakes, authorization revocation, callback identity, stale state/cleanup writes, normal/fallback prompts, and terminal human follow-ups.

Related

  • Idea: 01M43NCRFC9VF93RPM355FZAKJ
  • Investigation: 01M43B2JVR6AGN62PMXHFCTQD4
  • Task: tasks/archive/2026-10-04-stable-task-identity-sleep-wake.md

Agent Preflight

  • Preflight completed before code changes

Classification

  • cross-component-change
  • business-logic-change
  • docs-sync-change
  • security-sensitive-change
  • ui-change

External References

N/A: existing repository APIs and runtime primitives; no external API contract changed.

Codebase Impact Analysis

apps/api session sleep/recovery, snapshot claim/outcome, TaskRunner state/callbacks and VM admission cleanup; packages/shared task status contract; apps/web status consumers; packages/ui Sleeping badge; scripts/quality/node-pool-boundary obsolete INSERT inventory entry removed.

Documentation & Specs

Updated apps/www/src/content/docs/docs/architecture/overview.md to describe stable identity, reactivation, and unchanged legacy ownership.

Constitution & Risk Check

Checked Principle XI: no new hardcoded operational limits. Preserve existing task lineage and revocable authority; fence each wake separately so delayed runtime work cannot overwrite the next wake. Additive nullable D1 migration tested for upgrade and clean installation. No standing configuration or secret changes.

@coderabbitai

coderabbitai Bot commented Oct 4, 2026 •

Copy link
Copy Markdown

Review in Change Stack →

Navigate logical layers of code changes, visualize relationships, and explore their blast radius.

Note

Currently processing new changes in this PR. This may take a few minutes, please wait...

⚙️ Run configuration
  • Configuration used: Repository: raphaeltm/simple-agent-manager/.coderabbit.yaml
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: e2d3c143-6c4b-4eb4-8641-23d0ea585baf
📥 Commits

Reviewing files that changed from the base of the PR and between b217296 and ce4c7e2.

📒 Files selected for processing (55)
  • apps/api/src/db/migrations/0182_session_snapshot_recovery_attempt_id.sql
  • apps/api/src/db/schema.ts
  • apps/api/src/durable-objects/project-data/sessions.ts
  • apps/api/src/durable-objects/task-runner/agent-session-step.ts
  • apps/api/src/durable-objects/task-runner/attempt-storage.ts
  • apps/api/src/durable-objects/task-runner/index.ts
  • apps/api/src/durable-objects/task-runner/session-linking.ts
  • apps/api/src/durable-objects/task-runner/state-machine.ts
  • apps/api/src/durable-objects/task-runner/types.ts
  • apps/api/src/routes/workspaces/lifecycle.ts
  • apps/api/src/schemas/tasks.ts
  • apps/api/src/services/session-recovery-authority.ts
  • apps/api/src/services/session-recovery-task.ts
  • apps/api/src/services/session-recovery.ts
  • apps/api/src/services/session-sleep-teardown.ts
  • apps/api/src/services/session-snapshot-recovery-lifecycle.ts
  • apps/api/src/services/session-snapshot-sleep-lifecycle.ts
  • apps/api/src/services/session-snapshot-wake-outcome.ts
  • apps/api/src/services/task-runner-do.ts
  • apps/api/src/services/task-status.ts
  • apps/api/src/services/vm-admission-control.ts
  • apps/api/tests/integration/instant-idle-sleep-wake.test.ts
  • apps/api/tests/integration/session-recovery-handoff.test.ts
  • apps/api/tests/integration/session-sleep-lifecycle.test.ts
  • apps/api/tests/integration/task-failure-entrypoints-sql.test.ts
  • apps/api/tests/integration/workspace-eviction-recovery-http.test.ts
  • apps/api/tests/unit/db/session-snapshot-recovery-attempt-id-migration.test.ts
  • apps/api/tests/unit/durable-objects/project-data-sessions-wake.test.ts
  • apps/api/tests/unit/durable-objects/task-runner-agent-session.test.ts
  • apps/api/tests/unit/durable-objects/task-runner-attempt-storage.test.ts
  • apps/api/tests/unit/durable-objects/task-runner-build-started.test.ts
  • apps/api/tests/unit/durable-objects/task-runner-recovery-retry.test.ts
  • apps/api/tests/unit/durable-objects/task-runner-state-machine.test.ts
  • apps/api/tests/unit/routes/node-pool-upgrade-admission.test.ts
  • apps/api/tests/unit/routes/node-pool-upgrade-test-helpers.ts
  • apps/api/tests/unit/routes/session-wake-region-affinity.test.ts
  • apps/api/tests/unit/services/project-data-snapshot-recovery-wake.test.ts
  • apps/api/tests/unit/services/session-recovery-event-boundaries.test.ts
  • apps/api/tests/unit/services/session-recovery.test.ts
  • apps/api/tests/unit/services/task-status.test.ts
  • apps/api/tests/unit/task-runner-do-service.test.ts
  • apps/api/tests/unit/task-runner-static-wiring.test.ts
  • apps/api/tests/unit/workspace-lifecycle.test.ts
  • apps/api/tests/workers/project-data-service.test.ts
  • apps/api/tests/workers/task-runner-do-proxy.test.ts
  • apps/api/tests/workers/task-runner-do.test.ts
  • apps/web/src/components/project/TaskList.tsx
  • apps/web/src/pages/IdeaDetailPage.tsx
  • apps/www/src/content/docs/docs/architecture/overview.md
  • packages/shared/src/types/task.ts
  • packages/shared/tests/is-task-status.test.ts
  • packages/ui/src/components/StatusBadge.tsx
  • packages/ui/tests/StatusBadge.test.tsx
  • scripts/quality/node-pool-boundary/inventory-data.ts
  • tasks/archive/2026-10-04-stable-task-identity-sleep-wake.md
 _______________________________________
< 💖 Git blame less, Git forgive more 🤝. >
 ---------------------------------------
  \
   \   (\__/)
       (•ㅅ•)
       /   づ
✨ Finishing Touches
📝 Generate docstrings
  • Commit to this branch
  • Create a new PR
🧪 Generate unit tests (beta)
  • Commit to this branch
  • Create a new PR
  • Autopilot · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@codspeed

codspeed Bot commented Oct 4, 2026 •

Copy link
Copy Markdown
Contributor

Merging this PR will not alter performance

✅ 6 untouched benchmarks


Comparing sam/implement-stable-task-identity-7pwd61 (ce4c7e2) with main (9ef726c)1

Open in CodSpeed

Footnotes

  1. No successful run was found on main (b217296) during the generation of this report, so 9ef726c was used instead as the comparison base. There might be some changes unrelated to this pull request in this report. ↩

@simple-agent-manager

Copy link
Copy Markdown
Contributor Author

Playwright visual review completed on the actual TaskList/StatusBadge and IdeaDetailPage components with mocked sleeping tasks and long stress text, at 375×667 and 1280×800. Screenshots are preserved in the SAM project library (project login required).

Surface Mobile Desktop
TaskList + Sleeping badge Mobile screenshot Desktop screenshot
IdeaDetailPage sleeping → Executing Mobile screenshot Desktop screenshot

Both the UI reviewer and root reviewed all four final screenshots for overflow, clipping, readability, and responsive layout. Fixed two findings before capture: the missing Sleeping badge mapping (previously Unknown) and TaskList grid intrinsic sizing that overflowed mobile viewports. Final screenshots have no horizontal overflow or new visual issues. Long IdeaDetail titles intentionally exercise vertical scrolling.

@sonarqubecloud

sonarqubecloud Bot commented Oct 4, 2026

Copy link
Copy Markdown

@simple-agent-manager simple-agent-manager Bot added the coderabbit-review Trigger CodeRabbit review for opt-in PRs label Oct 4, 2026
@raphaeltm

Copy link
Copy Markdown
Owner

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Oct 4, 2026 •

Copy link
Copy Markdown
⚠️ Action not completed

Pull request base or head changed.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@simple-agent-manager

Copy link
Copy Markdown
Contributor Author

CodeRabbit was requested at 23:22 UTC after green CI and staging. At 23:37 UTC, after approximately 15 minutes, no review or inline findings had arrived; its check remains pending. Recording the no-response outcome and proceeding with the authorized best-effort merge. Live VM sleep/wake was not exercised; the PR documents the bounded staging checks and lack of an eligible VM fixture.

@simple-agent-manager
simple-agent-manager Bot merged commit ee80b0e into main Oct 4, 2026
33 of 34 checks passed
@simple-agent-manager
simple-agent-manager Bot deleted the sam/implement-stable-task-identity-7pwd61 branch October 4, 2026 23:37
@simple-agent-manager

Copy link
Copy Markdown
Contributor Author

PR #2230 shipped as squash commit ee80b0e; source branch deleted.

simple-agent-manager Bot pushed a commit that referenced this pull request Oct 5, 2026
Delta audit of all 214 backlog files against the 26 PRs merged since
2026-09-30. Adds a dated block to 25 files (8 with new progress, 17 with a
corrected fact or new finding), deletes one superseded entry, archives one
obsolete entry that an archived task still links to (link repointed), and
files the #2230 sleeping-status gaps as a new entry.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
simple-agent-manager Bot pushed a commit that referenced this pull request Oct 5, 2026
PR #2230 made a slept VM conversation keep its original task row and added
the `sleeping` task status (execution_step NULL while idle, `queued` while a
wake is claimed). The project chat page restored ProvisioningIndicator for
any task that was "not terminal and not in_progress", so every idle slept
chat rendered "Starting... Waiting for task runner..." with a timer counting
from the task's original start, and a waking chat stacked that block on top
of WakeProgressBanner.

- Extract the provisioning poll + restore into useProvisioningTracker.
- Gate restore on PROVISIONING_TASK_STATUSES (queued, delegated) instead of
  a denylist, skip sessions whose status is sleeping, and exit the poll when
  the task sleeps.
- Key the restore effect on the selected session's taskId/status so
  unrelated sidebar deltas no longer trigger a task fetch.
- Behavioral unit tests for the hook; a CI-run Playwright audit for idle and
  waking slept sessions; realistic own-task mock in wake-progress-audit.
- Rule 79: a new value in a shared status enum must audit every denylist.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
simple-agent-manager Bot pushed a commit that referenced this pull request Oct 5, 2026
The sparkline note cited FailureCard.tsx lines that use the
--sam-color-fg-secondary custom property, not the text-fg-secondary class;
separate the two. Add pointer-correction notes to the two recovery and
sleep entries whose citations #2223 and #2230 moved (one pointed past the
end of the rewritten session-recovery.ts).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
simple-agent-manager Bot added a commit that referenced this pull request Oct 5, 2026
* task: add weekly queue reconciliation 2026-10-05

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* task: start weekly queue reconciliation 2026-10-05

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* chore(tasks): archive eight shipped ACP and GPT-6.1 active tasks

Each file's work is merged and live: production runs main HEAD ee80b0e
(Deploy Production 37245799681). Each archived file gets a provenance
footer naming its landing PR, merge commit and first successful production
deploy; boxes stay unticked unless evidence exists. The ProjectData
capacity emergency stays active with a 2026-10-05 status block (9.72 GB
and falling, breaker closed, 0 failed or poisoned migrations).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* chore(tasks): reconcile the backlog against this week's merges

Delta audit of all 214 backlog files against the 26 PRs merged since
2026-09-30. Adds a dated block to 25 files (8 with new progress, 17 with a
corrected fact or new finding), deletes one superseded entry, archives one
obsolete entry that an archived task still links to (link repointed), and
files the #2230 sleeping-status gaps as a new entry.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* chore(tasks): draft the 2026-10-05 reconciliation ledger and format touched files

Adds the ledger (active, open PRs, findings, per-file backlog verdicts),
extends the sleeping-status follow-up entry with send_durable_message and
the failed-wake shape change, and runs prettier on the five files whose
inserted blocks were not formatted.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* chore(tasks): record the memory pass and the ranked open list in the ledger

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* chore(tasks): address reconciliation review findings

The sparkline note cited FailureCard.tsx lines that use the
--sam-color-fg-secondary custom property, not the text-fg-secondary class;
separate the two. Add pointer-correction notes to the two recovery and
sleep entries whose citations #2223 and #2230 moved (one pointed past the
end of the rewritten session-recovery.ts).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* chore(tasks): archive the 2026-10-05 reconciliation ledger

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Raphaël Titsworth-Morin <raphael@raphaeltm.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
simple-agent-manager Bot added a commit that referenced this pull request Oct 5, 2026
…2231)

* fix(web): stop showing the provisioning banner on sleeping sessions

PR #2230 made a slept VM conversation keep its original task row and added
the `sleeping` task status (execution_step NULL while idle, `queued` while a
wake is claimed). The project chat page restored ProvisioningIndicator for
any task that was "not terminal and not in_progress", so every idle slept
chat rendered "Starting... Waiting for task runner..." with a timer counting
from the task's original start, and a waking chat stacked that block on top
of WakeProgressBanner.

- Extract the provisioning poll + restore into useProvisioningTracker.
- Gate restore on PROVISIONING_TASK_STATUSES (queued, delegated) instead of
  a denylist, skip sessions whose status is sleeping, and exit the poll when
  the task sleeps.
- Key the restore effect on the selected session's taskId/status so
  unrelated sidebar deltas no longer trigger a task fetch.
- Behavioral unit tests for the hook; a CI-run Playwright audit for idle and
  waking slept sessions; realistic own-task mock in wake-progress-audit.
- Rule 79: a new value in a shared status enum must audit every denylist.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

* fix(web): keep sidebar session status live and backstop the provisioning gate

Review follow-ups for the sleeping-session provisioning banner fix:

- useSessionReducer: apply `status` from `session.updated`. ProjectData
  broadcasts status 'sleeping' on sleep and 'active' on wake, but the
  reducer only mapped topic/taskId/workspaceId, so a list entry's status
  lagged until the 10-minute reconcile and the sleeping-session gate could
  read a stale value.
- useProvisioningTracker: also require `startedAt` to be null before
  restoring (started_at is written once, when the agent first starts, and
  a wake never resets it); call loadSessions() on the sleeping poll exit;
  make workspaceUrl a poll dependency so storing it does not leave a
  closure refetching the workspace every tick; retry a failed restore
  fetch a bounded, env-configurable number of times.
- Tests for each guard (each proven discriminating by reverting it), and
  numeric timestamps in the Playwright fixture so the sidebar renders a
  date instead of "Invalid Date".
- Rule 79 now cites the production incident task and the fix PR.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

* test(web): share the sleeping-chat Playwright mocks; address Sonar findings

- Extract the route mocks duplicated between wake-progress-audit and
  sleeping-session-audit into audit-helpers (setupSleepingChatMocks,
  makeMockProject, makeIdleSessionState).
- Replace the fixed 1.5 s waits with awaitOwnTaskFetchOutcome, a bounded
  wait on the session's own-task fetch, so the absence assertions observe
  the restore effect's outcome.
- Split rawToSessionEvent's session.updated mapping into
  sessionUpdatedPayload (cognitive complexity back under the limit) and
  carry status only when it is a string.
- Number.parseInt for the new retry constant.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

---------

Co-authored-by: Raphaël Titsworth-Morin <raphael@raphaeltm.com>
Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>

This branch was successfully deployed

1 active deployment
staging — ce4c7e2b Deployed Oct 4, 2026 by simple-agent-manager[bot] via smoke-tests #2237
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

coderabbit-review Trigger CodeRabbit review for opt-in PRs

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants