11 KiB
created, status, requirements, system_design, legacy_specs
| created | status | requirements | system_design | legacy_specs | ||
|---|---|---|---|---|---|---|
| 2026-09-12 | implemented |
|
|
Implementation plan: Initial task brief
Overview
Preserve the task brief when a user starts a prepared session through Chat. First extend atomic message admission. Then connect composition and dispatch. Finally prove transcript visibility on desktop and phone. All work is sequential.
Source: GitHub issue #3615.
Investigated revision: 8892920514250dfc9873725f90d736a5cc7e388a.
The issue had no comments or image attachments during investigation.
The authenticated user carlosflorencio was assigned on 2026-09-12.
Confirmed root cause
hooks/use-message-handler.tssubmits the additional text throughmessage.add.internal/task/handlers/message_handlers.go:wsAddMessagepersists the submitted content without the task description.dispatchPromptAsyncforwards the committed content toforwardMessageAsPrompt.StartCreatedSessionuses the supplied nonempty prompt. Its description fallback applies only to an empty prompt.hooks/use-processed-messages.ts:shouldShowTaskDescriptionFallbackremoves the synthetic brief after any stored user message appears.
The transcript behavior conforms to its existing specification. The missing contract is preservation during direct first-message admission. Do not weaken the UI fallback predicate or change automatic workflow fallback semantics.
Reproduction evidence
A temporary internal/task/handlers/issue3615_repro_test.go used the existing
runCreatedMessageContextTest harness. It created an ordinary task with a
nonempty description and a single CREATED session. It submitted
rebase on latest main through the real handler and task service.
(cd apps/backend && go test -tags fts5 ./internal/task/handlers -run '^TestReproIssue3615$' -count=1 -v)
The assertion failed for the expected reason:
saved brief=false, saved instruction=true, description intact=true
original task brief omitted from saved first message
FAIL TestReproIssue3615
This reproduction used a repository fake and no agent process. Agent omission is supported by the dispatch source trace and issue evidence, not a live-agent run. The temporary test was removed after recording the result. No runtime was launched.
Permanent regression: TestWSAddMessage_InitialTaskBrief in
apps/backend/internal/task/handlers/message_handlers_initial_task_brief_test.go.
Use the existing firstTurnCaptureOrchestrator to assert saved and dispatched
visible content, then cover the real orchestrator composition separately.
Scope
In scope
- Direct first-message brief composition for ordinary CREATED sessions.
- Atomic selection using the existing durable session prompt boundary.
- Idempotency, rollback, description snapshots, and concurrent admission.
- Existing structured, passthrough, saved-prompt, attachment, and queue integration.
- Persisted prompt #1 visibility on desktop and phone.
Out of scope
- Production or permanent test changes during this design turn.
- Historical transcript backfill, new prompt ordinals, or synthetic user history.
- Changes to automatic workflow entry, Office, Quick Chat, or configuration policies.
- New public replacement controls, API fields, or database migrations.
- Provider-level delivery guarantees after crashes.
Technical approach
Follow the system design. A server-only initial candidate travels from the handler through the service. The repository chooses it inside the existing prompt write transaction. The handler dispatches the returned content with its matching trusted context.
Do not call HasUserPromptHistory outside a transaction and then write later.
Do not select by PromptIndex == 1 alone: automatic fallback reserves ordinal
zero before its user row exists. Preserve the existing fallback reservation.
Compose and deduplicate the raw brief and instruction before one server-owned preparer call. Carry the resulting content, trusted reference context, and an explicit prepared-state bit as one candidate through admission and dispatch; the bit preserves an accepted empty expansion snapshot. Compare the description snapshot during admission and refresh only the candidate when it is stale. Keep replay identity based on the original request. Preserve plan-comment transaction and attachment ownership. Validate the final rendered content at the database boundary before insertion.
Authorize the task/session pair before reading mutable task state. Atomic admission gives only the selected candidate created-session launch ownership. Later contenders are persisted and queued with turn-start already processed and an admission-order dispatch marker, so queue fast paths wait for the admitted launch. Only the selected queued plan-comment candidate notifies the lifecycle starter. This keeps visible content, trusted expansion, and launch ownership paired across direct and queued delivery.
The rendered structure stays unchanged. Stored prompt content corrects visibility. No new locale keys are expected. Any added product copy must use existing localization rules.
ASCII UI preview
UI-01: Chat after first message (desktop and phone)
Before Proposed
+-------------------------+ +-------------------------+
| User #1 | | User #1 |
| rebase on latest main | | Original task brief |
| | | |
| Agent response | | rebase on latest main |
+-------------------------+ | Agent response |
| Composer [Send] | +-------------------------+
+-------------------------+ | Composer [Send] |
+-------------------------+
Entry: open the task, then send a preparatory message before its first start.
AC references: AC-TASKS-INITIAL-TASK-BRIEF-001.1, .2, .7.
The before view is supported by the source predicate and reproduction.
Desktop uses the existing Chat pane. Phone uses full-height Chat through
task-layout.tsx and SessionMobileLayout. Both share this content order.
The transcript scrolls vertically. The composer retains its existing fixed
region and phone safe-area behavior. Long content uses existing expansion
controls and history navigation. No new drawer, button, or hover action is required.
Content order and durable visibility are required. Borders and spacing are illustrative.
Tests
| Criteria | Test and boundary |
|---|---|
.1, .2, .4, .10 |
TestWSAddMessage_InitialTaskBrief, TestWSAddMessage_InitialTaskBriefExpandsCombinedPromptAtAdmission, TestWSAddMessage_InitialTaskBriefKeepsAcceptedExpansionWhenDefinitionsChange, handler persistence and captured dispatch |
.3, .5, .6 |
TestInitialTaskBriefAdmission, SQLite transaction, fallback reservation, rollback, and replay |
.5, .6 |
TestInitialTaskBriefAdmissionPostgres, cross-connection transaction parity |
.8, .9 |
TestStartCreatedSession_InitialTaskBrief, TestApplyWorkflowAndPlanMode_PreservesEmptyAcceptedPromptSnapshot, handler saved-reference table cases, and queued initial-brief delivery |
.2, .7 |
use-processed-messages-fallback.test.ts, synthetic row replacement with combined prompt |
All criterion suffixes refer to AC-TASKS-INITIAL-TASK-BRIEF-001.
Repository tests must include two distinct first submissions, a direct/fallback
race, zero reservation, message deletion, restart, stale description, and rollback.
Handler cases must include normal launch, queued promotion, session redirection,
attachments, plan comments, saved references, equality, empty brief, and excluded modes.
E2E tests
Add e2e/tests/chat/initial-task-brief.spec.ts for chromium and
e2e/tests/chat/mobile-initial-task-brief.spec.ts for mobile-chrome.
Seed a task without starting it. Open Chat, observe the brief, and submit the
preparatory instruction through the composer. Assert both texts in prompt #1,
reload, and assert them again. Send a later message and assert no brief replay.
These flows cover .1, .2, .3, and .7. Use existing causal WebSocket waits.
Work orders
- Task 01: Atomic initial content selection — done
- Task 02: First-message composition — done
- Task 03: Transcript visibility evidence — done
Related packages and documentation
The completed workflow-step-agent-start-ownership package owns reset/start
routing. Its scope and results remain unchanged. The transcript visibility
package owns pagination. This package consumes both contracts without rewriting
their completed work orders or test results.
Task 03 added a short explanation to docs/public/tasks-and-workflows.md with
the implemented behavior.
Verification results
- Permanent backend admission, handler, service, and orchestrator regressions passed, including combined saved-reference preparation, accepted-context dispatch, and queued delivery.
- Review-remediation regressions passed for task/session pair authorization, stale-description candidate refresh without repeated turn-start hooks, admission-order launch ownership, deferred queue fast-path delivery, accepted empty expansion snapshots, and rendered prompt size validation.
- SQLite admission tests passed, including rollback, stale snapshots, deletion, restart, fallback races, zero reservations, and plan-comment queues.
- PostgreSQL parity test was skipped because
KANDEV_TEST_POSTGRES_DSNis not configured in this environment. go vetpassed for all changed backend packages.make -C apps/backend lint,make -C apps/backend build, andgo run ./cmd/sqlguard ./internalpassed.- Race-enabled initial-admission tests and
go test -race ./internal/persistence/storeconformance -count=1passed. pnpm exec vitest run hooks/use-processed-messages-fallback.test.tspassed.pnpm run typecheckpassed.pnpm run i18n:checkpassed.- Targeted changed-file ESLint passed with zero warnings, and
pnpm run e2e:sleep-ratchetpassed. - Managed
chromiumandmobile-chromeE2E tests passed, including reload and later-message behavior. - Both public-doc validators passed; the specification test suite passed 36 tests, all specification files passed, and
git diff --checkpassed.
Risks
- Candidate selection must pair visible content with the correct trusted expansion.
- A nonempty workflow template can replace a direct prompt during launch composition.
- A fallback reservation has no visible row yet but still owns the first boundary.
- Plan-comment admission and queued content must select the same candidate atomically.
- Existing affected conversations require manual brief recovery. This package does not backfill them.