Commit graph

8 commits

Author SHA1 Message Date
e56e63b1f5 dashboard: move Decision Health card into TOC sidebar column
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>
2026-02-26 13:29:34 +01:00
aab8bb1bbb dashboard: fix KPI sidebar to fixed top-right position
- `.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>
2026-02-26 12:07:49 +01:00
3212a5be93 dashboard: prominent KPI infobox, doc-overlay component, decisions reference page
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>
2026-02-26 11:48:47 +01:00
61c43af3a4 dashboard: decision age, KPI bar, and open-age health indicator
- 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>
2026-02-26 07:50:54 +01:00
02b2542a2a dashboard: cumulative decisions chart with flexible period selector
- 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>
2026-02-26 07:22:25 +01:00
a74bb9f732 Dashboard decisions: list view with MultiSelect filters
- 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>
2026-02-26 00:39:44 +01:00
34b1114a01 Live dashboard: replace data loaders with client-side polling
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>
2026-02-24 23:19:26 +01:00
0ea2788943 Add state-hub v0.1 — local-first state service for the Custodian
Implements the first live layer of the Custodian cognitive infrastructure:
PostgreSQL schema, FastAPI REST API, FastMCP stdio server, and Observable
Framework telemetry dashboard.

- state-hub/: full stack (docker-compose, FastAPI, Alembic, MCP server, dashboard)
- 5 DB tables: topics, workstreams, tasks, decisions, progress_events
- 11 MCP tools + 5 resources registered in .mcp.json
- Observable dashboard: Overview, Workstreams, Decisions, Progress pages
- CLAUDE.md: session protocol (get_state_summary / add_progress_event ritual)
- ~/.claude/CLAUDE.md: global cross-project reference to the hub
- scripts/pull_image.py: WSL2 TLS-resilient Docker image downloader

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-24 17:47:49 +01:00