Add internal-meeting-brief — first real skill in the Brief family

Real-tested 2026-09-21 against the APTA 2026 booth 09-16 planning meeting
(recap mode). Includes:
- skills/internal-meeting-brief/SKILL.md — full workflow: topic resolution,
  continuity manifest, agenda/recap branching, attendee capture/normalization,
  scoped data pulls, synthesis, render, archive.
- assets/brief-components.css — canonical shared component library (cards,
  flow, layerbox/filepill, unitgrid, quad, compare, specbar, actions+status
  pills, note callouts x4 tones, colvis/ring), MPM tokens from CW-028,
  required light/dark toggle, print rules.
- references/section-structure.md — fixed-vs-dynamic section contract,
  explicitly marked unproven beyond one real run.

Known limitation: Plaud MCP connector is currently non-functional (local
server via Claude Desktop, times out). Brief was built from a manually
uploaded transcript, not a live pull.

Five more skills planned, not started: vendor-partner-brief,
status-update-brief, five-whys-brief, kickoff-brief, development-brief.
Full design history in CW-027's Concept.md (Drive).
This commit is contained in:
Bryan Gilliom (via Claude)
2026-09-22 17:37:52 +00:00
parent 1fd2f91762
commit c98daed984
5 changed files with 488 additions and 2 deletions
+142
View File
@@ -0,0 +1,142 @@
---
name: internal-meeting-brief
description: Generate an MPM-branded internal meeting briefing document as a single-file HTML artifact — covers internal planning sessions, executive leadership meetings, and project team meetings (e.g. APTA planning, status reviews, internal design discussions). Produces agenda-mode (pre-meeting prep, pulling the previous meeting's transcript) or recap-mode (post-meeting summary, pulling the current meeting's transcript). Always use this skill when the user asks to "brief this meeting," "recap the meeting," "prep me for [meeting]," "write up the [meeting name] meeting," or names an internal MPM meeting/topic and wants it documented or summarized — even if they don't say "internal-meeting-brief" by name or don't mention CoWork/Brief explicitly. Part of the CW-027 Brief plugin family; see git.mpm.to/mpm/brief.
---
# internal-meeting-brief
Generates a single self-contained HTML briefing document for an internal MPM meeting,
built on Brief's shared MPM-branded component library. Does the work of assembling the
brief itself — pulling from connected tools — rather than requiring the person to
hand-supply meeting notes.
Read `assets/brief-components.css` and `references/section-structure.md` before
generating any brief. The CSS is the canonical, only source of Brief's visual
language — never re-derive it inline. The section-structure doc is the fixed-vs-dynamic
contract for what this skill's output actually contains.
## Prerequisites
This skill uses, but does not own, the following connected tools — confirm they're
reachable before starting, and degrade gracefully (see Hard Rules) if one isn't:
- **Plaud** — meeting transcripts (recap: current meeting; agenda: previous meeting)
- **Odoo** (MCP) — linked Project/tasks, Sales/Purchase Orders, Knowledge Base,
Helpdesk tickets
- **Google Workspace** (MCP) — Gmail, Google Chat, Drive, Sheets
- **Google Drive** — the topic's continuity folder (`_topic-state.md` + brief history)
If any of these fail outright (not just "returns nothing," but errors or times out),
say so plainly in the generated brief's Notes & Flags section rather than silently
omitting that source. See "Known limitation" below for a real, currently-open example.
## Workflow
### 1. Resolve the topic
Every brief belongs to a project/topic, not just a meeting instance. Ask which
topic/project this meeting is about if it isn't obvious from context. Search Google
Drive for an existing topic folder (naming pattern: `<Topic Name> — Meeting Briefs`)
before creating a new one. If an Odoo Project already exists for this topic and has an
attached Drive folder, use that folder instead of creating a parallel one.
### 2. Read (or create) the continuity manifest
Open `_topic-state.md` in the topic folder. If it doesn't exist, this is the topic's
first run — create it with the schema below, and expect a fuller interview in the
following steps since there's no history to draw on yet.
`_topic-state.md` schema: linked Odoo Project ID / SO / PO, linked Google Chat Space,
Plaud recording ID/pattern, last-meeting date, running open-items/decisions ledger,
attendee list, learned spreadsheet task-registry column mapping (if this topic uses one
— see step 5), brief-history log (date/type/mode/link), and a "Related documents"
table for cross-referencing other MPM document types about the same real-world topic
(pre-mortems, BAI build docs, etc. — see CW-027 Concept.md's rewrap-vs-harvest
principle; don't merge their content into this ledger, just reference them).
### 3. Determine mode: Agenda or Recap
Agenda mode (pre-meeting prep) pulls the *previous* meeting's transcript and any
updates since. Recap mode (post-meeting) pulls the *current* meeting's transcript. Ask
if not specified by the request.
### 4. Capture and normalize attendees
- **First run for this topic:** ask who's attending / who attended.
- **Recurring topic:** pre-fill from the manifest's last attendee list and ask "same as
last time, or any changes?" — not a blank-slate interview.
- **Recap mode with a Plaud transcript available:** prefer *actual* attendance from the
transcript's speaker attribution over the pre-meeting expected list — someone who
showed up unexpectedly and spoke shouldn't be treated as absent.
- **Normalize into two groups:**
- Internal MPM attendees — record by name for the brief; no further resolution
needed (no external allowlist implications for this brief type).
- External attendees (rare for this brief type, but possible) — cross-reference
against Odoo contacts to resolve/confirm email addresses rather than trusting raw
input.
- **If Plaud's diarization didn't resolve a speaker to a name:** render the literal
transcript label ("Speaker 1," "Speaker 3"). Do not guess a name from context, even
when a guess feels obvious. Flag unresolved speakers in the Notes & Flags section.
### 5. Pull data, scoped to what this brief type actually needs
Not a monolithic "pull everything" — internal-meeting-brief's real needs, based on the
first run, are:
- Plaud transcript (per mode, above) — the primary source
- Gmail / Google Chat: updates since the manifest's last-meeting date, scoped by
project/topic keywords, never a blanket search
- Odoo Project tasks, if a linked project exists (expect this to be sparse or absent —
PM-tool adoption is inconsistent; fall back to a spreadsheet task registry if the
topic uses one, learned via a one-time interview on first use and stored in the
manifest, never assumed to follow a universal schema)
Sales/Purchase Orders and Helpdesk ticket review are not typically relevant to this
brief type (they matter more to vendor-partner-brief and status-update-brief) — don't
pull them by default.
### 6. Synthesize into the section structure
Follow `references/section-structure.md` exactly: six fixed sections in order, dynamic
sections only where the meeting's actual content has a structure that calls for one.
Real, verified content over generic summary — carry forward specific facts (names,
dates, exact technical decisions), not vague paraphrase.
### 7. Render
Single self-contained HTML file. Include `assets/brief-components.css` inline (don't
link out to it — the brief must survive as a standalone file). Include: sticky jump-nav,
a working light/dark toggle (`data-theme` attribute, default light), and the
`@media print` rules from the shared CSS (forces light, hides nav/toggle, avoids
awkward page breaks).
### 8. Archive
Save the generated HTML into the topic's Drive folder. Update `_topic-state.md`: append
to the brief-history log, update the running open-items/decisions ledger (carry forward
anything still open from this run), update the attendee list, update last-meeting date.
### 9. Present
Hand the file to the person. Don't silently skip presenting it even if archived — the
person needs to actually see and review it, not just trust it happened.
## Hard rules
- **Never fabricate.** No matching Plaud recording, no linked Odoo data, an empty
Gmail/Chat scan — say so plainly in Notes & Flags. A brief with visible gaps is
correct; a brief with invented content to fill them is not.
- **Bounded queries only.** Gmail/Chat scans are scoped by project keyword + date
window from the manifest. Never an open-ended search.
- **No live publishing yet.** This skill produces a local file only. Hosting/publishing
(a shareable link, external access control) is CW-029 (Brief Server) — deliberately
separate, deliberately not built yet. Don't attempt to stand up delivery
infrastructure as part of running this skill.
## Known limitation (open as of 2026-09-21)
The Plaud MCP connector has failed on every attempt so far — first appeared to be an
account/workspace mismatch, but a later attempt timed out with a message indicating it
runs as a **local server via the Claude Desktop app**, not a cloud connector. Confirmed
still broken after Bryan verified the connector's own settings looked correct. Treat
Plaud as unreliable until this is resolved — the one real brief produced so far
(2026-09-16 APTA meeting) used a manually uploaded transcript as a workaround, not a
live pull. Don't assume this is fixed without testing it again.
## Provenance
Component library, tokens, and this workflow were derived from two real test runs
(2026-09-21): a recap brief for a real APTA 2026 booth planning meeting, and a
rewrap of an unrelated pre-mortem document to validate the component system against a
different content shape. See CW-027's Concept.md (Drive) for full design history and
the five other planned skills in this family (vendor-partner-brief, status-update-brief,
five-whys-brief, kickoff-brief, development-brief) — none built yet.
@@ -0,0 +1,236 @@
/* ==========================================================================
Brief — shared component library (CW-027)
Canonical CSS for all Brief skills. Do not fork per-brief — edit here.
Design tokens sourced from CW-028 (@jason/ui-kit, src/lib/tokens.json).
Light theme is default; dark theme via [data-theme="dark"]; print always
forces light regardless of the on-screen toggle state.
Re-pull tokens from git.alwisp.com/jason/ui-kit at each Brief release in
case Jason has updated them — see CW-027 Concept.md, "Design system
source of truth."
========================================================================== */
:root{
--bg:#FAF8F4; --surface:#FFFFFF; --surface-2:#F4F0EA; --border:#DED8D1;
--text:#272326; --muted:#665F62;
--brand:#79640E; --brand-bright:#665308; --brand-dark:#5C4B07; --brand-fg:#FFFFFF;
--success:#217A4A; --success-fg:#FFFFFF;
--warning:#7A5B00; --warning-fg:#FFFFFF;
--danger:#A42D20; --danger-fg:#FFFFFF;
--info:#366B99; --info-fg:#FFFFFF;
--radius-sm:6px; --radius-md:10px; --radius-lg:14px; --radius-xl:20px;
--shadow-sm:0 1px 2px 0 rgb(20 16 18 / .10);
--shadow-md:0 4px 12px -2px rgb(20 16 18 / .14), 0 2px 4px -2px rgb(20 16 18 / .10);
--shadow-lg:0 12px 32px -8px rgb(20 16 18 / .20), 0 4px 8px -4px rgb(20 16 18 / .12);
--shadow-glow:0 0 0 1px rgb(121 100 14 / .18), 0 8px 28px -6px rgb(121 100 14 / .20);
--ease-out:cubic-bezier(0.22,1,0.36,1);
--dur-fast:120ms; --dur-base:180ms; --dur-slow:320ms;
}
[data-theme="dark"]{
--bg:#232022; --surface:#2B282A; --surface-2:#333031; --border:#3A3638;
--text:#F5F1EC; --muted:#A99F97;
--brand:#DCBB4F; --brand-bright:#F5CD15; --brand-dark:#998643; --brand-fg:#232022;
--success:#62C890; --success-fg:#232022;
--warning:#E4C85B; --warning-fg:#232022;
--danger:#D76F4A; --danger-fg:#232022;
--info:#76A9D6; --info-fg:#232022;
--shadow-glow:0 0 0 1px rgb(220 187 79 / .20), 0 8px 28px -6px rgb(220 187 79 / .28);
}
/* Fonts: production should self-host from CW-001's assets/fonts/*.ttf.
This @import is a portability fallback for previewing outside that
pipeline — swap it for local <link>/@font-face at publish time. */
@import url('https://fonts.googleapis.com/css2?family=Montserrat:wght@600;700&family=Open+Sans:wght@400;600&family=JetBrains+Mono:wght@500&display=swap');
*{box-sizing:border-box;}
body{
margin:0; background:var(--bg); color:var(--text);
font-family:"Open Sans",system-ui,sans-serif; line-height:1.55;
transition:background var(--dur-base) var(--ease-out), color var(--dur-base) var(--ease-out);
}
h1,h2,h3,h4{font-family:"Montserrat",system-ui,sans-serif;}
code,.mono{font-family:"JetBrains Mono",ui-monospace,monospace;}
/* ---- Header ---- */
header{
background:linear-gradient(135deg, var(--brand-dark), var(--brand));
color:#fff; padding:32px 6vw 26px; position:relative;
}
[data-theme="dark"] header{background:linear-gradient(135deg,#3a2f08,var(--brand-dark));}
header .wordmark{
display:inline-flex; align-items:center; gap:8px; font-family:"Montserrat";
font-weight:700; font-size:15px; letter-spacing:1px; opacity:.9; margin-bottom:10px;
}
header .wordmark .dot{width:8px; height:8px; border-radius:50%; background:#fff;}
header .eyebrow{font-size:12.5px; letter-spacing:2px; text-transform:uppercase; opacity:.8;}
header h1{margin:8px 0 4px; font-size:26px; font-weight:700; max-width:860px;}
header .meta{margin-top:12px; font-size:13px; opacity:.9; display:flex; flex-wrap:wrap; gap:18px;}
header .meta b{font-weight:600;}
.theme-toggle{
position:absolute; top:28px; right:6vw; background:rgba(255,255,255,.16);
border:1px solid rgba(255,255,255,.35); color:#fff; border-radius:999px;
padding:7px 14px; font-size:12.5px; font-weight:600; cursor:pointer;
transition:background var(--dur-fast) var(--ease-out);
}
.theme-toggle:hover{background:rgba(255,255,255,.28);}
/* ---- Sticky jump-nav ---- */
nav.toc{
background:var(--surface); border-bottom:1px solid var(--border);
padding:10px 6vw; display:flex; flex-wrap:wrap; gap:6px 16px;
position:sticky; top:0; z-index:50; font-size:12.5px;
}
nav.toc a{color:var(--brand); text-decoration:none; white-space:nowrap; font-weight:600;}
nav.toc a:hover{text-decoration:underline;}
/* ---- Layout & section rhythm ---- */
main{padding:26px 6vw 60px; max-width:1180px; margin:0 auto;}
section{margin-bottom:42px;}
section > .sechead{
display:flex; align-items:baseline; gap:10px; margin-bottom:14px;
border-bottom:3px solid var(--brand); padding-bottom:8px;
}
.secnum{
background:var(--brand); color:var(--brand-fg); font-weight:700; font-size:14px;
width:28px; height:28px; border-radius:var(--radius-sm); display:flex;
align-items:center; justify-content:center; flex-shrink:0;
}
.sechead h2{margin:0; font-size:19px; color:var(--text);}
.sechead .sub{font-size:12px; font-weight:400; color:var(--muted); margin-left:4px;}
.sec-note{font-size:13px; color:var(--muted); margin:8px 0 14px; max-width:75ch;}
/* ---- Cards (c2/c3/c4/c5 densities) ---- */
.cards{display:grid; gap:14px;}
.cards.c2{grid-template-columns:repeat(2,1fr);}
.cards.c3{grid-template-columns:repeat(3,1fr);}
.cards.c4{grid-template-columns:repeat(4,1fr);}
.cards.c5{grid-template-columns:repeat(5,1fr);}
@media(max-width:900px){.cards.c3,.cards.c4,.cards.c5{grid-template-columns:1fr 1fr;}}
@media(max-width:600px){.cards.c2,.cards.c3,.cards.c4,.cards.c5{grid-template-columns:1fr;}}
.card{
background:var(--surface); border:1px solid var(--border); border-radius:var(--radius-md);
padding:16px; box-shadow:var(--shadow-sm);
transition:box-shadow var(--dur-base) var(--ease-out), transform var(--dur-base) var(--ease-out);
}
.card:hover{box-shadow:var(--shadow-md); transform:translateY(-1px);}
.card h3{margin:0 0 6px; font-size:14.5px; color:var(--text);}
.card p{margin:6px 0; font-size:13px; color:var(--muted);}
.icon{
width:36px; height:36px; border-radius:var(--radius-sm); display:flex;
align-items:center; justify-content:center; color:#fff; font-size:17px;
font-weight:700; margin-bottom:8px;
}
.sensorgrid .card{text-align:center;}
.sensorgrid .icon{margin:0 auto 8px;}
/* ---- Flow (sequential process) ---- */
.flow{display:flex; align-items:stretch; gap:10px; flex-wrap:wrap;}
.flow .step{flex:1; min-width:160px;}
.flow .arrow{align-self:center; font-size:20px; color:var(--muted); padding:0 2px;}
/* ---- Layerbox + filepill (tiered component grouping) ---- */
.layerbox{border-radius:var(--radius-lg); padding:16px 18px; margin-bottom:12px; border:2px solid var(--border);}
.layer-base{background:color-mix(in srgb, var(--info) 8%, var(--surface)); border-color:var(--info);}
.layer-ext{background:color-mix(in srgb, var(--warning) 10%, var(--surface)); border-style:dashed; border-color:var(--warning);}
.layerbox .tag{
display:inline-block; font-size:10.5px; font-weight:700; letter-spacing:.5px;
padding:2px 9px; border-radius:999px; color:#fff; margin-bottom:8px;
}
.tag-base{background:var(--info);} .tag-ext{background:var(--warning); color:var(--text);}
.filepill{
display:inline-flex; flex-direction:column; background:var(--surface); border:1px solid var(--border);
border-radius:var(--radius-sm); padding:8px 12px; margin:4px 8px 4px 0; font-size:12.5px; min-width:160px;
}
.filepill b{font-size:13px; color:var(--text);}
.filepill span{color:var(--muted);}
/* ---- Unitgrid (spec/comparison matrix) ---- */
table.unitgrid{border-collapse:collapse; width:100%; margin-top:10px; font-size:12.5px;}
table.unitgrid th, table.unitgrid td{border:1px solid var(--border); padding:8px 10px; text-align:center;}
table.unitgrid th{background:var(--text); color:var(--bg); font-weight:600;}
table.unitgrid td.yes{color:var(--success); font-weight:700;}
table.unitgrid td.no{color:var(--muted);}
table.unitgrid td:first-child{text-align:left; font-weight:600;}
/* ---- Quad (2x2 flagship callouts) ---- */
.quad{display:grid; grid-template-columns:1fr 1fr; gap:14px;}
@media(max-width:700px){.quad{grid-template-columns:1fr;}}
.quadcard{
border-radius:var(--radius-md); padding:14px 16px; background:var(--surface);
border:1px solid var(--border); border-left-width:5px; border-left-style:solid;
}
.q-1{border-left-color:var(--info);}
.q-2{border-left-color:var(--warning);}
.q-3{border-left-color:var(--danger);}
.q-4{border-left-color:var(--success);}
.quadcard h4{margin:0 0 6px; font-size:13.5px; color:var(--text);}
.quadcard p{font-size:12.5px; margin:4px 0; color:var(--muted);}
/* ---- Compare (two-column contrast) ---- */
.compare{display:grid; grid-template-columns:1fr 1fr; gap:16px;}
@media(max-width:700px){.compare{grid-template-columns:1fr;}}
.compare .col{border-radius:var(--radius-md); padding:14px 16px; border:1px solid var(--border);}
.col-a{background:color-mix(in srgb, var(--info) 8%, var(--surface));}
.col-b{background:color-mix(in srgb, var(--brand) 8%, var(--surface));}
.compare h3{margin-top:0; font-size:14px;}
.compare ul{margin:8px 0 0; padding-left:18px; font-size:12.5px; color:var(--muted);}
.compare li{margin-bottom:8px;}
/* ---- Specbar (stat cards) ---- */
.specbar{display:flex; flex-wrap:wrap; gap:14px;}
.spec{flex:1; min-width:160px; background:var(--surface); border:1px solid var(--border); border-radius:var(--radius-md); padding:14px;}
.spec .val{font-size:22px; font-weight:700; color:var(--brand); font-family:"Montserrat";}
.spec .lbl{font-size:11.5px; color:var(--muted); margin-top:2px;}
/* ---- Actions table + status pills ---- */
table.actions{border-collapse:collapse; width:100%; font-size:12.5px;}
table.actions th{background:var(--text); color:var(--bg); padding:8px 10px; text-align:left; font-weight:600;}
table.actions td{padding:9px 10px; border-bottom:1px solid var(--border); vertical-align:top; color:var(--text);}
table.actions tr:nth-child(even) td{background:var(--surface-2);}
.status{display:inline-block; font-size:10.5px; font-weight:700; padding:2px 10px; border-radius:999px; white-space:nowrap;}
.status.info{background:var(--info); color:var(--info-fg);}
.status.warn{background:var(--warning); color:var(--warning-fg);}
.status.danger{background:var(--danger); color:var(--danger-fg);}
.status.success{background:var(--success); color:var(--success-fg);}
.status.muted{background:var(--muted); color:var(--surface);}
/* ---- Note callouts (4 semantic tones) ---- */
.note{border-radius:var(--radius-sm); padding:12px 16px; font-size:13px; border-left:4px solid; margin-bottom:10px;}
.note.info{background:color-mix(in srgb, var(--info) 10%, var(--surface)); border-color:var(--info);}
.note.warn{background:color-mix(in srgb, var(--warning) 12%, var(--surface)); border-color:var(--warning);}
.note.danger{background:color-mix(in srgb, var(--danger) 10%, var(--surface)); border-color:var(--danger);}
.note.success{background:color-mix(in srgb, var(--success) 10%, var(--surface)); border-color:var(--success);}
.note b{color:var(--text);}
/* ---- Colvis / conic-gradient ring (space/percentage allocation) ---- */
.colvis{display:flex; gap:16px; flex-wrap:wrap; align-items:stretch;}
.colvis .colcard{flex:1; min-width:230px; background:var(--surface); border:1px solid var(--border); border-radius:var(--radius-md); padding:16px; text-align:center;}
.colvis .ring{
width:110px; height:110px; border-radius:50%; margin:0 auto 10px; position:relative;
display:flex; align-items:center; justify-content:center; font-weight:700; color:var(--text); font-size:12.5px;
}
.ring-main{background:conic-gradient(var(--brand) 0 35%, var(--info) 35% 65%, var(--warning) 65% 100%);}
.ring-main::after{content:""; position:absolute; width:68px; height:68px; background:var(--surface); border-radius:50%;}
.colvis .ring span{position:relative; z-index:2;}
.legend{display:flex; flex-wrap:wrap; gap:8px; justify-content:center; font-size:11px; margin-top:6px; color:var(--muted);}
.legend .dot{display:inline-block; width:9px; height:9px; border-radius:50%; margin-right:4px;}
/* ---- Footer ---- */
footer{padding:22px 6vw; color:var(--muted); font-size:11.5px; text-align:center; border-top:1px solid var(--border); margin-top:20px;}
/* ==========================================================================
PRINT — always light, no chrome, avoid awkward breaks.
PDF generation at publish time should render this media state.
========================================================================== */
@media print{
.theme-toggle, nav.toc{display:none !important;}
body{background:#FAF8F4 !important; color:#272326 !important;}
header{background:#79640E !important; -webkit-print-color-adjust:exact; print-color-adjust:exact;}
.card, .quadcard, .layerbox, .filepill, table.unitgrid, table.actions, .note, .colcard, .spec{
break-inside:avoid;
}
section{break-inside:avoid-page;}
a{color:inherit; text-decoration:none;}
}
@@ -0,0 +1,63 @@
# internal-meeting-brief — section structure
Derived from the first real run (2026-09-21, APTA 2026 Booth 09-16 recap) and made
explicit here so every future brief has the same skeleton instead of reinventing its
structure per meeting. This is the contract — read it before generating a brief.
## Always present (fixed, in this order)
1. **Header** — title (meeting subject, not the raw Plaud filename), meeting date +
duration, prepared date, source (transcript / manual notes), mode (Agenda/Recap).
2. **Attendees** — one card per attendee. Internal MPM people resolved by name where
possible. If Plaud's speaker diarization didn't resolve a name, render the literal
transcript label ("Speaker 1," "Speaker 3") — never guess a name. Follow with a
`note.info` flagging any unresolved speakers explicitly, so it's visible, not buried.
3. **Topics Covered** — a `cards` grid, one card per distinct subject actually
discussed. Card count and grid density (c2/c3/c4) follow the number of real topics —
don't pad to hit a round number, don't force unrelated topics into one card to save
space.
4. **Key Decisions** (recap) or **Discussion Plan** (agenda) — decisions actually made
(recap) or points to be raised (agenda). Use `quad` when there are 3-5 distinct,
roughly parallel decisions; use plain prose or a `note` when there's only one or two,
since forcing a single decision into a quad grid wastes space and implies false
parallelism.
5. **Open Items** — an `actions` table with status pills. Every action item needs an
owner field even if the honest value is "Unassigned" — never leave the column blank,
since a blank reads as "forgotten to track" rather than "no owner yet."
6. **Notes & Flags** — one `note` per genuinely separate concern: data-source
limitations encountered (a failed pull, a missing transcript), naming/identity
uncertainty, anything that needed a judgment call worth surfacing rather than
silently resolving. This section exists specifically so the never-fabricate rule has
somewhere to put its flags, visibly, not as a footnote.
## Present only when content genuinely calls for it (dynamic)
A dynamic section is content that has a **specific internal structure** the fixed
sections above would flatten into an unreadable wall of text or an over-long table row.
Add one only when the meeting's actual content has this shape — never as decoration,
never because a template "should" have variety.
| If the content is... | Use... | Real example |
|---|---|---|
| A sequential, ordered process (3+ steps, each depending on the last) | `flow` | Anti-vandalism 3-tier escalation (09-16 meeting) |
| A named component/system with distinct sub-parts worth breaking out | `layerbox` + `filepill` | (not yet exercised on a real internal-meeting-brief; seen in development-brief-flavored source material) |
| A genuine two-sided contrast (us/them, before/after, keep/avoid) | `compare` | (not yet exercised on internal-meeting-brief; used in vendor-partner-style source material) |
| A spec/BOM-style matrix with yes/no or multi-column comparison | `unitgrid` | (not yet exercised) |
| A handful of headline numbers worth calling out at a glance | `specbar` | (not yet exercised on internal-meeting-brief) |
**Rule of thumb:** if you're reaching for a dynamic section and can't point to the
specific part of the meeting that has this shape, don't add it. The fixed six sections
above should carry ordinary meeting content on their own. Dynamic sections are earned
by unusual content structure, not added for visual variety.
## What's still unproven
This contract is based on exactly one real run. It hasn't been tested against:
- Agenda mode (only recap mode has run for real)
- A meeting with genuinely no clear "topics" (a single-subject deep-dive)
- A meeting needing more than one dynamic section
- A recurring topic's second brief (pre-fill/delta-confirm behavior for attendees,
per CW-027 Concept.md, hasn't been exercised — the 09-16 brief was a topic's first
run, full interview by necessity)
Revise this file after the second real run rather than treating it as settled.