# Mode 5b, Chat-shell composition: the canonical parts

Script: `scripts/dev/audit-shell-composition.mjs` (repo-local), npm gates
`audit:shell-composition{,:strict,:all}`. Static AST walk over
`apps/**/*.html`, `playgrounds/**/*.html`, `catalog/page-shells/**/*.html`, no browser needed; pre-commit fast. Shares one script and one output
contract with the `<admin-shell>` census
([admin-shell-anatomy](admin-shell-anatomy.md)): the script's own `CHAT_PARTS`
array is the mechanical census; this file is the human review standard.
Canonical source: `packages/web-modules/chat/chat-shell/chat-shell.yaml`
(the behavioral contract) and `playgrounds/chat/app/chat.contents.html`
(the canonical rendered reference, cited by `apps/genui/PATTERNS.md`'s
chrome-decision table as chat-shell's canonical demo).

`gh#2909`/`apps/genui/PATTERNS.md:329-337` established that `apps/genui`
(gen-ui, factory-chat) is a real `<chat-shell>` consumer that a
`<admin-shell>`-only mode 5 sweep never scanned, this anatomy closes that
blind spot.

## The canonical parts

1. `<chat-shell provider="…" model="…" proxy-url="…">` outer.
2. `<chat-thread>` direct child, the message scroll surface. Required:
   without it there is nowhere for the host's rendering pipeline to append
   messages.
3. `<chat-thread> > <chat-empty>` as (typically first) child, the
   empty-state placeholder shown via the `[empty]` reflected attribute
   before any message exists.
4. `<chat-composer>` direct child, the input region.
5. `<chat-composer> > <chat-input-ui>` (or `<input-ui>`) inner child, the
   actual input; a composer with no primitive input inside has nothing to
   submit.
6. `<chat-header>` direct child, optional top chrome bar (name, status,
   actions). When present, expected to carry `[slot="name"]` and
   `[slot="status"]` (typically a `<chat-status>`), a header with neither
   is bare chrome with no identifying content.
7. `<chat-sidebar slot="leading"|"trailing">`, optional conversation-history
   or inspector rail.
8. No generic layout primitive (`<col-ui>`, `<row-ui>`, `<stack-ui>`) as a
   **direct child** of `<chat-shell>`, the shell's CSS lays out children by
   tag selector (`chat-thread`, `chat-composer`, etc.); a generic wrapper
   defeats that and the shell's `:has(chat-thread[streaming])` cross-cut
   styling.

## Severity mapping

- **critical**, `<chat-shell>` present but missing `<chat-thread>` or
  `<chat-composer>` (parts 2, 4). The shell can't render a usable
  conversation surface without both.
- **warning**, `<chat-composer>` has no inner `<chat-input-ui>`/`<input-ui>`
  (part 5); a `<chat-header>` present but missing both `[slot="name"]` and
  `[slot="status"]` content (part 6); a generic layout primitive
  (`col-ui`/`row-ui`/`stack-ui`) authored as a direct child (part 8).
- **info**, `<chat-thread>` missing its `<chat-empty>` first child (part 3;
  a thread pre-seeded with real messages legitimately skips this);
  `<chat-header>` absent entirely (part 6 is optional chrome);
  `<chat-sidebar>` absent (part 7, forward-looking per the yaml, chat is
  typically single-pane).

## What the script flags (mechanical subset)

| Symptom | Diagnosis |
|---|---|
| `<chat-shell>` with no `<chat-thread>` | critical, part 2 |
| `<chat-shell>` with no `<chat-composer>` | critical, part 4 |
| `<chat-composer>` with no `<chat-input-ui>`/`<input-ui>` child | warning, part 5 |
| `<chat-header>` present, no `[slot="name"]` and no `[slot="status"]`/`<chat-status>` | warning, part 6 |
| `<chat-shell>` direct child is `col-ui`/`row-ui`/`stack-ui` | warning, part 8 (legacy-generic-layout leak) |
| `<chat-thread>` with no `<chat-empty>` child | info, part 3 |

## Opt-out contract

Same annotation mechanism as admin-shell: `<chat-shell
data-shell-opt-out="reason">` downgrades every finding on that shell to
info and prints the reason for reviewers.

## Triage

- Canonical product surface (`apps/genui` chat/factory-chat pages,
  `playgrounds/chat/*`) → fix mandatory.
- A narrow single-feature playground isolating one chat behavior → fix
  optional; annotate the opt-out.
- Never point this audit at `packages/web-modules/chat/**/*.examples.html`
  or `packages/web-components/components/*/*.html` (single-primitive
  spotlights), the script's `isShowcaseDemo`/showcase-path exclusion
  already keeps those out of scope, same as admin-shell.
- `:strict` is the CI/publish posture; keep warn-only while iterating
  locally.

## Legacy shapes, never re-authored

`chat-shell.yaml`'s own description lists the ADR-0024-retired legacy
data-attribute shapes (`<section data-chat-messages>`, `<chat-input-ui
data-chat-input>`, `<empty-state-ui data-chat-empty>`, `<header
data-chat-name>`) as silently unrecognized, not merely deprecated. This
audit does not re-detect them (a separate concern from anatomy
completeness), `verify:no-legacy-shell-shapes` in `npm run check` already
covers that ground.
