> For the complete documentation index, see [llms.txt](https://faction-os.gitbook.io/faction-os-docs/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://faction-os.gitbook.io/faction-os-docs/.spec_system/archive/sessions/phase20-session09-container-dispatch-decision/spec.md).

# Session Specification

**Session ID**: `phase20-session09-container-dispatch-decision` **Phase**: 20 - Orchestration Actionability Execution **Status**: Not Started **Created**: 2026-06-28 **Package**: null **Package Stack**: mixed TypeScript across `packages/protocol`, `apps/server`, and `apps/web`

***

## 1. Session Overview

This session makes the Phase 20 container dispatch decision by approving a narrow local container executor slice for queue and campaign dispatch. The current codebase already has direct terminal/container routes, a `ContainerRuntimeManager`, Docker and image probes, idempotent isolated-spawn runs, timeout handling, cleanup posture, and compact container execution attachments. What is missing is the queue/campaign execution bridge that proves container work through the same executable task contract used by terminal, Git, and file tasks.

The session is next because Phase 20 has already completed the truthful capability baseline, queue terminal execution, queue Git execution, campaign dispatch, campaign DAG recovery, file mutation, file executor integration, and managed-agent lifecycle control. Session 09 is the next unfinished phase stub, and sessions 10 and 11 depend on truthful executor-family posture before templates, channels, and release evidence can claim a complete orchestration surface.

The approved scope is intentionally narrow: queue and campaign container tasks may run only the existing bounded isolated-spawn check through `ContainerRuntimeManager.runIsolatedSpawn()`. The session does not add arbitrary Docker commands, image builds, workspace mutation inside containers, remote execution, hosted execution, Worker command bridges, or expanded Docker isolation claims.

***

## 2. Objectives

1. Extend the protocol-owned task queue executable contract to include a bounded `container` payload and compact container execution summaries.
2. Add server-side container dispatch to `TaskExecutionCoordinator` by reusing `ContainerRuntimeManager` probes, idempotency, timeout, unavailable, failure, cleanup, and attachment behavior.
3. Wire queue and campaign dispatch so container executable tasks produce visible queue transitions, execution-run evidence, and retryable unavailable or failed states.
4. Update web queue/campaign surfaces and docs so direct container runtime readiness is clearly distinct from queue/campaign container orchestration readiness.

***

## 3. Prerequisites

### Required Sessions

* [x] `phase19-session12-terminal-and-containers` - Provides direct local terminal/container routes, runtime probes, isolated-spawn execution, and compact container attachments.
* [x] `phase20-session01-truthful-capability-baseline` - Establishes truthful executor labels and no-overclaim wording.
* [x] `phase20-session02-queue-terminal-execution` - Provides the queue dispatch pattern, duplicate guards, execution-run linkage, and terminal result surfacing.
* [x] `phase20-session04-campaign-executable-dispatch` - Provides campaign-to-queue executable dispatch.
* [x] `phase20-session05-campaign-dag-recovery` - Provides dependency-aware campaign dispatch, retry, unavailable, and blocked-state behavior.

### Required Tools Or Knowledge

* Node 26.2.0 and npm 11.16.0 from `.spec_system/CONVENTIONS.md`.
* Existing `TaskQueueExecutablePayload`, `TaskExecutionCoordinator`, `PlanCampaignManager`, `ContainerRuntimeManager`, terminal/container routes, queue web workbench, and campaign workbench.
* Current local-first redaction rules for commands, terminal output, raw Docker output, file contents, diffs, broad paths, tokens, provider payloads, webhook bodies, logs, exports, and replay.

### Environment Requirements

* Local repo checkout with npm workspaces installed.
* Tests use fake container runners and must not require live Docker.
* Live runtime verification may report unavailable when Docker or the default image is missing; that state is an accepted product outcome when surfaced truthfully.
* No provider credentials, hosted account, Worker proxy, remote executor, analytics service, database, or new native dependency is required.

***

## 4. Scope

### In Scope (MVP)

* Operators can create a container queue task - Add a container create mode with safe image/runtime labels, bounded input validation, and product-facing copy only.
* Operators can dispatch a container queue task - Execute the existing isolated-spawn path through the coordinator with duplicate-trigger prevention while in-flight, timeout handling, retryable failed or unavailable states, and compact execution evidence.
* Campaign dispatch can run container executable tasks - Store container executable payloads on campaign tasks, bridge them to queue entries, and preserve DAG dependency, retry, failed, unavailable, and partial-failure semantics.
* Container runtime failures are truthful - Missing runtime, missing image, preview-only runtime, policy block, timeout, failed run, and duplicate dispatch produce explicit queue/campaign result summaries rather than silent completion.
* Broad surfaces stay compact - REST responses, WebSocket frames, queue rows, campaign graph rows, docs, diagnostics, exports, and tests expose only safe labels, counts, ids, runtime label, cleanup posture, execution run id, container run id, state, and recovery guidance.
* Release wording is corrected - API, architecture, isolation, server, and web docs distinguish direct container runtime controls from queue/campaign container orchestration support.

### Out Of Scope (Deferred)

* Arbitrary Docker or Apple Containers commands - Reason: this session only approves the existing isolated-spawn operation.
* Docker image build, pull, push, compose, volume, network, shell, or package-script orchestration - Reason: those are separate executor operations requiring their own threat model and tests.
* Workspace mutation through container mounts - Reason: file mutation and rollback stay owned by the file executor path.
* Remote containers, hosted execution, Worker command bridges, SSH, tunnels, browser-to-terminal bridges, or public orchestration sharing - Reason: Phase 20 remains local-first and no-claim for remote or hosted execution.
* Raw Docker output, container stdout/stderr, command bodies, raw image inspect output, full paths, tokens, secrets, provider payloads, or webhook bodies in broad surfaces - Reason: scoped sensitive data must not leak into rows, events, docs, logs, exports, or replay.
* Database, persistence schema, migration, or external service work - Reason: command-center and queue state remain manager-owned local runtime state.

***

## 5. Technical Approach

### Architecture

Protocol should extend `packages/protocol/src/taskQueue.ts` rather than adding a side-channel payload. Add `container` to `TASK_QUEUE_EXECUTABLE_KIND_VALUES`, create a `TaskQueueContainerExecutablePayload`, include `container` in `TaskQueueExecutionFamily`, map the execution kind to `container_run`, and add container summary metadata such as `containerRunId`, `runtime`, `cleanupPosture`, and `recoveryNote`. Parser coverage should validate safe optional `heroId`, `heroLabel`, `imageName`, `runtime`, `commandLabel`, `idempotencyKey`, `executionRunId`, and `recoveryNote` fields while rejecting blocked raw payload names.

Server behavior should add a `containerRuntime` dependency to `TaskExecutionCoordinator` and implement `dispatchContainer()`. The method should follow the existing terminal/Git/file coordinator pattern: resolve the executable payload, reject stale revisions and duplicate dispatch, create a queued `CommandCenterExecutionRun`, mark it executing only when an execution attempt starts, call `ContainerRuntimeManager.runIsolatedSpawn()`, complete the run with the manager result, and update the queue as completed, unavailable, or blocked. It should reuse the manager's result attachment instead of exposing raw probe or container output.

Campaign behavior should extend `PlanCampaignManager.dispatchQueueExecutable()` and `executionReadinessForExecutable()` so container tasks participate in dependency ordering, retry, partial-failure, unavailable, and queue-link evidence exactly like other executable families. Campaign preview/refinement paths already accept `TaskQueueExecutablePayload`; they should accept the new container variant through the shared parser and preserve it when tasks are refined.

Web behavior should add a `Container` queue create mode and container executable helpers in `apps/web/src/lib/orchestrationApi.ts`. Queue rows and campaign graph rows should render labels such as `Dispatch container`, `Retry container`, `Container run`, runtime label, cleanup posture, and unavailable reasons without raw Docker output. Controls must include loading, empty, error, offline, and duplicate-in-flight states, accessible names, and focus behavior consistent with the existing queue and campaign controls.

### Design Patterns

* Protocol-first contracts: shared task queue executable and summary types land before server and web wiring.
* Manager-owned runtime boundary: Docker probing, image checks, timeouts, cleanup, idempotency, and result attachments remain inside `ContainerRuntimeManager`.
* Coordinator convergence: queue and campaign dispatch use one `TaskExecutionCoordinator` path for terminal, Git, file, and container families.
* Fail closed before execution: missing runtime, missing image, preview-only runtime, unsafe payloads, stale revisions, and duplicate triggers return explicit unavailable or conflict states.
* Broad-summary plus scoped-detail split: broad surfaces expose compact labels and ids only, never raw Docker output, command bodies, terminal output, paths, tokens, secrets, provider payloads, or webhook bodies.

***

## 6. Deliverables

### Files To Create

| File                                                           | Purpose                                                                                                                                                | Est. Lines |
| -------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------ | ---------- |
| `apps/server/tests/taskExecutionCoordinator.container.test.ts` | Focused coordinator coverage for container queue dispatch success, unavailable runtime, timeout/failure, duplicate dispatch, and broad payload safety. | \~220      |

### Files To Modify

| File                                                           | Changes                                                                                                                                                      | Est. Lines |
| -------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------ | ---------- |
| `packages/protocol/src/taskQueue.ts`                           | Add container executable payload, parser, execution family/kind, execution summary metadata, and blocked raw-field validation.                               | \~180      |
| `packages/protocol/src/orchestrationCommandCenter.ts`          | Reuse or expose container runtime/cleanup parser helpers needed by task queue summaries.                                                                     | \~60       |
| `packages/protocol/tests/orchestrationCommandCenter.test.ts`   | Cover container queue payload parsing, execution summary parsing, unavailable metadata, and blocked raw-field rejection.                                     | \~140      |
| `apps/server/src/managers/taskExecutionCoordinator.ts`         | Inject `ContainerRuntimeManager`, implement `dispatchContainer()`, create container runs, map manager results to queue states, and keep attachments compact. | \~240      |
| `apps/server/src/managers/planCampaignManager.ts`              | Add container execution readiness, dispatch switch, retry behavior, and campaign task outcome mapping.                                                       | \~120      |
| `apps/server/src/routes/orchestration.ts`                      | Route queue dispatch for `executable.kind: "container"` and emit queue plus execution updates.                                                               | \~60       |
| `apps/server/src/server.ts`                                    | Pass the existing `containerRuntime` manager into `TaskExecutionCoordinator`.                                                                                | \~20       |
| `apps/server/tests/orchestration.test.ts`                      | Add route-level queue and campaign container dispatch coverage with fake container runtime results and WebSocket event privacy assertions.                   | \~200      |
| `apps/server/tests/containerRuntimeManager.test.ts`            | Add timeout and missing-image assertions that queue dispatch can rely on without live Docker.                                                                | \~80       |
| `apps/web/src/lib/orchestrationApi.ts`                         | Add container queue executable helper, create input support, response validation, and safe summary fields.                                                   | \~120      |
| `apps/web/src/lib/commandCenterUi.ts`                          | Add container family labels, dispatch/retry labels, runtime/cleanup/unavailable copy, and safe result rendering.                                             | \~120      |
| `apps/web/src/components/orchestration/QueueWorkbench.tsx`     | Add container create mode, safe image/runtime controls, accessible labels, offline/error/in-flight disabled states, and product-facing copy.                 | \~160      |
| `apps/web/src/components/orchestration/CampaignWorkbench.tsx`  | Allow task refinement to attach container executable payloads and display container readiness without implying arbitrary Docker support.                     | \~140      |
| `apps/web/src/components/orchestration/OrchestrationShell.tsx` | Wire container create/refine helpers, refresh queue/campaign results, and preserve duplicate in-flight keys.                                                 | \~90       |
| `apps/web/tests/orchestrationApi.test.ts`                      | Cover container executable serialization, parser validation, and blocked raw-field rejection.                                                                | \~90       |
| `apps/web/tests/commandCenterUi.test.ts`                       | Cover container labels, unavailable copy, cleanup posture, retry labels, and redaction.                                                                      | \~110      |
| `apps/web/tests/QueueWorkbench.test.tsx`                       | Cover container create controls, accessible labels, offline disabled state, and duplicate in-flight handling.                                                | \~130      |
| `apps/web/tests/CampaignWorkbench.test.tsx`                    | Cover container task refinement and product-facing campaign dispatch labels.                                                                                 | \~120      |
| `tests/e2e/orchestration-command-center.e2e.ts`                | Add browser proof for create -> dispatch -> observe container queue result or truthful unavailable state.                                                    | \~120      |
| `docs/api/README_api.md`                                       | Document queue/campaign container executable support, direct route distinction, compact result metadata, and privacy boundary.                               | \~70       |
| `docs/ARCHITECTURE.md`                                         | Update command-center architecture wording so queue/campaign container dispatch is listed as the bounded approved subset.                                    | \~40       |
| `docs/isolation-and-sandbox.md`                                | Update the container threat model with queue/campaign isolated-spawn scope and denied operations.                                                            | \~80       |
| `apps/server/README_server.md`                                 | Document server-side container queue/campaign dispatch, unavailable states, and no arbitrary Docker claim.                                                   | \~50       |
| `apps/web/README_web.md`                                       | Document web queue/campaign container labels, create mode, unavailable states, and redaction rules.                                                          | \~40       |

***

## 7. Success Criteria

### Functional Requirements

* [ ] A queue entry with `executable.kind: "container"` can dispatch through `TaskExecutionCoordinator`, create a `container_run` execution run, and finish as completed, unavailable, or blocked based on the manager result.
* [ ] A campaign task with a container executable payload creates a queue entry, dispatches through the same coordinator path, and preserves DAG dependency, retry, failed, unavailable, and partial-failure semantics.
* [ ] Missing Docker, missing image, preview-only runtime, timeout, failed isolated spawn, stale revision, and duplicate in-flight dispatch produce explicit product-facing result summaries.
* [ ] Web queue create and campaign refine flows can attach container executable payloads without exposing arbitrary Docker command controls.
* [ ] Capability labels, docs, and UI copy distinguish direct container runtime readiness from queue/campaign container orchestration support.
* [ ] Broad REST responses, WebSocket events, UI rows, docs, diagnostics, exports, replay, and tests do not expose raw Docker output, raw command bodies, terminal output, stdout, stderr, file contents, diffs, broad absolute paths, tokens, provider payloads, webhook bodies, logs, or raw probe output.

### Testing Requirements

* [ ] Protocol tests cover container executable payloads, execution summaries, runtime metadata, cleanup posture, unavailable states, and blocked raw-field rejection.
* [ ] Server tests cover queue container dispatch success, unavailable runtime, timeout/failure, missing image, duplicate in-flight protection, stale revision conflicts, campaign dispatch integration, retry behavior, and event privacy.
* [ ] Web tests cover container create controls, campaign refinement, queue/campaign labels, unavailable copy, offline/error states, duplicate in-flight guards, and redaction.
* [ ] Browser e2e proves a container queue task reaches a visible executed or truthful unavailable result without raw sensitive output.

### Non-Functional Requirements

* [ ] Container dispatch executes only the existing bounded isolated-spawn operation.
* [ ] No arbitrary Docker command, image build, workspace mutation, remote execution, hosted execution, Worker bridge, tunnel, or browser-to-terminal behavior is introduced.
* [ ] Container dispatch is duplicate-trigger protected and idempotent where idempotency keys are supplied.
* [ ] Timeout, cleanup, failed, and unavailable states remain visible and retryable where appropriate.
* [ ] Existing terminal, Git, file, managed-agent, queue, and campaign behavior remains compatible.

### Quality Gates

* [ ] All files ASCII-encoded
* [ ] Unix LF line endings
* [ ] Code follows project conventions
* [ ] Primary user-facing surfaces contain product-facing copy only
* [ ] Focused protocol, server, web, browser, workspace quality, and `git diff --check` commands pass

***

## 8. Implementation Notes

### Working Assumptions

* The session is cross-package by design: the analyzer reports `package: null`, the stub lists `packages/protocol`, `apps/server`, and `apps/web`, and the feature spans shared contracts, local runtime execution, and cockpit UI. Planning can proceed with `Package: null` because every task path is repo-root-relative.
* The approved path is bounded isolated spawn, not arbitrary Docker orchestration: `ContainerRuntimeManager.runIsolatedSpawn()` already enforces safe image labels, runtime probes, idempotency, timeouts, cleanup posture, compact attachments, and redaction. Planning can proceed by routing queue/campaign dispatch to that manager instead of adding a broader Docker surface.
* Live Docker availability is not required for session completion: the PRD accepts truthful unavailable states, and existing tests use fake container runners. Planning can proceed with fake-runner success/failure coverage plus browser evidence that either executed or unavailable results are visible.
* Campaign refinement is the safest UI entry point for campaign container payloads: `CampaignWorkbenchTaskRefinementInput` already accepts `TaskQueueExecutablePayload`, so the session can add container support there without inventing a separate campaign editor.

### Conflict Resolutions

* Phase 19 docs currently describe direct terminal/container controls and say queue/campaign execution is limited to terminal and Git in some places. The chosen interpretation is that those docs were accurate before Phase 20 session 09 and must be updated once this bounded queue/campaign container slice lands.
* The Phase 20 stub allows either supported or unsupported container dispatch. The chosen interpretation is supported, narrowly scoped dispatch because source evidence shows an existing manager-owned isolated-spawn operation with probes, timeout, idempotency, cleanup, compact attachment, and tests.
* Security notes warn that Docker isolation beyond documented capability remains no-claim. The chosen interpretation is to keep the claim limited to queue/campaign dispatch of the existing isolated-spawn check and explicitly deny arbitrary Docker, mount, network, image-build, remote, hosted, and Worker execution.

### Key Considerations

* \[P19] Executor claims are family-scoped: container readiness applies only to the isolated-spawn queue/campaign slice after protocol, server, web, docs, and tests prove it.
* \[P19] Scoped detail stays separate from broad rows: raw Docker output, command bodies, terminal output, diffs, file contents, broad paths, tokens, provider payloads, webhook bodies, and raw probe output stay out of broad surfaces.
* \[P03-packages/protocol] Protocol leads cross-package work: shared queue payload and summary types land before server and web consumers.
* \[P19] Command-center state is manager-owned: idempotency, revisions, queue transitions, execution runs, event emission, and bounded snapshots stay in managers.
* \[P07] Redaction is boundary-specific: route responses, WebSocket events, UI rows, docs, diagnostics, screenshots, and tests each need explicit minimization.

### Potential Challenges

* Docker support can be overclaimed: docs and UI must say this is only bounded local isolated spawn through queue/campaign dispatch.
* Missing live Docker could look like failure: tests should use fake runners, while product behavior reports unavailable states with recovery copy.
* Campaign task refinement can drift from queue create: use the shared `TaskQueueExecutablePayload` parser and UI helper to build both payloads.
* Container output can leak: all result summaries and attachments must come from `ContainerRuntimeManager`, not raw stdout, stderr, image inspect output, or Docker errors.
* Retry semantics can duplicate work: use existing in-flight locks and idempotency keys for queue and campaign dispatch.

### Relevant Considerations

* \[P19] **Executor claims are family-scoped**: Only the isolated-spawn operation can become queue/campaign executable in this session.
* \[P19] **Scoped detail stays separate from broad rows**: Container queue/campaign rows expose compact labels and ids only.
* \[P03-packages/protocol] **Protocol leads cross-package work**: Queue payload and summary contracts lead server and web changes.
* \[P19] **Command-center state is manager-owned**: Coordinator and managers own state transitions and compact updates.
* \[P19] **Do not mark a family executor-ready without gates**: Runtime probes, image checks, timeouts, cleanup, tests, and docs are required before any ready label appears.

### Behavioral Quality Focus

Checklist active: Yes Top behavioral risks for this session:

* State-mutating container dispatch runs twice from repeated clicks, stale tabs, campaign retry, or WebSocket replay.
* UI or docs imply arbitrary Docker, remote, hosted, Worker, or broader isolation support when only bounded local isolated spawn is implemented.
* Raw Docker output, command bodies, terminal output, image inspect output, broad paths, tokens, provider payloads, webhook bodies, or logs leak into broad rows, events, docs, screenshots, or tests.

***

## 9. Testing Strategy

### Unit Tests

* Protocol tests for container executable parsing, execution summaries, cleanup posture, runtime labels, unavailable states, and blocked raw-field rejection.
* Server coordinator tests for container dispatch success, unavailable runtime, missing image, timeout/failure, duplicate in-flight lock, stale revision, and compact attachment mapping.
* Web helper tests for container create payloads, family labels, retry labels, cleanup posture, unavailable copy, and redaction.

### Integration Tests

* Queue route test that creates a container executable task, dispatches it through a fake ready container runtime, and observes a compact `container_run` execution update.
* Queue route test that dispatches with fake missing runtime or image and records an unavailable queue state with retry guidance.
* Campaign route test that refines a task with a container executable payload, dispatches the approved campaign, and preserves DAG outcome buckets and queue/execution links.
* Web component tests that create/refine container tasks and verify accessible labels, disabled offline states, duplicate in-flight controls, and no raw output rendering.

### Runtime Verification

* Playwright app test creates a container queue task from the Queue workbench, dispatches it, and verifies either `Container run` executed evidence or truthful unavailable copy is visible while raw Docker output, command text, broad paths, tokens, provider payloads, and webhook bodies are absent.

### Edge Cases

* Docker runtime unavailable.
* Docker image missing.
* Apple Containers ready but Docker execution required.
* Runtime probe times out.
* Isolated spawn returns nonzero exit.
* Dispatch request carries stale expected revision.
* Duplicate idempotency key or in-flight dispatch repeats.
* Campaign dependency is failed, unavailable, blocked, waiting, or planning-only.
* UI loses server connection before dispatch or after an optimistic refresh.
* Container executable payload includes blocked raw field names.
* Runtime label, image label, hero label, or recovery note is too long or unsafe.

***

## 10. Dependencies

### Other Sessions

* Depends on: `phase19-session12-terminal-and-containers`, `phase20-session01-truthful-capability-baseline`, `phase20-session02-queue-terminal-execution`, `phase20-session04-campaign-executable-dispatch`, `phase20-session05-campaign-dag-recovery`
* Depended by: `phase20-session10-templates-and-channel-intake`, `phase20-session11-release-evidence-and-event-privacy`

***

## Next Steps

Run the `implement` workflow step to begin implementation.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://faction-os.gitbook.io/faction-os-docs/.spec_system/archive/sessions/phase20-session09-container-dispatch-decision/spec.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
