fix: preserve queued session ownership and visibility (#3755)
This commit is contained in:
@@ -0,0 +1,54 @@
|
||||
# ADR-2026-09-16-passive-session-inspection: Keep inspection separate from execution ownership
|
||||
|
||||
**Status:** proposed
|
||||
**Date:** 2026-09-16
|
||||
**Area:** workflow
|
||||
|
||||
## Context
|
||||
|
||||
Workflow parking and process loss both appear as resumable sessions without a
|
||||
running agent. Treating these cases alike lets opening an old conversation wake
|
||||
it. The same resume request currently receives manual ceiling privileges.
|
||||
A sibling ready event can then reconcile a queued task to Review.
|
||||
|
||||
## Decision
|
||||
|
||||
Passive inspection carries explicit intent across the client/server boundary.
|
||||
The server verifies workflow parking and queued ownership before launch side
|
||||
effects. Workflow parking is durable policy state, separate from execution-stamped
|
||||
stop-event suppression and from the background-work projection.
|
||||
|
||||
The exact workflow entry and destination own the deferred launch. The visible
|
||||
conversation does not own it. Task reconciliation considers valid deferred work
|
||||
as well as running sessions. Queue UI consumes a bounded task-status projection,
|
||||
not transcript text or a second client queue.
|
||||
|
||||
Explicit user execution remains possible and retains current manual admission.
|
||||
It does not transfer workflow ownership from the queued recipient. A valid
|
||||
workflow re-entry can release parking for its selected recipient.
|
||||
|
||||
## Consequences
|
||||
|
||||
The implementation adds a durable parking marker and explicit inspection
|
||||
semantics. Old tasks need conservative recognition of existing park provenance.
|
||||
The browser must propagate inspection intent through recovery fallbacks.
|
||||
Existing manual callers remain compatible; this is not a new authorization grant.
|
||||
|
||||
Counts in queue details are observations with freshness, not queue positions.
|
||||
Task and summary revisions must prevent a delayed update from undoing a clear.
|
||||
|
||||
## Alternatives considered
|
||||
|
||||
- Disable all automatic recovery: changes unrelated recovery workflows and the
|
||||
existing user preference. Suppress only ineligible passive execution.
|
||||
- Mark predecessors Completed: loses the deliberate nonterminal park/reuse behavior.
|
||||
- Treat any stop-intent tombstone as permanent parking: a tombstone must survive
|
||||
legitimate reuse to suppress delayed callbacks, so it cannot own current policy.
|
||||
- Add a hard limit to every manual launch: changes the existing admission contract.
|
||||
- Repair only the sidebar spinner: leaves unintended execution and wrong task state intact.
|
||||
|
||||
## Related records
|
||||
|
||||
- [Requirements](../specs/tasks/requirements/queued-session-ownership.md)
|
||||
- [Design](../specs/tasks/system-design/queued-session-ownership.md)
|
||||
- [Workflow lifecycle decision](2026-08-31-workflow-profile-session-switch-policy.md)
|
||||
@@ -0,0 +1,288 @@
|
||||
---
|
||||
created: 2026-09-16
|
||||
status: in_progress
|
||||
requirements:
|
||||
- REQ-TASKS-QUEUED-SESSION-OWNERSHIP-001
|
||||
- REQ-TASKS-QUEUED-SESSION-OWNERSHIP-002
|
||||
- REQ-TASKS-QUEUED-SESSION-OWNERSHIP-003
|
||||
system_design:
|
||||
- ../../specs/tasks/system-design/queued-session-ownership.md
|
||||
legacy_specs: []
|
||||
---
|
||||
|
||||
# Implementation plan: Queued session ownership
|
||||
|
||||
## Overview
|
||||
|
||||
Keep Luna queued when a workflow enters Implement, keep the parked Astra
|
||||
conversation untouched during inspection, and make waiting visible on desktop
|
||||
and phone. Deliver three sequential outcomes: inspection safety, queue lifecycle
|
||||
correctness, then a complete queue projection and UI.
|
||||
|
||||
The task system owns this package because the deferred workflow entry owns its
|
||||
recipient and state. Agent capacity and workflow WIP policy remain separate.
|
||||
Read the [requirements](../../specs/tasks/requirements/queued-session-ownership.md),
|
||||
[design](../../specs/tasks/system-design/queued-session-ownership.md), and
|
||||
[decision](../../decisions/2026-09-16-passive-session-inspection.md).
|
||||
|
||||
## Evidence and conformance
|
||||
|
||||
Read-only investigation of task `ef15115f-12b9-4f8e-ba9f-bc0cd7e01bd8`, using
|
||||
stored conversations, session lists, and backend build `1293d65a8e` (dirty):
|
||||
|
||||
| Lisbon time, 2026-09-16 | Observed event |
|
||||
| --- | --- |
|
||||
| 21:15:44 | Manual move to Implement selects new primary Luna session `c7451c7d-8468-4b45-8c67-ef6427390c01`; task becomes SCHEDULING. |
|
||||
| 21:15:48 | Astra `8bc0ec46-6aef-43a5-b8f2-56c64cd680d0` is parked; Luna automatic launch is deferred at 5/5. |
|
||||
| 21:19:02 | Task open/focus and status checks precede Astra resume by about 135 ms. Resume is classified manual and admitted at 8/5. |
|
||||
| 21:19:06 | Astra boot-ready changes it to WAITING_FOR_INPUT, then changes the task from SCHEDULING to REVIEW. Luna remains CREATED. |
|
||||
| Through 21:23:00 | The scheduler continues retrying Luna every 20 seconds; its accepted queue entry survives. |
|
||||
|
||||
The backend evidence does not prove a scheduler prompt to Astra. It shows a
|
||||
resume through the shared launch path. Timing and frontend source support
|
||||
open-time resumption; the exact user click and empty-output warning event remain
|
||||
unproven. Do not encode either as an established cause.
|
||||
|
||||
The original diagnostic archive is task-local, not a required implementation
|
||||
input: `.kandev/diagnostics/c79c09e35c0b6b608246d9280e0d220f.zip`. Its manifest
|
||||
reports truncation of older logs; the incident window was present.
|
||||
|
||||
Confirmed defects are `buildResumeRequest` sharing manual admission with passive
|
||||
recovery, and `writeTaskReviewState` ignoring a CREATED deferred destination.
|
||||
Existing lifecycle AC-TASKS-WORKFLOW-PROFILE-SESSIONS-001.4 defines parking but
|
||||
does not explicitly exclude inspection. The new requirement pair defines that
|
||||
gap and queue visibility. Manual overrides remain allowed by
|
||||
AC-AGENTS-SESSION-CEILING-001.2.
|
||||
|
||||
## Scope
|
||||
|
||||
### In scope
|
||||
|
||||
- Durable workflow parking, explicit passive intent, guarded status/ensure/resume.
|
||||
- Exact queued recipient and entry identity; state reconciliation and replay races.
|
||||
- Revisioned queue details in sidebar, task details, and phone navigation.
|
||||
- Regression tests, restart evidence, localization, and user documentation.
|
||||
|
||||
### Out of scope
|
||||
|
||||
- Hard limits for explicit manual launches, new limits/settings, queue ordering or ETA.
|
||||
- A global queue page, Office scheduling, provider policy, or new session states.
|
||||
- Changes to source/destination profile selection or workflow WIP admission.
|
||||
- Rewriting historical transcript warnings or assuming the unexplained warning's cause.
|
||||
|
||||
## Technical approach
|
||||
|
||||
Task 01 adds parking metadata and passive-source handling end to end, including
|
||||
status/launch/ensure eligibility and the browser recovery hook. Task 02 binds
|
||||
workflow deferrals to their entry and guards state and clear operations. Task 03
|
||||
extends `task/statussummary` and delivers all queue surfaces together.
|
||||
|
||||
No new SQL column or scheduler is planned. Conditional operations on existing
|
||||
metadata and task state must be tested through both supported database contracts.
|
||||
Never clear callback tombstones to implement unpark. Never use background-work
|
||||
parking as workflow parking. Existing old records need conservative migration
|
||||
or passive suppression, not guessed ownership.
|
||||
|
||||
## ASCII UI preview
|
||||
|
||||
### UI-01: Desktop task row and detail, queued destination
|
||||
|
||||
Entry: move to Implement, then reopen the task or select Astra.
|
||||
|
||||
```text
|
||||
Before (observed) After
|
||||
Review Scheduling
|
||||
Investigate issue [clock] Investigate issue Queued
|
||||
|
||||
+-------------------------------------------------------------------+
|
||||
| Investigate issue Implement |
|
||||
| Queued: Luna. Waiting for session capacity |
|
||||
| 5 of 5 in use. Checked just now. Queued since 21:15 |
|
||||
| Starts automatically when capacity is available. |
|
||||
| [Astra] [Luna: Queued] [Plan] |
|
||||
| Parked for workflow. Send a message to continue this conversation. |
|
||||
| Astra conversation ... |
|
||||
+-------------------------------------------------------------------+
|
||||
```
|
||||
|
||||
The task queue region is outside conversation scroll and remains when Astra is
|
||||
selected. The parked note is conversation-specific. Selecting Luna removes
|
||||
the parked note but keeps queue status; it does not show an unsolicited Start
|
||||
or Resume prompt. Copy and spacing are illustrative; placement and identity are required.
|
||||
|
||||
### UI-02: Phone task navigation and detail
|
||||
|
||||
```text
|
||||
Task navigator (existing bottom drawer)
|
||||
+------------------------------------+
|
||||
| Tasks Close|
|
||||
| [clock] Investigate issue Queued | <- scrolling task list
|
||||
+------------------------------------+
|
||||
|
||||
Task detail (direct navigation)
|
||||
+------------------------------------+
|
||||
| Investigate issue Implement |
|
||||
| Queued: Luna |
|
||||
| Waiting for session capacity |
|
||||
| 5 of 5. Checked just now. |
|
||||
| Queued since 21:15 |
|
||||
| Starts automatically. |
|
||||
| [Astra v] | <- existing session picker
|
||||
| Parked for workflow. |
|
||||
| Send a message to continue here. |
|
||||
| Conversation ... | <- single chat scroll owner
|
||||
| Composer |
|
||||
| Chat | Plan | Changes | More | <- existing safe-area nav
|
||||
+------------------------------------+
|
||||
```
|
||||
|
||||
Reuse `SessionTaskSwitcherSheet`, `TaskSwitcherDrawer`, `MobileSessionsPicker`,
|
||||
and the dedicated mobile layout. No stacked desktop panes or extra disclosure
|
||||
drawer. Required queue text is visible without hover; existing navigation owns
|
||||
touch/focus behavior. New interactive targets, if needed, are at least 44 px on
|
||||
phones/coarse pointers; ordinary desktop sizing remains unchanged.
|
||||
|
||||
### UI-03: Freshness and settlement, both viewports
|
||||
|
||||
```text
|
||||
Loading: Queue status loading... (do not offer a duplicate launch)
|
||||
Disconnected: Queued: Luna. Reconnecting. Capacity last checked 21:16.
|
||||
Read failure: Queued: Luna. Capacity unavailable. Automatic retry pending.
|
||||
Replay error: Queued: Luna. Launch retry pending. [existing error details]
|
||||
Ambiguous: Queued launch needs recovery. [existing recovery surface]
|
||||
Dispatched: Queue region removed; ordinary Luna Starting/Running status.
|
||||
Dropped: Queue region removed; existing disposition/error remains visible.
|
||||
No deferral: No queue region. Ordinary task behavior.
|
||||
```
|
||||
|
||||
UI-01 through UI-03 cover requirement 003. Counts are timestamped observations,
|
||||
not an ordinal queue position. Pending questions and real failures remain visible.
|
||||
Desktop and phone share the view model, while phone uses stacked text. Status
|
||||
changes use accessible text; frequent population updates are not live announcements.
|
||||
|
||||
## Tests
|
||||
|
||||
The following are planned tests, not tests run during package creation. AC suffixes
|
||||
refer to `AC-TASKS-QUEUED-SESSION-OWNERSHIP-`.
|
||||
|
||||
| Work order | Test file and planned cases | Criteria |
|
||||
| --- | --- | --- |
|
||||
| 01 | `orchestrator/queued_session_inspection_test.go`: `TestQueuedSessionInspection` (parked/queued, free/full, explicit, unknown); `TestWorkflowParking` (no runtime, consumed tombstone, newer stamp, re-entry) | 001.1-6 |
|
||||
| 01 | `task/repository/sqlite/workflow_parking_test.go`: `TestWorkflowParking` (conditional writes and restart); backend service/turn and frontend recovery tests | 001.1, 001.4, 001.6; 003.7 |
|
||||
| 02 | `orchestrator/queued_session_ownership_test.go`: `TestQueuedSessionOwnership` (sibling boot/idle/failure, explicit sibling run); `TestQueuedEntryReplay` (exact-once, restart, deleted/terminal/moved, newer-record CAS races) | 002.1-6 |
|
||||
| 03 | `task/statussummary/projector_launch_queue_test.go`, `rebuild_launch_queue_test.go`; task service/DTO tests; `task-status-summary` handler and queue view-model tests | 003.1-5 |
|
||||
| 03 | Desktop/mobile rendered specs below | 001.1-3; 002.1-4; 003.1-7 |
|
||||
|
||||
Each work order must record behavioral RED before correction and all exact GREEN
|
||||
commands. Existing test scaffolds are not evidence of this defect until exercised.
|
||||
|
||||
## E2E tests
|
||||
|
||||
Create `apps/web/e2e/tests/workflow/queued-session-ownership.spec.ts` (`chromium`)
|
||||
and `mobile-queued-session-ownership.spec.ts` (`mobile-chrome`) with shared
|
||||
`queued-session-ownership-helpers.ts`. Extend the desktop file from Task 01
|
||||
through Task 03 rather than duplicating the same lifecycle fixture.
|
||||
|
||||
Use the isolated worker backend's `useEnv` for a ceiling of 1, with restoration
|
||||
in `finally`. Start and settle a source session, occupy capacity using a separate
|
||||
controllable mock task, then move through the topbar into a different profile's
|
||||
auto-start step. Assert Luna exists and is queued before inspection. Capture
|
||||
transport before opening the task, selecting Astra, reloading, and reconnecting.
|
||||
Prove no Astra boot/prompt/queued-message additions and unchanged primary ownership.
|
||||
Do not use helpers that click recovery or reload as part of an idle wait.
|
||||
|
||||
Release only the fixture's capacity holder. Observe Luna's one prompt delivery,
|
||||
queue removal, and untouched Astra. Add explicit Astra follow-up as a separate
|
||||
case; it must leave Luna's queue intact. Use real service/repository tests for
|
||||
deterministic restart and simultaneous CAS races. E2E restart supplements them
|
||||
by checking visible restoration without manually reconstructing queue state.
|
||||
|
||||
Phone tests enter through the task drawer, choose each session, inspect queue
|
||||
details, and observe automatic dispatch. Assert no document horizontal overflow,
|
||||
visible queue text at 393 px, long-name wrapping, and existing picker target
|
||||
geometry. A genuine empty prompt retains its warning in unit tests; queue waiting
|
||||
and passive navigation produce none in the rendered scenario.
|
||||
|
||||
## Work orders
|
||||
|
||||
- [in_progress] [Task 01: Preserve parked sessions during inspection](task-01-preserve-parked-sessions.md)
|
||||
- [in_progress] [Task 02: Preserve queued entry lifecycle](task-02-preserve-queued-entry.md)
|
||||
- [in_progress] [Task 03: Expose queue status across task surfaces](task-03-expose-queue-status.md)
|
||||
|
||||
Implementation is complete for all three sequential slices. The work orders
|
||||
remain in progress because the required PostgreSQL checks need
|
||||
`KANDEV_TEST_POSTGRES_DSN`, which is not configured in this workspace. No
|
||||
subagents are authorized by this plan.
|
||||
|
||||
## Related delivery records
|
||||
|
||||
[Workflow lifecycle](../workflow-profile-session-reuse/plan.md),
|
||||
[explicit targeting](../workflow-session-targeting/plan.md),
|
||||
[same-profile fresh sessions](../workflow-same-profile-new-session/plan.md), and
|
||||
[session ceiling](../session-concurrency-ceiling/plan.md) are compatibility inputs.
|
||||
Their results are historical and do not prove this intersection. This package
|
||||
owns the new cases; it does not reopen completed work or change lifecycle defaults.
|
||||
|
||||
## Documentation impact
|
||||
|
||||
During Task 03, update `docs/public/tasks-and-workflows.md` (explanation) and
|
||||
`docs/public/agents-and-profiles.md` only where they describe inspection/recovery.
|
||||
Explain the distinction between WIP waiting and session-capacity waiting.
|
||||
No public page is changed during this design turn. Preserve existing overview
|
||||
and configuration defaults. Check root README/screenshot references for affected wording.
|
||||
|
||||
## Verification results
|
||||
|
||||
Design-package validation on 2026-09-16:
|
||||
|
||||
- `python3 scripts/list-docs.py validate`: passed (282 decisions, 971 specifications).
|
||||
- `python3 scripts/lint-spec-files.test.py`: passed (36 tests).
|
||||
- `python3 scripts/lint-spec-files.py --all`: passed.
|
||||
- Catalog queries for `queued-session-ownership` and `passive-session-inspection`:
|
||||
discovered the new requirement, design, and decision.
|
||||
- Work-order reference check: all three files reference existing requirement/AC
|
||||
IDs and system-design paths, with pending status and verification sections.
|
||||
- `git diff --check`: passed.
|
||||
- `git status --short -- docs/plans/queued-session-ownership`: confirmed the new
|
||||
untracked package; files are ready for review and have not been committed.
|
||||
|
||||
Implementation and available rendered verification on 2026-09-17:
|
||||
|
||||
- Task 01 inspection and recovery coverage passed with
|
||||
`go test -race ./internal/orchestrator -run
|
||||
'TestQueuedSessionInspection|TestWorkflowParking|Test.*Resume|Test.*ProfileSwitch'
|
||||
-count=1`, the repository parking test, the focused frontend recovery tests,
|
||||
typecheck, the backend build, and the desktop queued-session scenario.
|
||||
- Task 02 queue lifecycle coverage passed with the race-focused orchestrator
|
||||
suite, SQLite deferred-entry and service suites, the created-session Send Now
|
||||
test, the desktop queued-session and workflow-targeting scenarios, and the
|
||||
stale-successor compare-and-set test.
|
||||
- Task 03 projection and UI coverage passed with statussummary/DTO/service
|
||||
tests, the race-focused launch-queue suite, 93 focused frontend tests,
|
||||
frontend typecheck and lint, the desktop and mobile scenarios, and the
|
||||
localized queue view-model/component tests.
|
||||
- `make -C apps/backend build` passed. `pnpm run i18n:check`,
|
||||
`pnpm run i18n:ratchet`, public-doc validation, specification validation,
|
||||
and `git diff --check` passed.
|
||||
- `cd apps/web && pnpm test` passed (2,140 files, 18,465 tests, 4 skipped).
|
||||
- `make -C apps/backend test` exercised all backend packages and passed the
|
||||
task-related packages, but the repository-wide command exits nonzero on
|
||||
unrelated environment-sensitive existing tests in process probing, home
|
||||
configuration discovery, launcher configuration/restart, and the Office
|
||||
priority migration fixture.
|
||||
- The scoped E2E sleep lint preview and sleep ratchet passed. The full
|
||||
`lint:e2e-sleeps` audit still reports the checkout's unrelated baseline
|
||||
violations, so it is not used as a clean repository gate.
|
||||
- The required PostgreSQL checks were not run because
|
||||
`KANDEV_TEST_POSTGRES_DSN` is unset. The PostgreSQL parking contract test is
|
||||
present and skips without that environment value. Until an isolated DSN is
|
||||
supplied, Tasks 01 through 03 remain in progress.
|
||||
|
||||
## Risks
|
||||
|
||||
- Callback tombstones outlive actual parking; using them alone blocks valid reuse.
|
||||
- A stale REVIEW writer or replay clear can overwrite a newer accepted entry.
|
||||
- Passive-source omission in a fallback can still give opening manual privileges.
|
||||
- Projection refreshes can accidentally count as user activity and reorder tasks.
|
||||
- Legacy ambiguous ownership must surface recovery without dispatch or data loss.
|
||||
- The unexplained warning must not cause blanket suppression of genuine empty turns.
|
||||
@@ -0,0 +1,145 @@
|
||||
---
|
||||
id: "01-preserve-parked-sessions"
|
||||
title: "Preserve parked sessions during inspection"
|
||||
status: in_progress
|
||||
wave: 1
|
||||
depends_on: []
|
||||
plan: "plan.md"
|
||||
requirements:
|
||||
- REQ-TASKS-QUEUED-SESSION-OWNERSHIP-001
|
||||
- REQ-TASKS-QUEUED-SESSION-OWNERSHIP-003
|
||||
acceptance_criteria:
|
||||
- AC-TASKS-QUEUED-SESSION-OWNERSHIP-001.1
|
||||
- AC-TASKS-QUEUED-SESSION-OWNERSHIP-001.2
|
||||
- AC-TASKS-QUEUED-SESSION-OWNERSHIP-001.3
|
||||
- AC-TASKS-QUEUED-SESSION-OWNERSHIP-001.4
|
||||
- AC-TASKS-QUEUED-SESSION-OWNERSHIP-001.5
|
||||
- AC-TASKS-QUEUED-SESSION-OWNERSHIP-001.6
|
||||
- AC-TASKS-QUEUED-SESSION-OWNERSHIP-003.7
|
||||
system_design:
|
||||
- ../../specs/tasks/system-design/queued-session-ownership.md
|
||||
---
|
||||
|
||||
# Task 01: Preserve parked sessions during inspection
|
||||
|
||||
## Summary
|
||||
|
||||
Make workflow parking durable and keep passive inspection separate from explicit
|
||||
execution. Deliver the backend guard and browser caller changes together so
|
||||
opening the queued task cannot wake Astra or create another launch.
|
||||
|
||||
## In scope
|
||||
|
||||
- Implement the design's stamped `workflow_parking` metadata, no-runtime case,
|
||||
conservative legacy resolution, and conditional clear on legitimate activation.
|
||||
- Add inspection source and status eligibility; guard launch and ensure before
|
||||
side effects. Propagate no-execution outcomes through browser fallbacks.
|
||||
- Preserve actual manual overrides, direct conversation follow-ups, workflow
|
||||
re-entry, preference semantics for ordinary sessions, and existing permissions.
|
||||
- Add backend/repository RED tests, hook tests, and the first desktop lifecycle
|
||||
scenario in `queued-session-ownership.spec.ts` using the shared fixture.
|
||||
- Verify passive suppression creates no turn or empty-output warning. Keep the
|
||||
genuine empty-turn test; diagnose any failure rather than suppressing all notices.
|
||||
|
||||
## Out of scope
|
||||
|
||||
Queue UI markup belongs to Task 03. Task state/replay race repair belongs to
|
||||
Task 02. Do not change background-work parking, lifecycle defaults, or Office.
|
||||
|
||||
## Acceptance
|
||||
|
||||
1. The full/free capacity and preference on/off matrix leaves parked Astra
|
||||
untouched after open, tab selection, preview, reload, and reconnect, while
|
||||
preserving Luna's accepted payload and queue time.
|
||||
2. Explicit Astra execution targets Astra alone; valid workflow reuse succeeds.
|
||||
Old tombstones and no-runtime parking work across restart and stale-clear races.
|
||||
3. Status and request handlers both enforce the decision; ownership errors and
|
||||
queued responses never trigger fresh/resume fallback or manual-override notes.
|
||||
|
||||
## Verification
|
||||
|
||||
Run from the repository root. Bootstrap dependencies once if absent.
|
||||
|
||||
```bash
|
||||
(cd apps && pnpm install --frozen-lockfile)
|
||||
(cd apps/backend && go test -race ./internal/orchestrator -run 'TestQueuedSessionInspection|TestWorkflowParking|Test.*Resume|Test.*ProfileSwitch' -count=1)
|
||||
(cd apps/backend && go test ./internal/task/repository/sqlite -run 'TestWorkflowParking' -count=1)
|
||||
(cd apps/backend && test -n "$KANDEV_TEST_POSTGRES_DSN" && go test ./internal/task/repository/sqlite -run 'TestPostgresWorkflowParking' -count=1)
|
||||
(cd apps/backend && go test ./internal/task/service -run 'Test.*Turn|Test.*SessionMessage' -count=1)
|
||||
(cd apps/web && pnpm exec vitest run hooks/domains/session/use-session-resumption.test.ts hooks/domains/session/use-ensure-task-session.test.ts hooks/use-ensure-task-session.test.ts lib/services/session-launch-helpers.test.ts lib/ws/handlers/empty-turn-notice.test.ts)
|
||||
(cd apps/web && pnpm run typecheck)
|
||||
make -C apps/backend build
|
||||
(cd apps/web && pnpm e2e:run --project chromium tests/workflow/queued-session-ownership.spec.ts)
|
||||
git diff --check
|
||||
```
|
||||
|
||||
Add planned missing tests before their commands. PostgreSQL tests use
|
||||
`testutil.PostgresDSNFromEnv` and isolated schemas. Provision a disposable test
|
||||
database through the repository's existing test setup and set
|
||||
`KANDEV_TEST_POSTGRES_DSN` without printing it. The explicit environment guard
|
||||
prevents a skipped PostgreSQL test from counting as a pass. If unavailable,
|
||||
record the blocked database check and do not mark this work order done.
|
||||
Frontend behavior changes here do not change layout, so hook tests plus the
|
||||
desktop flow suffice for this slice; Task 03 owns the full mobile flow.
|
||||
|
||||
## Files likely touched
|
||||
|
||||
- `apps/backend/internal/task/models/models.go` and a focused parking model file.
|
||||
- `apps/backend/internal/task/repository/interface.go`, `sqlite/session.go`,
|
||||
`sqlite/session_workflow.go`, and new `workflow_parking_test.go`.
|
||||
- `apps/backend/internal/orchestrator/workflow_profile_session_lifecycle.go`.
|
||||
- `apps/backend/internal/orchestrator/session_launch.go`, `task_operations.go`,
|
||||
`ceiling_seam4.go`, `ceiling_replay.go`, and new `queued_session_inspection_test.go`.
|
||||
- `apps/backend/internal/orchestrator/dto/dto.go` (`TaskSessionStatusResponse`),
|
||||
`session_ensure.go`, and launch/ensure HTTP/WS mappings.
|
||||
- `apps/web/lib/services/session-launch-service.ts`, `session-launch-helpers.ts`.
|
||||
- `apps/web/hooks/domains/session/use-session-resumption.ts`,
|
||||
`use-session-resumption-operations.ts`, and both
|
||||
`hooks/use-ensure-task-session.ts` and `hooks/domains/session/use-ensure-task-session.ts`.
|
||||
- Their test files and the workflow E2E file/helper named above.
|
||||
|
||||
## Dependencies
|
||||
|
||||
None. Read the existing profile-switch, resume, launch, and empty-turn tests first.
|
||||
|
||||
## Risks
|
||||
|
||||
Stop-intent presence is not current parking. A queued or suppressed launch
|
||||
response must not be interpreted as a successful running session. A status read
|
||||
must not clear markers or promote the selected tab.
|
||||
|
||||
## Parallelism
|
||||
|
||||
`sequential`
|
||||
|
||||
## Inputs
|
||||
|
||||
[Design: inspection intent and durable workflow parking](../../specs/tasks/system-design/queued-session-ownership.md#inspection-intent).
|
||||
Use `event_handlers_workflow_profile_session_policy_test.go` and existing
|
||||
`use-session-resumption.test.ts` fixtures. Read the [plan's E2E contract](plan.md#e2e-tests).
|
||||
|
||||
## Results
|
||||
|
||||
Implementation is present. The durable stamped parking marker, passive launch
|
||||
source, status eligibility guard, and browser recovery propagation are covered
|
||||
by the existing orchestrator/model tests and the new repository parking test.
|
||||
The desktop workflow scenario confirms that inspecting the queued task and its
|
||||
parked source does not start, prompt, or queue activity for the source session.
|
||||
|
||||
Passing checks:
|
||||
|
||||
- `go test -race ./internal/orchestrator -run
|
||||
'TestQueuedSessionInspection|TestWorkflowParking|Test.*Resume|Test.*ProfileSwitch'
|
||||
-count=1`
|
||||
- `go test ./internal/task/repository/sqlite -run 'TestWorkflowParking' -count=1`
|
||||
- The focused frontend recovery, ensure, launch-helper, and empty-turn tests
|
||||
passed (7 files, 97 tests).
|
||||
- `pnpm run typecheck`
|
||||
- `make -C apps/backend build`
|
||||
- `pnpm e2e:run --project chromium
|
||||
tests/workflow/queued-session-ownership.spec.ts`
|
||||
- `git diff --check`
|
||||
|
||||
The PostgreSQL counterpart `TestPostgresWorkflowParking` is implemented, but
|
||||
the required command is blocked because `KANDEV_TEST_POSTGRES_DSN` is unset.
|
||||
The work order therefore remains in progress until that database check runs.
|
||||
@@ -0,0 +1,136 @@
|
||||
---
|
||||
id: "02-preserve-queued-entry"
|
||||
title: "Preserve queued entry lifecycle"
|
||||
status: in_progress
|
||||
wave: 2
|
||||
depends_on:
|
||||
- "01-preserve-parked-sessions"
|
||||
plan: "plan.md"
|
||||
requirements:
|
||||
- REQ-TASKS-QUEUED-SESSION-OWNERSHIP-002
|
||||
acceptance_criteria:
|
||||
- AC-TASKS-QUEUED-SESSION-OWNERSHIP-002.1
|
||||
- AC-TASKS-QUEUED-SESSION-OWNERSHIP-002.2
|
||||
- AC-TASKS-QUEUED-SESSION-OWNERSHIP-002.3
|
||||
- AC-TASKS-QUEUED-SESSION-OWNERSHIP-002.4
|
||||
- AC-TASKS-QUEUED-SESSION-OWNERSHIP-002.5
|
||||
- AC-TASKS-QUEUED-SESSION-OWNERSHIP-002.6
|
||||
system_design:
|
||||
- ../../specs/tasks/system-design/queued-session-ownership.md
|
||||
---
|
||||
|
||||
# Task 02: Preserve queued entry lifecycle
|
||||
|
||||
## Summary
|
||||
|
||||
Make task state and replay respect the exact queued workflow entry. A sibling
|
||||
ready event must not hide Luna's queue, and a stale replay must not affect a
|
||||
newer entry.
|
||||
|
||||
## In scope
|
||||
|
||||
- Bind workflow deferrals to the committed route/step/session identity.
|
||||
- Guard review-state reconciliation with working-session and valid-deferral
|
||||
predicates, including restoration from legacy REVIEW plus accepted deferral.
|
||||
- Serialize enqueue/state writes and observed-record dispatch/clear against
|
||||
successor records. Preserve prompt, turn, and session identity across retries.
|
||||
- Dispose obsolete/deleted/terminal destinations without retargeting; preserve
|
||||
records on transient failures. Keep archive/cancel and Office precedence.
|
||||
- Extend the desktop E2E flow to release capacity and verify Luna's one delivery.
|
||||
|
||||
## Out of scope
|
||||
|
||||
Queue rendering and summary schema belong to Task 03. No new scheduler, generic
|
||||
retry framework, WIP policy, global ordering, or profile-selection algorithm.
|
||||
|
||||
## Acceptance
|
||||
|
||||
1. `TestQueuedSessionOwnership` fails before the fix when a sibling boot-ready
|
||||
event turns SCHEDULING into REVIEW. Mixed CREATED+idle/failed/cancelled cases
|
||||
preserve Scheduling; explicit sibling running and settlement retain queue ownership.
|
||||
2. `TestQueuedEntryReplay` proves one destination delivery, restart recovery,
|
||||
old-record compatibility, invalidation on step change/deletion/cancellation,
|
||||
and transient-error retention without retargeting or duplicate prompts.
|
||||
3. Barrier-controlled races prove an old REVIEW write or replay clear cannot
|
||||
overwrite a new record. Stale callbacks cannot activate parked Astra.
|
||||
|
||||
## Verification
|
||||
|
||||
```bash
|
||||
(cd apps/backend && go test -race ./internal/orchestrator -run 'TestQueuedSessionOwnership|TestQueuedEntryReplay|Test.*Ceiling|Test.*ReviewState|Test.*BootReady' -count=1)
|
||||
(cd apps/backend && go test ./internal/task/repository/sqlite -run 'Test.*DeferredLaunch|Test.*QueuedEntry' -count=1)
|
||||
(cd apps/backend && test -n "$KANDEV_TEST_POSTGRES_DSN" && go test ./internal/task/repository/sqlite -run 'TestPostgresQueuedEntry' -count=1)
|
||||
(cd apps/backend && go test ./internal/task/service -run 'Test.*DeferredLaunch|Test.*Workflow' -count=1)
|
||||
make -C apps/backend build
|
||||
(cd apps/web && pnpm e2e:run --project chromium tests/workflow/queued-session-ownership.spec.ts tests/workflow/workflow-session-targeting.spec.ts)
|
||||
git diff --check
|
||||
```
|
||||
|
||||
Use a controllable runtime and real repository fixtures for RED and race cases.
|
||||
Do not substitute timing sleeps for an ordered conflicting operation. Record
|
||||
actual database coverage. `TestPostgresQueuedEntry` is a planned isolated-schema
|
||||
test using `KANDEV_TEST_POSTGRES_DSN` from Task 01. A missing database blocks this
|
||||
check; a skipped test is not verification. Keep the work order pending until its
|
||||
required database checks pass.
|
||||
|
||||
## Files likely touched
|
||||
|
||||
- `apps/backend/internal/orchestrator/event_handlers_streaming.go`,
|
||||
`event_handlers_agent.go`, `event_handlers_workflow.go`.
|
||||
- `apps/backend/internal/orchestrator/ceiling_defer.go`, `ceiling_replay.go`,
|
||||
`ceiling_seam2.go`, `ceiling_seam3.go`, and workflow route integration.
|
||||
- `apps/backend/internal/task/models/ceiling_launch.go` and route model helpers.
|
||||
- `apps/backend/internal/task/repository/interface.go`,
|
||||
`sqlite/deferred_launch_cas.go`, `sqlite/task.go`, and corresponding tests.
|
||||
- New `apps/backend/internal/orchestrator/queued_session_ownership_test.go`.
|
||||
- Workflow E2E file/helper introduced in Task 01.
|
||||
|
||||
## Dependencies
|
||||
|
||||
Task 01 establishes parked policy and passive launch outcomes. Its inspection
|
||||
tests remain mandatory compatibility evidence.
|
||||
|
||||
## Risks
|
||||
|
||||
Task-state serialization alone does not protect against an independently written
|
||||
deferred record. Guard identity at the persistence boundary. Validity checks
|
||||
must distinguish source read errors from proven obsolete work.
|
||||
|
||||
## Parallelism
|
||||
|
||||
`sequential`
|
||||
|
||||
## Inputs
|
||||
|
||||
[Design: deferred entry ownership and task reconciliation](../../specs/tasks/system-design/queued-session-ownership.md#deferred-entry-ownership).
|
||||
Read existing `ceiling_replay_test.go`, `ceiling_defer_test.go`,
|
||||
`event_handlers_workflow_deferred_launch_race_test.go`, and deferred CAS tests.
|
||||
|
||||
## Results
|
||||
|
||||
Implementation is present. Deferred entries retain the exact workflow route,
|
||||
step, destination session, prompt, and queue time. Review-state reconciliation,
|
||||
replay clearing, and Send Now admission use the destination identity and
|
||||
compare-and-set rules. A created destination now takes the explicit manual
|
||||
Send Now path, and a failed dispatch remains restorable by the queue worker.
|
||||
|
||||
Passing checks:
|
||||
|
||||
- `go test -race ./internal/orchestrator -run
|
||||
'TestQueuedSession|TestQueuedEntry|Test.*Ceiling.*Surface|Test.*LaunchQueue'
|
||||
-count=1`
|
||||
- `go test ./internal/task/repository/sqlite -run
|
||||
'Test.*DeferredLaunch|Test.*QueuedEntry' -count=1`
|
||||
- `go test ./internal/task/service -run
|
||||
'Test.*DeferredLaunch|Test.*Workflow' -count=1`
|
||||
- `go test ./internal/orchestrator -run
|
||||
'TestPromptSendNowClaimStartsCreatedSessionManually|TestPromptSendNowClaimSkipsOnTurnStartWhenAlreadyProcessed'
|
||||
-count=1`
|
||||
- `make -C apps/backend build`
|
||||
- `pnpm e2e:run --project chromium tests/workflow/queued-session-ownership.spec.ts
|
||||
tests/workflow/workflow-session-targeting.spec.ts` (6 tests passed)
|
||||
- `git diff --check`
|
||||
|
||||
The required PostgreSQL queued-entry check remains outstanding because
|
||||
`KANDEV_TEST_POSTGRES_DSN` is unset. The work order remains in progress until
|
||||
the isolated PostgreSQL verification runs.
|
||||
@@ -0,0 +1,201 @@
|
||||
---
|
||||
id: "03-expose-queue-status"
|
||||
title: "Expose queue status across task surfaces"
|
||||
status: in_progress
|
||||
wave: 3
|
||||
depends_on:
|
||||
- "02-preserve-queued-entry"
|
||||
plan: "plan.md"
|
||||
requirements:
|
||||
- REQ-TASKS-QUEUED-SESSION-OWNERSHIP-003
|
||||
acceptance_criteria:
|
||||
- AC-TASKS-QUEUED-SESSION-OWNERSHIP-003.1
|
||||
- AC-TASKS-QUEUED-SESSION-OWNERSHIP-003.2
|
||||
- AC-TASKS-QUEUED-SESSION-OWNERSHIP-003.3
|
||||
- AC-TASKS-QUEUED-SESSION-OWNERSHIP-003.4
|
||||
- AC-TASKS-QUEUED-SESSION-OWNERSHIP-003.5
|
||||
- AC-TASKS-QUEUED-SESSION-OWNERSHIP-003.6
|
||||
- AC-TASKS-QUEUED-SESSION-OWNERSHIP-003.7
|
||||
system_design:
|
||||
- ../../specs/tasks/system-design/queued-session-ownership.md
|
||||
---
|
||||
|
||||
# Task 03: Expose queue status across task surfaces
|
||||
|
||||
## Summary
|
||||
|
||||
Deliver the bounded queue summary and its desktop/phone presentation as one
|
||||
vertical slice. Users can inspect either conversation while seeing which
|
||||
session is queued, why it waits, and that retry is automatic.
|
||||
|
||||
## In scope
|
||||
|
||||
- `launch_queue` summary model, validation, source loading, rebuild, live
|
||||
publication, revision/invalidation, and explicit removal.
|
||||
- Capacity sampling and freshness without semantic task-activity churn.
|
||||
- Shared queue view model, sidebar label, task-level status region, selected
|
||||
session parking note, and suppression of duplicate queued-session launch prompts.
|
||||
- Full desktop/mobile lifecycle, reload, disconnect, unknown-capacity,
|
||||
long-name, prompt-warning, question/error coexistence, and dispatch coverage.
|
||||
- English, Portuguese, Simplified Chinese, and generated Traditional Chinese
|
||||
copy. Public workflow explanation and applicable source/API documentation.
|
||||
|
||||
## Out of scope
|
||||
|
||||
No global queue page, ETA, ordinal queue position, bypass control, new drawer,
|
||||
or modification of historical status messages. Do not count launches as queued prompts.
|
||||
|
||||
## Acceptance
|
||||
|
||||
1. Task list, boot, detail, and WS paths share the revisioned queue projection;
|
||||
stale updates cannot resurrect cleared work. Restart restores queued identity,
|
||||
missing capacity remains unknown, and refresh does not change activity ordering.
|
||||
2. UI-01 through UI-03 are realized with localized readable status, retained
|
||||
errors/questions, and independent task queue versus selected-session state.
|
||||
3. Desktop and phone tests prove passive inspection leaves Astra untouched and
|
||||
capacity release starts only Luna once, with queue status clearing automatically.
|
||||
|
||||
## ASCII UI preview
|
||||
|
||||
Excerpt of [the full plan previews](plan.md#ascii-ui-preview), requirement 003:
|
||||
|
||||
```text
|
||||
UI-01 Desktop
|
||||
Sidebar: [clock] Investigate issue Queued
|
||||
Detail: Queued: Luna. Waiting for session capacity
|
||||
5 of 5. Checked just now. Queued since 21:15
|
||||
Starts automatically when capacity is available.
|
||||
[Astra] [Luna: Queued] [Plan]
|
||||
Parked for workflow. Send a message to continue here.
|
||||
|
||||
UI-02 Phone
|
||||
Task drawer row: [clock] Investigate issue Queued
|
||||
Task detail:
|
||||
Queued: Luna
|
||||
Waiting for session capacity
|
||||
5 of 5. Checked just now. Queued since 21:15
|
||||
Starts automatically.
|
||||
[Astra v]
|
||||
Parked for workflow. Send a message to continue here.
|
||||
Conversation ...
|
||||
|
||||
UI-03 Shared outcomes
|
||||
Disconnected -> Queued, reconnecting, last checked time
|
||||
No count -> Capacity unavailable
|
||||
Replay error -> Retry pending plus existing error details
|
||||
Dispatched -> Queue region removed; normal Starting/Running
|
||||
```
|
||||
|
||||
Queue region is outside chat scroll, regardless of selected conversation. Use
|
||||
the existing mobile drawer/picker and dedicated layout, with one chat scroll
|
||||
owner and safe-area clearance. Names wrap in detail and truncate in navigation.
|
||||
No required hover disclosure. New action targets meet 44 px only on touch/mobile.
|
||||
These structural requirements are fixed; spacing and wording are illustrative.
|
||||
|
||||
## Verification
|
||||
|
||||
```bash
|
||||
(cd apps/backend && go test ./internal/task/statussummary ./internal/task/dto -count=1)
|
||||
(cd apps/backend && go test ./internal/task/service -run 'Test.*StatusSummary|Test.*LaunchQueue' -count=1)
|
||||
(cd apps/backend && go test -race ./internal/orchestrator -run 'TestQueuedSession|TestQueuedEntry|Test.*Ceiling.*Surface|Test.*LaunchQueue' -count=1)
|
||||
(cd apps/web && pnpm exec vitest run components/task/launch-queue-status.test.tsx lib/tasks/launch-queue-view-model.test.ts lib/ws/handlers/tasks-status-summary.test.ts hooks/domains/session/use-session-resumption.test.ts)
|
||||
(cd apps/web && pnpm run i18n:zh-hant && pnpm run i18n:check && pnpm run i18n:ratchet)
|
||||
(cd apps/web && pnpm run typecheck)
|
||||
make -C apps/backend build
|
||||
(cd apps/web && pnpm e2e:run --project chromium tests/workflow/queued-session-ownership.spec.ts tests/workflow/workflow-session-targeting.spec.ts)
|
||||
(cd apps/web && pnpm e2e:run --project mobile-chrome tests/workflow/mobile-queued-session-ownership.spec.ts)
|
||||
node --test scripts/validate-public-docs.test.mjs
|
||||
node scripts/validate-public-docs.mjs
|
||||
python3 scripts/list-docs.py validate
|
||||
python3 scripts/lint-spec-files.py --all
|
||||
git diff --check
|
||||
```
|
||||
|
||||
Create the named new component/view-model tests during RED. Run any additional
|
||||
modified test suite explicitly and record its command. The managed E2E runner
|
||||
builds fresh artifacts and owns cleanup; do not overlap desktop/mobile runs or
|
||||
use all-worker overrides. Compare rendered phone geometry and labels with UI-02.
|
||||
|
||||
## Files likely touched
|
||||
|
||||
- `apps/backend/internal/task/statussummary/{model,rebuild,projector,projector_events}.go`
|
||||
and new queue projection tests.
|
||||
- `apps/backend/internal/task/service/service_status_summary_rebuild.go`, task
|
||||
DTO enrichment, boot/list wiring, and the existing summary composition provider.
|
||||
- `apps/backend/internal/orchestrator/ceiling_defer.go`, `ceiling_replay.go`,
|
||||
`ceiling_sweep.go`, `ceiling_surface.go`, and tests.
|
||||
- `apps/web/lib/types/task-status-summary.ts`, `http.ts`, `backend.ts`.
|
||||
- `apps/web/lib/ws/handlers/task-status-summary.ts`, task hydration/merge paths.
|
||||
- `apps/web/lib/tasks/launch-queue-view-model.ts` (new) and tests.
|
||||
- `apps/web/components/task/launch-queue-status.tsx` (new), `task-item.tsx`,
|
||||
`task-switcher.tsx`, `task-chat-panel.tsx`, desktop task layout placement.
|
||||
- `apps/web/components/task/mobile/session-mobile-layout.tsx`,
|
||||
`session-task-switcher-sheet.tsx`, and session-picker presentation if needed.
|
||||
- `apps/web/src/locales/{en,pt-pt,zh-cn,zh-hk,zh-tw}` catalogs.
|
||||
- Workflow E2E specs/helper introduced by this package.
|
||||
- `docs/public/tasks-and-workflows.md`; inspect `agents-and-profiles.md` and
|
||||
`configuration.md` for related wording without changing startup defaults.
|
||||
|
||||
## Dependencies
|
||||
|
||||
Tasks 01 and 02 provide passive eligibility and authoritative queue lifecycle.
|
||||
|
||||
## Risks
|
||||
|
||||
Summary invalidation must carry clears, and old hydration must not resurrect
|
||||
queue state. Capacity sampling must not re-sort tasks or expose global session
|
||||
identities. A mobile status region must not cover the session picker or composer.
|
||||
|
||||
## Parallelism
|
||||
|
||||
`sequential`
|
||||
|
||||
## Inputs
|
||||
|
||||
[Design: queue projection and surfaces](../../specs/tasks/system-design/queued-session-ownership.md#queue-projection).
|
||||
Use existing queued-prompt summary tests as revision/rebuild examples without
|
||||
merging the two semantics. Read mobile parity, e2e, and docs-maintainer guidance.
|
||||
|
||||
## Results
|
||||
|
||||
Implementation is present. The revisioned `launch_queue` projection is loaded
|
||||
from durable task metadata, refreshed with capacity observations, and exposed
|
||||
through task list, sidebar, detail, desktop chat, and mobile navigation. The
|
||||
shared view model keeps queue status independent from the selected parked
|
||||
conversation, and the phone layout has one chat scroll owner.
|
||||
|
||||
Passing checks:
|
||||
|
||||
- `go test ./internal/task/statussummary ./internal/task/dto -count=1`
|
||||
- `go test ./internal/task/service -run
|
||||
'Test.*StatusSummary|Test.*LaunchQueue' -count=1`
|
||||
- `go test -race ./internal/orchestrator -run
|
||||
'TestQueuedSession|TestQueuedEntry|Test.*Ceiling.*Surface|Test.*LaunchQueue'
|
||||
-count=1`
|
||||
- Focused frontend tests for the queue component, view model, status-summary
|
||||
handler, and session recovery passed (93 tests).
|
||||
- `pnpm run typecheck`, `pnpm run lint`, `pnpm run i18n:zh-hant`,
|
||||
`pnpm run i18n:check`, and `pnpm run i18n:ratchet`
|
||||
- `pnpm test` passed (2,140 files, 18,465 tests, 4 skipped).
|
||||
- `make -C apps/backend build`
|
||||
- `pnpm e2e:run --project chromium tests/workflow/queued-session-ownership.spec.ts
|
||||
tests/workflow/workflow-session-targeting.spec.ts`
|
||||
- `pnpm e2e:run --project mobile-chrome
|
||||
tests/workflow/mobile-queued-session-ownership.spec.ts`
|
||||
- `node --test scripts/validate-public-docs.test.mjs`,
|
||||
`node scripts/validate-public-docs.mjs`, `python3 scripts/list-docs.py
|
||||
validate`, `python3 scripts/lint-spec-files.py --all`, and
|
||||
`git diff --check`
|
||||
|
||||
The rendered desktop and phone scenarios match the preview contract: queued
|
||||
destination and capacity are visible while the parked source is selected,
|
||||
queue status is present in task navigation and detail, names wrap on phone,
|
||||
and releasing the fixture capacity dispatches the destination once. The full
|
||||
E2E sleep lint audit retains unrelated baseline violations; the scoped preview
|
||||
and sleep ratchet pass.
|
||||
|
||||
The required PostgreSQL projection/rebuild coverage remains outstanding because
|
||||
`KANDEV_TEST_POSTGRES_DSN` is unset. The work order remains in progress until
|
||||
the isolated PostgreSQL verification runs. The repository-wide backend test
|
||||
target also reports unrelated existing environment-sensitive failures; the
|
||||
task-related backend packages pass.
|
||||
@@ -42,6 +42,10 @@ remain separate during repair.
|
||||
|
||||
## Risks
|
||||
|
||||
Follow-up: [queued session ownership](../queued-session-ownership/plan.md) adds
|
||||
passive-origin enforcement and task queue visibility. Existing manual override
|
||||
semantics and the completed work order remain unchanged.
|
||||
|
||||
- A repository read failure before a process callback is treated as not owned,
|
||||
so a reservation can wait for the sweep instead of being released by an
|
||||
ambiguous callback.
|
||||
|
||||
@@ -119,6 +119,12 @@ and save behavior.
|
||||
- [ ] [Task 03: Simplify the selector and add agent logos](task-03-expose-workflow-policy.md)
|
||||
- [ ] [Task 04: Prove all lifecycle combinations](task-04-prove-and-document-reuse-flows.md)
|
||||
|
||||
## Follow-up delivery
|
||||
|
||||
[Queued session ownership](../queued-session-ownership/plan.md) owns the later
|
||||
inspection/ceiling intersection and its regression matrix. This historical
|
||||
package does not establish that opening a parked predecessor is safe.
|
||||
|
||||
## Risks
|
||||
|
||||
- A transition path can use the destination end setting by mistake.
|
||||
|
||||
@@ -111,6 +111,10 @@ the shared backend policy rather than phone interaction.
|
||||
|
||||
## Related delivery records
|
||||
|
||||
[Queued session ownership](../queued-session-ownership/plan.md) adds the
|
||||
parked-predecessor and deferred-destination intersection. This completed repair
|
||||
retains its original scope and results.
|
||||
|
||||
[Workflow session targeting](../workflow-session-targeting/plan.md) delivered
|
||||
explicit initial and source-step recipients. Its completed results remain
|
||||
historical evidence, not proof of this profile-only case. This package owns
|
||||
|
||||
@@ -13,6 +13,10 @@ legacy_specs: []
|
||||
|
||||
## Overview
|
||||
|
||||
Follow-up: [queued session ownership](../queued-session-ownership/plan.md) covers
|
||||
inspection and admission after recipient selection. Its new cases do not reopen
|
||||
this package's delivered routing work or reuse its test results as queue evidence.
|
||||
|
||||
Allow Review to return to the task's initial agent or an earlier step's
|
||||
conversation. Keep **When this step starts** and **When this step ends** as
|
||||
independent controls. Keep lifecycle navigation visible above the recipient list.
|
||||
|
||||
@@ -247,6 +247,11 @@ exclusive health probe before it becomes eligible again. This shared error
|
||||
classification is used by task/Kanban and Office routing, while the per-
|
||||
candidate policies are configured on dynamic profiles.
|
||||
|
||||
When a task launch waits for session capacity, Kandev keeps the selected
|
||||
destination and retries it automatically. Inspecting another session does not
|
||||
resume a parked predecessor. Use an explicit **Resume** action or send a
|
||||
message for manual recovery. These actions can override the automatic ceiling.
|
||||
|
||||
Provider errors that occur before a result can use the configured action, such
|
||||
as retrying the current candidate or trying the next candidate. A started turn
|
||||
with an ambiguous result does not switch providers automatically. If no
|
||||
|
||||
@@ -601,6 +601,18 @@ destination queue. If the configured
|
||||
feeder is also full, creation returns a conflict. Ephemeral tasks are not
|
||||
counted.
|
||||
|
||||
A task can also show **Queued** after workflow entry selects a session but the
|
||||
agent session ceiling blocks automatic launch. This is different from WIP
|
||||
queueing: WIP waits before destination entry, while session-capacity queueing
|
||||
keeps the selected session and retries it automatically. Task details and the
|
||||
task navigator show the destination, the latest capacity observation, queue
|
||||
time, and retry state. They do not show a queue position or estimated start
|
||||
time. Capacity counts older than 40 seconds, or counts unavailable because the
|
||||
client is disconnected, are labelled stale while the destination remains
|
||||
visible. Opening a task or a parked predecessor does not start it. Use the
|
||||
explicit **Start** or **Resume** action, or send a message, to override the
|
||||
automatic ceiling for that conversation.
|
||||
|
||||
Integration watchers use the same admission rule. For example, a GitHub review
|
||||
watch targeting a `Review` step with a limit of two admits at most two newly
|
||||
observed pull requests at a time. Pull requests that lose the capacity race
|
||||
|
||||
@@ -63,6 +63,11 @@ origins never become manual during replay. The sweep clears a record only after
|
||||
successful dispatch. A repeated refusal leaves the original timestamp and
|
||||
payload in place.
|
||||
|
||||
The task-owned [queued session ownership design](../../tasks/system-design/queued-session-ownership.md)
|
||||
plans explicit passive-inspection classification at the caller boundary. Opening
|
||||
a conversation is not a manual override. Actual explicit execution retains this
|
||||
design's manual admission rule; workflow parking eligibility remains task-owned.
|
||||
|
||||
## Failure and recovery
|
||||
|
||||
Reservation ownership is session-keyed. A stale process-start callback first
|
||||
|
||||
@@ -12,6 +12,14 @@ owners:
|
||||
|
||||
This document is the migrated task-system source for the capability. The source detail below remains authoritative while the system is migrated into separate requirement and design records.
|
||||
|
||||
### Queued session ownership restriction
|
||||
|
||||
[Queued session ownership](queued-session-ownership.md) defines the restriction on
|
||||
open-time recovery: workflow-parked sessions and an accepted queued destination
|
||||
remain protected with either preference value. The default-off behavior below
|
||||
continues for otherwise eligible sessions. Explicit user execution and legitimate
|
||||
workflow re-entry retain their own activation paths.
|
||||
|
||||
## Requirements
|
||||
|
||||
### REQ-TASKS-PREVENT-AGENT-AUTOSTART-ON-OPEN-001: Prevent Agent Auto-Start On Open
|
||||
@@ -221,4 +229,4 @@ per-task variant in this feature.
|
||||
|
||||
- Whether the option should also gate the office advanced mode's
|
||||
`ensureExecution` resume once that WS field is actually wired. Currently a
|
||||
no-op; intentionally out of scope until the office flow auto-starts.
|
||||
no-op; intentionally out of scope until the office flow auto-starts.
|
||||
|
||||
@@ -0,0 +1,135 @@
|
||||
---
|
||||
status: draft
|
||||
system: tasks
|
||||
created: 2026-09-16
|
||||
owners:
|
||||
- kandev
|
||||
---
|
||||
|
||||
# Queued session ownership requirements
|
||||
|
||||
## Overview
|
||||
|
||||
A workflow can select its next session before instance capacity permits launch.
|
||||
Users must be able to inspect that task without waking a parked predecessor or
|
||||
losing the visible queued state. The task system owns the selected recipient,
|
||||
durable launch intent, and its presentation across task surfaces.
|
||||
|
||||
This capability extends [workflow session lifecycle](workflow-profile-session-lifecycle.md).
|
||||
The [agent ceiling](../../agents/requirements/session-concurrency-ceiling.md)
|
||||
continues to own capacity admission. A ceiling queue is distinct from a
|
||||
[workflow WIP queue](wip-limit-pull-system.md): WIP admission occurs before
|
||||
destination entry, whereas a ceiling can delay a session already selected by entry.
|
||||
|
||||
## Terminology
|
||||
|
||||
- **Passive inspection:** Opening, focusing, reloading, reconnecting, previewing,
|
||||
or selecting a conversation without requesting execution.
|
||||
- **Parked predecessor:** A conversation stopped by a workflow session switch.
|
||||
It remains available for reading, explicit follow-up, or later workflow reuse.
|
||||
- **Queued destination:** The exact session selected for a deferred workflow launch.
|
||||
- **Explicit execution:** A user selects Start/Resume or sends a message to an
|
||||
identified conversation. A valid workflow re-entry is a separate authorized trigger.
|
||||
|
||||
## Requirements
|
||||
|
||||
### REQ-TASKS-QUEUED-SESSION-OWNERSHIP-001: Inspection preserves execution ownership
|
||||
|
||||
**Intent:** Reading a task must not wake its retired workflow participant.
|
||||
|
||||
#### Acceptance criteria
|
||||
|
||||
- **AC-TASKS-QUEUED-SESSION-OWNERSHIP-001.1:** Passive inspection shall not
|
||||
start, resume, prompt, or enqueue work for a parked predecessor. This applies
|
||||
with free or full capacity and with either auto-start-on-open preference value.
|
||||
- **AC-TASKS-QUEUED-SESSION-OWNERSHIP-001.2:** When a destination is queued,
|
||||
passive inspection of any conversation shall preserve its recipient, prompt,
|
||||
queue time, primary ownership, and workflow step. It shall not create another launch.
|
||||
- **AC-TASKS-QUEUED-SESSION-OWNERSHIP-001.3:** Explicit execution for a parked
|
||||
predecessor shall target that conversation only. It shall not replace the
|
||||
queued destination, consume its prompt, or acquire its workflow ownership.
|
||||
- **AC-TASKS-QUEUED-SESSION-OWNERSHIP-001.4:** A later workflow entry that
|
||||
legitimately selects a parked conversation shall be able to reuse it under
|
||||
the existing lifecycle policy. Historical parking shall not permanently block reuse.
|
||||
- **AC-TASKS-QUEUED-SESSION-OWNERSHIP-001.5:** Passive recovery that remains
|
||||
eligible under existing preferences shall respect the automatic session
|
||||
ceiling. It shall never produce a manual-override audit message.
|
||||
- **AC-TASKS-QUEUED-SESSION-OWNERSHIP-001.6:** If current ownership cannot be
|
||||
established, passive inspection shall remain available without starting work
|
||||
or attempting a fresh-session fallback. Explicit recovery shall remain separately available.
|
||||
|
||||
### REQ-TASKS-QUEUED-SESSION-OWNERSHIP-002: Deferred work survives sibling lifecycle events
|
||||
|
||||
**Intent:** A queued launch must remain owned and retryable until its own outcome is known.
|
||||
|
||||
#### Acceptance criteria
|
||||
|
||||
- **AC-TASKS-QUEUED-SESSION-OWNERSHIP-002.1:** While an eligible queued
|
||||
destination exists and no session is executing work, the task shall remain
|
||||
Scheduling. A sibling becoming ready, idle, stopped, failed, or completed
|
||||
shall not move that task to Review or clear its queue.
|
||||
- **AC-TASKS-QUEUED-SESSION-OWNERSHIP-002.2:** If a sibling explicitly runs
|
||||
while the destination is queued, task activity shall reflect the running work
|
||||
and retain the queue indicator. When that sibling settles, the task shall
|
||||
return to Scheduling while the destination remains queued.
|
||||
- **AC-TASKS-QUEUED-SESSION-OWNERSHIP-002.3:** When capacity becomes available,
|
||||
automatic retry shall deliver the accepted launch to its exact eligible
|
||||
destination once. It shall not wake or send the step prompt to the predecessor.
|
||||
- **AC-TASKS-QUEUED-SESSION-OWNERSHIP-002.4:** Reload and backend restart shall
|
||||
preserve queued ownership and parked inspection behavior. Repeated refusal
|
||||
shall not reset queue time, replace the accepted prompt, or duplicate sessions.
|
||||
- **AC-TASKS-QUEUED-SESSION-OWNERSHIP-002.5:** If the destination is removed,
|
||||
cancelled, or superseded by a later workflow entry, its obsolete launch shall
|
||||
not run or retarget another session. The task shall expose the disposition.
|
||||
A transient read or replay error shall preserve accepted work for retry.
|
||||
- **AC-TASKS-QUEUED-SESSION-OWNERSHIP-002.6:** A stale replay or lifecycle event
|
||||
shall not clear, launch, or reconcile state for a newer queued entry. Explicit
|
||||
task cancellation and archive shall retain their existing precedence.
|
||||
|
||||
### REQ-TASKS-QUEUED-SESSION-OWNERSHIP-003: Visible launch queue
|
||||
|
||||
**Intent:** Users can distinguish waiting for capacity from a stopped or failed agent.
|
||||
|
||||
#### Acceptance criteria
|
||||
|
||||
- **AC-TASKS-QUEUED-SESSION-OWNERSHIP-003.1:** Desktop sidebar rows and the
|
||||
phone task navigator shall expose a labelled Queued indicator for deferred
|
||||
session launches, without requiring the queued conversation to be selected.
|
||||
- **AC-TASKS-QUEUED-SESSION-OWNERSHIP-003.2:** Task details shall show the
|
||||
queued destination, waiting reason, queue time, capacity observation, and
|
||||
automatic retry explanation outside the historical transcript. This status
|
||||
shall remain visible when the user selects a parked predecessor.
|
||||
- **AC-TASKS-QUEUED-SESSION-OWNERSHIP-003.3:** A parked conversation shall be
|
||||
identified as parked for the workflow. A queued destination shall not offer
|
||||
a misleading recovery prompt or imply that the user must restart it.
|
||||
- **AC-TASKS-QUEUED-SESSION-OWNERSHIP-003.4:** Queue status shall clear after
|
||||
confirmed dispatch or final disposition. Older snapshots shall not restore a
|
||||
cleared queue or erase newer queued work. Pending questions and real errors
|
||||
shall remain visible alongside queue status.
|
||||
- **AC-TASKS-QUEUED-SESSION-OWNERSHIP-003.5:** Capacity observations shall show
|
||||
when they were checked. When unavailable or disconnected, the interface
|
||||
shall retain known queued ownership and identify stale or unavailable counts.
|
||||
It shall not claim a queue position or an estimated start time.
|
||||
- **AC-TASKS-QUEUED-SESSION-OWNERSHIP-003.6:** Phone users shall inspect the
|
||||
same status and navigate conversations through the existing task drawer and
|
||||
session picker. Required information shall not depend on hover. New touch
|
||||
actions shall have at least 44 px hit targets, with no page horizontal overflow.
|
||||
- **AC-TASKS-QUEUED-SESSION-OWNERSHIP-003.7:** Passive inspection and ordinary
|
||||
queue waiting shall not generate an empty-output completion warning. A real
|
||||
prompt that completes without output shall retain its existing warning behavior.
|
||||
|
||||
## Compatibility and exclusions
|
||||
|
||||
Actual manual starts and resumes retain the existing ceiling override. This
|
||||
package does not turn the ceiling into a hard limit for explicit execution.
|
||||
Ordinary open-time recovery remains preference-controlled, subject to the
|
||||
ownership and automatic-admission conditions above.
|
||||
|
||||
No new session-state enum, global queue dashboard, queue reordering, ETA,
|
||||
capacity setting, workflow lifecycle setting, or provider-routing policy is added.
|
||||
Office scheduling, WIP admission order, terminal conversation recovery, and
|
||||
unrelated prompt queues retain their owning contracts.
|
||||
|
||||
## Design
|
||||
|
||||
- [Queued session ownership](../system-design/queued-session-ownership.md)
|
||||
@@ -34,6 +34,10 @@ fresh conversation for independent work.
|
||||
- **Profile re-entry:** A profile switch to an agent profile that already has a
|
||||
session on the task.
|
||||
|
||||
Inspection of parked sessions and deferred destination launches is specified in
|
||||
[queued session ownership](queued-session-ownership.md). Selecting a conversation
|
||||
for reading is not a workflow re-entry or an explicit request to execute it.
|
||||
|
||||
## Requirements
|
||||
|
||||
### REQ-TASKS-WORKFLOW-PROFILE-SESSIONS-001: Configurable step profile-session lifecycle
|
||||
|
||||
@@ -0,0 +1,240 @@
|
||||
---
|
||||
status: draft
|
||||
system: tasks
|
||||
requirements:
|
||||
- REQ-TASKS-QUEUED-SESSION-OWNERSHIP-001
|
||||
- REQ-TASKS-QUEUED-SESSION-OWNERSHIP-002
|
||||
- REQ-TASKS-QUEUED-SESSION-OWNERSHIP-003
|
||||
---
|
||||
|
||||
# Queued session ownership system design
|
||||
|
||||
## Purpose and boundaries
|
||||
|
||||
This design extends [workflow session lifecycle](workflow-profile-session-lifecycle.md)
|
||||
at the boundary between an accepted recipient, launch admission, and inspection.
|
||||
It uses the existing [agent ceiling](../../agents/system-design/session-concurrency-ceiling.md)
|
||||
and task-owned deferred record. It does not replace either queue or change WIP admission.
|
||||
|
||||
## Requirement mapping
|
||||
|
||||
| Requirement | Sections |
|
||||
| --- | --- |
|
||||
| REQ-TASKS-QUEUED-SESSION-OWNERSHIP-001 | Inspection intent; Durable workflow parking |
|
||||
| REQ-TASKS-QUEUED-SESSION-OWNERSHIP-002 | Deferred entry ownership; Task reconciliation |
|
||||
| REQ-TASKS-QUEUED-SESSION-OWNERSHIP-003 | Queue projection; Desktop and mobile surfaces; Failure and observability |
|
||||
|
||||
## Existing components
|
||||
|
||||
- `workflow_profile_session_lifecycle.go` parks a source and records an
|
||||
execution-stamped stop intent. That record has a durable consumed tombstone.
|
||||
- `session_launch.go:launchResume` classifies origin from `AutoStart`.
|
||||
`buildResumeRequest` currently omits that field for both explicit and open-time recovery.
|
||||
- `GetTaskSessionStatus` reports runtime resumability. The browser's
|
||||
`use-session-resumption.ts` drives recovery after a status read.
|
||||
- `handleAgentBootReady` calls `setSessionWaitingForInput`, which calls
|
||||
`writeTaskReviewState`. The current sibling guard recognizes working sessions,
|
||||
but not an eligible CREATED destination whose launch is deferred.
|
||||
- `ceiling_replay.go` replays by stored launch kind every 20 seconds and on
|
||||
release. `ceiling_surface.go` writes historical status messages.
|
||||
- `task/statussummary` persists a revisioned, bounded summary used by task
|
||||
list and detail consumers. Extend it rather than inventing a frontend queue.
|
||||
|
||||
## Inspection intent
|
||||
|
||||
Add optional `activation_source: "user_action" | "session_open"` to the unified
|
||||
launch request. Omission preserves existing explicit-call behavior. Reject
|
||||
unknown values. `session_open` cannot carry a prompt or grant recovery permission.
|
||||
The backend forces automatic admission for this source even if `auto_start`
|
||||
was omitted or false. Internal workflow and peer-message paths retain their
|
||||
existing explicit origins; do not mark all automatic work as passive inspection.
|
||||
|
||||
Add `auto_resume_allowed` and `auto_resume_blocked_reason` to session status.
|
||||
Reasons are closed values: `workflow_parked`, `launch_queued`, or
|
||||
`ownership_unavailable`; absence means no new ownership restriction. Keep
|
||||
`is_resumable` for explicit recovery. Populate this through one orchestrator
|
||||
eligibility helper shared by status, launch, and open-time ensure paths.
|
||||
|
||||
The browser consults these fields before `markSessionStarting`. Every passive
|
||||
resume sends `session_open`; explicit Resume and Send remain user actions.
|
||||
Inspect `useEnsureTaskSession` and `session.ensure` as well as tab recovery.
|
||||
An ensure for a task with an accepted queued destination returns that destination
|
||||
without launching, allocating another session, or switching to the visible tab.
|
||||
|
||||
Recheck under the existing session/entry lifecycle guards before reservation,
|
||||
turn creation, runtime launch, prompt creation, or fresh fallback. Return a
|
||||
successful no-execution disposition, proposed `activation_disposition:
|
||||
"suppressed" | "queued"`, with the reason and current session. Teach
|
||||
`session-launch-service.ts` and recovery operations to accept this as waiting,
|
||||
not launch success or an error that triggers workspace/fresh fallback.
|
||||
Transport errors stay errors. Preserve request-generation guards on late responses.
|
||||
|
||||
For an ordinary recoverable session without parking or pending work, retain the
|
||||
preference behavior and use automatic ceiling admission. If it is deferred,
|
||||
retain inspection source in its replay payload and revalidate eligibility on retry.
|
||||
If a task already has a different accepted launch, inspection cannot replace it
|
||||
or add a conflicting resume record. It returns the existing queued disposition.
|
||||
|
||||
## Durable workflow parking
|
||||
|
||||
Add a typed `workflow_parking` session metadata value with `stamp`,
|
||||
`parked_at`, and source entry identity where available. Record it even when no
|
||||
runtime execution exists. This is current policy, not evidence of background work.
|
||||
Do not reuse `parked_on_background_work` or clear the stop-intent tombstone.
|
||||
|
||||
Write parking with the parked session transition under the existing lifecycle
|
||||
guard and a conditional repository operation. A failed transition must not leave
|
||||
an unowned parking marker. Clear only the matching stamp when explicit execution
|
||||
is accepted or a workflow entry commits that session as recipient. No mark is
|
||||
cleared on a status read, focus, denied admission, or transient launch failure.
|
||||
Coordinate clear with the launch claim so failed attempts leave the conversation
|
||||
protected from subsequent passive recovery. A later park supersedes an older clear.
|
||||
|
||||
Existing parked tasks may lack this marker. During status/launch eligibility,
|
||||
recognize an execution-stamped workflow stop intent (including consumed state)
|
||||
only with non-primary source identity and no newer authorized activation/route.
|
||||
Inspect durable session execution timestamps and the committed workflow route;
|
||||
do not equate any WAITING_FOR_INPUT session with parking. If legacy evidence is
|
||||
ambiguous, deny passive execution with `ownership_unavailable`. Reading remains
|
||||
possible, and explicit recovery or an authoritative workflow selection resolves
|
||||
the ambiguity. Never fabricate queue work for an uncertain predecessor.
|
||||
|
||||
Keep metadata parsing in task models and conditional writes in the task
|
||||
repository, with SQLite/PostgreSQL conformance coverage. No new state enum or
|
||||
database column is required. Tests must include parking without a runtime,
|
||||
consumed tombstones, later reuse, explicit follow-up, restart, and stale clears.
|
||||
|
||||
## Deferred entry ownership
|
||||
|
||||
Extend workflow-origin deferred payloads with a nested entry binding containing
|
||||
workflow ID, destination step ID, committed route operation ID, and destination
|
||||
session ID. Obtain these from the existing `workflow_session_route` contract,
|
||||
not asynchronous history. Preserve the first payload and enqueue time across refusals.
|
||||
Generic start/resume records outside workflow entry keep their own eligibility rules.
|
||||
|
||||
Before replay, validate task membership, current entry identity, recipient,
|
||||
session state, and archive/cancellation status. A superseded, deleted, or terminal
|
||||
destination receives a final disposition without retargeting. Read failures
|
||||
retain the record. Old records without the binding are replayable only when the
|
||||
current committed route and exact session unambiguously agree; enrich them by CAS.
|
||||
Ambiguous records remain visible as requiring recovery, without dispatch.
|
||||
|
||||
Carry the observed record identity through dispatch and clear. A successful
|
||||
dispatch may clear only that record; it must not re-read and strip a successor's
|
||||
ceiling keys. Route changes, archive/cancel, and replay claims serialize using
|
||||
existing task-entry and lifecycle ownership. Never hold a DB transaction while
|
||||
calling the runtime. Add conditional repository operations where the existing
|
||||
read-then-write sequence cannot prove atomic ownership.
|
||||
|
||||
Recheck the claimed route before prompt admission. Preserve the stored turn and
|
||||
prompt ownership on retry; a second sweep must not create a second step message.
|
||||
An already-dispatched exact execution is acknowledged through existing correlated
|
||||
launch identity. No new scheduler, fan-out queue, or launch lease system is added.
|
||||
|
||||
## Task reconciliation
|
||||
|
||||
Within `writeTaskReviewState`, use the same task-runtime serialization as running
|
||||
state reconciliation. Reconcile eligible non-Office, non-archived tasks as follows:
|
||||
|
||||
1. Any authorized working session preserves normal IN_PROGRESS behavior.
|
||||
2. Otherwise, any valid deferred destination preserves or restores SCHEDULING.
|
||||
3. Only with neither condition may ordinary completion reconcile to REVIEW.
|
||||
|
||||
The second predicate is existential: a CREATED queued destination protects the
|
||||
task even when a sibling is idle, failed, cancelled, or completed. An arbitrary
|
||||
CREATED row with no accepted launch is not sufficient. Read errors fail closed.
|
||||
Guard the write against the observed queue/route identity so a concurrent enqueue
|
||||
cannot lose to an older REVIEW writer. Preserve explicit terminal task actions.
|
||||
|
||||
When a user explicitly runs the parked sibling, retain queue status alongside
|
||||
IN_PROGRESS; settling that sibling restores SCHEDULING. Do not promote it to
|
||||
primary or run destination entry actions. Keep existing completion-follow-up,
|
||||
Office, cancellation, and runtime-publication ordering protections.
|
||||
|
||||
The sweep also repairs legacy REVIEW+valid-deferral tasks to SCHEDULING when no
|
||||
session is working. This repair requires authoritative task and entry evidence;
|
||||
the browser never writes task state based on a badge.
|
||||
|
||||
## Queue projection
|
||||
|
||||
Add optional `launch_queue` to `TaskStatusSummary` and its frontend type. It is
|
||||
a complete replacement value under the existing summary revision:
|
||||
|
||||
```text
|
||||
launch_queue: null | {
|
||||
session_id?, agent_profile_id?, workflow_step_id?, queued_at,
|
||||
reason: "session_capacity" | "ownership_unavailable" | "replay_error",
|
||||
retrying: boolean,
|
||||
capacity: null | { in_use, limit, observed_at }
|
||||
}
|
||||
```
|
||||
|
||||
For session-backed workflow launches, session and profile are required. A
|
||||
sessionless start can use the generic task queue label without fabricating a
|
||||
session ID; it does not participate in parked-predecessor recipient matching.
|
||||
|
||||
Project sanitized identity and status from the durable ceiling record through a
|
||||
narrow provider at the task-service/orchestrator composition boundary. The task
|
||||
summary must not import the orchestrator or expose raw replay payloads, prompts,
|
||||
environment variables, or credentials. Resolve profile names through the existing
|
||||
authorized profile catalog; fall back to a generic session label if unavailable.
|
||||
|
||||
Extend summary rebuild, equality, validation, live projection, boot/list/detail
|
||||
enrichment, and `task.status_summary.updated`. Include explicit queue removal in
|
||||
the replacement summary. Missing fields on legacy snapshots are not a newer clear.
|
||||
Reuse existing revision/invalidation handling in `task-status-summary.ts` and
|
||||
task hydration; test old list snapshots after a queued update and after a clear.
|
||||
|
||||
Admission/refusal/dispatch/drop changes invalidate and rebuild affected summaries.
|
||||
The existing sweep refreshes observations at most once per pass; use one shared
|
||||
population sample per pass rather than a count query per row. Capacity is sampled
|
||||
from the ceiling controller, not copied forever from the original refusal.
|
||||
Changes to observations do not advance semantic task activity or reorder recent
|
||||
tasks. On restart rebuild queue ownership first; unavailable capacity is null.
|
||||
Observations older than two sweep intervals (40 seconds), or a disconnected
|
||||
client, are labelled stale. UI cannot infer dispatch from a count below the limit.
|
||||
|
||||
Queue presence does not increase `queued_prompt_count`: a deferred launch and a
|
||||
user prompt queue are different contracts. Pending question/error precedence and
|
||||
existing background-work indicators remain intact. No ordinal position is shown.
|
||||
|
||||
## Desktop and mobile surfaces
|
||||
|
||||
Share a queue view model and task-scoped status component. Desktop `TaskSwitcher`
|
||||
rows show Queued text with an existing clock/status icon. Task details place the
|
||||
status above conversation content, independently of selected session and transcript
|
||||
scroll. Show a separate parked note for the selected predecessor. The destination's
|
||||
CREATED start/recovery affordance yields to queued status while accepted work exists.
|
||||
|
||||
Use the existing `SessionTaskSwitcherSheet` phone drawer and
|
||||
`session-mobile-layout.tsx` dedicated composition. Place a compact task queue
|
||||
region above `MobileSessionsPicker`, outside the chat scroll. The navigator row
|
||||
shows the same Queued label. Long names wrap in details and truncate in rows.
|
||||
The user can inspect Astra while Luna remains named in the task queue region.
|
||||
|
||||
This is persistent status, so do not add a second drawer or global dashboard.
|
||||
Keep the existing fixed header/navigation, one chat scroll owner, dynamic viewport,
|
||||
and safe-area handling. Existing explicit execution controls remain available;
|
||||
no new bypass button is needed. Status text is keyboard/screen-reader readable,
|
||||
uses restrained polite announcements for state changes, and never announces every
|
||||
capacity sample. All new copy uses five-language i18n and the Traditional Chinese
|
||||
generation command. Previews and viewport assertions live in the work orders.
|
||||
|
||||
## Failure and observability
|
||||
|
||||
Emit structured, bounded reason codes for suppressed inspection, queued replay,
|
||||
stale-entry disposition, and protected state reconciliation. Include task,
|
||||
session, entry, and execution IDs in logs only, with no prompt content.
|
||||
Do not create lifecycle-only turns merely to announce a suppressed inspection.
|
||||
|
||||
Keep historical ceiling notes as history. The live status is independent and
|
||||
does not rewrite old audit messages. An ordinary deferral does not mean an empty
|
||||
prompt completed. Verify empty-turn handling at the real event boundary; the
|
||||
reported warning's exact origin was not proven, so do not remove valid warnings
|
||||
or claim its cause without a failing regression.
|
||||
|
||||
## Related records
|
||||
|
||||
- [Passive inspection decision](../../../decisions/2026-09-16-passive-session-inspection.md)
|
||||
- [Runtime state publication](runtime-state-publication-order.md)
|
||||
- [Implementation package](../../../plans/queued-session-ownership/plan.md)
|
||||
@@ -487,6 +487,10 @@ logs include session ID, execution ID, and intent stamp.
|
||||
|
||||
## Implementation plans
|
||||
|
||||
- [Queued session ownership](../../../plans/queued-session-ownership/plan.md)
|
||||
extends parking and admission through the paired
|
||||
[inspection and queue design](queued-session-ownership.md). Stop-intent
|
||||
tombstones remain callback evidence, not current activation policy.
|
||||
- [Explicit session targeting](../../../plans/workflow-session-targeting/plan.md)
|
||||
- [Same-profile fresh-session repair](../../../plans/workflow-same-profile-new-session/plan.md)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user