10 KiB
created, status, requirements, system_design, legacy_specs
| created | status | requirements | system_design | legacy_specs | ||
|---|---|---|---|---|---|---|
| 2026-09-25 | done |
|
|
Implementation Plan: Workflow entry saved-prompt delivery
Overview
Preserve saved-prompt definitions when workflow entry starts or resets a session. One sequential work order carries trusted context through composition, recording, and launch. It then verifies the profile-switch round trip and recovery paths.
Issue: #3922. The task system owns prompt delivery. Existing criteria cover persistence, trust, lookup failure, and passthrough behavior. Added criteria 001.12 and 001.13 make workflow-entry and recovery outcomes explicit.
Evidence and root cause
Source inspected at 3aa3233c78:
task_operations.go:buildWorkflowEntryPromptcallsbuildWorkflowPrompt, which discards the trusted-context return frombuildWorkflowPromptWithContext.event_handlers_workflow.go:autoStartStepPromptinjects runtime context for CREATED sessions and context resets. Its trusted arguments omit saved-prompt context. Canonicalization therefore removes the generated expansion before recording.task_operations.go:startCreatedSessionWithComposedPromptpasses an empty context tostartCreatedSession. That method skips composition but still callswrapCreatedSessionPrompt, creating another removal boundary.- Running-session dispatch usually bypasses these injectors. This explains why the same workflow prompt works without a session switch.
A temporary TestReproIssue3922 used the real SQLite prompt service and
buildWorkflowEntryPrompt with Follow @demo-rule. The expansion existed before
canonicalization and disappeared afterward. A control passed the resolver's exact
trusted value and retained the saved definition once. The diagnostic passed:
(cd apps/backend && go test ./internal/orchestrator -run '^TestReproIssue3922$' -count=1 -v)
This proves the composition/canonicalization defect, not the complete profile routing flow or a working fix. The temporary file was removed. Permanent integration regressions remain part of implementation.
Scope
In scope
- Preserve generated context on explicit auto-start and implicit profile-switch launches.
- Cover P1 to P2 and P2 to P1, existing-session controls, and context resets.
- Preserve context through composed launches and missing-execution recovery.
- Compare persisted and dispatched expansions, including Office context injection.
- Preserve existing handoff, entity-reference, mode, and queue behavior.
- Gate shared saved-prompt mutations on
org.config.managewhile preserving member reads and reference use. - Update the workflow saved-prompt public guidance with the implemented guarantee.
Out of scope
- Literal system-tag truncation or prompt-editor validation from the issue's secondary report.
- New UI warnings, fail-closed resolution, or prompt matching rules.
- Profile routing changes, queue schema changes, and queued-message edit/merge semantics.
- Passthrough expansion, frontend changes, release flags, or database migrations.
Technical approach
Change buildWorkflowEntryPrompt to return prompt, trusted expansion context,
and error. Use buildWorkflowPromptWithContext after the existing fallback claim.
Update every production caller and affected test caller.
Carry the context explicitly through autoStartStepPrompt, both runtime-context
injectors, and startCreatedSessionWithComposedPrompt. Pass it into the existing
startCreatedSession context argument. Do not recover trust from tagged text.
Use a small private input/options structure if needed to avoid excessive positional arguments.
Audit StartSessionForWorkflowStep, promptTaskOptions, and
fallbackFreshLaunchOnMissingExecution. Preserve the matching context across
already-composed retries and final launch wrapping. Replacement branches that
rebuild the prompt must use their newly returned context.
Keep queued replay on its existing backend-authoritative preparation path. Add a queue/recovery regression to detect stripping or duplicate expansions. Do not add persisted trust metadata or expand queue semantics for this repair. Keep mode transforms single-pass and completion handoff text last.
The existing server-owned expansion ADR remains authoritative. No new authority boundary or ADR is needed. The completed Quick Chat and launch-fallback packages retain their completed scope and recorded results; this package owns the additional workflow regressions.
Tests
New tests belong in
apps/backend/internal/orchestrator/workflow_entry_saved_prompt_test.go.
Use the real prompt service fixture from prompt_launch_fallback_test.go.
Do not append new cases to oversized existing test files.
All criterion suffixes below refer to AC-TASKS-SAVED-PROMPT-DELIVERY-001.
| Criteria | Planned regression |
|---|---|
| .6, .12 | TestWorkflowEntrySavedPrompt_ProfileSwitchRoundTrip: drive P1/P2/P1 through processOnEnter with no auto_start_agent; capture stored messages and asynchronous implicit-launch requests. |
| .6, .12 | TestWorkflowEntrySavedPrompt_DispatchModes: CREATED, reused WAITING_FOR_INPUT, ordinary reset, and Office reset-context sessions; plan mode. The Office case asserts the Office tool context and saved expansion in both prompt boundaries. |
| .6, .12, .13 | TestProcessOnEnterImplicitProfileSwitchTerminalizedGuard: terminalize the reused profile session at the deterministic pre-dispatch barrier, then verify the production replacement launch's session identity, stored and dispatched saved definition, and completion handoff. TestAutoStartStepPrompt_ReplacementLaunchReusesClaimedHandoff remains a same-session shared-claim control. |
| .6, .13 | TestWorkflowEntrySavedPrompt_Recovery and TestStartSessionForWorkflowStep_ComposedHandoffSurvivesLazyResumeFallback: missing execution and composed workflow-step recovery. |
| .4, .5, .8 | TestWorkflowEntrySavedPrompt_TrustGuards: forged blocks, unknown references, lookup failure, absent expander, passthrough, and empty prompt. |
| .12, .13 | TestWorkflowEntrySavedPrompt_Composition: nested references and workflow-level references. TestWorkflowEntrySavedPrompt_DispatchModes covers plan mode; the recovery test covers completion handoff ordering. |
| .13 | TestSendQueuedNowConsumesCeilingLaunchAndPreservesWorkflowPrompt: queued Send Now preserves the accepted expansion in the deferred launch. TestExecuteQueuedWorkflowPrompt_MissingExecutionKeepsDrainExpansion: a workflow queue message is re-resolved before it is recorded; if the saved definition changes during failed dispatch, the fresh-runtime launch keeps the drain-time expansion. |
| .14 | TestPromptMutationsRequireOrgConfigManage denies member POST, PATCH, and DELETE; TestPromptReadsRemainAvailableToOrgMembers preserves shared prompt reads. |
Run the CREATED-session regression before production edits. It must fail because the saved definition disappears, not because the fixture fails to launch. Assert visible references remain and each canonical prompt contains exactly one expansion block. Compare the saved definitions in persistence and dispatch. For prepared retries, mutate the saved record between preparation and wrapping and assert that the carried definition is not silently replaced.
End-to-end evidence
Backend service integration tests exercise routing, composition, message storage, and the agent-manager dispatch boundary. Mock external agent execution only. Use existing profile-switch and handoff fixtures with deterministic synchronization. No browser control or rendered UI changes, so no new Playwright test or UI preview is required.
Work orders
Verification results
Diagnostic reproduction passed on 2026-09-25 and was removed. The implementation and its verification completed on 2026-09-25:
- The focused orchestrator race suite passed, including workflow-entry dispatch, profile routing, composed launch, and fresh-runtime recovery tests.
- Review follow-up race tests passed for the Office reset injector, the
no-
auto_start_agentP1/P2/P1 asynchronous launches, and terminalized-session replacement with the carried handoff. - The prompt service and system-prompt race tests passed.
- Additional recovery, ceiling-deferral, and queued Send Now preservation tests passed under the race detector.
go build ./...passed fromapps/backend.python3 scripts/list-docs.py validatevalidated 305 decisions and 1151 specifications;python3 scripts/lint-spec-files.py --allpassed.- The public-doc validator tests passed (62 tests), and the validator accepted all 47 published pages.
gofmtandgit diff --checkpassed.- PR fixup coverage passes for prompt mutation authorization, member reads, non-composed recovery, queued workflow recovery after an in-flight saved-prompt edit, and a nil workflow step. The queue resolves once at drain before the message row is recorded, then fresh-runtime recovery carries that trusted context.
- Shared prompt mutations now require
org.config.manage. Public documentation states that prompts are instance-shared and records the current multi-org admin boundary.
The public workflow guidance now documents the preserved-context behavior. The
issue remains assigned to carlosflorencio. The implementation and its PR
fixup are tracked in PR #3931.
Risks
- Fixing only the first injector still loses the expansion at the second injector.
- Re-reading mutable definitions after recording can make persistence differ from dispatch.
- Trust inferred from prompt text would bypass the existing security boundary.
- Signature changes touch retry and replacement paths with cancellation and admission guards.
- Broad recomposition can duplicate plan-mode context, references, or handoff text.