feat(terminology): workplan-first dashboard and retirement backlog (STATE-WP-0069)
Add the ranked legacy-interface backlog (T01), rename dashboard navigation and user-facing copy to workplan while preserving wire-compat API keys (T02), and activate the retirement workplan with T01/T02 marked done.
This commit is contained in:
parent
4dc69bb8f5
commit
b2264d1f06
44 changed files with 382 additions and 253 deletions
|
|
@ -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" },
|
||||
],
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
},
|
||||
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
* initImprovementModal({apiBase: "http://127.0.0.1:8000"});
|
||||
*
|
||||
* Widget names can be declared explicitly via data attribute:
|
||||
* <div data-widget-name="Workstreams by Domain">…</div>
|
||||
* <div data-widget-name="Workplans by Domain">…</div>
|
||||
*
|
||||
* Otherwise the component walks the DOM to infer the nearest section heading.
|
||||
* Submissions are stored as technical-debt items with debt_type="dashboard-improvement".
|
||||
|
|
|
|||
|
|
@ -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)) {
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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`<div class="kpi-infobox">
|
|||
<div class="kpi-row-right"><div class="kpi-row-value">${edges.length}</div></div>
|
||||
</div>
|
||||
<div class="kpi-row">
|
||||
<span class="kpi-row-label">workstreams involved</span>
|
||||
<span class="kpi-row-label">workplans involved</span>
|
||||
<div class="kpi-row-right"><div class="kpi-row-value">${_wsWithDeps.size}</div></div>
|
||||
</div>
|
||||
</div>`;
|
||||
|
|
@ -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) {
|
|||
<thead>
|
||||
<tr>
|
||||
<th>Depends-on domain</th>
|
||||
<th>Depends-on workstream</th>
|
||||
<th>Depends-on workplan</th>
|
||||
<th></th>
|
||||
<th>Blocked-by domain</th>
|
||||
<th>Blocked-by workstream</th>
|
||||
<th>Blocked-by workplan</th>
|
||||
<th>Status</th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
|
|
|||
|
|
@ -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 |
|
||||
|
|
|
|||
|
|
@ -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:<slug>]` prefix |
|
||||
| **Third-party** | **Contribution artifact in `contrib/` + state hub registration** |
|
||||
|
||||
|
|
|
|||
|
|
@ -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 (`<help-tip>`) 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 `<select>` 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
|
||||
|
|
|
|||
|
|
@ -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/<from_id>/dependencies/ \
|
|||
-d '{"to_workstream_id": "<to_id>", "description": "..."}'
|
||||
```
|
||||
|
||||
To list dependencies for a workstream:
|
||||
To list dependencies for a workplan:
|
||||
|
||||
```
|
||||
list_dependencies(workstream_id="<uuid>")
|
||||
|
|
@ -77,10 +77,10 @@ list_dependencies(workstream_id="<uuid>")
|
|||
|
||||
## 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.
|
||||
|
||||
---
|
||||
|
||||
|
|
|
|||
|
|
@ -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 |
|
||||
|
|
|
|||
|
|
@ -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": "<uuid>"}`. 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.
|
||||
|
|
|
|||
|
|
@ -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="<uuid of appropriate workstream in the target domain>",
|
||||
workstream_id="<uuid of appropriate workplan in the target domain>",
|
||||
title="[repo:<target-slug>] 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:<this-slug>]` in their title and surfaces
|
||||
them in the orientation brief.
|
||||
|
||||
|
|
|
|||
|
|
@ -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 `<details>` with the task title and description (shown when different from the action note) |
|
||||
|
||||
|
|
@ -66,9 +66,9 @@ clear_human_flag(task_id = "<uuid>")
|
|||
|
||||
---
|
||||
|
||||
## Filtering by workstream
|
||||
## Filtering by workplan
|
||||
|
||||
`list_human_interventions(workstream_id="<uuid>")` via MCP returns only interventions for a specific workstream — useful for scoped reviews in agent sessions.
|
||||
`list_human_interventions(workstream_id="<uuid>")` via MCP returns only interventions for a specific workplan — useful for scoped reviews in agent sessions.
|
||||
|
||||
---
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 = "<uuid>", // link to relevant workstream (optional)
|
||||
workstream_id = "<uuid>", // link to relevant workplan (optional)
|
||||
topic_id = "<uuid>", // link to relevant topic (optional)
|
||||
detail = { "key": "value" } // any structured data worth preserving
|
||||
)
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
||||
|
|
|
|||
|
|
@ -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("<domain>")`, 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: `<repo-slug>`** is created in the
|
||||
A workplan titled **Repo Integration: `<repo-slug>`** 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=<slug> SCAN=1 REPO_PATH=<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/<DOMAIN>-WP-0001-<slug>.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("<domain>")` shows active workstreams,
|
||||
- **Session start:** `get_domain_summary("<domain>")` shows active workplans,
|
||||
blocking decisions, and recent progress — the standard orientation
|
||||
- **Ecosystem todos:** tasks with `[repo:<slug>]` 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.
|
||||
|
|
|
|||
|
|
@ -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:<slug>]` 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)
|
||||
|
|
|
|||
|
|
@ -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("<slug>")` to load active workstreams,
|
||||
1. **Orient** — call `get_domain_summary("<slug>")` to load active workplans,
|
||||
pending tasks, blocking decisions, and suggested next steps for this domain.
|
||||
2. **Check inbox** — call `get_messages(to_agent="<name>", 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`
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 |
|
||||
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
||||
|
|
|
|||
|
|
@ -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="<uuid>")
|
||||
advance_workstation(entity_type="workstream", entity_id="<uuid>", target_workstation="finished")
|
||||
get_flow_state(entity_type="workplan", entity_id="<uuid>")
|
||||
advance_workstation(entity_type="workplan", entity_id="<uuid>", 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/<uuid>/ \
|
|||
-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.
|
||||
|
|
|
|||
|
|
@ -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="<uuid>")
|
||||
advance_workstation(entity_type="workstream", entity_id="<uuid>", target_workstation="finished")
|
||||
get_flow_state(entity_type="workplan", entity_id="<uuid>")
|
||||
advance_workstation(entity_type="workplan", entity_id="<uuid>", 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.*
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -148,10 +148,10 @@ if (_h1) { _h1.style.position = "relative"; withDocHelp(_h1, "/docs/overview");
|
|||
display(html`<div class="warning" style="display:${summary.error ? '' : 'none'}">⚠️ ${summary.error ?? ''}</div>`);
|
||||
```
|
||||
|
||||
## 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`<select
|
||||
class="ws-mode-select"
|
||||
aria-label="Workstream chart mode with matching workstream counts"
|
||||
title="Choose which workstreams to show; counts are matching workstreams"
|
||||
aria-label="Workplan chart mode with matching workplan counts"
|
||||
title="Choose which workplans to show; counts are matching workplans"
|
||||
>
|
||||
${_MODE_GROUPS.map(group => html`<optgroup label=${group.label}>
|
||||
${group.options.map(([value, label]) => html`<option value=${value}>${label} (${_workstreamsForMode(value, wsAll).length})</option>`)}
|
||||
|
|
@ -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`<p style="color:gray">${_emptyMsg[_chartModeValue] ?? "No workstreams."}</p>`);
|
||||
display(html`<p style="color:gray">${_emptyMsg[_chartModeValue] ?? "No workplans."}</p>`);
|
||||
} else {
|
||||
display(Plot.plot({
|
||||
y: {
|
||||
|
|
@ -445,7 +445,7 @@ const decCount = (decisions.open ?? 0) + (decisions.escalated ?? 0);
|
|||
const statusEl = html`<div>
|
||||
<div class="grid grid-cols-4" style="gap:1rem;margin-bottom:0.75rem">
|
||||
<a class="card card-link" href="./workstreams">
|
||||
<h3>Active Workstreams</h3>
|
||||
<h3>Active Workplans</h3>
|
||||
<p class="big-num">${ws.active ?? 0}</p>
|
||||
<small>${ws.blocked ?? 0} blocked</small>
|
||||
</a>
|
||||
|
|
@ -510,7 +510,7 @@ const typeBadgeClass = {
|
|||
};
|
||||
|
||||
if (nextSteps.length === 0) {
|
||||
display(html`<p class="ns-empty">No actionable suggestions right now — all open workstreams are making progress or waiting on decisions.</p>`);
|
||||
display(html`<p class="ns-empty">No actionable suggestions right now — all open workplans are making progress or waiting on decisions.</p>`);
|
||||
} else {
|
||||
display(html`<div class="ns-grid">${nextSteps.map(s => html`
|
||||
<div class="ns-card">
|
||||
|
|
@ -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`<div class="hint-box">
|
||||
<strong>💡 Getting started</strong>
|
||||
<p>These registered projects have no workstreams yet:</p>
|
||||
<p>These registered projects have no workplans yet:</p>
|
||||
<ul>${emptyRegistered.map(t => html`<li>
|
||||
<strong>${t.domain_slug}</strong> — open repo in Claude Code and say <em>"Hi!"</em> to kick off first session, or run <code>custodian create-workstream --domain ${t.domain_slug} --title "My first workstream"</code> manually
|
||||
<strong>${t.domain_slug}</strong> — open repo in Claude Code and say <em>"Hi!"</em> to kick off first session, or create a workplan file under <code>workplans/</code> and run <code>statehub fix-consistency</code>
|
||||
</li>`)}</ul>
|
||||
</div>`);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
---
|
||||
title: Workstream Definition of Done
|
||||
title: Workplan Definition of Done
|
||||
---
|
||||
|
||||
```js
|
||||
|
|
|
|||
|
|
@ -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/<id>` | `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.
|
||||
|
||||
---
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 ?? "—"},
|
||||
],
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -174,13 +174,13 @@ display(html`<div style="display:grid;grid-template-columns:repeat(auto-fit,minm
|
|||
const sorted = sortRows(aggregate.by_workstream ?? [], sortOrder);
|
||||
const rows = sorted.slice(0, maxResults);
|
||||
if (rows.length === 0) {
|
||||
display(html`<p style="color:var(--theme-foreground-muted)">No workstream data yet.</p>`);
|
||||
display(html`<p style="color:var(--theme-foreground-muted)">No workplan data yet.</p>`);
|
||||
} 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(),
|
||||
|
|
|
|||
|
|
@ -65,7 +65,7 @@ Connected applications, services, and local tools used across the Custodian ecos
|
|||
display(html`<div class="app-grid">
|
||||
${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({
|
||||
|
|
|
|||
|
|
@ -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(", ") : "—";
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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`<div style="color:red;padding:1rem">⚠️ ${raw.error}</div>`);
|
||||
} 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`<h1 style="font-size:1.1rem;margin-bottom:0.25rem">Workstream · <em>${shortName}</em></h1>`);
|
||||
display(html`<h1 style="font-size:1.1rem;margin-bottom:0.25rem">Workplan · <em>${shortName}</em></h1>`);
|
||||
display(html`<p style="margin-top:0"><a href="/">← Overview</a> | <a href="/workstreams">← Workplans</a> | <a href="/token-cost">← Token Cost</a></p>`);
|
||||
|
||||
display(html`<div class="ws-summary">
|
||||
<div><span>Status</span>${statusControl({
|
||||
entity: raw,
|
||||
type: "workstream",
|
||||
type: "workplan",
|
||||
statuses: WORKSTREAM_STATUSES,
|
||||
onSaved: () => setTimeout(() => location.reload(), 450),
|
||||
})}</div>
|
||||
|
|
@ -53,7 +53,7 @@ if (raw.error) {
|
|||
|
||||
display(html`<h2>Tasks</h2>`);
|
||||
if (sortedTasks.length === 0) {
|
||||
display(html`<p style="color:gray">No tasks are attached to this workstream.</p>`);
|
||||
display(html`<p style="color:gray">No tasks are attached to this workplan.</p>`);
|
||||
} else {
|
||||
display(html`<table class="task-table">
|
||||
<thead><tr><th>Status</th><th>Priority</th><th>Task</th><th>Human</th></tr></thead>
|
||||
|
|
|
|||
|
|
@ -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`<p class="triage-muted">No repeated recommendations are visible in the loaded 14-day window.</p>`
|
||||
: html`<table class="triage-table">
|
||||
<thead><tr><th>Workstream</th><th>Times Recommended</th><th>Most Frequent Action</th></tr></thead>
|
||||
<thead><tr><th>Workplan</th><th>Times Recommended</th><th>Most Frequent Action</th></tr></thead>
|
||||
<tbody>${rows.map(row => html`<tr>
|
||||
<td>${candidateNode(row.candidate, index)}</td>
|
||||
<td>${row.count} / ${Math.max(1, windowReports.length)} reports</td>
|
||||
|
|
|
|||
21
dashboard/test/terminology-nav.test.mjs
Normal file
21
dashboard/test/terminology-nav.test.mjs
Normal file
|
|
@ -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/);
|
||||
});
|
||||
108
docs/workplan-terminology-legacy-retirement-backlog.md
Normal file
108
docs/workplan-terminology-legacy-retirement-backlog.md
Normal file
|
|
@ -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)
|
||||
|
|
@ -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"
|
||||
```
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue