Add Decisions and Workstreams reference docs with heading help wiring
- Remove residual constitution footnote from progress page header - Create src/docs/decisions.md: types, statuses, resolution history chart, filter bar, card anatomy, Decision Health KPI, escalation protocol - Create src/docs/workstreams.md: status distribution chart, filter bar, table columns, dependency graph, create/update patterns - Wire withDocHelp(h1) on Decisions and Workstreams pages pointing to new docs - Add both pages to Reference nav section in observablehq.config.js Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -10,6 +10,8 @@ export default {
|
||||
name: "Reference",
|
||||
pages: [
|
||||
{ name: "Live Data", path: "/docs/live-data" },
|
||||
{ name: "Workstreams", path: "/docs/workstreams" },
|
||||
{ name: "Decisions", path: "/docs/decisions" },
|
||||
{ name: "Decision Health", path: "/docs/decisions-kpi" },
|
||||
{ name: "Progress Log", path: "/docs/progress-log" },
|
||||
],
|
||||
|
||||
@@ -160,6 +160,9 @@ const _liveEl = html`<div class="live-indicator">
|
||||
</div>`;
|
||||
withDocHelp(_liveEl, "/docs/live-data");
|
||||
|
||||
const _h1 = document.querySelector("#observablehq-main h1");
|
||||
if (_h1) { _h1.style.position = "relative"; withDocHelp(_h1, "/docs/decisions"); }
|
||||
|
||||
// ── Inject into TOC sidebar: KPI first (prepend → bottom), live last (→ top) ─
|
||||
const _toc = document.querySelector("#observablehq-toc");
|
||||
if (_toc) {
|
||||
|
||||
138
state-hub/dashboard/src/docs/decisions.md
Normal file
138
state-hub/dashboard/src/docs/decisions.md
Normal file
@@ -0,0 +1,138 @@
|
||||
---
|
||||
title: Decisions — Reference
|
||||
---
|
||||
|
||||
# Decisions — Reference
|
||||
|
||||
The Decisions page tracks every choice that matters: things pending a verdict, things already resolved, and things that have been escalated for human approval before action can proceed.
|
||||
|
||||
---
|
||||
|
||||
## Decision types
|
||||
|
||||
| Type | Meaning |
|
||||
|---|---|
|
||||
| **pending** | A question or fork that still needs an answer — actively blocking or influencing work |
|
||||
| **made** | A resolved choice; kept for historical context and to explain why things are the way they are |
|
||||
|
||||
---
|
||||
|
||||
## Decision statuses
|
||||
|
||||
| Status | Border | Meaning |
|
||||
|---|---|---|
|
||||
| **open** | blue | Pending, no urgent flag |
|
||||
| **escalated** | amber | Requires human approval before any action (constitution §4) |
|
||||
| **resolved** | green | Decision has been made and recorded |
|
||||
| **superseded** | gray | Replaced by a newer decision |
|
||||
|
||||
Decisions are sorted by status (escalated → open → resolved → superseded), then by deadline (earliest first within the same status group).
|
||||
|
||||
---
|
||||
|
||||
## Resolution History chart
|
||||
|
||||
An area + step chart showing cumulative decisions over time. Each dot marks a period where at least one decision was recorded or resolved.
|
||||
|
||||
**Period selector** — choose the time window:
|
||||
|
||||
| Period | Bucket | Use for |
|
||||
|---|---|---|
|
||||
| day | hour | Today's activity |
|
||||
| week | day | Rolling 7 days |
|
||||
| month | week | Current calendar month |
|
||||
| quarter | month | Current quarter |
|
||||
| YTD | month | Year to date |
|
||||
| year | month | Rolling 12 months |
|
||||
| all | month | Full history |
|
||||
|
||||
The chart respects the active filter — changing type, status, or search narrows the data plotted.
|
||||
|
||||
---
|
||||
|
||||
## Filter bar
|
||||
|
||||
| Filter | Effect |
|
||||
|---|---|
|
||||
| **Type** | Show only `pending` or `made` decisions |
|
||||
| **Status** | Show one or more of open / escalated / resolved / superseded |
|
||||
| **Search** | Case-insensitive substring match on the decision title |
|
||||
|
||||
All filters are applied client-side on the last 500 decisions fetched from the API.
|
||||
|
||||
---
|
||||
|
||||
## Decision cards
|
||||
|
||||
Each card shows:
|
||||
|
||||
- **Type badge** — amber `pending` or indigo `made`
|
||||
- **Status badge** — colour-coded (see table above)
|
||||
- **Domain** — which of the six tracked domains this decision belongs to (if linked to a topic)
|
||||
- **Due date** — shown in red with ⚠ if the deadline has passed
|
||||
- **Age badge** — `open Xd` for unresolved decisions; `took Xd` for resolved ones. Turns amber when an open decision has been open longer than the current average resolution time.
|
||||
- **Created date** — when the decision was first recorded
|
||||
- **Title** — the decision question or statement
|
||||
- **Description / rationale** — first 200 characters, truncated with `…`
|
||||
- **Resolved by** — who resolved it and when (resolved decisions only)
|
||||
- **Escalation note** — amber panel explaining why human approval is required (escalated decisions only)
|
||||
|
||||
---
|
||||
|
||||
## Decision Health card
|
||||
|
||||
The **Decision Health** widget in the right margin shows two KPIs computed from the full (unfiltered) dataset:
|
||||
|
||||
| KPI | How it's calculated |
|
||||
|---|---|
|
||||
| **avg resolve** | Mean time from creation to resolution, computed over the last 5 resolved decisions |
|
||||
| **avg open age** | Mean age of all currently open or escalated decisions |
|
||||
|
||||
**Color coding for avg open age:**
|
||||
|
||||
| Color | Condition |
|
||||
|---|---|
|
||||
| black (inherit) | All open decisions younger than the avg resolve time |
|
||||
| amber | At least one open decision older than the avg resolve time |
|
||||
| red | Mean open age exceeds the avg resolve time |
|
||||
|
||||
---
|
||||
|
||||
## Escalation
|
||||
|
||||
Any `pending` decision whose title or rationale contains financial or legal keywords is automatically escalated by the API at creation time. Escalated decisions:
|
||||
|
||||
- Sort to the top of the list
|
||||
- Carry an amber escalation note explaining the reason
|
||||
- Trigger the warning box at the bottom of the page listing all escalated items
|
||||
- **Must be reviewed and approved by Bernd before any related action is taken (constitution §4)**
|
||||
|
||||
To clear an escalation, resolve the decision via `resolve_decision()` in the MCP server or the REST API.
|
||||
|
||||
---
|
||||
|
||||
## Adding decisions
|
||||
|
||||
Via MCP:
|
||||
|
||||
```
|
||||
record_decision(
|
||||
title = "Should we use Redis or Postgres for session storage?",
|
||||
decision_type = "pending",
|
||||
workstream_id = "<uuid>",
|
||||
rationale = "Postgres is already in the stack; Redis adds a dependency",
|
||||
deadline = "2026-03-01"
|
||||
)
|
||||
```
|
||||
|
||||
Via REST:
|
||||
|
||||
```bash
|
||||
curl -X POST http://127.0.0.1:8000/decisions/ \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"title": "…", "decision_type": "pending", "workstream_id": "<uuid>"}'
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
*Decisions are never deleted — only resolved or superseded (constitution §5).*
|
||||
110
state-hub/dashboard/src/docs/workstreams.md
Normal file
110
state-hub/dashboard/src/docs/workstreams.md
Normal file
@@ -0,0 +1,110 @@
|
||||
---
|
||||
title: Workstreams — Reference
|
||||
---
|
||||
|
||||
# Workstreams — Reference
|
||||
|
||||
A workstream is a bounded unit of work within a topic. It carries a status, an optional owner and due date, and belongs to exactly one of the six project domains. The Workstreams page gives you a filtered, visual overview of all active work and the dependency graph between workstreams.
|
||||
|
||||
---
|
||||
|
||||
## Status Distribution chart
|
||||
|
||||
A horizontal bar chart showing the count of workstreams in each status for the current filter selection. Updates immediately as filters change.
|
||||
|
||||
| Status | Meaning |
|
||||
|---|---|
|
||||
| **active** | Work in progress or ready to start |
|
||||
| **blocked** | Waiting on something outside the workstream — see Dependencies |
|
||||
| **completed** | Done |
|
||||
| **archived** | Closed without completion; no longer relevant |
|
||||
|
||||
---
|
||||
|
||||
## Filter bar
|
||||
|
||||
| Filter | Effect |
|
||||
|---|---|
|
||||
| **Domain** | Multi-select — show only workstreams from selected domains |
|
||||
| **Status** | Multi-select — show only workstreams with selected statuses |
|
||||
| **Owner** | Text substring match on the owner field (case-insensitive) |
|
||||
|
||||
Leaving a filter empty means "show all". All three filters combine with AND logic. Filters persist across polls — selections are not lost when the page refreshes live data.
|
||||
|
||||
The six domains are: `custodian`, `railiance`, `markitect`, `coulomb_social`, `personhood`, `foerster_capabilities`.
|
||||
|
||||
---
|
||||
|
||||
## All Workstreams table
|
||||
|
||||
| Column | Source |
|
||||
|---|---|
|
||||
| Title | Workstream title |
|
||||
| Domain | Derived from the parent topic |
|
||||
| Status | Current workstream status |
|
||||
| Owner | Assigned person (or `—` if unset) |
|
||||
| Due | Target completion date (or `—`) |
|
||||
| Updated | Last modification timestamp |
|
||||
|
||||
Up to 20 rows displayed; paginate for more.
|
||||
|
||||
---
|
||||
|
||||
## Dependencies
|
||||
|
||||
The Dependencies section shows workstreams that have at least one `depends_on` or `blocks` relationship. Each card displays:
|
||||
|
||||
- **Workstream title** and current status badge
|
||||
- **↳ depends on** — workstreams that must complete before this one can proceed
|
||||
- **⊳ blocks** — workstreams that are waiting on this one
|
||||
|
||||
Dependencies are created via the MCP server:
|
||||
|
||||
```
|
||||
create_dependency(
|
||||
from_workstream_id = "<uuid>", # the one that depends
|
||||
to_workstream_id = "<uuid>", # the prerequisite
|
||||
description = "needs auth before API can be built"
|
||||
)
|
||||
```
|
||||
|
||||
If no dependency edges exist for the current filter, the section shows an empty-state message.
|
||||
|
||||
---
|
||||
|
||||
## Creating workstreams
|
||||
|
||||
Via MCP:
|
||||
|
||||
```
|
||||
create_workstream(
|
||||
topic_id = "<uuid>",
|
||||
title = "Build user authentication",
|
||||
description = "JWT-based auth, refresh tokens, middleware",
|
||||
status = "active",
|
||||
owner = "Bernd",
|
||||
due_date = "2026-04-01"
|
||||
)
|
||||
```
|
||||
|
||||
Via REST:
|
||||
|
||||
```bash
|
||||
curl -X POST http://127.0.0.1:8000/workstreams/ \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"topic_id": "<uuid>", "title": "…", "status": "active"}'
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Updating workstream status
|
||||
|
||||
```
|
||||
update_workstream_status(workstream_id="<uuid>", status="completed")
|
||||
```
|
||||
|
||||
Valid transitions: `active` → `blocked` / `completed` / `archived`; `blocked` → `active`; `completed` → `archived`.
|
||||
|
||||
---
|
||||
|
||||
*Workstreams are never hard-deleted — use `archived` to close them without losing history.*
|
||||
@@ -30,8 +30,6 @@ const _ts = progState.ts;
|
||||
|
||||
# Progress Log
|
||||
|
||||
*Append-only per constitution §5 — no deletions.*
|
||||
|
||||
```js
|
||||
import {injectTocTop} from "./components/toc-sidebar.js";
|
||||
import {withDocHelp} from "./components/doc-overlay.js";
|
||||
|
||||
@@ -58,6 +58,9 @@ const _liveEl = html`<div class="live-indicator">
|
||||
</div>`;
|
||||
withDocHelp(_liveEl, "/docs/live-data");
|
||||
injectTocTop("live-indicator", _liveEl);
|
||||
|
||||
const _h1 = document.querySelector("#observablehq-main h1");
|
||||
if (_h1) { _h1.style.position = "relative"; withDocHelp(_h1, "/docs/workstreams"); }
|
||||
```
|
||||
|
||||
```js
|
||||
|
||||
Reference in New Issue
Block a user