diff --git a/dashboard/observablehq.config.js b/dashboard/observablehq.config.js
index c675b98..e30abbe 100644
--- a/dashboard/observablehq.config.js
+++ b/dashboard/observablehq.config.js
@@ -54,7 +54,7 @@ export default {
pages: [
{ name: "Repository DoI", path: "/policy/repo-doi" },
{ name: "Service DoM", path: "/policy/service-dom" },
- { name: "Workstream DoD", path: "/policy/workstream-dod" },
+ { name: "Workplan DoD", path: "/policy/workstream-dod" },
],
},
{
@@ -69,7 +69,7 @@ export default {
],
},
{
- name: "Workstreams",
+ name: "Workplans",
path: "/workstreams",
collapsible: true,
open: false,
@@ -120,9 +120,9 @@ export default {
{ name: "TPSC — GDPR Maturity", path: "/docs/gdpr-maturity" },
{ name: "Technical Debt", path: "/docs/debt" },
{ name: "Todo", path: "/docs/todo" },
- { name: "Workstream Health", path: "/docs/workstream-health-index" },
- { name: "Workstream Lifecycle", path: "/docs/workstream-lifecycle" },
- { name: "Workstreams", path: "/docs/workstreams" },
+ { name: "Workplan Health", path: "/docs/workstream-health-index" },
+ { name: "Workplan Lifecycle", path: "/docs/workstream-lifecycle" },
+ { name: "Workplans", path: "/docs/workstreams" },
{ name: "Suggestions", path: "/docs/suggestions" },
{ name: "WSJF Triage", path: "/docs/wsjf-triage" },
],
diff --git a/dashboard/src/components/entity-modal.js b/dashboard/src/components/entity-modal.js
index ef3f26f..12da4fc 100644
--- a/dashboard/src/components/entity-modal.js
+++ b/dashboard/src/components/entity-modal.js
@@ -3,9 +3,9 @@
*
* Usage:
* import {openEntityModal} from "./components/entity-modal.js";
- * row.addEventListener("click", () => openEntityModal(entity, "workstream"));
+ * row.addEventListener("click", () => openEntityModal(entity, "workplan"));
*
- * Supported types: "workstream" | "task" | "ep" | "td"
+ * Supported types: "workplan" | "task" | "ep" | "td"
*/
const _STYLE_ID = "entity-modal-styles";
@@ -216,7 +216,7 @@ function _buildBody(entity, type) {
return _field(label, v);
};
- if (type === "workstream") {
+ if (type === "workplan") {
els.push(
bf("Status", entity.status, _STATUS_STYLE),
tf("Domain", entity.domain ?? entity.topic_title ?? "—"),
@@ -261,7 +261,7 @@ function _buildBody(entity, type) {
bf("Status", entity.status, _STATUS_STYLE),
bf("Priority", entity.priority, _PRIORITY_STYLE),
tf("Domain", entity.domain ?? "—"),
- tf("Workstream", entity.workstream_title ?? "—"),
+ tf("Workplan", entity.workstream_title ?? "—"),
tf("Assignee", entity.assignee ?? "—"),
tf("Due", entity.due_date ?? "—"),
);
@@ -285,7 +285,7 @@ function _buildBody(entity, type) {
bf("Priority", entity.priority, _PRIORITY_STYLE),
tf("Type", entity.ep_type ?? "—"),
tf("Domain", entity.domain ?? "—"),
- tf("Workstream", entity.workstream_title ?? "—"),
+ tf("Workplan", entity.workstream_title ?? "—"),
tf("Location", entity.location ?? "—"),
);
if (entity.description) {
@@ -302,7 +302,7 @@ function _buildBody(entity, type) {
bf("Status", entity.status, _STATUS_STYLE),
tf("Type", entity.debt_type ?? "—"),
tf("Domain", entity.domain ?? "—"),
- tf("Workstream", entity.workstream_title ?? "—"),
+ tf("Workplan", entity.workstream_title ?? "—"),
tf("Location", entity.location ?? "—"),
);
if (entity.description) {
@@ -319,8 +319,8 @@ function _buildBody(entity, type) {
/**
* Open a detail modal for the given entity.
- * @param {object} entity - The entity data object (workstream, task, ep, or td)
- * @param {string} type - One of: "workstream" | "task" | "ep" | "td"
+ * @param {object} entity - The entity data object (workplan, task, ep, or td)
+ * @param {string} type - One of: "workplan" | "task" | "ep" | "td"
*/
export function openEntityModal(entity, type) {
_ensureStyles();
diff --git a/dashboard/src/components/field-help.js b/dashboard/src/components/field-help.js
index 96e412e..f49c6d9 100644
--- a/dashboard/src/components/field-help.js
+++ b/dashboard/src/components/field-help.js
@@ -99,13 +99,13 @@ export const FIELD_HELP = {
doc: "/docs/tasks",
},
workstream_id: {
- label: "Workstream ID",
- description: "The workstream this event belongs to; auto-resolved from task if not set directly.",
+ label: "Workplan ID",
+ description: "The workplan this event belongs to; auto-resolved from task if not set directly.",
doc: "/docs/workstreams",
},
repo_id: {
label: "Repo ID",
- description: "The managed repo this event is attributed to; auto-resolved from workstream.",
+ description: "The managed repo this event is attributed to; auto-resolved from workplan.",
doc: "/docs/repos",
},
session_id: {
@@ -142,14 +142,14 @@ export const FIELD_HELP = {
description: "Timestamp when this token event was recorded (UTC).",
},
- // ── Workstream ──────────────────────────────────────────────────────────────
+ // ── Workplan ──────────────────────────────────────────────────────────────
slug: {
label: "Slug",
description: "URL-safe short identifier for this entity.",
},
title: {
label: "Title",
- description: "Human-readable name for this workstream or task.",
+ description: "Human-readable name for this workplan or task.",
},
status: {
label: "Status",
@@ -158,12 +158,12 @@ export const FIELD_HELP = {
},
topic_id: {
label: "Topic ID",
- description: "The topic this workstream is grouped under.",
+ description: "The topic this workplan is grouped under.",
doc: "/docs/reference#topics",
},
repo_goal_id: {
label: "Repo Goal ID",
- description: "Optional link to a repo-level strategic goal this workstream advances.",
+ description: "Optional link to a repo-level strategic goal this workplan advances.",
doc: "/docs/goals",
},
diff --git a/dashboard/src/components/improvement-modal.js b/dashboard/src/components/improvement-modal.js
index e37ad50..c2cdb51 100644
--- a/dashboard/src/components/improvement-modal.js
+++ b/dashboard/src/components/improvement-modal.js
@@ -6,7 +6,7 @@
* initImprovementModal({apiBase: "http://127.0.0.1:8000"});
*
* Widget names can be declared explicitly via data attribute:
- *
…
+ * …
*
* Otherwise the component walks the DOM to infer the nearest section heading.
* Submissions are stored as technical-debt items with debt_type="dashboard-improvement".
diff --git a/dashboard/src/components/wsjf-triage.js b/dashboard/src/components/wsjf-triage.js
index 20210f2..cff6e29 100644
--- a/dashboard/src/components/wsjf-triage.js
+++ b/dashboard/src/components/wsjf-triage.js
@@ -80,8 +80,8 @@ export function candidateKeysForWorkplan(item = {}) {
export function buildCandidateIndex(workplanIndex = {}) {
const byCandidate = new Map();
- const workstreams = workplanIndex.workstreams ?? {};
- for (const [id, item] of Object.entries(workstreams)) {
+ const workplans = workplanIndex.workplans ?? workplanIndex.workstreams ?? {};
+ for (const [id, item] of Object.entries(workplans)) {
const resolved = {id, ...item};
byCandidate.set(normalizeCandidate(id), resolved);
for (const key of candidateKeysForWorkplan(item)) {
diff --git a/dashboard/src/data/workstreams/[id].json.py b/dashboard/src/data/workstreams/[id].json.py
index 92774cb..d4a511b 100644
--- a/dashboard/src/data/workstreams/[id].json.py
+++ b/dashboard/src/data/workstreams/[id].json.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-"""Observable data loader: fetches a single workstream by ID."""
+"""Observable data loader: fetches a single workplan by ID."""
import json
import os
import sys
@@ -11,7 +11,7 @@ API_BASE = os.environ.get("API_BASE", "http://127.0.0.1:8000").rstrip("/")
ws_id = sys.argv[1] if len(sys.argv) > 1 else ""
if not ws_id:
- print(json.dumps({"error": "No workstream ID provided"}))
+ print(json.dumps({"error": "No workplan ID provided"}))
sys.exit(1)
try:
diff --git a/dashboard/src/dependencies.md b/dashboard/src/dependencies.md
index 4553fbb..644ecad 100644
--- a/dashboard/src/dependencies.md
+++ b/dashboard/src/dependencies.md
@@ -8,7 +8,7 @@ import {normalizeWorkstreamStatus} from "./components/workplan-status.js";
```
```js
-// Fetch workstreams + topics + dep edges; /state/deps replaces the heavier
+// Fetch workplans + topics + dep edges; /state/deps replaces the heavier
// /state/summary which was only used here to extract dependency edges.
const depState = (async function*() {
let failures = 0;
@@ -70,7 +70,7 @@ const _kpiBox = html`
-
workstreams involved
+
workplans involved
`;
@@ -89,7 +89,7 @@ injectTocTop("dep-kpi-box", _kpiBox);
injectTocTop("live-indicator", _liveEl);
```
-Directed edges between open workstreams. An edge **A → B** means A cannot
+Directed edges between open workplans. An edge **A → B** means A cannot
fully proceed until B reaches a satisfactory state.
```js
@@ -113,10 +113,10 @@ if (edges.length === 0) {
Depends-on domain
- Depends-on workstream
+ Depends-on workplan
Blocked-by domain
- Blocked-by workstream
+ Blocked-by workplan
Status
diff --git a/dashboard/src/docs/capabilities.md b/dashboard/src/docs/capabilities.md
index 11f57df..e4af82a 100644
--- a/dashboard/src/docs/capabilities.md
+++ b/dashboard/src/docs/capabilities.md
@@ -219,7 +219,7 @@ and age in days.
| Concept | Relationship |
|---------|-------------|
| **SCOPE.md** | Defines what a repo *is responsible for* — the catalog registers what it *can provide* |
-| **Dependencies** | Workstream-to-workstream edges — capabilities are higher-level, domain-to-domain |
+| **Dependencies** | Workplan-to-workplan edges — capabilities are higher-level, domain-to-domain |
| **Extension Points** | Design forks for *future* enhancement — capabilities are *operational* requests |
| **Contributions** | Outbound upstream work — capabilities are *inbound* requests between internal domains |
| **Human Interventions** | Flagged tasks for Bernd — capabilities are agent-to-agent coordination |
diff --git a/dashboard/src/docs/contributions.md b/dashboard/src/docs/contributions.md
index d773ea4..9736a74 100644
--- a/dashboard/src/docs/contributions.md
+++ b/dashboard/src/docs/contributions.md
@@ -56,7 +56,7 @@ communication taxonomy:
| Todo class | Mechanism |
|------------|-----------|
-| Internal | Workplan file + task in this repo's workstream |
+| Internal | Workplan file + task in this repo's workplan |
| Ecosystem | State hub task with `[repo:]` prefix |
| **Third-party** | **Contribution artifact in `contrib/` + state hub registration** |
diff --git a/dashboard/src/docs/dashboard.md b/dashboard/src/docs/dashboard.md
index 6441df8..656f9f6 100644
--- a/dashboard/src/docs/dashboard.md
+++ b/dashboard/src/docs/dashboard.md
@@ -6,7 +6,7 @@ title: Dashboard — Technical Reference
The State Hub dashboard is the primary visual interface for the Custodian
ecosystem. It provides live, reactive views of all tracked domains,
-workstreams, tasks, decisions, contributions, SBOM data, and agent activity —
+workplans, tasks, decisions, contributions, SBOM data, and agent activity —
all sourced from the local FastAPI state service.
---
@@ -63,7 +63,7 @@ Current loaders:
| File | API endpoint |
|---|---|
| `summary.json.py` | `/state/summary` |
-| `workstreams.json.py` | `/workplans/` |
+| `workplans.json.py` | `/workplans/` |
| `contributions.json.py` | `/contributions/` |
| `decisions.json.py` | `/decisions/` |
| `domains.json.py` | `/domains/` |
@@ -120,7 +120,7 @@ The dashboard has 30+ pages organised in four navigation groups:
| Page | Route | Purpose |
|---|---|---|
-| Overview | `/` | Cross-domain summary — workstream chart, status KPIs, blocking decisions, recent activity |
+| Overview | `/` | Cross-domain summary — workplan chart, status KPIs, blocking decisions, recent activity |
| Capabilities | `/capability-requests` | Capability request routing and fulfilment status |
| Contributions | `/contributions` | Upstream contribution Kanban (bug reports, feature requests, upstream PRs) |
| Domains | `/domains` | Per-domain health overview and management |
@@ -140,7 +140,7 @@ The dashboard has 30+ pages organised in four navigation groups:
| Repo Sync | `/repo-sync` | Consistency checker results and sync status |
| SBOM | `/sbom` | Software bill of materials — packages, licences, copyleft risk |
-### Workstreams section
+### Workplans section
| Page | Route | Purpose |
|---|---|---|
@@ -173,7 +173,7 @@ Exports shared runtime configuration used by every live-polling page:
### `entity-modal.js`
A lightweight detail overlay for entities. Any table row or card can call
`openEntityModal(entity, type)` to open a full-detail panel without navigating
-away from the page. Supports four entity types: `workstream`, `task`, `ep`
+away from the page. Supports four entity types: `workplan`, `task`, `ep`
(extension point), and `td` (technical debt).
Also exports `buildEntityTable()` — a function that constructs a consistent,
@@ -183,7 +183,7 @@ overflow ellipsis, and native tooltip-on-hover for truncated values.
### `toc-sidebar.js`
Provides `injectTocTop(id, element)` — injects a DOM element into the
Observable Framework table-of-contents sidebar above the page's first section
-heading. Used on the Overview and Workstreams pages to embed live KPI infoboxes
+heading. Used on the Overview and Workplans pages to embed live KPI infoboxes
directly in the sidebar.
### `doc-overlay.js`
@@ -194,12 +194,12 @@ without leaving the current page.
### `help-tip.js`
A custom HTML element (``) that renders an inline abbreviated label
with an expandable tooltip containing a longer description and a link to the
-relevant reference page. Used in the Workstream Health Index card to annotate
+relevant reference page. Used in the Workplan Health Index card to annotate
each metric abbreviation.
### `multiselect.js`
A multi-value dropdown filter input compatible with Observable's `Inputs.form()`
-reactive pattern. Used on the Workstreams and Tasks pages for domain and status
+reactive pattern. Used on the Workplans and Tasks pages for domain and status
filtering.
### `improvement-modal.js`
@@ -223,17 +223,17 @@ shows green when the API is reachable and red with a restart command when it
is not. This allows the dashboard to be used as a persistent, always-on monitor
without requiring a page refresh.
-### Workstream Health Index (WHI)
+### Workplan Health Index (WHI)
-The Workstreams page computes a **Workstream Health Index** — a single
+The Workplans page computes a **Workplan Health Index** — a single
composite score (0–100%) derived from five graph metrics:
| Metric | Abbrev. | Weight | Interpretation |
|---|---|---|---|
-| Dependency Density | DD | 30% | Average deps per open workstream; high = tightly coupled |
-| Blocked Ratio | BR | 25% | Share of workstreams in a blocked state |
-| Single-Point Risk | SPR | 15% | Share of workstreams that others depend on but are not yet complete |
-| Parallel Execution Potential | PEP | 20% | Share of workstreams that could start/continue immediately |
+| Dependency Density | DD | 30% | Average deps per open workplan; high = tightly coupled |
+| Blocked Ratio | BR | 25% | Share of workplans in a blocked state |
+| Single-Point Risk | SPR | 15% | Share of workplans that others depend on but are not yet complete |
+| Parallel Execution Potential | PEP | 20% | Share of workplans that could start/continue immediately |
| Cross-Domain Dependency Ratio | CDDR | 10% | Share of edges crossing domain boundaries |
A **Cycle Presence Indicator** (CPI) detected via DFS halves the total score
@@ -241,17 +241,17 @@ when a dependency cycle is found, since cyclic dependencies cause deadlock.
The index is computed per-domain as well as globally and displayed in the
TOC sidebar as a persistent KPI card.
-### Multi-mode workstream chart
+### Multi-mode workplan chart
The Overview page renders a horizontal stacked bar chart using `@observablehq/plot`
-showing task counts (done / progress / wait / todo) per workstream.
+showing task counts (done / progress / wait / todo) per workplan.
A `` dropdown switches between:
- **Lifecycle modes**: proposed, ready, active, blocked, backlog, finished, archived
- **Health modes**: needs review, stalled
- **Time modes**: last 1h, 24h, 7d, 30d, today, this week, this month
-Domains are sorted by most recent workstream activity (most active domain at
+Domains are sorted by most recent workplan activity (most active domain at
the top). Title labels and done/total counters are overlaid directly on the bars.
### Resolve-in-place for blocking decisions
@@ -271,14 +271,14 @@ in direct production dependencies.
### Dependency graph
-The Dependencies page and the Workstreams page both surface inter-workstream
-dependency data. Each workstream card shows the workstreams it depends on
-(`↳ depends on`) and the workstreams it blocks (`⊳ blocks`), derived from
+The Dependencies page and the Workplans page both surface inter-workplan
+dependency data. Each workplan card shows the workplans it depends on
+(`↳ depends on`) and the workplans it blocks (`⊳ blocks`), derived from
the `WorkstreamDependency` table.
### Entity modals
-Any table row on any list page (workstreams, tasks, extension points, tech debt)
+Any table row on any list page (workplans, tasks, extension points, tech debt)
can be clicked to open a detail modal with full field data, dependency lists,
task progress, and timestamps — without a page navigation or a separate detail
route.
@@ -309,7 +309,7 @@ needed in the source directory). Typical mark types used across the dashboard:
| Mark | Used for |
|---|---|
| `Plot.barX` | Horizontal stacked task-count bars, SBOM licence distribution |
-| `Plot.text` | Workstream title labels and done/total counters overlaid on bars |
+| `Plot.text` | Workplan title labels and done/total counters overlaid on bars |
| `Plot.ruleX([0])` | Zero-axis rule on all bar charts |
Charts are rendered as inline SVG and inherit Observable Framework's theme
@@ -339,4 +339,4 @@ data and shows the offline error state on each page.
- [Live Data](/docs/live-data) — polling mechanism and offline behaviour in detail
- [Connecting to the Hub](/docs/connecting) — MCP server registration
- [Overview](/docs/overview) — Overview page feature walkthrough
-- [Workstreams](/docs/workstreams) — Workstreams page and WHI in depth
+- [Workplans](/docs/workstreams) — Workplans page and WHI in depth
diff --git a/dashboard/src/docs/dependencies.md b/dashboard/src/docs/dependencies.md
index 84a6fad..34fd5a6 100644
--- a/dashboard/src/docs/dependencies.md
+++ b/dashboard/src/docs/dependencies.md
@@ -5,15 +5,15 @@ title: Dependencies — Reference
# Dependencies — Reference
The Dependencies page shows the directed dependency graph between open
-workstreams — which workstreams are waiting on others to reach a satisfactory
+workplans — which workplans are waiting on others to reach a satisfactory
state before they can fully proceed.
---
## What is a dependency edge?
-A dependency edge **A → B** means workstream A cannot fully proceed until
-workstream B is in a satisfactory state (typically `finished` or `archived`).
+A dependency edge **A → B** means workplan A cannot fully proceed until
+workplan B is in a satisfactory state (typically `finished` or `archived`).
Edges are used to model real sequencing constraints: for example, a shared
library must reach a stable release before downstream domains can build on it.
@@ -31,18 +31,18 @@ Each row shows:
| Column | Meaning |
|--------|---------|
-| **Depends-on domain** | Domain of the dependent workstream (the one waiting) |
-| **Depends-on workstream** | Title of the workstream that has the dependency |
+| **Depends-on domain** | Domain of the dependent workplan (the one waiting) |
+| **Depends-on workplan** | Title of the workplan that has the dependency |
| **→** | Direction arrow |
-| **Blocked-by domain** | Domain of the prerequisite workstream |
-| **Blocked-by workstream** | Title of the workstream that must complete first |
+| **Blocked-by domain** | Domain of the prerequisite workplan |
+| **Blocked-by workplan** | Title of the workplan that must complete first |
| **Status** | Current status of the prerequisite (green = active, grey = finished/archived) |
---
## KPI sidebar card
-Shows the total number of edges and the number of distinct workstreams involved
+Shows the total number of edges and the number of distinct workplans involved
in at least one dependency relationship.
---
@@ -67,7 +67,7 @@ curl -X POST http://127.0.0.1:8000/workplans//dependencies/ \
-d '{"to_workstream_id": "", "description": "..."}'
```
-To list dependencies for a workstream:
+To list dependencies for a workplan:
```
list_dependencies(workstream_id="")
@@ -77,10 +77,10 @@ list_dependencies(workstream_id="")
## Cycle detection
-The Workstream Health Index (WHI) includes a **Cycle Penalty Index (CPI)**
+The Workplan Health Index (WHI) includes a **Cycle Penalty Index (CPI)**
metric that detects circular dependencies using depth-first search. If CPI = 1,
a cycle exists and the WHI is penalised by 50%. The WHI KPI card on the
-[Workstreams](/workstreams) page will display a cycle alert.
+[Workplans](/workstreams) page will display a cycle alert.
---
diff --git a/dashboard/src/docs/extensions.md b/dashboard/src/docs/extensions.md
index 08a3615..2f560e5 100644
--- a/dashboard/src/docs/extensions.md
+++ b/dashboard/src/docs/extensions.md
@@ -42,7 +42,7 @@ be pursued.
| Status | Meaning |
|--------|---------|
| **open** | Identified, not yet acted on |
-| **in_progress** | Being implemented as part of an active workstream |
+| **in_progress** | Being implemented as part of an active workplan |
| **addressed** | The capability has been built |
| **deferred** | Intentionally postponed |
| **wont_fix** | Decided not to pursue — kept for documentation |
diff --git a/dashboard/src/docs/goals.md b/dashboard/src/docs/goals.md
index 0523275..39a4a20 100644
--- a/dashboard/src/docs/goals.md
+++ b/dashboard/src/docs/goals.md
@@ -4,7 +4,7 @@ title: Goals — Reference
# Goals — Reference
-The Goals page shows strategic intent at two levels — **domain** and **repository** — and how they relate. It provides context for why workstreams exist and what they collectively deliver.
+The Goals page shows strategic intent at two levels — **domain** and **repository** — and how they relate. It provides context for why workplans exist and what they collectively deliver.
---
@@ -123,9 +123,9 @@ The Goals page groups everything by domain:
---
-## Linking workstreams to repo goals
+## Linking workplans to repo goals
-Workstreams carry an optional `repo_goal_id` field. Setting it traces *why* a workstream exists — which specific repo goal it contributes to. This connection is currently recorded in the DB but is not yet visualised in the Workstreams page.
+Workplans carry an optional `repo_goal_id` field. Setting it traces *why* a workplan exists — which specific repo goal it contributes to. This connection is currently recorded in the DB but is not yet visualised in the Workplans page.
To set the link when creating a workplan through the preferred API, pass `repo_goal_id`. To update an existing one, use `PATCH /workplans/{id}/` with `{"repo_goal_id": ""}`. Legacy `create_workstream` and `/workstreams/{id}/` callers remain compatibility-supported while they are metered.
@@ -133,4 +133,4 @@ To set the link when creating a workplan through the preferred API, pass `repo_g
## Design rationale
-Goals are intentionally separate from workstreams. A workstream is a unit of *deliverable work*; a goal is a statement of *strategic intent*. Goals are stable and long-lived; workstreams are created, completed, and replaced as work advances. The goal hierarchy (domain → repo → workstream) provides the context needed to understand why any given piece of work exists.
+Goals are intentionally separate from workplans. A workplan is a unit of *deliverable work*; a goal is a statement of *strategic intent*. Goals are stable and long-lived; workplans are created, completed, and replaced as work advances. The goal hierarchy (domain → repo → workplan) provides the context needed to understand why any given piece of work exists.
diff --git a/dashboard/src/docs/inter-repo-communication.md b/dashboard/src/docs/inter-repo-communication.md
index ae1fb8b..1b67779 100644
--- a/dashboard/src/docs/inter-repo-communication.md
+++ b/dashboard/src/docs/inter-repo-communication.md
@@ -37,7 +37,7 @@ appropriate coordination channel (see below). Do not write the files yourself.
A **task** is the state hub data entity encapsulating a suggested or required
piece of work. Tasks live in the state hub database, are always scoped to a
-workstream, and are the universal unit of cross-repo coordination. Tasks are
+workplan, and are the universal unit of cross-repo coordination. Tasks are
neutral — they describe *what* should be done, not *who* does it or *where*.
### Todo
@@ -69,11 +69,11 @@ Todo
Use this when you identify work that belongs to another repo registered in the
Custodian State Hub.
-### Step 1 — Create a state hub task in the target domain's workstream
+### Step 1 — Create a state hub task in the target domain's workplan
```python
create_task(
- workstream_id="",
+ workstream_id="",
title="[repo:] Brief description of the required work",
priority="medium", # low | medium | high | critical
description="Full context: why this work is needed and what the expected outcome is"
@@ -133,7 +133,7 @@ whose stored workstation/status label is `active`, with tasks in `wait`,
`todo`, or `progress`.
**Ecosystem todos targeting this repo** (Step 1 of orientation) —
-`get_state_summary()` returns all open tasks across all workstreams. The session
+`get_state_summary()` returns all open tasks across all workplans. The session
protocol filters for tasks with `[repo:]` in their title and surfaces
them in the orientation brief.
diff --git a/dashboard/src/docs/interventions.md b/dashboard/src/docs/interventions.md
index b0cc95c..5a31439 100644
--- a/dashboard/src/docs/interventions.md
+++ b/dashboard/src/docs/interventions.md
@@ -33,7 +33,7 @@ Tasks are sorted by priority (critical → high → medium → low), then by sta
| Priority badge | `critical` / `high` / `medium` / `low` |
| Status chip | Current task status |
| Domain | Source domain slug |
-| Workstream | Parent workstream title |
+| Workplan | Parent workplan title |
| Action note | The `intervention_note` — what the human needs to do |
| Task detail | Expandable `` with the task title and description (shown when different from the action note) |
@@ -66,9 +66,9 @@ clear_human_flag(task_id = "")
---
-## Filtering by workstream
+## Filtering by workplan
-`list_human_interventions(workstream_id="")` via MCP returns only interventions for a specific workstream — useful for scoped reviews in agent sessions.
+`list_human_interventions(workstream_id="")` via MCP returns only interventions for a specific workplan — useful for scoped reviews in agent sessions.
---
diff --git a/dashboard/src/docs/overview.md b/dashboard/src/docs/overview.md
index 36ba5b2..ce827ac 100644
--- a/dashboard/src/docs/overview.md
+++ b/dashboard/src/docs/overview.md
@@ -12,9 +12,9 @@ blocking decisions, and system-derived next-step suggestions.
## Sections
-### Open Workstreams by Repository
+### Open Workplans by Repository
-A horizontal stacked bar chart showing workstreams grouped by domain and then
+A horizontal stacked bar chart showing workplans grouped by domain and then
by repository. Each bar is broken into four task-status segments:
| Colour | Segment |
@@ -25,11 +25,11 @@ by repository. Each bar is broken into four task-status segments:
| light grey | todo |
The left axis shows the `domain / repository` label once per repository group.
-The `done/total` count is printed to the right of each bar. Workstreams with no
+The `done/total` count is printed to the right of each bar. Workplans with no
tasks yet show a grey "— no tasks yet" label.
Hovering a bar shows the repository, domain, and backing workplan filename when
-the workstream is file-backed. Clicking a bar or its label opens the workstream
+the workplan is file-backed. Clicking a bar or its label opens the workplan
drilldown page with the attached task list.
### Contribution & SBOM Health
@@ -48,7 +48,7 @@ Four metric cards:
| Card | Meaning |
|------|---------|
-| **Active Workstreams** | Count of active/blocked execution workstreams |
+| **Active Workplans** | Count of active/blocked execution workplans |
| **Blocking Decisions** | Pending decisions with status `open` or `escalated` — orange border if > 0 |
| **Blocked Tasks** | Click to expand the list with blocking reasons |
| **Events Today** | Progress events created on today's date |
@@ -56,8 +56,8 @@ Four metric cards:
### What's next?
System-derived action suggestions from `GET /state/next_steps`. Suggestions are
-generated when a decision is resolved or a workstream dependency is cleared, and
-they point to the first open task in the relevant workstream. These are derived
+generated when a decision is resolved or a workplan dependency is cleared, and
+they point to the first open task in the relevant workplan. These are derived
on request and never persisted.
### Blocking Decisions
diff --git a/dashboard/src/docs/progress-log.md b/dashboard/src/docs/progress-log.md
index bfd430e..8efdd0b 100644
--- a/dashboard/src/docs/progress-log.md
+++ b/dashboard/src/docs/progress-log.md
@@ -24,7 +24,7 @@ Each event carries:
| `event_type` | string | Free-form label categorising the event (see below) |
| `author` | string | Who created the event — `custodian` for agent-generated events, or a human name |
| `topic_id` | UUID? | Links the event to a topic (optional) |
-| `workstream_id` | UUID? | Links to a workstream (optional) |
+| `workstream_id` | UUID? | Links to a workplan (optional) |
| `task_id` | UUID? | Links to a task (optional) |
| `decision_id` | UUID? | Links to a decision (optional) |
| `detail` | JSON? | Arbitrary structured data — commits, counts, file paths, metrics, etc. |
@@ -38,10 +38,10 @@ These types are used by the State Hub's built-in write operations:
| Type | When emitted |
|---|---|
-| `workstream_created` | A new workstream was registered |
-| `workstream_status_changed` | Workstream moved between canonical lifecycle states |
+| `workstream_created` | A new workplan was registered |
+| `workstream_status_changed` | Workplan moved between canonical lifecycle states |
| `workstation_advanced` | Flow-aware movement via `advance_workstation()` succeeded |
-| `task_created` | A new task was added to a workstream |
+| `task_created` | A new task was added to a workplan |
| `task_status_changed` | Task moved to wait / todo / progress / done / cancel |
| `decision_recorded` | A decision (pending or made) was recorded |
| `decision_resolved` | A pending decision was resolved |
@@ -77,7 +77,7 @@ Via the MCP server (in a Claude Code session):
add_progress_event(
summary = "What happened, in one clear sentence",
event_type = "milestone", // or note, blocker, insight, …
- workstream_id = "", // link to relevant workstream (optional)
+ workstream_id = "", // link to relevant workplan (optional)
topic_id = "", // link to relevant topic (optional)
detail = { "key": "value" } // any structured data worth preserving
)
diff --git a/dashboard/src/docs/ralph-workplan.md b/dashboard/src/docs/ralph-workplan.md
index a95b4e6..a6970a7 100644
--- a/dashboard/src/docs/ralph-workplan.md
+++ b/dashboard/src/docs/ralph-workplan.md
@@ -181,7 +181,7 @@ The skill is **fully self-contained** — it reads and writes only the workplan
file. It does not call the State Hub API or require network access.
If the project also integrates with the State Hub (via the MCP tunnel), the
-agent can additionally report progress and mark workstream tasks done through
+agent can additionally report progress and mark workplan tasks done through
the MCP tools during the loop — but this is optional and independent of the
ralph-workplan lifecycle.
diff --git a/dashboard/src/docs/repo-integration.md b/dashboard/src/docs/repo-integration.md
index d615c4c..fa46bf7 100644
--- a/dashboard/src/docs/repo-integration.md
+++ b/dashboard/src/docs/repo-integration.md
@@ -15,12 +15,12 @@ during and after integration.
The custodian acts as a **coach**: it registers the repo, writes an
integration suggestion, and generates a structured set of onboarding tasks.
The repo's own Claude agent acts as the **executor**: it reads those tasks,
-makes all changes to the repo, and closes out the onboarding workstream.
+makes all changes to the repo, and closes out the onboarding workplan.
| Role | Responsibility |
|------|---------------|
-| **Custodian** | Registers the repo, generates `CLAUDE.custodian.md`, creates the onboarding workstream and tasks, monitors integration status via the dashboard |
-| **Repo agent** | Integrates `CLAUDE.custodian.md` → `CLAUDE.md`, writes the first workplan, ingests the SBOM, catalogues EPs/TDs, closes the onboarding workstream |
+| **Custodian** | Registers the repo, generates `CLAUDE.custodian.md`, creates the onboarding workplan and tasks, monitors integration status via the dashboard |
+| **Repo agent** | Integrates `CLAUDE.custodian.md` → `CLAUDE.md`, writes the first workplan, ingests the SBOM, catalogues EPs/TDs, closes the onboarding workplan |
The custodian never writes files into another repo directly. All changes to
the target repo are made from inside that repo by its own agent. This upholds
@@ -52,7 +52,7 @@ What happens automatically:
2. The domain is validated; the domain's topic ID is resolved
3. `CLAUDE.custodian.md` is written to the repo root — the integration suggestion
4. The repo is registered in the State Hub (`POST /repos/`)
-5. A **Repo Integration** workstream is created in the domain's topic with 4
+5. A **Repo Integration** workplan is created in the domain's topic with 4
onboarding tasks
6. A progress event is logged
@@ -65,14 +65,14 @@ claude
Once Claude starts, run `/init` to trigger the integration. The repo agent
reads `CLAUDE.custodian.md`, calls `get_domain_summary("")`, sees the
-Repo Integration workstream, and works through the 4 onboarding tasks
+Repo Integration workplan, and works through the 4 onboarding tasks
autonomously. No human interaction is needed unless the agent has a question.
### Step 4 — Monitor on the Repos page
The [Repos](/repos) page shows each repo's integration status. An **integrating**
-badge appears on repos with an active Repo Integration workstream. The badge
-clears when the workstream is marked finished.
+badge appears on repos with an active Repo Integration workplan. The badge
+clears when the workplan is marked finished.
---
@@ -88,13 +88,13 @@ topic ID, and slug.
The repo agent integrates this content into the existing `CLAUDE.md` (or
creates a new one) and deletes the suggestion file. It is not meant to persist.
-### Repo Integration workstream
+### Repo Integration workplan
-A workstream titled **Repo Integration: ``** is created in the
+A workplan titled **Repo Integration: ``** is created in the
target domain's topic. It is visible via `get_domain_summary()` at the repo
agent's next session start.
-> **ADR-001 note:** This workstream is a DB-first bootstrapping exception.
+> **ADR-001 note:** This workplan is a DB-first bootstrapping exception.
> The file-first principle does not apply here because the repo has no
> `workplans/` directory yet. Writing the first workplan file is task T2.
@@ -103,7 +103,7 @@ agent's next session start.
| # | Title | Priority | What it means |
|---|-------|----------|---------------|
| T1 | Integrate `CLAUDE.custodian.md` → `CLAUDE.md` | high | Merge the suggestion into the existing CLAUDE.md; delete the suggestion file; commit |
-| T2 | Write first workplan and initialise `workplans/` | high | Create `workplans/` and write the first workplan file per ADR-001; register the workstream in the hub |
+| T2 | Write first workplan and initialise `workplans/` | high | Create `workplans/` and write the first workplan file per ADR-001; register the workplan in the hub |
| T3 | Ingest SBOM | medium | Run `make ingest-sbom REPO= SCAN=1 REPO_PATH=` from the state-hub dir |
| T4 | Register known EPs and TDs | low | Catalogue extension points and technical debt using the MCP tools |
@@ -111,17 +111,17 @@ agent's next session start.
## Repo Agent: First Session Protocol
-When `get_domain_summary()` returns a **Repo Integration** workstream, the
+When `get_domain_summary()` returns a **Repo Integration** workplan, the
repo agent should:
1. Read `CLAUDE.custodian.md` alongside the existing `CLAUDE.md`
2. Execute T1 first — merge and delete the suggestion file, commit
3. Execute T2 — create `workplans/-WP-0001-.md` covering the
- primary near-term work; register the workstream in the hub via MCP
+ primary near-term work; register the workplan in the hub via MCP
4. Execute T3 — ingest the SBOM so the repo appears green on the Repos page
5. Execute T4 — a quick scan for obvious EPs/TDs; defer if nothing obvious
6. Mark each task `done` in the hub
-7. Mark the Repo Integration workstream `finished`
+7. Mark the Repo Integration workplan `finished`
8. Log a progress event summarising the integration
The agent should resolve each task independently and in order. It does not
@@ -132,10 +132,10 @@ merge conflict in CLAUDE.md.
## After Integration
-Once the onboarding workstream is closed, the repo participates in the full
+Once the onboarding workplan is closed, the repo participates in the full
custodian ecosystem:
-- **Session start:** `get_domain_summary("")` shows active workstreams,
+- **Session start:** `get_domain_summary("")` shows active workplans,
blocking decisions, and recent progress — the standard orientation
- **Ecosystem todos:** tasks with `[repo:]` in their title created by
other agents appear in the domain summary and signal cross-repo work
@@ -165,4 +165,4 @@ suggestion. The repo agent should integrate and delete it.
**Repo already registered (slug conflict)**
The command is idempotent for the repo row. Onboarding tasks are re-created
-only if no active Repo Integration workstream already exists.
+only if no active Repo Integration workplan already exists.
diff --git a/dashboard/src/docs/sbom.md b/dashboard/src/docs/sbom.md
index e57e0b5..9037b3c 100644
--- a/dashboard/src/docs/sbom.md
+++ b/dashboard/src/docs/sbom.md
@@ -160,7 +160,7 @@ hand-rolled parsers for comprehensive coverage.
When a compliance gap is identified in a registered repo, the finding is routed
as an **ecosystem todo**: a state hub task with `[repo:]` in the title,
-created in the target domain's workstream. The target repo's session protocol
+created in the target domain's workplan. The target repo's session protocol
surfaces it automatically at next session start.
See the full standard: [`/docs/inter-repo-communication`](/docs/inter-repo-communication)
diff --git a/dashboard/src/docs/state-hub.md b/dashboard/src/docs/state-hub.md
index 5453092..8ffeb87 100644
--- a/dashboard/src/docs/state-hub.md
+++ b/dashboard/src/docs/state-hub.md
@@ -13,7 +13,7 @@ seconds rather than minutes.
## Why it exists
-Software projects accumulate invisible state. Workstreams stall, decisions go
+Software projects accumulate invisible state. Workplans stall, decisions go
unresolved, dependency licences drift, integration gaps widen — and none of
this is visible without opening every file in every repository. For a single
repo with a single engineer this is manageable. Across six domains, fifteen
@@ -36,9 +36,9 @@ indexes and reflects their state.
| Role | Description |
|---|---|
| **Derived Data Store** | All hub data is computed from repo files and records. The hub holds no original information — it can be wiped and rebuilt from scratch at any time without data loss. |
-| **Read Model** | Provides fast, pre-computed answers to common orientation queries: active workstreams, blocking decisions, DoI compliance tiers, SBOM licence risk, GDPR warnings. |
+| **Read Model** | Provides fast, pre-computed answers to common orientation queries: active workplans, blocking decisions, DoI compliance tiers, SBOM licence risk, GDPR warnings. |
| **Agent Orchestration Layer** | Exposes an MCP server (Model Context Protocol) so that Claude Code sessions in any registered repository can orient themselves, record progress, resolve decisions, and coordinate with each other — all through a uniform tool interface. |
-| **Cross-Repo Observatory** | The only place where data from all repositories is visible together. Detects dependencies between workstreams, licence risks that span repos, and integration gaps that no single repo can see about itself. |
+| **Cross-Repo Observatory** | The only place where data from all repositories is visible together. Detects dependencies between workplans, licence risks that span repos, and integration gaps that no single repo can see about itself. |
### What it is not
@@ -82,7 +82,7 @@ Invalidation). The practical consequence:
| `uv.lock`, `package-lock.json`, etc. | SBOM entries + licence risk | `make ingest-sbom REPO=` |
| `tpsc.yaml` | Third-party service declarations + GDPR warnings | `make ingest-tpsc REPO=` |
| `SCOPE.md` capability blocks | Capability catalog | `make ingest-capabilities REPO=` |
-| `workplans/*.md` | Workstream + task status | `statehub fix-consistency` |
+| `workplans/*.md` | Workplan + task status | `statehub fix-consistency` |
| Repo files + DB records | DoI compliance tier | Fingerprint cache, auto-refreshed on read |
---
@@ -96,7 +96,7 @@ ecosystem — the coordinator that no individual repo can be.
Every Claude Code session in a registered repository follows the same ritual:
-1. **Orient** — call `get_domain_summary("")` to load active workstreams,
+1. **Orient** — call `get_domain_summary("")` to load active workplans,
pending tasks, blocking decisions, and suggested next steps for this domain.
2. **Check inbox** — call `get_messages(to_agent="", unread_only=True)`
to receive coordination messages from other agents or from prior sessions.
@@ -119,8 +119,8 @@ communication:
- A capability request (`request_capability()`) routes to the domain that
advertises the relevant capability in its `SCOPE.md`. The fulfilling agent
accepts it, does the work, and marks it complete — unblocking the requesting
- workstream automatically.
-- Workstream dependencies (`create_dependency()`) let the hub surface "what
+ workplan automatically.
+- Workplan dependencies (`create_dependency()`) let the hub surface "what
is blocking what" across repos that have never directly communicated.
### Kaizen agents
@@ -144,7 +144,7 @@ every repo's CLAUDE.md.
▼
┌─────────────────────────────────────────────────────────────┐
│ PostgreSQL Database │
-│ domains managed_repos workstreams tasks decisions │
+│ domains managed_repos workplans tasks decisions │
│ sbom_entries tpsc_entries doi_cache capability_catalog │
│ progress_events agent_messages repo_goals … │
└─────────┬───────────────────────────────────────────────────┘
@@ -161,7 +161,7 @@ every repo's CLAUDE.md.
▼
┌─────────────────────────────────────────────────────────────┐
│ Observable Framework Dashboard (:3000) │
-│ Overview Repositories Workstreams Decisions SBOM │
+│ Overview Repositories Workplans Decisions SBOM │
│ TPSC Contributions Goals Capabilities … │
└─────────────────────────────────────────────────────────────┘
```
@@ -186,7 +186,7 @@ The hub's schema is organised in concentric layers:
`domains` → `managed_repos` → `repo_goals` → `domain_goals`
**Work tracking (active):**
-`workstreams` → `tasks` → `workstream_dependencies`
+`workplans` → `tasks` → `workstream_dependencies`
**Decision log (append-only):**
`decisions` · `progress_events` · `agent_messages`
diff --git a/dashboard/src/docs/tasks.md b/dashboard/src/docs/tasks.md
index 6b6b4fc..d6f11f8 100644
--- a/dashboard/src/docs/tasks.md
+++ b/dashboard/src/docs/tasks.md
@@ -4,7 +4,7 @@ title: Tasks — Reference
# Tasks — Reference
-The Tasks page shows all tasks across every workstream and domain, with live
+The Tasks page shows all tasks across every workplan and domain, with live
filtering, a workstation distribution chart, and a waiting-tasks highlight
section.
@@ -70,7 +70,7 @@ Shows cards for every task currently in the `wait` workstation within the
active filter. Each card displays:
- Priority badge and status
-- Domain and workstream context
+- Domain and workplan context
- Task title
- Wait reason (amber background)
diff --git a/dashboard/src/docs/todo.md b/dashboard/src/docs/todo.md
index 49986ee..03e29d3 100644
--- a/dashboard/src/docs/todo.md
+++ b/dashboard/src/docs/todo.md
@@ -18,7 +18,7 @@ boundary rule and routing workflows.
### Internal
-Open tasks (`wait`, `todo`, `progress`) in **custodian domain workstreams**
+Open tasks (`wait`, `todo`, `progress`) in **custodian domain workplans**
whose title does not contain a `[repo:]` routing prefix.
These are tasks this agent is directly responsible for and can address within
@@ -26,7 +26,7 @@ the current repo.
### Ecosystem (inbound)
-Tasks from **any workstream** whose title contains `[repo:the-custodian]`.
+Tasks from **any workplan** whose title contains `[repo:the-custodian]`.
These tasks were created by agents in other repos to route work to the custodian.
When a task with this prefix appears, the session protocol picks it up, the
diff --git a/dashboard/src/docs/workstream-health-index.md b/dashboard/src/docs/workstream-health-index.md
index 20fd9f8..82d1104 100644
--- a/dashboard/src/docs/workstream-health-index.md
+++ b/dashboard/src/docs/workstream-health-index.md
@@ -1,10 +1,10 @@
---
-title: Workstream Health Index — Reference
+title: Workplan Health Index — Reference
---
-# Workstream Health Index (WHI)
+# Workplan Health Index (WHI)
-The **Workstream Health Index** is a composite score in the range [0, 1] that measures how well the workstream network is structured for parallel execution and stable progress. It is displayed as a live KPI card in the right margin of the Workstreams page and recomputes on every poll (every 15 seconds).
+The **Workplan Health Index** is a composite score in the range [0, 1] that measures how well the workplan network is structured for parallel execution and stable progress. It is displayed as a live KPI card in the right margin of the Workplans page and recomputes on every poll (every 15 seconds).
**1.0 = ideal independence · 0.0 = severe systemic dysfunction**
@@ -25,14 +25,14 @@ The **Workstream Health Index** is a composite score in the range [0, 1] that me
### DD — Dependency Density
```
-DD = total dependency edges / (active + blocked workstreams)
+DD = total dependency edges / (active + blocked workplans)
```
-Measures structural coupling. Low DD means independent, parallelizable work. Completed and archived workstreams are excluded — they no longer constrain progress.
+Measures structural coupling. Low DD means independent, parallelizable work. Completed and archived workplans are excluded — they no longer constrain progress.
| DD | Warning |
|---|---|
-| > 1.0 | 🔴 red — more than one dependency per workstream on average |
+| > 1.0 | 🔴 red — more than one dependency per workplan on average |
| 0.5 – 1.0 | 🟠 orange |
| ≤ 0.5 | ok |
@@ -41,7 +41,7 @@ Measures structural coupling. Low DD means independent, parallelizable work. Com
### BR — Blocked Ratio
```
-BR = blocked workstreams / (active + blocked workstreams)
+BR = blocked workplans / (active + blocked workplans)
```
Measures immediate operational impact. BR ≈ 0 means flow is unobstructed.
@@ -57,7 +57,7 @@ Measures immediate operational impact. BR ≈ 0 means flow is unobstructed.
### SPR — Single-Point Risk
```
-SPR = max dependents on one incomplete workstream / (active + blocked)
+SPR = max dependents on one incomplete workplan / (active + blocked)
```
Detects concentration of blocking power. High SPR means one delay propagates widely — a structural SPOF.
@@ -73,12 +73,12 @@ Detects concentration of blocking power. High SPR means one delay propagates wid
### PEP — Parallel Execution Potential
```
-PEP = ready or active workstreams with all deps finished / (ready + active + blocked)
+PEP = ready or active workplans with all deps finished / (ready + active + blocked)
```
-Estimates how much work can proceed right now. A workstream is eligible if its
+Estimates how much work can proceed right now. A workplan is eligible if its
stored workstation label is `ready` or `active` and the flow/dependency checks report no
-unmet dependency assertion; practically, every workstream it depends on has
+unmet dependency assertion; practically, every workplan it depends on has
reached `finished` or `archived`.
| PEP | Warning |
@@ -134,11 +134,11 @@ Result is clamped to [0, 1].
## Domain breakdown
-The card also shows a per-domain WHI computed using **intra-domain workstreams and intra-domain edges only**. This measures each domain's internal autonomy — how well its workstreams are decomposed relative to each other, independent of cross-domain dependencies.
+The card also shows a per-domain WHI computed using **intra-domain workplans and intra-domain edges only**. This measures each domain's internal autonomy — how well its workplans are decomposed relative to each other, independent of cross-domain dependencies.
A domain with WHI = 100% is fully self-contained and parallelizable internally. Its global contribution to the program-level WHI may still be reduced by cross-domain dependencies (captured in CDDR).
-The domain breakdown is shown when at least two domains have active workstreams.
+The domain breakdown is shown when at least two domains have active workplans.
---
@@ -146,10 +146,10 @@ The domain breakdown is shown when at least two domains have active workstreams.
| Symptom | Action |
|---|---|
-| High DD | Decompose tightly coupled workstreams; remove unnecessary dependencies |
-| High BR | Unblock workstreams — resolve the blocking condition, or mark dependency as finished if done |
-| High SPR | Split the bottleneck workstream into independent deliverables |
-| Low PEP | Complete prerequisite workstreams or re-sequence work |
+| High DD | Decompose tightly coupled workplans; remove unnecessary dependencies |
+| High BR | Unblock workplans — resolve the blocking condition, or mark dependency as finished if done |
+| High SPR | Split the bottleneck workplan into independent deliverables |
+| Low PEP | Complete prerequisite workplans or re-sequence work |
| High CDDR | Refactor cross-domain dependencies into shared contracts or invert the dependency |
| CPI = 1 | Find and break the cycle — identify which dependency edge is incorrect and remove it |
diff --git a/dashboard/src/docs/workstream-kpi.md b/dashboard/src/docs/workstream-kpi.md
index 18ab7e1..1f516df 100644
--- a/dashboard/src/docs/workstream-kpi.md
+++ b/dashboard/src/docs/workstream-kpi.md
@@ -1,10 +1,10 @@
-# Workstream Health Index (WHI)
+# Workplan Health Index (WHI)
## Introduction & Requirements Specification
**Status:** Draft
-**Purpose:** Define a quantitative KPI for structural health, coupling, and flow efficiency of workstreams
+**Purpose:** Define a quantitative KPI for structural health, coupling, and flow efficiency of workplans
**Scope:** Program-level coordination across domains and within domains
**Primary Audience:** Project leads, system architects, program management, AI orchestration agents
@@ -12,7 +12,7 @@
## 1. Problem Statement
-Modern complex initiatives consist of multiple concurrent workstreams distributed across teams and domains. Ideally, workstreams should be:
+Modern complex initiatives consist of multiple concurrent workplans distributed across teams and domains. Ideally, workplans should be:
* Independently executable
* Minimally coupled
@@ -46,9 +46,9 @@ Therefore, a dedicated metric is required to assess:
## 2. Conceptual Model
-Workstreams form a **directed dependency graph**:
+Workplans form a **directed dependency graph**:
-* Nodes = workstreams
+* Nodes = workplans
* Edges = prerequisite relationships
* Status = operational state
* Domains = logical grouping
@@ -64,9 +64,9 @@ Health is determined by:
---
-## 3. Definition: Workstream Health Index (WHI)
+## 3. Definition: Workplan Health Index (WHI)
-The **Workstream Health Index (WHI)** is a composite KPI representing the overall coordination efficiency and structural soundness of the workstream network.
+The **Workplan Health Index (WHI)** is a composite KPI representing the overall coordination efficiency and structural soundness of the workplan network.
WHI is normalized to a value in the range:
@@ -98,7 +98,7 @@ WHI aggregates the following primary indicators.
**Purpose:** Measure structural coupling introduced during planning.
[
-DD = \frac{\text{Number of dependency edges}}{\text{Number of active + blocked workstreams}}
+DD = \frac{\text{Number of dependency edges}}{\text{Number of active + blocked workplans}}
]
Interpretation:
@@ -115,7 +115,7 @@ Completed and archived streams are excluded because they no longer constrain pro
**Purpose:** Measure immediate operational impact of dependencies.
[
-BR = \frac{\text{Blocked workstreams}}{\text{Active + Blocked workstreams}}
+BR = \frac{\text{Blocked workplans}}{\text{Active + Blocked workplans}}
]
Interpretation:
@@ -130,7 +130,7 @@ Interpretation:
**Purpose:** Detect concentration of blocking power.
[
-SPR = \frac{\text{Max number of dependents on one incomplete workstream}}{\text{Active + Blocked}}
+SPR = \frac{\text{Max number of dependents on one incomplete workplan}}{\text{Active + Blocked}}
]
High SPR indicates fragile structure where one delay propagates widely.
@@ -141,13 +141,13 @@ High SPR indicates fragile structure where one delay propagates widely.
**Purpose:** Estimate how much work can proceed immediately.
-A workstream is eligible if:
+A workplan is eligible if:
* Status = ready or active
* All dependencies are finished or archived
[
-PEP = \frac{\text{Eligible ready or active workstreams}}{\text{Ready + Active + Blocked}}
+PEP = \frac{\text{Eligible ready or active workplans}}{\text{Ready + Active + Blocked}}
]
---
@@ -214,7 +214,7 @@ Recommended:
DD_{critical} = 1.0
]
-Meaning: one dependency per workstream is considered heavily coupled.
+Meaning: one dependency per workplan is considered heavily coupled.
---
@@ -224,7 +224,7 @@ WHI must be computed at three levels:
### 6.1 Intra-Domain WHI
-Using only workstreams and dependencies within the domain.
+Using only workplans and dependencies within the domain.
Purpose:
@@ -254,7 +254,7 @@ Computed on the full graph.
### 🟢 GREEN — Healthy Structure
-**Condition:** Workstreams are largely independent and flow is stable.
+**Condition:** Workplans are largely independent and flow is stable.
Recommended thresholds:
@@ -370,7 +370,7 @@ The metric system is designed to be:
## 11. Summary
-The Workstream Health Index provides a quantitative measure of how effectively an organization structures work for parallel execution and stable progress.
+The Workplan Health Index provides a quantitative measure of how effectively an organization structures work for parallel execution and stable progress.
It captures both:
diff --git a/dashboard/src/docs/workstream-lifecycle.md b/dashboard/src/docs/workstream-lifecycle.md
index 89bf4b6..49860fd 100644
--- a/dashboard/src/docs/workstream-lifecycle.md
+++ b/dashboard/src/docs/workstream-lifecycle.md
@@ -1,10 +1,10 @@
---
-title: Workstream Lifecycle - Reference
+title: Workplan Lifecycle - Reference
---
-# Workstream Lifecycle - Reference
+# Workplan Lifecycle - Reference
-A workstream is an information object that occupies a named lifecycle state.
+A workplan is an information object that occupies a named lifecycle state.
The stored `status` field keeps that state, while the task-flow engine derives
which other states are reachable and which exit assertions are blocking
movement. Dashboard health filters such as `needs_review` and `stalled` are
@@ -43,7 +43,7 @@ backlog -> proposed -> ready -> active -> finished -> archived
| **stalled** | Task counts + timestamp | Work started, but there has been no meaningful progress after the threshold |
`needs_review` and `stalled` can appear beside lifecycle states. They should
-not be written into workplan frontmatter or directly into the workstream
+not be written into workplan frontmatter or directly into the workplan
`status` field.
---
@@ -70,8 +70,8 @@ behind explicit tooling, not done silently.
## Flow Operations
```text
-get_flow_state(entity_type="workstream", entity_id="")
-advance_workstation(entity_type="workstream", entity_id="", target_workstation="finished")
+get_flow_state(entity_type="workplan", entity_id="")
+advance_workstation(entity_type="workplan", entity_id="", target_workstation="finished")
```
Direct status patching still exists for bootstrap and compatibility work:
@@ -82,5 +82,5 @@ curl -X PATCH http://127.0.0.1:8000/workplans// \
-d '{"status": "finished"}'
```
-Workstreams are never hard-deleted. Use `finished` for completed
+Workplans are never hard-deleted. Use `finished` for completed
implementation and `archived` for historical records outside normal planning.
diff --git a/dashboard/src/docs/workstreams.md b/dashboard/src/docs/workstreams.md
index fdfd8b6..fcd4382 100644
--- a/dashboard/src/docs/workstreams.md
+++ b/dashboard/src/docs/workstreams.md
@@ -1,25 +1,25 @@
---
-title: Workstreams — Reference
+title: Workplans — Reference
---
-# Workstreams — Reference
+# Workplans — Reference
-A workstream is a bounded unit of work within a topic. It carries a stored
+A workplan is a bounded unit of work within a topic. It carries a stored
workstation label in the `status` field, an optional owner and due date, and
-belongs to exactly one project domain. The Workstreams page gives you a
+belongs to exactly one project domain. The Workplans page gives you a
filtered, visual overview of active work, derived blocked state, and the
-dependency graph between workstreams.
+dependency graph between workplans.
The [Daily WSJF Triage](/wsjf-triage) page is a companion review surface for
activity-core's daily recommendations. It links recommendation candidates back
-to workstream detail pages when the candidate can be resolved through the
+to workplan detail pages when the candidate can be resolved through the
workplan index.
---
## Workstation Distribution chart
-A horizontal bar chart showing the count of workstreams in each stored
+A horizontal bar chart showing the count of workplans in each stored
workstation/status label for the current filter selection. Updates immediately
as filters change.
@@ -33,7 +33,7 @@ as filters change.
| **finished** | Implementation is complete |
| **archived** | Closed historical record |
-See [Workstream Lifecycle](/docs/workstream-lifecycle) for the full task-flow
+See [Workplan Lifecycle](/docs/workstream-lifecycle) for the full task-flow
model including derived health labels (`needs_review`, `stalled`) and
assertion-based blocking.
@@ -43,8 +43,8 @@ assertion-based blocking.
| Filter | Effect |
|---|---|
-| **Domain** | Multi-select — show only workstreams from selected domains |
-| **Status** | Multi-select — show only workstreams with selected workstation labels |
+| **Domain** | Multi-select — show only workplans from selected domains |
+| **Status** | Multi-select — show only workplans with selected workstation labels |
| **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.
@@ -53,11 +53,11 @@ The six domains are: `custodian`, `railiance`, `markitect`, `coulomb_social`, `p
---
-## All Workstreams table
+## All Workplans table
| Column | Source |
|---|---|
-| Title | Workstream title |
+| Title | Workplan title |
| Domain | Derived from the parent topic |
| Status | Current stored workstation/status label |
| Owner | Assigned person (or `—` if unset) |
@@ -70,11 +70,11 @@ 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:
+The Dependencies section shows workplans 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
+- **Workplan title** and current status badge
+- **↳ depends on** — workplans that must complete before this one can proceed
+- **⊳ blocks** — workplans that are waiting on this one
Dependencies are created via the MCP server:
@@ -90,7 +90,7 @@ If no dependency edges exist for the current filter, the section shows an empty-
---
-## Creating workstreams
+## Creating workplans
Via MCP:
@@ -115,11 +115,11 @@ curl -X POST http://127.0.0.1:8000/workplans/ \
---
-## Advancing a workstream
+## Advancing a workplan
```
-get_flow_state(entity_type="workstream", entity_id="")
-advance_workstation(entity_type="workstream", entity_id="", target_workstation="finished")
+get_flow_state(entity_type="workplan", entity_id="")
+advance_workstation(entity_type="workplan", entity_id="", target_workstation="finished")
```
Movement is flow-aware: the task-flow engine evaluates the target
@@ -130,4 +130,4 @@ and compatibility work, but normal lifecycle movement should prefer
---
-*Workstreams are never hard-deleted — use `archived` to close them without losing history.*
+*Workplans are never hard-deleted — use `archived` to close them without losing history.*
diff --git a/dashboard/src/docs/wsjf-triage.md b/dashboard/src/docs/wsjf-triage.md
index 3d35bec..ec714a4 100644
--- a/dashboard/src/docs/wsjf-triage.md
+++ b/dashboard/src/docs/wsjf-triage.md
@@ -17,7 +17,7 @@ GET /progress/?event_type=daily_triage&limit=14
Each event carries the report under `detail.report`, with a summary and a list
of recommendations. Candidate values are resolved through
`/workplans/index` so file-backed workplans can link to their
-workstream detail pages.
+workplan detail pages.
## How to read recommendations
@@ -50,7 +50,7 @@ Confidence labels mean:
## Pattern view
The pattern table aggregates recommendations in the loaded 14-day window. It is
-useful for spotting recurring human gates, stale revisit signals, or workstreams
+useful for spotting recurring human gates, stale revisit signals, or workplans
that keep surfacing as the next best piece of work.
No write controls live on this page. It is intentionally a review page so the
diff --git a/dashboard/src/index.md b/dashboard/src/index.md
index 879a6d1..5a37cab 100644
--- a/dashboard/src/index.md
+++ b/dashboard/src/index.md
@@ -148,10 +148,10 @@ if (_h1) { _h1.style.position = "relative"; withDocHelp(_h1, "/docs/overview");
display(html`⚠️ ${summary.error ?? ''}
`);
```
-## Workstreams by Repository
+## Workplans by Repository
```js
-// ── Filter workstreams by selected mode ───────────────────────────────────────
+// ── Filter workplans by selected mode ───────────────────────────────────────
// Lifecycle modes match stored canonical status values.
// Health modes are derived labels; they are not stored lifecycle states.
// Time modes filter by updated_at / created_at.
@@ -251,8 +251,8 @@ function _setChartMode(value) {
```js
const _modeSelect = html`
${_MODE_GROUPS.map(group => html`
${group.options.map(([value, label]) => html`${label} (${_workstreamsForMode(value, wsAll).length}) `)}
@@ -274,7 +274,7 @@ import * as Plot from "npm:@observablehq/plot";
const _chartModeValue = _modeValue(_chartModeState);
const _chartWsFiltered = _workstreamsForMode(_chartModeValue, wsAll);
-// Sort by domain, then repository, then most recently updated workstream.
+// Sort by domain, then repository, then most recently updated workplan.
// The axis labels show each domain/repo group once.
const chartWs = [..._chartWsFiltered].sort((a, b) => {
const domainCompare = (a.domain ?? "").localeCompare(b.domain ?? "");
@@ -289,7 +289,7 @@ const chartWs = [..._chartWsFiltered].sort((a, b) => {
const _isTimeBased = !_STATUS_MODES.has(_chartModeValue) && !_HEALTH_MODES.has(_chartModeValue);
function _wsWeight(s) { return (isClosedWorkstream(s) || normalizeWorkstreamStatus(s) === "blocked") ? "bold" : "normal"; }
-// ── y-axis: domain/repo label for first workstream per repository only ────────
+// ── y-axis: domain/repo label for first workplan per repository only ────────
const _yLabels = {};
const _seen = new Set();
for (const w of chartWs) {
@@ -321,24 +321,24 @@ function _wsTitle(d) {
// ── Render ────────────────────────────────────────────────────────────────────
if (chartWs.length === 0) {
const _emptyMsg = {
- proposed: "No proposed workstreams.",
- ready: "No ready workstreams.",
- active: "No active workstreams.",
- blocked: "No blocked workstreams.",
- backlog: "No backlog workstreams.",
- finished: "No finished workstreams.",
- archived: "No archived workstreams.",
- needs_review: "No ready workstreams need review.",
- stalled: "No stalled workstreams — everything is moving.",
- "1h": "No workstreams changed in the last hour.",
- "1d": "No workstreams changed in the last 24 hours.",
- "7d": "No workstreams changed in the last 7 days.",
- "30d": "No workstreams changed in the last 30 days.",
- today: "No workstreams changed today.",
- week: "No workstreams changed this week.",
- month: "No workstreams changed this month.",
+ proposed: "No proposed workplans.",
+ ready: "No ready workplans.",
+ active: "No active workplans.",
+ blocked: "No blocked workplans.",
+ backlog: "No backlog workplans.",
+ finished: "No finished workplans.",
+ archived: "No archived workplans.",
+ needs_review: "No ready workplans need review.",
+ stalled: "No stalled workplans — everything is moving.",
+ "1h": "No workplans changed in the last hour.",
+ "1d": "No workplans changed in the last 24 hours.",
+ "7d": "No workplans changed in the last 7 days.",
+ "30d": "No workplans changed in the last 30 days.",
+ today: "No workplans changed today.",
+ week: "No workplans changed this week.",
+ month: "No workplans changed this month.",
};
- display(html`${_emptyMsg[_chartModeValue] ?? "No workstreams."}
`);
+ display(html`${_emptyMsg[_chartModeValue] ?? "No workplans."}
`);
} else {
display(Plot.plot({
y: {
@@ -445,7 +445,7 @@ const decCount = (decisions.open ?? 0) + (decisions.escalated ?? 0);
const statusEl = html`
- Active Workstreams
+ Active Workplans
${ws.active ?? 0}
${ws.blocked ?? 0} blocked
@@ -510,7 +510,7 @@ const typeBadgeClass = {
};
if (nextSteps.length === 0) {
- display(html`
No actionable suggestions right now — all open workstreams are making progress or waiting on decisions.
`);
+ display(html`
No actionable suggestions right now — all open workplans are making progress or waiting on decisions.
`);
} else {
display(html`
${nextSteps.map(s => html`
@@ -543,7 +543,7 @@ if (regs.length === 0) {
```
```js
-// Registered domains with no workstreams yet — show a getting-started hint
+// Registered domains with no workplans yet — show a getting-started hint
const regs = pageState.milestones ?? [];
const registeredDomains = new Set(regs.map(e => e.detail?.domain).filter(Boolean));
const emptyRegistered = (summary.topics ?? []).filter(t =>
@@ -553,9 +553,9 @@ const emptyRegistered = (summary.topics ?? []).filter(t =>
if (emptyRegistered.length > 0) {
display(html`
💡 Getting started
-
These registered projects have no workstreams yet:
+
These registered projects have no workplans yet:
${emptyRegistered.map(t => html`
- ${t.domain_slug} — open repo in Claude Code and say "Hi!" to kick off first session, or run custodian create-workstream --domain ${t.domain_slug} --title "My first workstream" manually
+ ${t.domain_slug} — open repo in Claude Code and say "Hi!" to kick off first session, or create a workplan file under workplans/ and run statehub fix-consistency
`)}
`);
}
diff --git a/dashboard/src/interventions.md b/dashboard/src/interventions.md
index 27d7771..a688147 100644
--- a/dashboard/src/interventions.md
+++ b/dashboard/src/interventions.md
@@ -7,7 +7,7 @@ import {API, POLL_HEAVY, apiFetch, pollDelay, waitForVisible} from "./components
```
```js
-// Live poll: all tasks (filtered client-side) + workstreams + topics
+// Live poll: all tasks (filtered client-side) + workplans + topics
const interventionState = (async function*() {
let failures = 0;
while (true) {
diff --git a/dashboard/src/policy/workstream-dod.md b/dashboard/src/policy/workstream-dod.md
index ae6762f..ac78314 100644
--- a/dashboard/src/policy/workstream-dod.md
+++ b/dashboard/src/policy/workstream-dod.md
@@ -1,5 +1,5 @@
---
-title: Workstream Definition of Done
+title: Workplan Definition of Done
---
```js
diff --git a/dashboard/src/reference.md b/dashboard/src/reference.md
index e5118d4..25ec465 100644
--- a/dashboard/src/reference.md
+++ b/dashboard/src/reference.md
@@ -29,15 +29,15 @@ convention used in the Custodian State Hub.
| [Extension Points](/docs/extensions) | EP types, statuses, priorities, registration |
| [Inter-Repo Communication](/docs/inter-repo-communication) | Boundary rule, Internal/Ecosystem/Third-party taxonomy, routing workflows |
| [Live Data](/docs/live-data) | Poll interval, live indicator states, offline recovery |
-| [Overview](/docs/overview) | State summary sections, workstream chart, blocking decisions, next steps |
+| [Overview](/docs/overview) | State summary sections, workplan chart, blocking decisions, next steps |
| [Progress Log](/docs/progress-log) | Event types, append-only policy, session protocol |
| [Repos](/docs/repos) | Repo registry, SBOM coverage map, ingestion commands |
| [SBOM](/docs/sbom) | Lockfile ingestion, licence report, copyleft detection |
| [Tasks](/docs/tasks) | Task statuses, priorities, filter bar, status distribution chart |
| [Technical Debt](/docs/debt) | Debt types, severities, statuses, registration |
| [Todo](/docs/todo) | Internal/Ecosystem/Third-party classification, data sources |
-| [Workstream Health](/docs/workstream-health-index) | WHI formula, six base metrics, per-domain breakdown |
-| [Workstreams](/docs/workstreams) | Workstream statuses, dependency edges, WHI KPI card |
+| [Workplan Health](/docs/workstream-health-index) | WHI formula, six base metrics, per-domain breakdown |
+| [Workplans](/docs/workstreams) | Workplan statuses, dependency edges, WHI KPI card |
| [WSJF Triage](/docs/wsjf-triage) | Daily triage reports, action vocabulary, advisory review workflow |
---
@@ -73,7 +73,7 @@ Currently implemented record types:
|-------------|-------------|-----------------|
| `token-events` | `/token-events/
` | `GET /token-events/{id}` |
-Further record types (repos, workstreams, tasks) will be added in subsequent workplans.
+Further record types (repos, workplans, tasks) will be added in subsequent workplans.
---
diff --git a/dashboard/src/repos.md b/dashboard/src/repos.md
index 2f06d98..e9b11ef 100644
--- a/dashboard/src/repos.md
+++ b/dashboard/src/repos.md
@@ -39,7 +39,7 @@ const domains = _domains ?? [];
const sbom = _sbom ?? [];
const eps = _eps ?? [];
const tds = _tds ?? [];
-const workstreams = _workstreams ?? [];
+const workplans = _workstreams ?? [];
const doi = doiData; // reactive — updates when lazy fetch completes
// DoI lookups
@@ -53,9 +53,9 @@ const DOI_TIER_LABEL = {none: "None", core: "Core", standard: "Standard", full:
const domainById = Object.fromEntries(domains.map(d => [d.id, d]));
const domainBySlug = Object.fromEntries(domains.map(d => [d.slug, d]));
-// Active "repo-integration-{slug}" workstreams — signals onboarding in progress
+// Active "repo-integration-{slug}" workplans — signals onboarding in progress
const integratingBySlug = Object.fromEntries(
- workstreams
+ workplans
.filter(w => w.status === "active" && w.slug?.startsWith("repo-integration-"))
.map(w => [w.slug.replace("repo-integration-", ""), w])
);
@@ -83,7 +83,7 @@ for (const td of tds) {
tdByDomain[td.domain] = (tdByDomain[td.domain] ?? 0) + 1;
}
}
-// Contributions: try to map via workstream → topic → domain (not available here; skip for now)
+// Contributions: try to map via workplan → topic → domain (not available here; skip for now)
// Use domain slug from contributions' related_workstream if available — fallback: count by type only
// Build enriched repo rows
diff --git a/dashboard/src/tasks.md b/dashboard/src/tasks.md
index ae22608..68fa6b0 100644
--- a/dashboard/src/tasks.md
+++ b/dashboard/src/tasks.md
@@ -224,7 +224,7 @@ display(buildEntityTable(
{label: "Priority", key: "priority"},
{label: "Title", key: "title", cls: "et-title-col et-title-cell"},
{label: "Domain", key: "domain"},
- {label: "Workstream", key: "workstream_title", cls: "et-ws-col et-ws-cell"},
+ {label: "Workplan", key: "workstream_title", cls: "et-ws-col et-ws-cell"},
{label: "Assignee", render: t => t.assignee ?? "—"},
{label: "Due", render: t => t.due_date ?? "—"},
],
diff --git a/dashboard/src/todo.md b/dashboard/src/todo.md
index 7a5e693..0d4ffc8 100644
--- a/dashboard/src/todo.md
+++ b/dashboard/src/todo.md
@@ -8,7 +8,7 @@ const THIS_REPO = "the-custodian";
```
```js
-// Live poll: tasks + workstreams + topics + contributions
+// Live poll: tasks + workplans + topics + contributions
const todoState = (async function*() {
let failures = 0;
while (true) {
@@ -136,7 +136,7 @@ if (_h1) { _h1.style.position = "relative"; withDocHelp(_h1, "/docs/todo"); }
## Internal
-Work fully addressable within this repo. Open tasks in custodian workstreams
+Work fully addressable within this repo. Open tasks in custodian workplans
without a cross-repo routing prefix.
```js
diff --git a/dashboard/src/token-cost.md b/dashboard/src/token-cost.md
index 4d9923e..5786080 100644
--- a/dashboard/src/token-cost.md
+++ b/dashboard/src/token-cost.md
@@ -174,13 +174,13 @@ display(html`No workstream data yet.`);
+ display(html`
No workplan data yet.
`);
} else {
display(Inputs.table(rows.map((r, i) => ({...r, _ref: i})), {
columns: ["_ref", "label", "tokens_in", "tokens_out", "tokens_total", "event_count"],
- header: {_ref: "REF", label: "Workstream", tokens_in: "Tokens In", tokens_out: "Tokens Out", tokens_total: "Total", event_count: "Events"},
+ header: {_ref: "REF", label: "Workplan", tokens_in: "Tokens In", tokens_out: "Tokens Out", tokens_total: "Total", event_count: "Events"},
format: {
- _ref: (_, i) => refCell(i + 1, "workstreams", rows[i].scope_id),
+ _ref: (_, i) => refCell(i + 1, "workplans", rows[i].scope_id),
label: d => nameCell(d, d),
tokens_in: d => d.toLocaleString(),
tokens_out: d => d.toLocaleString(),
diff --git a/dashboard/src/tools.md b/dashboard/src/tools.md
index d9d5314..5083b7d 100644
--- a/dashboard/src/tools.md
+++ b/dashboard/src/tools.md
@@ -65,7 +65,7 @@ Connected applications, services, and local tools used across the Custodian ecos
display(html`
${appCard({
icon: "🗄️", name: "State Hub API", status: apiUp,
- desc: "FastAPI backend — the source of truth for all workstream, task, and decision data.",
+ desc: "FastAPI backend — the source of truth for all workplan, task, and decision data.",
url: "http://127.0.0.1:8000/docs", label: "127.0.0.1:8000 · Swagger UI",
})}
${appCard({
diff --git a/dashboard/src/workplan-queue.md b/dashboard/src/workplan-queue.md
index ca20bd0..052fef9 100644
--- a/dashboard/src/workplan-queue.md
+++ b/dashboard/src/workplan-queue.md
@@ -62,7 +62,7 @@ function statusCell(row) {
function blockers(row) {
const parts = [];
- if (row.blocked_by_workstream_ids?.length) parts.push(`${row.blocked_by_workstream_ids.length} workstream`);
+ if (row.blocked_by_workstream_ids?.length) parts.push(`${row.blocked_by_workstream_ids.length} workplan`);
if (row.blocked_by_task_ids?.length) parts.push(`${row.blocked_by_task_ids.length} task`);
return parts.length ? parts.join(", ") : "—";
}
diff --git a/dashboard/src/workstreams.md b/dashboard/src/workstreams.md
index 20fee33..e3faa2c 100644
--- a/dashboard/src/workstreams.md
+++ b/dashboard/src/workstreams.md
@@ -8,7 +8,7 @@ import {WORKSTREAM_STATUSES, isClosedWorkstream, normalizeWorkstreamStatus} from
```
```js
-// Fetch workstreams + topics + dep edges in parallel; /state/deps replaces the
+// Fetch workplans + topics + dep edges in parallel; /state/deps replaces the
// heavier /state/summary which was only used here to extract dependency edges.
const wsState = (async function*() {
let failures = 0;
@@ -50,7 +50,7 @@ const _ts = wsState.ts;
```
```js
-// ── Workstream Health Index (WHI) ────────────────────────────────────────────
+// ── Workplan Health Index (WHI) ────────────────────────────────────────────
const _idToDomain = Object.fromEntries(data.map(w => [w.id, w.domain ?? "unknown"]));
const _closedIds = new Set(data.filter(w => isClosedWorkstream(w.status)).map(w => w.id));
const _openCount = openWs.length;
@@ -63,7 +63,7 @@ const _DD = _openCount > 0 ? _totalEdges / _openCount : 0;
// Blocked Ratio
const _BR = _openCount > 0 ? openWs.filter(w => w.status === "blocked").length / _openCount : 0;
-// Single-Point Risk — max inbound edges on one incomplete workstream
+// Single-Point Risk — max inbound edges on one incomplete workplan
const _inbound = {};
for (const e of _allEdges) {
if (!_closedIds.has(e.to)) _inbound[e.to] = (_inbound[e.to] ?? 0) + 1;
@@ -72,7 +72,7 @@ const _SPR = _openCount > 0
? (Object.keys(_inbound).length > 0 ? Math.max(...Object.values(_inbound)) : 0) / _openCount
: 0;
-// Parallel Execution Potential — ready/active workstreams with all deps finished
+// Parallel Execution Potential — ready/active workplans with all deps finished
const _PEP = _openCount > 0
? openWs.filter(w => ["ready", "active"].includes(normalizeWorkstreamStatus(w.status)) && w.depends_on.every(d => _closedIds.has(d.workstream_id))).length / _openCount
: 0;
@@ -282,7 +282,7 @@ display(Plot.plot({
display(_filtersForm);
{
- // Enrich each workstream with tasks/deps data from open_workstreams summary
+ // Enrich each workplan with tasks/deps data from open_workstreams summary
const _openWsMap = Object.fromEntries(openWs.map(w => [w.id, w]));
const _wsTable = buildEntityTable(
filtered,
@@ -290,12 +290,12 @@ display(_filtersForm);
{label: "Title", key: "title", cls: "et-title-col et-title-cell",
render: w => w.title},
{label: "Domain", key: "domain"},
- {label: "Status", render: w => statusControl({entity: w, type: "workstream", statuses: WORKSTREAM_STATUSES})},
+ {label: "Status", render: w => statusControl({entity: w, type: "workplan", statuses: WORKSTREAM_STATUSES})},
{label: "Owner", render: w => w.owner ?? "—"},
{label: "Due", render: w => w.due_date ?? "—"},
{label: "Updated", render: w => new Date(w.updated_at).toLocaleDateString()},
],
- w => openEntityModal({...w, ..._openWsMap[w.id]}, "workstream"),
+ w => openEntityModal({...w, ..._openWsMap[w.id]}, "workplan"),
);
display(_wsTable);
}
diff --git a/dashboard/src/workstreams/[id].md b/dashboard/src/workstreams/[id].md
index dae777b..dcc56f6 100644
--- a/dashboard/src/workstreams/[id].md
+++ b/dashboard/src/workstreams/[id].md
@@ -1,5 +1,5 @@
---
-title: Workstream
+title: Workplan
---
```js
@@ -18,8 +18,8 @@ const [raw, taskRows, workplanIndex] = await Promise.all([
.then(r => r.ok ? r.json() : [])
.catch(() => []),
fetch(`${API}/workplans/index`)
- .then(r => r.ok ? r.json() : {workstreams: {}})
- .catch(() => ({workstreams: {}})),
+ .then(r => r.ok ? r.json() : {workplans: {}})
+ .catch(() => ({workplans: {}})),
]);
```
@@ -27,16 +27,16 @@ const [raw, taskRows, workplanIndex] = await Promise.all([
if (raw.error) {
display(html`
⚠️ ${raw.error}
`);
} else {
- const workplan = (workplanIndex.workstreams ?? {})[wsId] ?? {};
+ const workplan = (workplanIndex.workplans ?? workplanIndex.workstreams ?? {})[wsId] ?? {};
const name = raw.title || raw.slug || wsId;
const shortName = name.length > 60 ? name.slice(0, 60) + "…" : name;
- display(html`
Workstream · ${shortName} `);
+ display(html`
Workplan · ${shortName} `);
display(html`
← Overview | ← Workplans | ← Token Cost
`);
display(html`
Status ${statusControl({
entity: raw,
- type: "workstream",
+ type: "workplan",
statuses: WORKSTREAM_STATUSES,
onSaved: () => setTimeout(() => location.reload(), 450),
})}
@@ -53,7 +53,7 @@ if (raw.error) {
display(html`
Tasks `);
if (sortedTasks.length === 0) {
- display(html`
No tasks are attached to this workstream.
`);
+ display(html`
No tasks are attached to this workplan.
`);
} else {
display(html`
Status Priority Task Human
diff --git a/dashboard/src/wsjf-triage.md b/dashboard/src/wsjf-triage.md
index a1569f2..c593923 100644
--- a/dashboard/src/wsjf-triage.md
+++ b/dashboard/src/wsjf-triage.md
@@ -23,7 +23,7 @@ import {
const triageState = (async function*() {
let failures = 0;
while (true) {
- let events = [], workplanIndex = {workstreams: {}}, ok = false;
+ let events = [], workplanIndex = {workplans: {}}, ok = false;
try {
const [reportsResp, indexResp] = await Promise.all([
apiFetch("/progress/?event_type=daily_triage&limit=14"),
@@ -31,7 +31,7 @@ const triageState = (async function*() {
]);
ok = reportsResp.ok && indexResp.ok;
events = reportsResp.ok ? await reportsResp.json() : [];
- workplanIndex = indexResp.ok ? await indexResp.json() : {workstreams: {}};
+ workplanIndex = indexResp.ok ? await indexResp.json() : {workplans: {}};
} catch {}
failures = ok ? 0 : failures + 1;
yield {events, workplanIndex, ok, ts: new Date()};
@@ -42,7 +42,7 @@ const triageState = (async function*() {
```js
const reports = normalizeTriageReports(triageState.events ?? []);
-const candidateIndex = buildCandidateIndex(triageState.workplanIndex ?? {workstreams: {}});
+const candidateIndex = buildCandidateIndex(triageState.workplanIndex ?? {workplans: {}});
const _ok = triageState.ok ?? false;
const _ts = triageState.ts;
const latestReport = reports[0] ?? null;
@@ -140,7 +140,7 @@ function renderPatterns(reports, index) {
${rows.length === 0
? html`No repeated recommendations are visible in the loaded 14-day window.
`
: html`
- Workstream Times Recommended Most Frequent Action
+ Workplan Times Recommended Most Frequent Action
${rows.map(row => html`
${candidateNode(row.candidate, index)}
${row.count} / ${Math.max(1, windowReports.length)} reports
diff --git a/dashboard/test/terminology-nav.test.mjs b/dashboard/test/terminology-nav.test.mjs
new file mode 100644
index 0000000..c191d80
--- /dev/null
+++ b/dashboard/test/terminology-nav.test.mjs
@@ -0,0 +1,21 @@
+import assert from "node:assert/strict";
+import {readFileSync} from "node:fs";
+import test from "node:test";
+import {fileURLToPath} from "node:url";
+import {dirname, join} from "node:path";
+
+const root = join(dirname(fileURLToPath(import.meta.url)), "..");
+const config = readFileSync(join(root, "observablehq.config.js"), "utf8");
+const indexMd = readFileSync(join(root, "src/index.md"), "utf8");
+
+test("dashboard navigation uses workplan labels", () => {
+ assert.match(config, /name: "Workplans"/);
+ assert.doesNotMatch(config, /name: "Workstreams"/);
+});
+
+test("overview page uses workplan-first user-facing copy", () => {
+ assert.match(indexMd, /## Workplans by Repository/);
+ assert.match(indexMd, /Active Workplans/);
+ assert.doesNotMatch(indexMd, /No active workstreams\./);
+ assert.doesNotMatch(indexMd, /Active Workstreams/);
+});
\ No newline at end of file
diff --git a/docs/workplan-terminology-legacy-retirement-backlog.md b/docs/workplan-terminology-legacy-retirement-backlog.md
new file mode 100644
index 0000000..f946caa
--- /dev/null
+++ b/docs/workplan-terminology-legacy-retirement-backlog.md
@@ -0,0 +1,108 @@
+# Workplan Terminology Legacy Retirement Backlog
+
+Date: 2026-07-08
+Owner: `STATE-WP-0069` (child of `CUST-WP-0055`)
+Baseline: `the-custodian/docs/evidence/workstream-terminology-baseline-20260708.json`
+
+This backlog ranks every metered legacy `workstream` interface still present in
+State Hub. **Removal requires legacy-meter evidence** — zero measured calls in
+the review window, replacement verified, no manual hold.
+
+Authoritative interface matrix: `docs/workplan-terminology-transition.md`.
+
+## Retirement rule (unchanged)
+
+1. Registered in `legacy-meter`
+2. Replacement reference verified
+3. No manual hold
+4. Zero measured calls in the review window
+
+Activity-core runs the weekly review; State Hub owns usage state and removal.
+
+## Scan allowlist (grep tooling)
+
+Exclude these paths from non-compat prose counts (see
+`the-custodian/tools/scan_workstream_allowlist.yaml`):
+
+| Area | Paths |
+| --- | --- |
+| Compat REST | `api/routers/workstreams.py`, `api/routers/workstream_dependencies.py` |
+| Legacy meter | `api/routers/legacy_meter.py`, `api/services/legacy_meter.py`, `api/models/legacy_meter.py`, `migrations/` |
+| MCP aliases | `mcp_server/` |
+| Transition docs | `docs/workplan-terminology-transition.md`, this file, `docs/nats-event-subjects.md` |
+| Regression tests | `tests/test_legacy_meter.py`, `tests/test_routers_core.py` |
+| CLI compat | `custodian_cli.py`, `scripts/consistency_check.py` |
+
+Dashboard prose is **not** allowlisted — `STATE-WP-0069` T02 drives it to zero
+`prose:workstream` in `dashboard/src/`.
+
+## Ranked backlog
+
+Risk order: REST > MCP > events > dashboard prose > internal identifiers.
+
+| Phase | Legacy-meter key | Replacement | Risk | Owner task |
+| ---: | --- | --- | --- | --- |
+| 1 | `rest_api:GET /workstreams/` | `GET /workplans/` | REST | T04 |
+| 1 | `rest_api:POST /workstreams/` | `POST /workplans/` | REST | T04 |
+| 1 | `rest_api:GET /workstreams/{workstream_id}` | `GET /workplans/{workplan_id}` | REST | T04 |
+| 1 | `rest_api:PATCH /workstreams/{workstream_id}` | `PATCH /workplans/{workplan_id}` | REST | T04 |
+| 1 | `rest_api:DELETE /workstreams/{workstream_id}` | `DELETE /workplans/{workplan_id}` | REST | T04 |
+| 1 | `rest_api:GET /workstreams/workplan-index` | `GET /workplans/index` | REST | T04 |
+| 2 | `rest_api:GET /workstreams/{workstream_id}/dependencies/` | `GET /workplans/{workplan_id}/dependencies/` | REST | T04 |
+| 2 | `rest_api:POST /workstreams/{workstream_id}/dependencies/` | `POST /workplans/{workplan_id}/dependencies/` | REST | T04 |
+| 2 | `rest_api:DELETE /workstreams/{workstream_id}/dependencies/{dep_id}` | `DELETE /workplans/{workplan_id}/dependencies/{dep_id}` | REST | T04 |
+| 2 | `rest_api:PATCH /execution/workstreams/{workstream_id}/intent` | `PATCH /execution/workplans/{workplan_id}/intent` | REST | T04 |
+| 3 | `mcp:create_workstream` | `create_workplan` | MCP | T03 |
+| 3 | `mcp:update_workstream` | `update_workplan` | MCP | T03 |
+| 3 | `mcp:update_workstream_status` | `update_workplan_status` | MCP | T03 |
+| 3 | `mcp:list_workstreams` | `list_workplans` | MCP | T03 |
+| 3 | `state://workstreams/{topic_slug}` | `state://workplans/{topic_slug}` (proposed) | MCP resource | T03 |
+| 4 | `event_subject:org.statehub.workstream.completed` | `org.statehub.workplan.completed` | Event | T05 |
+| 5 | Dashboard nav label `Workstreams` | `Workplans` (URL compat retained) | Prose | T02 |
+| 5 | `dashboard/src/index.md` user-facing copy | workplan-first strings | Prose | T02 |
+| 6 | `open_workstreams` summary cache key | `open_workplans` | Internal | T06 |
+| 6 | `flows/workstream.yaml` entity id | workplan successor flow | Internal | T06 |
+
+### Query-param aliases (not separately metered today)
+
+These accept `workstream_id` alongside `workplan_id` on preferred routes:
+
+- `GET /tasks/` — `api/routers/tasks.py`
+- `GET /decisions/` — `api/routers/decisions.py`
+- `GET /token-events/` — `api/routers/token_events.py`
+
+Retire param aliases in T04 after route retirement; document callers via
+weekly review component headers (`X-StateHub-Component`).
+
+## Grep budget by phase
+
+Measured with:
+
+```bash
+python ~/the-custodian/tools/scan_workstream_terminology.py --repo state-hub --apply-allowlist --json
+python ~/the-custodian/tools/scan_workstream_terminology.py --repo state-hub --check-prose-gate
+```
+
+| Phase | Target |
+| --- | --- |
+| After T02 | Zero `prose:workstream` in `dashboard/src/` |
+| After T03 | MCP tool docstrings and error messages workplan-first |
+| After T04 | OpenAPI lists `/workplans` only; `/workstreams` returns 410 or unmounted |
+| After T07 | Total repo hits reduced ≥50% from 2026-07-08 baseline |
+
+## Sequencing
+
+```
+T01 backlog (this document) ──► T02 dashboard prose
+ ├─► T03 MCP deprecation warnings → alias removal
+ ├─► T04 REST retirement (per-key zero usage)
+ ├─► T05 stop dual-publish (after CUST-WP-0055 T03)
+ ├─► T06 internal renames
+ └─► T07 closeout
+```
+
+## Related workplans
+
+- `STATE-WP-0054` — compatibility layer and legacy-meter (finished)
+- `STATE-WP-0069` — this retirement plan
+- `CUST-WP-0055` — fleet coordination; activity-core catalog alignment (T03)
\ No newline at end of file
diff --git a/workplans/STATE-WP-0069-workplan-terminology-legacy-retirement.md b/workplans/STATE-WP-0069-workplan-terminology-legacy-retirement.md
index 5838bc7..b7e0de3 100644
--- a/workplans/STATE-WP-0069-workplan-terminology-legacy-retirement.md
+++ b/workplans/STATE-WP-0069-workplan-terminology-legacy-retirement.md
@@ -4,7 +4,7 @@ type: workplan
title: "Workplan terminology legacy retirement (State Hub)"
domain: infotech
repo: state-hub
-status: proposed
+status: active
owner: codex
topic_slug: custodian
planning_priority: medium
@@ -72,7 +72,7 @@ excluded once documented in T01).
```task
id: STATE-WP-0069-T01
-status: todo
+status: done
priority: high
state_hub_task_id: "ffc186e0-807d-4ee4-b11f-3f769af2ab2d"
```
@@ -96,7 +96,7 @@ Done when the backlog is reviewed and each interface has a phase assignment (T02
```task
id: STATE-WP-0069-T02
-status: todo
+status: done
priority: high
state_hub_task_id: "996e484e-8cfb-4c9e-8682-c9c3da0c1d72"
```