| title | Completion Funnel |
|---|---|
| sidebarTitle | Completion Funnel |
| description | The semantic completion authority and its handoff to transactional task lifecycle. |
{/* [LAYER: INFRASTRUCTURE] */}
src/core/task/tools/completion/CompletionFunnel.ts is the sole semantic authority that decides whether a task is durably complete.
It is intentionally separate from:
ExecutionFunnel, which admits and classifies one tool operation; andTaskLifecycleFunnel, which commits generation-bound task state.
Tool execution success is not task completion.
| Concern | Authority |
|---|---|
| Completion evidence, gates, action eligibility, canonical identity, durable completion CAS, and completion event | CompletionFunnel |
| Task lifecycle state and terminal outcome | TaskLifecycleFunnel |
| Tool approval, permit, dispatch, and operation terminal event | ExecutionFunnel |
| Completion/lifecycle display | UI projection only |
The durable semantic result remains the task_completions row. After that result commits, CompletionFunnel submits one generation-bound SettleCompletion fact to TaskLifecycleFunnel. The lifecycle funnel validates the current task generation and cancellation fence, commits terminal outcome completed, and publishes the immutable lifecycle event.
Neither funnel duplicates the other:
CompletionFunneldoes not assign terminal task state.TaskLifecycleFunneldoes not re-run completion gates or infer semantic success.- UI does not treat a completion-shaped transcript, receipt, or successful tool event as lifecycle truth.
The completion monolith owns the complete semantic transaction:
- Collect one canonical completion snapshot.
- Evaluate the registered gates in deterministic order.
- Produce one binding next action or terminal decision.
- Compute the canonical completion identity.
- Validate the current coordination lease and task state version.
- Commit or load the durable
task_completionsrecord. - Submit the durable completion fact to
TaskLifecycleFunnel. - Publish the terminal
CompletionFunnelEventonly after lifecycle commit succeeds.
This ordering prevents a completion UI event from racing ahead of task lifecycle truth.
The semantic completion identity is a schema-versioned canonical digest over the task, evaluated state version, checkpoint, outcome, and decision schema. The SQLite transaction validates the current lease tuple and state version before inserting the terminal row.
Duplicate and conflict policy:
| Durable condition | Result |
|---|---|
| Same decision and payload | Return idempotently |
| Different decision, same terminal outcome | Preserve the existing durable completion |
| Different terminal outcome | Fail closed |
| Same identity, different payload | Treat as corruption/collision and fail closed |
TaskLifecycleFunnel then applies its own generation and cancellation laws. A completion fact that durably predates a cancellation request can prove that ordering with authoritativeAt; a later or unproven fact cannot bypass the cancellation fence.
CompletionFunnelEvent explains the semantic completion decision and its gate trace. TaskLifecycleEvent explains the committed task-state transition.
Consumers must not merge fields or infer one from the other:
- completion event: “the completion transaction committed”;
- lifecycle event: “generation G transitioned to terminal completed at revision R.”
The webview displays task terminality only from the lifecycle event. The semantic completion event may provide details, but it cannot create, repair, reopen, or override lifecycle state.
- Gate denial returns a non-terminal completion event and does not change lifecycle state.
- Durable completion persistence failure cannot publish terminal completion.
- Lifecycle rejection after durable completion is treated as a terminalization error and prevents a false terminal UI event.
- A stale task generation, pending cancellation, active attached child, or conflicting terminal outcome fails closed.
- Execution of
attempt_completionmay itself succeed as a tool operation without independently terminalizing the task.
Resume reads the committed lifecycle record and active completion evidence:
- terminal completed generations allow user continuation by creating a new generation (
ResumeWithGeneration) when new user feedback, prompt resends, or pre-completion timeline restores occur; getTerminalCompletionEvidenceinsrc/shared/completion/taskCompletionEvidence.tsevaluates message history sequentially (reopensCompletedTask); pre-completion checkpoint restores or user feedback override terminal evidence, resolvingresolveTaskResumeAskback toresume_task;- dual-action UI controls (
buttonConfig.ts) provide explicit "Resume task" (primary) and "New chat" (secondary) actions on completion rows; - generic transcript bookkeeping cannot demote or revive terminal state;
- old completion callbacks cannot mutate a replacement generation.
See Task lifecycle authority and Resume and recovery.
npx cross-env TS_NODE_PROJECT=./tsconfig.unit-test.json mocha --no-config \
--timeout 10000 --exit --extension ts \
--require ts-node/register \
--require tsconfig-paths/register \
--require source-map-support/register \
--require ./src/test/requires.cjs \
src/core/task/tools/completion/__tests__/CompletionFunnel.test.ts \
src/core/task/lifecycle/__tests__/TaskLifecycleFunnel.test.tsThe focused tests prove that a completion fact produces one terminal lifecycle event and that UI completion projections cannot create lifecycle truth.
- Only
CompletionFunneldecides semantic task completion. - Only
TaskLifecycleFunnelcommits terminal task lifecycle state. - Durable semantic completion precedes lifecycle completion submission.
- Terminal completion UI follows lifecycle commit.
- Tool execution success cannot complete a task.
- No transcript, receipt, cache, or compatibility field can synthesize lifecycle terminality.