docs(workplans): write files for 4 pre-ADR-001 orphan workstreams
Resolves all orphan-workstream FAIL findings from validate_repo_adr.
The custodian domain now passes 47/47 checks (0 warn, 0 fail).
Files written:
CUST-WP-0001 custodian-agent-runtime (2 tasks: 1 done, 1 todo)
CUST-WP-0002 contribution-tracking-sbom (15 tasks, v0.5 scope
reductions annotated inline)
CUST-WP-0003 whi-kpi-card (9 tasks)
CUST-WP-0004 ep-td-tracking (10 tasks: 4 done, 6 todo)
All files cross-reference state_hub_workstream_id and
state_hub_task_id for future sync reconciliation.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
186
workplans/CUST-WP-0003-whi-kpi-card.md
Normal file
186
workplans/CUST-WP-0003-whi-kpi-card.md
Normal file
@@ -0,0 +1,186 @@
|
||||
---
|
||||
id: CUST-WP-0003
|
||||
type: workplan
|
||||
title: "State Hub v0.4 — Workstream Health Index (WHI) KPI Card"
|
||||
domain: custodian
|
||||
status: active
|
||||
owner: custodian
|
||||
topic_slug: custodian
|
||||
state_hub_workstream_id: 9cc32158-2f5c-4ef6-9713-aacce4623d5e
|
||||
created: "2026-02-26"
|
||||
updated: "2026-02-28"
|
||||
---
|
||||
|
||||
# State Hub v0.4 — Workstream Health Index (WHI) KPI Card
|
||||
|
||||
## Summary
|
||||
|
||||
Implement the Workstream Health Index (WHI) — a composite structural-health
|
||||
KPI — as a live card injected into the TOC sidebar of the Workstreams
|
||||
dashboard page. All six metrics are computable client-side from data
|
||||
already fetched by `workstreams.md`; no API or schema changes required.
|
||||
|
||||
## Context
|
||||
|
||||
The WHI formula and metric definitions are specified in
|
||||
`state-hub/dashboard/src/docs/workstream-kpi.md`. This workplan covers
|
||||
only the implementation of that spec as running dashboard code.
|
||||
|
||||
The six base metrics:
|
||||
- **DD** — Dependency Density: edge count / open workstream count
|
||||
- **BR** — Blocked Ratio: blocked workstreams / open count
|
||||
- **SPR** — Single Point of Risk: max inbound edges / open count
|
||||
- **PEP** — Progression Enablement Proportion: ready-to-start workstreams
|
||||
- **CDDR** — Cross-Domain Dependency Ratio: cross-domain edges / total edges
|
||||
- **CPI** — Cycle Penalty Indicator: 1 if any cycle detected, 0 otherwise
|
||||
|
||||
WHI formula: `0.30*(1-DDnorm) + 0.25*(1-BR) + 0.15*(1-SPR) + 0.20*PEP + 0.10*(1-CDDR)`
|
||||
CPI penalty: `WHI = WHI * 0.5` if CPI=1.
|
||||
|
||||
## Tasks
|
||||
|
||||
### P1 — Verify dependency edge fields in open_workstreams
|
||||
|
||||
```task
|
||||
id: CUST-WP-0003-T01
|
||||
state_hub_task_id: 243646e0-b77a-41e7-ac51-82c5828e63d2
|
||||
status: todo
|
||||
priority: high
|
||||
```
|
||||
|
||||
Confirm that `summary.open_workstreams[].depends_on[]` and `blocks[]`
|
||||
each carry `workstream_id`, `workstream_slug`, and `workstream_title`.
|
||||
Verify these fields are sufficient to build a complete directed dependency
|
||||
graph client-side without additional API calls. (Already verified during
|
||||
workplan design — open_workstreams is the confirmed data source.)
|
||||
|
||||
### P2.1 — Build directed dependency graph from openWs + completedIds
|
||||
|
||||
```task
|
||||
id: CUST-WP-0003-T02
|
||||
state_hub_task_id: 6dbef71f-d2d7-44ee-abb8-279dbaeec505
|
||||
status: todo
|
||||
priority: high
|
||||
```
|
||||
|
||||
In `workstreams.md`: derive `completedIds = new Set` of IDs of workstreams
|
||||
with status completed. Build an adjacency list: for each entry in openWs,
|
||||
map workstream id → array of `depends_on[].workstream_id`. Build reverse
|
||||
map (prerequisite id → list of dependent ids) for SPR computation. Also
|
||||
build `idToDomain` map from `data[]` for CDDR.
|
||||
|
||||
### P2.2 — Implement DFS cycle detection (CPI)
|
||||
|
||||
```task
|
||||
id: CUST-WP-0003-T03
|
||||
state_hub_task_id: f0d5c107-6029-4ad0-af00-645d35ce7db0
|
||||
status: todo
|
||||
priority: high
|
||||
```
|
||||
|
||||
Implement a DFS-based topological sort over the dependency adjacency list.
|
||||
Detect back edges using visited / inStack colour sets. Return `CPI = 1`
|
||||
if any cycle found, `CPI = 0` otherwise. Only nodes in openWs participate
|
||||
(completed/archived workstreams excluded). Edge case: isolated nodes (no
|
||||
deps, no dependents) are valid and never form cycles.
|
||||
|
||||
### P2.3 — Compute DD, BR, SPR, PEP, CDDR
|
||||
|
||||
```task
|
||||
id: CUST-WP-0003-T04
|
||||
state_hub_task_id: 6da60567-cc46-4a32-9855-b07bafe2faeb
|
||||
status: todo
|
||||
priority: high
|
||||
```
|
||||
|
||||
Using the graph from P2.1:
|
||||
- `DD`: totalEdges / openCount, where totalEdges = openWs.flatMap(w=>w.depends_on).length
|
||||
- `BR`: openWs.filter(w=>w.status==="blocked").length / openCount
|
||||
- `SPR`: max inbound-edge count across prerequisite workstreams in openWs / openCount
|
||||
- `PEP`: openWs.filter(w=>active && all depends_on are in completedIds).length / openCount
|
||||
- `CDDR`: crossDomainEdges / totalEdges (edge with different domain endpoints); 0 if no edges
|
||||
|
||||
### P2.4 — WHI formula: normalisation + CPI penalty
|
||||
|
||||
```task
|
||||
id: CUST-WP-0003-T05
|
||||
state_hub_task_id: 29b2dbbd-5d60-49b6-ae84-3dbf22167df7
|
||||
status: todo
|
||||
priority: high
|
||||
```
|
||||
|
||||
Implement the weighted aggregation:
|
||||
```
|
||||
DDnorm = min(1, DD / 1.0) // DD_critical = 1.0
|
||||
WHI = 0.30*(1-DDnorm) + 0.25*(1-BR) + 0.15*(1-SPR) + 0.20*PEP + 0.10*(1-CDDR)
|
||||
if CPI === 1: WHI = WHI * 0.5
|
||||
```
|
||||
Clamp to [0, 1]. Return `{whi, dd, ddNorm, br, spr, pep, cddr, cpi, openCount, edgeCount}`.
|
||||
Factor into `computeWHI(nodes, edges, idToDomain)` for reuse in per-domain scope.
|
||||
|
||||
### P2.5 — Per-domain WHI breakdown
|
||||
|
||||
```task
|
||||
id: CUST-WP-0003-T06
|
||||
state_hub_task_id: 8ce5ef74-5eb8-4259-9b11-dde13bf84a89
|
||||
status: todo
|
||||
priority: medium
|
||||
```
|
||||
|
||||
For each domain present in openWs, compute a domain-scoped WHI:
|
||||
- `domainNodes = openWs.filter(w => idToDomain[w.id] === domain)`
|
||||
- `domainEdges = domainNodes.flatMap(w => w.depends_on.filter(d => idToDomain[d.workstream_id] === domain))`
|
||||
- `result = computeWHI(domainNodes, domainEdges, idToDomain)`
|
||||
|
||||
Store as `[{domain, whi, br, pep, cpi, openCount}]`. Skip domains with
|
||||
`openCount === 0`.
|
||||
|
||||
### P3 — WHI KPI card UI
|
||||
|
||||
```task
|
||||
id: CUST-WP-0003-T07
|
||||
state_hub_task_id: 91efba5c-3be2-4bfe-b5ef-1b261e9423f2
|
||||
status: todo
|
||||
priority: high
|
||||
```
|
||||
|
||||
Build the `_whiBox` element in `workstreams.md` (mirrors `_kpiBox` in
|
||||
`decisions.md`):
|
||||
- Card title: "Workstream Health"
|
||||
- Main WHI value with health state label: GREEN ≥ 0.75 / ORANGE ≥ 0.50 / RED < 0.50
|
||||
- Sub-metric rows for DD, BR, SPR, PEP, CDDR with individual warning colours
|
||||
- Cycle alert row (red ⚠) when CPI=1
|
||||
- Domain breakdown: compact rows with domain name + coloured score
|
||||
- Empty state if openCount=0 or no edges
|
||||
|
||||
Inject via `injectTocTop("whi-kpi-box", _whiBox)`. Wire
|
||||
`withDocHelp(_whiBox, "/docs/workstream-health-index")`.
|
||||
|
||||
### P4.1 — Create src/docs/workstream-health-index.md
|
||||
|
||||
```task
|
||||
id: CUST-WP-0003-T08
|
||||
state_hub_task_id: 4c898472-e4ae-49a2-b6cd-7aa1a3c7604a
|
||||
status: todo
|
||||
priority: medium
|
||||
```
|
||||
|
||||
Reference documentation for the WHI KPI card. Cover: purpose, all six
|
||||
metrics (formula + interpretation), WHI aggregation formula with CPI
|
||||
penalty, DD normalisation, health state thresholds, domain breakdown,
|
||||
cycle detection, and how to improve a poor score. Update
|
||||
`workstream-kpi.md` to link to this doc.
|
||||
|
||||
### P4.2 — Wire withDocHelp and add to Reference nav
|
||||
|
||||
```task
|
||||
id: CUST-WP-0003-T09
|
||||
state_hub_task_id: 20976663-7ac9-4909-8029-a479190f52ff
|
||||
status: todo
|
||||
priority: low
|
||||
```
|
||||
|
||||
Confirm `withDocHelp(_whiBox, "/docs/workstream-health-index")` is wired
|
||||
(from P3). Add `{ name: "Workstream Health", path: "/docs/workstream-health-index" }`
|
||||
to the Reference pages array in `observablehq.config.js`. Verify
|
||||
Reference nav renders correctly in `npm run dev`.
|
||||
Reference in New Issue
Block a user