Assign a stable id to the KPI element so the previous instance can be
found and removed before the fresh one is prepended to the TOC sidebar.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Inject the KPI box into #observablehq-toc (the framework's right-column
aside) instead of position:fixed. The TOC column already doesn't scroll,
so no CSS tricks are needed. Falls back to a float:right inline block if
the TOC element is absent.
- Remove .kpi-sidebar-outer and its fixed positioning
- Remove min-width/max-width from .kpi-infobox; add margin-bottom to
separate it from the TOC links below
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- `.kpi-sidebar-outer` is now `position: fixed; top: 3.75rem; right: 1.5rem;`
so the Decision Health box stays visible while scrolling
- Re-adds the live indicator as a standalone cell (was accidentally dropped
when the combined `decisions-header` flex layout was removed)
- CSS: replaces `.decisions-header` block with `.kpi-sidebar-outer`;
`.live-indicator` is now standalone (text-align right, margin-bottom)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
KPI infobox
- Replace slim kpi-bar with a boxed card (border, shadow, 195–240px) floating
right in a flex header alongside the live indicator
- Rows: avg resolve time (last ≤5 resolved) + avg open age (all open)
- avg open age colored via CSS var --oc: red/orange/black per threshold
- "no open decisions" shown as muted italic when queue is empty
doc-overlay component (src/components/doc-overlay.js)
- withDocHelp(element, docPath) — adds absolute-positioned ? button
that is invisible until the parent is hovered; click opens overlay
- Overlay: fixed backdrop + animated box with iframe; closes on Esc,
backdrop click, or the close button
- CSS injected once via style tag (STYLE_ID guard, same pattern as MultiSelect)
? buttons wired up in decisions.md
- KPI infobox → /docs/decisions-kpi
- Cumulative chart (wrapped in position:relative div) → /docs/decisions-kpi
- Filter & List section header → /docs/decisions-kpi
Reference page (src/docs/decisions-kpi.md)
- Standalone Observable Framework page at /docs/decisions-kpi
- Documents: KPI card (avg resolve, avg open age, color thresholds),
Resolution History chart (cumulative, period→resolution mapping, filter
interaction, timestamp logic), Filter & List (type/status/search, card
age badge, escalation)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- KPI bar top-right: avg resolution time (last ≤5 resolved decisions)
and avg open age with count; replaces old live-bar with kpi-bar row
- Color logic for avg-open-age KPI:
red — mean open age > avg resolve time
orange — any single open decision exceeds avg resolve time
black — all open decisions younger than avg resolve time
- Decision cards: age badge in header showing "open Xd/h/w" for
open/escalated or "took X" for resolved/superseded; orange when an
open decision has aged past the avg resolve time baseline
- fmtDuration() helper: compact duration formatting (m/h/d/w/mo)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Replace static per-month bar chart with cumulative step-area chart
- Period selector: day / week / month / quarter / YTD / year / all
- Time resolution adapts to period:
day → hours, week → days, month → weeks,
quarter/YTD/year/all → months
- Chart respects the type/status/search filter (uses filtered, not data)
- Chart and period selector appear before the filter form and list
- Use Generators.input() to decouple filter form creation from its
display position; display(_filtersForm) renders it below the chart
- Dots on chart mark buckets where decisions occurred; tip shows delta
- "all" period derives start from earliest decision in filtered set
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Replace Pending/Made tab + Inputs.table with MultiSelect filters and
a proper list view
- Filters: Type (pending/made), Status (open/escalated/resolved/superseded),
title text search — all stable across polls (no data dependency)
- Each decision renders as a compact card: left border coloured by status
(blue=open, amber=escalated, green=resolved, gray=superseded), type and
status badges, domain context, deadline (red+overdue warning if past),
full title, description/rationale snippet, resolved-by attribution
- Decisions sorted: escalated → open → resolved → superseded, then by
deadline ascending within each group
- Fetch now includes topics alongside decisions for domain name join
- Escalation warning box and velocity chart retained
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
CORS: add CORSMiddleware to FastAPI for localhost:3000 so browser fetch
works across ports without errors.
All four pages now use async generator cells that call the API directly
and re-yield every 15 s — no data loader cache, no manual cache clearing.
Each page shows a live status bar (● green/red · last updated time).
Offline state shows the `make api` hint inline.
index.md: add "Registered Projects" section — polls
/progress/?event_type=milestone&limit=500 and filters for
"Project registered with State Hub:" events; shows project name,
domain, path, and registration timestamp.
workstreams.md: fix broken domain column — now fetches /workstreams/
and /topics/ in parallel and joins on topic_id client-side.
Previously the domain column showed "unknown" for all rows because
WorkstreamRead schema doesn't include domain.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>