ADR-209: Executive Briefing Generator Integration
Status: Accepted Date: 2026-02-17 Deciders: Hal Casteel (CTO) Extends: ADR-197 (Unified Web Publishing Component System)
Context
Problem
CODITECT projects require executive-level briefing dashboards that synthesize project data into actionable narratives for C-suite personas (CEO, CMO, CIO, CFO). The current Web Publishing Platform (WPP, ADR-197) provides rich markdown/JSX/Mermaid rendering with 8 reusable components and 28+ lazy-loaded dashboards, but lacks:
- AI-narrated content generation — dashboards display static data; there is no pipeline to generate contextual narratives from structured project data
- Interactive decision capture — no pattern for executives to record decisions within dashboards with state persistence across tab switches
- Data-driven dashboard assembly — dashboards are hand-authored JSX; there is no mechanism to generate dashboards from database queries + computed metrics
- Executive-specific UI primitives — components like progress rings, radar charts, status dots, and expandable cards with AI narratives are not in the shared component library
A prototype executive briefing system has been developed that demonstrates a complete 3-phase pipeline (query → compute → narrate → assemble) producing a 5-tab interactive dashboard from SQLite data. This ADR integrates that capability into the WPP as a general-purpose platform feature.
Scope
This ADR is a general CODITECT coditect-core platform solution. Any CODITECT project (product development, research, consulting, compliance) can generate executive briefings by:
- Populating a standardized SQLite schema with project data
- Running the Python orchestrator with project-specific configuration
- Receiving a fully-rendered JSX dashboard with AI narratives
Current WPP Architecture (ADR-197)
| Component | LOC | Purpose |
|---|---|---|
viewer.jsx | 528 | Hash-routed viewer with sidebar, search, presentation mode |
Sidebar.jsx | 144 | Navigation with toggle-all and collapse state |
MarkdownRenderer.jsx | 287 | unified/remark/rehype pipeline with Mermaid, KaTeX |
SearchPanel.jsx | 156 | Full-text search across dashboards |
ProjectSwitcher.jsx | 85 | Multi-project dropdown (ADR-170) |
PresentationMode.jsx | 120 | Fullscreen dashboard cycling |
Breadcrumbs.jsx | 52 | Navigation path display |
TableOfContents.jsx | 89 | Auto-generated heading navigation |
| 28 dashboards | ~15K | Lazy-loaded JSX dashboards across categories |
New Executive Briefing Components
| Layer | Component | LOC | Purpose |
|---|---|---|---|
| Spec | executive-briefing-generator.md | 1,225 | System prompt defining 3-phase pipeline |
| Spec | component-data-contracts.md | 457 | TypeScript interfaces for 12 data structures |
| Spec | methodology-references.md | 297 | 24 verified citations with confidence levels |
| Impl | generate-briefing.py | 961 | Python orchestrator (query→compute→narrate→assemble) |
| Impl | init-database.sql | 520 | Schema DDL (22 tables + 5 views) |
| Impl | seed-*.sql | 440 | Representative seed data |
| Output | *-csuite-briefing.jsx | 1,976 | 5-tab interactive dashboard (gold standard) |
| Output | executive-briefing-data.json | 867 | Computed data manifest |
Component Diff Analysis
75% reusability — the majority of new code addresses gaps in the existing WPP:
| Existing WPP | New Briefing | Overlap | Gap |
|---|---|---|---|
| Sidebar with collapse | Sidebar with forwardRef, toggleAll | 80% | toggleAll already merged (J.18) |
| MarkdownRenderer | N/A (JSX-only) | 0% | No markdown in briefings |
| SearchPanel | N/A | 0% | Briefings use tab navigation |
| Hash routing | Tab routing | 30% | Different navigation paradigm |
| CSS variables | Inline T object tokens | 10% | Token unification needed |
| N/A | ProgressRing | 0% | New primitive needed |
| N/A | RadarChart | 0% | New primitive needed |
| N/A | StatusDot | 0% | New primitive needed |
| N/A | ExpandableCard | 0% | New pattern needed |
| N/A | Decision capture | 0% | New interaction pattern |
| N/A | SQLite data layer | 0% | New data pipeline |
| N/A | AI narrative gen | 0% | New LLM integration |
6 Extractable UI Primitives
| Primitive | Atomic Level | Existing in ADR-085? | Description |
|---|---|---|---|
StatusDot | Atom | No | Colored dot (green/amber/red) with optional pulse |
Badge | Atom | No | Status label (HIGH/MEDIUM/LOW) with semantic color |
SectionTitle | Atom | No | Heading with icon, persona tag, and accent color |
ExpandableCard | Molecule | No | Click-to-expand card with animation + AI narrative |
ProgressRing | Molecule | No | SVG circular progress with percentage label |
RadarChart | Molecule | No | SVG radar/spider chart (6 axes) with overlay |
Decision
D1: Executive Briefing as WPP Dashboard Type
Executive briefings integrate as a new dashboard category in the WPP, not as a separate application.
Implementation:
- New dashboard category:
executive-briefing/alongsideplanning/,system/,tracking/ - Lazy-loaded via existing WPP
React.lazy()pattern - Accessible through sidebar navigation and hash routing
- Compatible with search, presentation mode, and multi-project switching
Rationale: Maintaining a single viewer with consistent UX across all dashboard types eliminates tool sprawl. Executives access briefings through the same interface as technical dashboards.
D2: UI Primitive Extraction into Atomic Design Hierarchy (ADR-085)
The 6 UI primitives are extracted into the shared component library following ADR-085's Atomic Design levels:
Atoms (3 new):
StatusDot— semantic status indicator (green/amber/red)Badge— labeled status chip with urgency colorsSectionTitle— icon + heading + persona tag
Molecules (3 new):
ExpandableCard— container with click-to-expand behavior, animation, and slot for AI narrativeProgressRing— SVG circular progress visualizationRadarChart— SVG spider chart with current/target overlays
Location: tools/web-publishing-platform/components/atoms/ and components/molecules/
Interface contract: Each primitive accepts a TypeScript props interface documented in component-data-contracts.md.
D3: Design Token Unification with design-system.json (ADR-091)
The executive briefing's inline T object is reconciled with design-system.json as the single source of truth:
| T Object Token | design-system.json Mapping | Resolution |
|---|---|---|
T.navy (#0B1629) | colors.semantic.surface-dark | Map to semantic token |
T.navyLight (#2D3F5E) | colors.semantic.surface-dark-light | Add to semantic palette |
T.teal (#0D9488) | colors.brand.primary | Already exists as primary |
T.gold (#C8A951) | colors.semantic.highlight | Add highlight token |
T.red (#DC2626) | colors.semantic.danger | Already exists |
T.amber (#D97706) | colors.semantic.warning | Already exists |
T.green (#059669) | colors.semantic.success | Already exists |
T.*Ghost (8-10% opacity) | colors.semantic.*-ghost | Add ghost variants |
T.headerFrom/To (#4B6DA0/#5B80B2) | colors.gradient.header | Add gradient tokens |
T.font (Outfit) | typography.fontFamily.display | Already exists |
T.fontMono (JetBrains Mono) | typography.fontFamily.mono | Already exists |
Tab accent colors are registered as colors.dashboard.tab.*:
- summary: teal (#0D9488)
- accomplishments: blue (#3B82F6)
- decisions: amber (#F59E0B)
- investment: emerald (#10B981)
- methodology: indigo (#6366F1)
Runtime: The generated JSX consumes tokens from a T constant that is auto-generated from design-system.json at build time. Claude.ai artifact mode uses inline values since no build step is available.
D4: SQLite + Python Orchestrator Data Layer
Project data flows through a standardized SQLite schema into a Python orchestrator:
Project Data Sources → SQLite (22 tables + 5 views) → Python Orchestrator → JSX Dashboard
├── 15 SQL queries
├── 8 metric computations
├── ~50 narrative generations (LLM)
└── JSX template assembly
Schema (22 tables):
- Core:
projects,sessions,session_events,tracks,sprints,tasks - Decisions:
decisions,decision_options,decision_dependencies - Analysis:
risks,competitors,cost_inputs,market_data - Architecture:
architecture_axes,gtm_readiness - Financial:
revenue_milestones,unit_economics - Documentation:
methodology_sections,references_table - Caching:
narrative_cache,briefing_snapshots
Views (5):
v_sprint_summary— aggregated sprint progressv_velocity_metrics— traditional vs. agentic velocityv_decision_status— decision completion statev_risk_summary— computed risk scoresv_track_progress— per-track completion percentage
Why SQLite:
- Zero infrastructure — runs alongside Claude Code with no server
- Single-file portable — entire project database in one
.dbfile - WAL mode — concurrent reads during briefing generation
- Standard SQL — migration path to PostgreSQL when needed
D5: Narrative Caching with SHA-256 Hash
AI-generated narratives are cached in a narrative_cache table keyed by (component_id, data_hash):
CREATE TABLE narrative_cache (
component_id TEXT NOT NULL,
data_hash TEXT NOT NULL,
narrative TEXT NOT NULL,
model TEXT DEFAULT 'claude-sonnet-4-5-20250929',
generated_at TEXT NOT NULL,
tokens_used INTEGER,
PRIMARY KEY (component_id, data_hash)
);
Cache hit: If the SHA-256 hash of the input data matches a cached entry, the stored narrative is reused. This saves ~60% of LLM tokens on repeat generation when data hasn't changed.
Cache invalidation: When any underlying data changes, the hash changes, triggering regeneration for that component only. Unchanged components retain their cached narratives.
Token budget: Full generation ~50 narrative calls at ~200 tokens each = ~10,000 tokens. With caching, typical regeneration = ~4,000 tokens.
D6: Interactive Decision Capture Pattern
Executive briefings include an interactive decision capture system where C-suite personas can record decisions directly in the dashboard:
State architecture:
// Lifted to parent component — persists across tab switches
const [decisions, setDecisions] = useState({}); // {[decisionIdx]: optionIdx}
const selectDecision = (idx, optIdx) => {
setDecisions(prev => {
const next = {...prev};
if (next[idx] === optIdx) delete next[idx]; // toggle off
else next[idx] = optIdx; // select
return next;
});
};
Tab badge: Shows {decided}/{total} count. Gold when in progress, green when all decided.
Clipboard export: Decisions can be exported as formatted text for meeting minutes.
Key constraint: stopPropagation on option click prevents card expand/collapse from firing when recording a decision.
D7: Single-File JSX Constraint for Artifact Compatibility
Generated dashboards MUST be deployable in two modes:
| Mode | Constraint | Use Case |
|---|---|---|
| Claude.ai Artifact | Single file, single default export, no imports except React hooks + lucide-react + recharts | Executive sharing via Claude conversations |
| WPP Integration | Standard React component, can import shared primitives | Integrated dashboard viewer |
Resolution: The Python orchestrator generates both formats:
executive-briefing-standalone.jsx— self-contained artifact with inline primitives and tokensexecutive-briefing.jsx— WPP-integrated version importing shared components fromcomponents/
Template switching: A --mode standalone|integrated flag on the orchestrator controls which template is used.
D8: 3-Phase Pipeline Architecture
The briefing generation follows a deterministic 3-phase pipeline:
Phase 1: Query + Compute (0 LLM tokens, <1s)
- Execute 15 SQL queries against project SQLite database
- Compute 8 derived metrics (velocity ratios, cost projections, unit economics, risk scores)
- Produce structured JSON data for all 12 component data contracts
Phase 2: Narrate (~10K LLM tokens, ~30s)
- For each component, check narrative cache
- Generate AI narratives only for changed components
- Each narrative prompt includes component context, persona, and tone guidelines
- Narratives explain significance, not just describe data
Phase 3: Assemble (0 LLM tokens, <1s)
- Populate JSX template with computed data + generated narratives
- Apply design tokens from resolved
Tobject - Output final JSX file + JSON data manifest
Alignment with ADR-199: This mirrors the two-phase token optimization pattern — Phase 1 is the "Node.js metrics" equivalent (zero AI tokens), Phase 2 is the "AI narrative" layer.
D9: Component Data Contract Standard
Each JSX component consumes a formally defined JSON structure. The 12 data contracts serve as the interface between the Python orchestrator and the JSX template:
| Contract | Type | Fields | AI-Generated Fields |
|---|---|---|---|
| SESSION_METRICS | Array[6] | label, value, sub, narrative | narrative |
| QUADRANTS | Array[4] | title, icon, persona, metric, body | body |
| GTM_READINESS | Array[N] | area, status, detail, narrative | narrative |
| ARCH_MATURITY | Array[N] | axis, current, target, narrative | narrative |
| ACCOMPLISHMENTS | Array[5] | rank, title, metric, roiNote, detail | roiNote, detail |
| SESSION_FLOW | Array[N] | time, label, color, narrative | narrative |
| DECISIONS | Array[N] | title, urgency, options, context, stakes | context, stakes |
| DECISION_DEPS | Array[N] | from, to, note, narrative | narrative |
| RISK_MATRIX | Array[N] | name, likelihood, impact, narrative | narrative |
| SPRINT_DATA | Array[N] | id, tasks, done, label, narrative | narrative |
| INVESTMENT_DATA | Object | buildCost, humanEquivalent, unitEconomics | per-metric narratives |
| COMPETITORS | Array[N] | name, fit, strength, weakness, narrative | narrative |
TypeScript interfaces are defined in component-data-contracts.md and serve as the canonical reference for both the Python orchestrator's output and the JSX template's input.
D10: Lazy-Loaded Tab Architecture
The 5-tab executive briefing uses independent expand state per tab to prevent state leakage:
| Tab | State Type | Expand Keys |
|---|---|---|
| Executive Summary | Set<number|string> | "metric-0", "progress", "sprint", "gtm-0".. |
| Accomplishments | Set<number|string> + flowIdx: number|null | Card indices + single-select timeline |
| Decisions | Set<number|string> | "dec-0", "risk-0", "dep-0" |
| Investment | Set<string> | "ue-0", "rev-0", "comp-0" |
| Methodology | Set<number> | Section indices 0-14 |
Why per-tab state: Each tab renders independently. Expanding a card on one tab does not affect other tabs. The single exception is decisions state which is lifted to the parent because it persists across the Decisions tab and the Executive Summary tab badge.
D11: Multi-Project Executive Briefing Support
Executive briefings support the multi-project architecture from ADR-170:
- Each project maintains its own SQLite database
- The
project-manifest.json(ADR-170) lists available projects with their briefing database paths - The Python orchestrator accepts
--project <id>to target a specific project - Generated JSX files follow the naming convention:
executive-briefing-{project-id}.jsx - The WPP ProjectSwitcher (ADR-197 D11) handles switching between project briefings
D12: Landing Page First Architecture
The executive briefing landing page (executive-landing.jsx) serves as the default home view for the WPP dashboard viewer, replacing the category grid:
- Default view:
DEFAULT_BRANDING.homeDashboardis set to"dashboards-executive-executive-landing"inviewer.jsx - Single data source: The landing page consumes exclusively from
project-dashboard-data.json(Node.js generator) - Zero duplication: Enforced by build-time validator (
validate-dedup.py) andRESERVED_KEYSboundary inBriefingValidator - Progressive disclosure: Hero metrics above the fold, expandable track narratives and risk/recommendation cards below
- Actionable insights: Every element answers "What should I do about this?" — risks link to tracks, recommendations include effort estimates
- Less is more: Target <30 data points on initial view, detail on demand via expandable sections
- Multi-project compatible: Accepts
projectJsonUrlprop from ProjectSwitcher (J.18.4), falls back to default JSON path
Design principles documented in internal/analysis/executive-briefing/landing-page-design-direction-2026-02-17.md.
Consequences
Positive
- Any CODITECT project can generate executive briefings by populating the SQLite schema
- 6 new shared UI primitives (3 atoms + 3 molecules) enrich the component library for all dashboards
- AI narratives transform raw metrics into persona-targeted insights
- Narrative caching reduces LLM costs by ~60% on repeat generations
- Dual-mode output (standalone + integrated) maximizes distribution flexibility
- Design token unification brings all dashboards under
design-system.jsongovernance
Negative
- Python dependency — the orchestrator requires Python 3.10+ with
anthropicSDK (already available in CODITECT venvs) - Claude API dependency — narrative generation requires API key (mitigated by
--dry-runmode with placeholder narratives) - SQLite schema migration — adding new tables to existing project databases requires migration scripts
Neutral
- Single-file JSX constraint limits component reuse within artifact mode but ensures broad distribution
- 22-table schema is comprehensive but well-documented; seed scripts serve as templates
- Existing WPP dashboards are unaffected — executive briefings are additive
Implementation
File Locations
tools/web-publishing-platform/
├── components/
│ ├── atoms/
│ │ ├── StatusDot.jsx # NEW (D2)
│ │ ├── Badge.jsx # NEW (D2)
│ │ └── SectionTitle.jsx # NEW (D2)
│ ├── molecules/
│ │ ├── ExpandableCard.jsx # NEW (D2)
│ │ ├── ProgressRing.jsx # NEW (D2)
│ │ └── RadarChart.jsx # NEW (D2)
│ └── ... (existing)
├── dashboards/
│ └── executive-briefing/ # NEW category (D1)
│ └── executive-briefing.jsx
├── scripts/
│ ├── generate-briefing.py # Python orchestrator (D4, D8)
│ ├── init-database.sql # Schema DDL (D4)
│ └── seed-template.sql # Template seed data
├── specs/
│ ├── executive-briefing-generator.md # System prompt (D8)
│ ├── component-data-contracts.md # Interface specs (D9)
│ └── methodology-references.md # Citation database
└── design-tokens/
└── executive-briefing-tokens.json # Token mapping (D3)
Migration Path
- Phase 1: Extract UI primitives into
components/atoms/andcomponents/molecules/ - Phase 2: Register tokens in
design-system.jsonand generateTobject mapping - Phase 3: Integrate Python orchestrator into
scripts/with CLI interface - Phase 4: Create
dashboards/executive-briefing/category in WPP - Phase 5: Add executive briefing to scaffold templates for new projects
Track Tasks
Implementation tracked in TRACK-J Section J.19 (Executive Briefing Generator Integration).
Alternatives Considered
A1: Standalone Executive Briefing Application
Build a separate React app specifically for executive briefings.
Rejected: Creates tool sprawl, duplicates WPP infrastructure, and fragments the user experience. Executives should use the same viewer as technical teams.
A2: Pure LLM Generation (No Python Orchestrator)
Have the LLM generate the entire dashboard from raw project data.
Rejected: Non-reproducible (same data produces different dashboards), expensive (full JSX generation = ~50K tokens per run), and un-auditable (no traceable computation path for derived metrics).
A3: External BI Tool Integration (Metabase, Grafana)
Use an existing BI tool for executive dashboards.
Rejected: Adds infrastructure dependency, doesn't support AI narratives, and breaks the single-viewer UX. The WPP approach requires zero additional infrastructure.
A4: Inline T Object (No Token Unification)
Keep the executive briefing's T object as-is without mapping to design-system.json.
Rejected: Creates a parallel token system that drifts from the platform standard. Unified tokens ensure visual consistency when briefing components appear alongside other dashboards.
References
- ADR-197: Unified Web Publishing Component System
- ADR-085: Atomic Design Component Library (component hierarchy)
- ADR-091: Unified Design System Architecture (design-system.json SSOT)
- ADR-163: Agentic Trajectory Dashboard Architecture (precedent pattern)
- ADR-170: Multi-Project Executive Dashboard (multi-project support)
- ADR-199: Two-Phase Project Status Token Optimization (pipeline pattern)
component-data-contracts.md— TypeScript interface specificationsexecutive-briefing-generator.md— System prompt specification