# Agent input observability Slice 1 — request

**Goal:** Make the actual task instructions immediately readable in every factory attempt detail while honestly identifying inherited session context and stating that attachment accounting was not recorded.

**Context:** The two factory attempt-detail surfaces currently lead with collapsed `System prompt` and `User prompt` blocks. The work request is buried inside known rendered factory messages under `### prompt`, so the owner sees wrapper prose such as “Implement the work described in `prompt`” instead of the work. Existing attempt records are sufficient for a task-first bridge, but they do not carry typed attachment accounting or authoritative retry lineage. This slice must expose what can be proven from current web data and label every gap.

**Files:**

- Create `apps/web/src/components/factory/AgentInputPanel.tsx` — shared owner-facing task, current-message, inherited-context, exact-message, and attachment-coverage presentation.
- Create `apps/web/src/components/factory/AgentInputPanel.test.tsx` — focused parser and rendering contract tests.
- Modify `apps/web/src/components/factory/FactoryStepDrawer.tsx` — replace its independent prompt presentation with the shared panel and accept run-scoped attempts.
- Modify `apps/web/src/components/factory/FactoryStepDrawer.test.tsx` — prove task-first and ambiguity behavior through this drawer.
- Modify `apps/web/src/components/factory/FactoryRunContent.tsx` — pass the selected attempt plus the containing run’s attempts to the step drawer.
- Modify `apps/web/src/components/factory/FactoryTraceTables.tsx` — replace its independent prompt presentation with the shared panel; thread the containing run’s attempts through attempt table/detail selection.
- Modify `apps/web/src/components/factory/FactoryTraceTables.test.tsx` — prove task-first and prior-turn behavior through the table drawer.
- Modify `apps/web/src/components/factory/FactoryTimeline.tsx` — provide full run-scoped attempts when a phase-filtered table opens attempt details.
- Modify other existing factory table callers only where their type contract must pass the already-held run attempt array; do not change their visible behavior.

**Contract:**

- Shared component:
  - `AgentInputPanel({ attempt, runAttempts }: { attempt: FactoryAgentAttemptView; runAttempts: FactoryAgentAttemptView[] }): JSX.Element`
- Pure presentation derivation exported for focused tests:
  - `deriveAgentInputPresentation(attempt: FactoryAgentAttemptView, runAttempts: FactoryAgentAttemptView[]): AgentInputPresentation`
- `AgentInputPresentation` contains:
  - `taskText: string`
  - `taskSource: 'known_template' | 'exact_current_message' | 'prior_turn'`
  - `currentMessage: string | null`
  - `priorTurns: FactoryAgentAttemptView[]`
  - `ambiguity: string | null`
- Known initial template titles are exactly `Build Task`, `Plan Task`, `Scout Task`, `Review Task`, and `Document Task`.
- A known-template task is the exact Markdown body between the unique line `### prompt` and the unique following line `### previous_envelope`, after removing only the separator newline belonging to those headings. Do not trim or normalize task content.
- Parsing succeeds only when the message has one recognized top-level task title, exactly one prompt marker, exactly one later terminal marker, and valid ordering. Repeated/missing markers or an unrecognized title are ambiguous.
- Prior turns are attempts from the supplied `runAttempts` only when all are true: same non-null `sessionId`, strictly before the selected attempt, and deterministically ordered by valid `startedAt`, then `attemptId`. Never group null session IDs.
- Recover a correction’s stable task only from the nearest strictly prior attempt with the same `phaseId` whose known-template extraction succeeds uniquely. Missing/equal/invalid time ordering, null phase identity, or no unique prior extraction is ambiguous.
- Existing `FactoryAttemptTable` callers must be able to pass the containing run attempt array separately from the rows currently visible in that table. A phase-filtered table must not lose earlier run context.

**Behavior:**

- Render `Task instructions` before exact model messages. For a uniquely extracted task, render the complete Markdown task open by default with no `Read more` action required.
- Label extracted content `Derived from the exact user message` so Slice 1 does not imply a first-class producer field exists.
- For later same-session turns, show `Inherited context` with the prior recorded turn count and one row per prior turn using its agent name and absolute start timestamp; omit an unavailable value rather than inventing it. Do not expose attempt IDs on the owner-facing row and do not infer whether a correction was a parse retry or a check retry.
- If a correction has one eligible prior task, render that stable task and show the exact current correction separately under `This dispatch`.
- On any ambiguity, render the complete exact current user message as the task-facing content and show this literal owner-facing statement: `The stable task or inherited context could not be separated from this message.` Never infer that task or inheritance was absent.
- Always show this literal Slice 1 coverage statement: `Attachment accounting was not recorded for this attempt.` Do not display zero attachments.
- Keep exact forensic messages available as collapsed `System message` and `User message`; do not duplicate the old independent prompt blocks outside the shared panel.
- If `userPrompt` is null, show `Task instructions were not recorded for this attempt.` Exact system-message evidence remains available when present.
- Existing identity, command, tool-call, diff, and gate evidence remains unchanged.
- Compose current Astryx/deck-ui controls already used on this page. Do not create a generic primitive, add raw visual values, or port unrelated factory controls.

**Out of scope:**

- Producer, tracer, schema, collector, provider, prompt-template, or request-resolution changes.
- Typed attachment inventory, snapshots, image/text attachment previews, retention, quotas, or artifact-route changes.
- Claims that historical attempts have complete input or model-context capture.
- Guessing retry causes or grouping attempts across runs, phases, or null session IDs.
- Any implementation work for the later packet-capture slice.

**Acceptance:**

- Run focused tests:
  - `pnpm --filter web test -- src/components/factory/AgentInputPanel.test.tsx src/components/factory/FactoryStepDrawer.test.tsx src/components/factory/FactoryTraceTables.test.tsx`
  - Expected: PASS for exact known-template extraction, byte-preserving task body, unknown/repeated/misordered marker fallback, null prompt, current correction, nearest eligible prior task, cross-run input exclusion by caller scope, null-session exclusion, same-session prior turns, phase mismatch, equal/invalid timestamp ambiguity, and both drawer integrations.
- Run static checks after focused tests:
  - `pnpm --filter web typecheck`
  - Expected: zero Astro/TypeScript errors.
  - `git diff --check`
  - Expected: exit 0.
- Run the broad web build once after focused/static checks pass:
  - `pnpm --filter web build`
  - Expected: exit 0 with no new warnings attributable to this change.
- Submit through the repository ship path; do not hand-push or hand-merge.
- Installed owner-flow proof from `origin/main`:
  1. enter `/factory` through normal navigation;
  2. open a real run and an initial attempt;
  3. verify the full authored work request is visible under `Task instructions` without opening `User message`;
  4. open a later same-session correction when available and verify the stable task plus current message are distinct, or use an authoritative real fixture through the supported runtime seam;
  5. verify `Attachment accounting was not recorded for this attempt.` is visible and no zero-attachment claim appears;
  6. open exact messages and compare them with the existing trace record.
- Completion evidence is the installed `/factory` interaction above, not route liveness or component existence.
