From ef51b99ff56cbe433d8131259641008190b0ded0 Mon Sep 17 00:00:00 2001 From: tegwick Date: Thu, 9 Jul 2026 01:48:53 +0200 Subject: [PATCH] STATE-WP-0072: remediate remaining workstream HTTP callers Research sweep captured in research/20260709-workstream-caller-sweep.md. Migrate dashboard detail tasks query, custodian_cli POST bodies, and onboarding curl to workplan-first paths; re-capture 8h legacy-meter evidence. --- custodian_cli.py | 12 +-- dashboard/src/workstreams/[id].md | 2 +- .../legacy-meter-weekly-review-20260709.json | 8 +- .../workstream-caller-inventory-20260709.md | 78 ++++++++++++++++++ docs/onboarding.md | 2 +- research/20260709-workstream-caller-sweep.md | 57 +++++++++++++ ...E-WP-0072-workstream-caller-remediation.md | 81 +++++++++++++++++++ 7 files changed, 228 insertions(+), 12 deletions(-) create mode 100644 docs/evidence/workstream-caller-inventory-20260709.md create mode 100644 research/20260709-workstream-caller-sweep.md create mode 100644 workplans/STATE-WP-0072-workstream-caller-remediation.md diff --git a/custodian_cli.py b/custodian_cli.py index 9498b57..f0638b9 100644 --- a/custodian_cli.py +++ b/custodian_cli.py @@ -293,7 +293,7 @@ def cmd_register(args: argparse.Namespace) -> None: ] for title, priority, description in tasks: _api_post("/tasks/", { - "workstream_id": ws_id, + "workplan_id": ws_id, "title": title, "priority": priority, "description": description, @@ -446,9 +446,9 @@ def cmd_create_workstream(args: argparse.Namespace) -> None: }) _api_post("/progress/", { "topic_id": topic_id, - "workstream_id": ws["id"], - "event_type": "workstream_created", - "summary": f"Workstream created: {args.title}", + "workplan_id": ws["id"], + "event_type": "workplan_created", + "summary": f"Workplan created: {args.title}", "author": "custodian", "detail": {"owner": args.owner, "slug": slug}, }) @@ -475,14 +475,14 @@ def cmd_create_task(args: argparse.Namespace) -> None: workstream_id = match["id"] task = _api_post("/tasks/", { - "workstream_id": workstream_id, + "workplan_id": workstream_id, "title": args.title, "priority": args.priority, "description": args.description, "assignee": args.assignee, }) _api_post("/progress/", { - "workstream_id": workstream_id, + "workplan_id": workstream_id, "task_id": task["id"], "event_type": "task_created", "summary": f"Task created: {args.title}", diff --git a/dashboard/src/workstreams/[id].md b/dashboard/src/workstreams/[id].md index dcc56f6..b44937f 100644 --- a/dashboard/src/workstreams/[id].md +++ b/dashboard/src/workstreams/[id].md @@ -14,7 +14,7 @@ const [raw, taskRows, workplanIndex] = await Promise.all([ fetch(`${API}/workplans/${wsId}`) .then(r => r.ok ? r.json() : r.json().then(e => ({error: e.detail ?? `HTTP ${r.status}`}))) .catch(e => ({error: String(e)})), - fetch(`${API}/tasks/?workstream_id=${wsId}&limit=1000`) + fetch(`${API}/tasks/?workplan_id=${wsId}&limit=1000`) .then(r => r.ok ? r.json() : []) .catch(() => []), fetch(`${API}/workplans/index`) diff --git a/docs/evidence/legacy-meter-weekly-review-20260709.json b/docs/evidence/legacy-meter-weekly-review-20260709.json index d07adfc..dade590 100644 --- a/docs/evidence/legacy-meter-weekly-review-20260709.json +++ b/docs/evidence/legacy-meter-weekly-review-20260709.json @@ -1,12 +1,12 @@ { - "captured_at": "2026-07-08T23:35:18.486286+00:00", + "captured_at": "2026-07-08T23:48:41.675130+00:00", "api_base": "http://127.0.0.1:8000", "workplan": "STATE-WP-0070", "retired_interfaces": [], "weekly_review": { - "generated_at": "2026-07-08T23:35:18.459774Z", - "window_start": "2026-07-08T15:35:18.219148Z", - "window_end": "2026-07-08T23:35:18.219148Z", + "generated_at": "2026-07-08T23:48:41.652056Z", + "window_start": "2026-07-08T15:48:41.473474Z", + "window_end": "2026-07-08T23:48:41.473474Z", "cadence": "weekly", "activity_core_handoff": { "activity_id": "statehub-legacy-interface-review", diff --git a/docs/evidence/workstream-caller-inventory-20260709.md b/docs/evidence/workstream-caller-inventory-20260709.md new file mode 100644 index 0000000..47bb971 --- /dev/null +++ b/docs/evidence/workstream-caller-inventory-20260709.md @@ -0,0 +1,78 @@ +# Workstream caller inventory — 2026-07-09 (second sweep) + +Follow-up after `STATE-WP-0071` railiance01 deploy. Eight-hour legacy-meter window +(2026-07-09) still shows heavy `GET /workstreams/*` traffic (~1.7k in 8h for +`GET /workstreams/` alone); attribution remains mostly `unknown`. + +## Newly found — actionable HTTP callers + +| Caller | Repo | Legacy usage | Fix | +| --- | --- | --- | --- | +| `dashboard/src/workstreams/[id].md` | state-hub | `GET /tasks/?workstream_id=` | → `?workplan_id=` | +| `custodian_cli.py` | state-hub | `POST /tasks/` body `workstream_id` (onboarding, add-task) | → `workplan_id` | +| `runtime/prompts/daily_statehub_wsgi_triage.md` | the-custodian | Instructs `GET /workstreams/workplan-index` (**410**) and `?workstream_id=` enrichment | → `/workplans/index`, `?workplan_id=` | +| `k8s/railiance/21-custodian-runtime.yaml` | activity-core | Same stale prompt text projected to cluster | Roll after prompt fix | +| `wise-validator/reporter.py` | wise-validator | `POST /progress/` body `workstream_id` | → `workplan_id` | +| `session_memory/curate/decisions.py` | agentic-resources | Dual-write `workplan_id` + `workstream_id` on decisions | Drop `workstream_id` key | + +## Newly found — response / field aliases (no extra REST path) + +| Caller | Repo | Notes | +| --- | --- | --- | +| `context_resolvers/state_hub.py` `_safe_next_step` | activity-core | Dual-keys `workplan_*` + `workstream_*` in digest JSON (downstream prose only) | +| `k8s/railiance/20-runtime.yaml` sink configs | activity-core | `workstream_id:` in YAML sink scope — read bridge in `state_hub_write.py` | +| `schedule_health.py` | activity-core | Accepts legacy param; prefers `workplan_id` | +| `dashboard/src/components/field-help.js` | state-hub | Nav links `/workstreams/{id}` (UI route compat, not API) | +| `api/routers/state.py` | state-hub | Response fields `workstream_id`, `open_workstreams` in `/state/summary` | +| `runtime/context.py` | the-custodian | Reads `open_workstreams` from summary (response field, not REST caller) | + +## Confirmed migrated (no change since 2026-07-08 inventory) + +- `scripts/consistency_check.py`, `cleanup_stale_tasks.py`, `validate_repo_adr.py` → `/workplans/` +- `custodian_cli.py` list/CRUD paths → `/workplans/` (body fields still legacy — see above) +- Dashboard list pages (`workstreams.md`, `extensions.md`, `tasks.md`, …) → `apiFetch("/workplans/")` +- Dashboard data loaders → `GET /workplans` +- `mcp_server/server.py` REST calls → `/workplans` (tool/param aliases remain by design) +- `activity-core/context_resolvers` index/detail/tasks fetches → `/workplans/*` +- `can-you-assist/shell_session.py` orientation → `GET /workplans/?` + +## Intentional legacy (meter-gated — STATE-WP-0070) + +| Surface | Notes | +| --- | --- | +| `api/routers/workstreams.py` | Compat router; `workplan-index` + `DELETE` already **410** | +| `api/routers/workstream_dependencies.py` | Legacy dependency aliases | +| `api/routers/execution.py` | `PATCH /execution/workstreams/{id}/intent` | +| Query/body aliases on `/tasks/`, `/progress/`, `/decisions/` | Metered per-key | +| MCP tools `create_workstream`, `list_workstreams`, … | Aliases; internal REST uses `/workplans/` | +| `state://workstreams/{topic_slug}` resource | Deprecated wrapper | +| DB columns / JSON response fields `workstream_id` | STATE-WP-0070 T04 | +| Frontmatter `state_hub_workstream_id` | Fleet bridge — separate migration | +| `tests/test_legacy_meter.py`, `test_routers_core.py` | Regression coverage | + +## Likely sources of remaining `GET /workstreams/*` volume + +1. **Remote fix-consistency hosts** not yet on `state-hub` ≥ `14b7d84` (coulombcore runners, cron sweep nodes). +2. **Dashboard detail page** task poll via `?workstream_id=` (every workplan detail view). +3. **Agent prompts** still telling models to call retired `workplan-index` legacy path (410 but metered). +4. **External REST clients** (bookmarks, old scripts, Claude settings curl examples in `activity-core/.claude/settings.local.json`). +5. **Legacy query aliases** elsewhere in dashboard/docs (`docs/onboarding.md` curl example). + +## Remediation (STATE-WP-0072 — 2026-07-09) + +- [x] `dashboard/src/workstreams/[id].md` → `?workplan_id=` +- [x] `custodian_cli.py` POST bodies → `workplan_id` +- [x] `docs/onboarding.md` curl → `/workplans/` +- [x] `the-custodian/runtime/prompts/daily_statehub_wsgi_triage.md` +- [x] `activity-core/k8s/railiance/21-custodian-runtime.yaml` +- [x] `wise-validator/reporter.py`, `agentic-resources/curate/decisions.py` +- [x] 8h meter re-capture (`legacy-meter-weekly-review-20260709.json`) + +Outstanding: remote fix-consistency hosts; activity-core k8s rollout of prompt projection; meter decline over subsequent 8h windows. + +## Verification + +```bash +python scripts/capture_legacy_meter_evidence.py # 8h window +rg '/workstreams|workstream_id' --glob '!**/workplans/**' --glob '!**/tests/**' +``` \ No newline at end of file diff --git a/docs/onboarding.md b/docs/onboarding.md index 34087b6..e40a900 100644 --- a/docs/onboarding.md +++ b/docs/onboarding.md @@ -103,7 +103,7 @@ Restart Claude Code after MCP registration. ```bash cat .custodian-brief.md - curl -s "http://127.0.0.1:8000/workstreams/?status=active" | python3 -m json.tool + curl -s "http://127.0.0.1:8000/workplans/?status=active" | python3 -m json.tool ``` ## Domain Collaborator: New Person diff --git a/research/20260709-workstream-caller-sweep.md b/research/20260709-workstream-caller-sweep.md new file mode 100644 index 0000000..9273c5e --- /dev/null +++ b/research/20260709-workstream-caller-sweep.md @@ -0,0 +1,57 @@ +# Workstream caller sweep — 2026-07-09 + +**Parent:** `STATE-WP-0070` T01 follow-up after `STATE-WP-0071` railiance01 deploy. +**Evidence:** `docs/evidence/workstream-caller-inventory-20260709.md` +**Meter context:** 8-hour capture (`legacy-meter-weekly-review-20260709.json`) — `GET /workstreams/` ~1,752 calls/window; attribution mostly `unknown`. + +## Method + +1. Targeted `rg` across `state-hub`, `activity-core`, `the-custodian`, fleet repos (Python/JS/YAML). +2. Fleet terminology scan: `the-custodian/tools/scan_workstream_terminology.py --json` (82 repos). +3. Cross-check against `docs/evidence/workstream-caller-inventory-20260708.md`. + +## Fleet scan summary (82 repos) + +| Repo | Occurrences | Notable runtime patterns | +| --- | ---: | --- | +| state-hub | 13,562 | `path:workstreams/` 171; `api:workstream_id` 603; python 800 | +| activity-core | 176 | `context_resolvers/state_hub.py`, k8s prompt YAML | +| the-custodian | 1,220 | `runtime/prompts/daily_statehub_wsgi_triage.md` | +| wise-validator | (small) | `reporter.py` progress POST | +| agentic-resources | 11 py | `curate/decisions.py` dual-write | + +Most fleet hits are workplans, agent-guidance, or session_memory blobs — not live REST callers. + +## Actionable HTTP callers (fix in STATE-WP-0072) + +| Caller | Repo | Legacy | Fix | +| --- | --- | --- | --- | +| `dashboard/src/workstreams/[id].md` | state-hub | `GET /tasks/?workstream_id=` | `?workplan_id=` | +| `custodian_cli.py` | state-hub | `POST /tasks/`, `/progress/` body `workstream_id` | `workplan_id` | +| `docs/onboarding.md` | state-hub | curl `GET /workstreams/?status=active` | `/workplans/` | +| `runtime/prompts/daily_statehub_wsgi_triage.md` | the-custodian | `/workstreams/workplan-index` (410), `?workstream_id=` | `/workplans/index`, `?workplan_id=` | +| `k8s/railiance/21-custodian-runtime.yaml` | activity-core | Same prompt projection | Sync with custodian prompt | +| `wise-validator/reporter.py` | wise-validator | progress body `workstream_id` | `workplan_id` | +| `session_memory/curate/decisions.py` | agentic-resources | dual-write both scope keys | `workplan_id` only | + +## Confirmed migrated (no regression) + +- `consistency_check.py`, `cleanup_stale_tasks.py`, `validate_repo_adr.py` → `/workplans/` +- Dashboard list pages + data loaders → `/workplans/` +- MCP server REST → `/workplans/` (legacy tool names remain) +- activity-core resolver fetches → `/workplans/*` +- can-you-assist `shell_session.py` → `/workplans/?` + +## Intentional legacy (STATE-WP-0070 — meter-gated) + +- `api/routers/workstreams.py`, `workstream_dependencies.py`, execution intent alias +- Query/body aliases on tasks/progress/decisions (until T04) +- MCP aliases, `state://workstreams/` resource +- DB/response fields, `state_hub_workstream_id` frontmatter + +## Verification + +```bash +python scripts/capture_legacy_meter_evidence.py # 8h default +rg '/workstreams|workstream_id' --glob '!**/workplans/**' --glob '!**/tests/**' +``` \ No newline at end of file diff --git a/workplans/STATE-WP-0072-workstream-caller-remediation.md b/workplans/STATE-WP-0072-workstream-caller-remediation.md new file mode 100644 index 0000000..c1de6bb --- /dev/null +++ b/workplans/STATE-WP-0072-workstream-caller-remediation.md @@ -0,0 +1,81 @@ +--- +id: STATE-WP-0072 +type: workplan +title: "Workstream caller remediation (second sweep)" +domain: infotech +repo: state-hub +status: finished +owner: codex +topic_slug: custodian +planning_priority: high +planning_order: 72 +created: "2026-07-09" +updated: "2026-07-09" +--- + +# STATE-WP-0072 — Workstream caller remediation + +**Parent:** `STATE-WP-0070` (phase-2 legacy retirement). +**Research:** `research/20260709-workstream-caller-sweep.md` + +## Goal + +Eliminate remaining production HTTP callers that hit legacy `workstream_id` +query/body params or `/workstreams/*` paths, so 8-hour legacy-meter windows +show declining `GET /workstreams/*` counts. + +## Task: state-hub dashboard and CLI + +```task +id: STATE-WP-0072-T01 +status: done +priority: high +``` + +- `dashboard/src/workstreams/[id].md` — tasks fetch uses `?workplan_id=` +- `custodian_cli.py` — task/progress POST bodies use `workplan_id` +- `docs/onboarding.md` — curl example uses `/workplans/` + +Done when no state-hub runtime file POSTs or GETs legacy workstream paths/params. + +## Task: Daily triage prompt (the-custodian + activity-core projection) + +```task +id: STATE-WP-0072-T02 +status: done +priority: high +``` + +- `the-custodian/runtime/prompts/daily_statehub_wsgi_triage.md` — `/workplans/index`, `?workplan_id=` +- `activity-core/k8s/railiance/21-custodian-runtime.yaml` — matching prompt text + +Done when prompt no longer references `/workstreams/workplan-index`. + +## Task: Cross-repo progress/decision POST bodies + +```task +id: STATE-WP-0072-T03 +status: done +priority: medium +``` + +- `wise-validator/src/wisevalidator/reporter.py` — `workplan_id` on progress POST +- `agentic-resources/session_memory/curate/decisions.py` — drop `workstream_id` dual-write +- Update tests in both repos + +Done when tests pass and POST bodies use `workplan_id` only. + +## Task: Verify and capture meter evidence + +```task +id: STATE-WP-0072-T04 +status: done +priority: high +``` + +1. `rg` confirm no missed runtime callers in fixed repos. +2. `python scripts/capture_legacy_meter_evidence.py` (8h window). +3. Update `docs/evidence/workstream-caller-inventory-20260709.md` checklist. +4. Archive workplan when evidence captured. + +Done when 8h capture committed and STATE-WP-0072 `finished`. \ No newline at end of file