diff --git a/README.md b/README.md index 8b3055b..9b96378 100644 --- a/README.md +++ b/README.md @@ -256,7 +256,7 @@ use `/state/health`, not `/state/summary`. |--------|-----------| | `/topics` | CRUD (soft-delete: `archived`) | | `/workplans` | Preferred CRUD surface for repo-backed workplans (soft-delete: `archived`) | -| `/workstreams` | Retired REST routes (410); use `/workplans`. Rejected calls remain metered | +| `/workstreams` | Legacy compatibility CRUD surface; usage is recorded by legacy-meter | | `/tasks` | CRUD (soft-delete: `cancel`); `PATCH` updates status | | `/decisions` | CRUD (soft-delete: `superseded`); auto-escalation | | `/progress` | `GET` list + `POST` append — no DELETE | diff --git a/dashboard/src/docs/goals.md b/dashboard/src/docs/goals.md index 5ee237c..39a4a20 100644 --- a/dashboard/src/docs/goals.md +++ b/dashboard/src/docs/goals.md @@ -127,7 +127,7 @@ The Goals page groups everything by domain: 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": ""}`. The legacy `create_workstream` tool is removed and `/workstreams/{id}` returns 410; use `create_workplan` and `/workplans/{id}`. +To set the link when creating a workplan through the preferred API, pass `repo_goal_id`. To update an existing one, use `PATCH /workplans/{id}/` with `{"repo_goal_id": ""}`. Legacy `create_workstream` and `/workstreams/{id}/` callers remain compatibility-supported while they are metered. --- diff --git a/docs/evidence/STATE-WP-0079-caller-and-receiver-review-20260905.md b/docs/evidence/STATE-WP-0079-caller-and-receiver-review-20260905.md deleted file mode 100644 index eaf6bb9..0000000 --- a/docs/evidence/STATE-WP-0079-caller-and-receiver-review-20260905.md +++ /dev/null @@ -1,92 +0,0 @@ -# STATE-WP-0079 caller and receiver review — 2026-09-05 - -## Actions and scope - -User authorized the proposed SBOM meter retirements, caller tracing/migration, -and refreshed cutover checklist. No application image, production writer, -network policy, runtime deployment, or compatibility handler was changed. - -A fresh seven-day primary review re-confirmed both candidates before mutation. -Direct Nexus licence-report and snapshot reads returned HTTP 200 from the State -Hub pod. Both meter records were patched with STATE-WP-0079-T05 provenance. -The saved before/after receipt is -`STATE-WP-0079-sbom-retirement-20260905.json`: eight retired, seven legacy, -zero remaining candidates. Handler deletion is not claimed by meter retirement. - -## Caller trace - -Searched non-hidden source trees under `/home/worsch` for `workstream_id`, -`/workstreams`, and the two SBOM endpoints, covering Python, shell, JS/TS and -YAML while excluding tests, dependency trees, docs, archives and fixtures. -517 matching lines were triaged by receiver and operation. A second Markdown -instruction scan excluded workplans, generated indexes, docs, archives and -session evidence. Matching strings alone were not treated as runtime callers. - -- Repo Manager's licence-report client uses explicit `SBOM_NEXUS_URL`; it is a - direct Nexus client, not evidence of a State Hub caller. -- SBOM Nexus importer intentionally reads source and target snapshots/licences - for migration comparison. Its matching paths do not establish ongoing use. -- The bundled State Hub skill advertised removed `create_workstream` and - `POST /workstreams/`; README and dashboard goals documentation also described - retired routes as supported. Corrected these to current workplan contracts, - file-first sync and component attribution. -- No current hard-coded State Hub workstream route caller was found in the - scanned runtime sources. This does not cover hidden installations, remote - checkouts, dynamically built paths or past one-off commands. - -Targeted local agent-session review extracted only tool-call timestamp, working -repository and legacy path. Full session contents were not copied into evidence. - -| Time (UTC) | Caller context | Observed operation | Confidence / correction | -| --- | --- | --- | --- | -| 2026-09-04 17:21:25.339 | Claude agent, fluid-telegram | Task query with legacy `workstream_id`, targeting `f2373858-c932-5a4d-81b6-db9a3595135a` | Actual command in session history; within four seconds of meter last_seen 17:21:29.173850. Strong correlation, not request-ID proof. AGENTS.md now prescribes canonical query and `X-StateHub-Component: fluid-telegram` | -| 2026-08-29 12:57:27.083 | Claude agent, ops-warden | Task query with legacy `workstream_id`, targeting `ae3ff76f-883d-5e2f-b6aa-144d61e8fdef` | Actual command in session history. AGENTS.md now prescribes canonical query and `X-StateHub-Component: ops-warden` | - -Caller guidance commits: fluid-telegram `f7af151`, ops-warden `96dbb22`. -Both changes are restricted to the repository-owned AGENTS.md extension. - -Replayed only the **canonical** task queries with those component headers: -HTTP 200, 8 and 5 tasks respectively. No legacy query was replayed, so the -retirement clocks were not reset by verification. Agent instructions reduce -future misuse; they do not prove that future sessions will follow them. - -Remaining attribution: the meter's 11 task-filter calls are not all individually -explained, seven workstream-detail calls remain unidentified, and the one SBOM -index call remains unidentified. These are STATE-WP-0079-T07 live work, not -claimed completed migrations. - -## Log retention limit - -Requested seven days of `deployment/state-hub` pod logs. Available logs start -2026-09-04T20:10:36Z, after the relevant last-seen timestamps. No matching legacy -requests appear in that retained interval. Kubernetes has no previous container -log for this pod. Hence these logs cannot retrospectively identify the calls; -absence in this interval is not evidence of seven quiet days. - -## Receiving runtime probe - -The live State Hub deployment image was `main-cdff3b7`; its configmap directs -both SBOM read and write compatibility paths to the cluster Nexus service. - -`core-hub-api` and `core-hub-api-candidate` deployments both reported 1/1 ready. -From the State Hub pod, requests to both Core Hub service addresses on port 8010 -were connection-refused. Cause was not established and no connectivity change -was made. From candidate pod loopback, `/openapi.json` returned a **Hub Core -Runtime** schema with 31 paths. It exposes `/api/v2/interaction-events`, but no -`/messages`, `/progress`, `/token-events` or `/interface-changes` family. - -Shared Python routers exist for messages/progress, but importing them into -State Hub does not deploy them on the owner runtime or migrate their rows. -HUB-WP-0005's successful Core Hub `/api/v2` absorption must not be used as proof -of the State Hub family cutover. STATE-WP-0079-T08 owns the bounded follow-up: -identify/expose one deployed message-read contract, historical data projection, -transport and parity/rollback evidence before changing any reader/writer. - -## Validation - -- Live primary identity and fresh seven-day eligibility verified before PATCH. -- Direct receiving SBOM reads: 200; canonical caller task reads: 200. -- State Hub skill passes the skill-creator frontmatter validator; this also - corrected an existing unquoted colon that made its description invalid YAML. -- Documentation and caller-instruction edits pass `git diff --check`. -- No executable application code changed; no database test suite was needed. diff --git a/docs/evidence/STATE-WP-0079-sbom-retirement-20260905.json b/docs/evidence/STATE-WP-0079-sbom-retirement-20260905.json deleted file mode 100644 index 3dd3e0a..0000000 --- a/docs/evidence/STATE-WP-0079-sbom-retirement-20260905.json +++ /dev/null @@ -1,1572 +0,0 @@ -{ - "captured_at": "2026-09-05T08:04:47.855699+00:00", - "workplan": "STATE-WP-0079", - "api_base": "http://127.0.0.1:8000", - "health": { - "status": "ok", - "db": "connected", - "instance_role": "primary", - "instance_label": "railiance01", - "schema": { - "status": "ok", - "applied": "b5e6f7a8c9d0", - "expected": "b5e6f7a8c9d0" - } - }, - "before": { - "generated_at": "2026-09-05T08:04:48.276126Z", - "window_start": "2026-08-29T08:04:48.185252Z", - "window_end": "2026-09-05T08:04:48.185252Z", - "cadence": "weekly", - "activity_core_handoff": { - "activity_id": "statehub-legacy-interface-review", - "cadence": "weekly", - "source_endpoint": "/legacy-meter/weekly-review", - "state_owner": "state-hub", - "scheduler_owner": "activity-core" - }, - "interfaces": [ - { - "interface": { - "id": "8051fb40-66c9-4dc4-a413-13e8573e04a3", - "interface_key": "event_subject:org.statehub.workstream.completed", - "interface_kind": "event_subject", - "legacy_since": "2026-06-04T06:09:42.198193Z", - "replacement_ref": "org.statehub.workplan.completed", - "owner_component": "state-hub.events", - "status": "retired", - "replacement_verified": true, - "manual_hold": false, - "hold_reason": null, - "notes": "Retired by STATE-WP-0069 closeout", - "retired_at": "2026-08-31T08:55:06.871333Z", - "created_at": "2026-06-04T06:09:42.198193Z", - "updated_at": "2026-08-31T08:55:06.756087Z" - }, - "all_time": { - "calls": 247, - "tenant_count": 1, - "user_count": 1, - "component_count": 1, - "tenants": { - "unknown": 247 - }, - "users": { - "unknown": 247 - }, - "components": { - "state-hub.events": 247 - } - }, - "window": { - "calls": 0, - "tenant_count": 0, - "user_count": 0, - "component_count": 0, - "tenants": {}, - "users": {}, - "components": {} - }, - "last_seen_at": "2026-07-13T13:22:00.748140Z", - "retirement_candidate": false, - "retirement_reason": "already retired" - }, - { - "interface": { - "id": "cd9342fd-27e7-4a46-a1be-d41499e106a3", - "interface_key": "rest_api:DELETE /workstreams/{workstream_id}", - "interface_kind": "rest_api", - "legacy_since": "2026-06-06T17:28:13.052813Z", - "replacement_ref": "/workplans/{workplan_id}", - "owner_component": "state-hub.api", - "status": "retired", - "replacement_verified": true, - "manual_hold": false, - "hold_reason": null, - "notes": "Retired by STATE-WP-0069 closeout", - "retired_at": "2026-08-31T08:55:08.200322Z", - "created_at": "2026-06-06T17:28:13.052813Z", - "updated_at": "2026-08-31T08:55:08.089714Z" - }, - "all_time": { - "calls": 1, - "tenant_count": 1, - "user_count": 1, - "component_count": 1, - "tenants": { - "unknown": 1 - }, - "users": { - "unknown": 1 - }, - "components": { - "unknown": 1 - } - }, - "window": { - "calls": 0, - "tenant_count": 0, - "user_count": 0, - "component_count": 0, - "tenants": {}, - "users": {}, - "components": {} - }, - "last_seen_at": "2026-06-06T17:28:13.047529Z", - "retirement_candidate": false, - "retirement_reason": "already retired" - }, - { - "interface": { - "id": "d0294dce-7913-4268-94c3-1b2502aefb0f", - "interface_key": "rest_api:GET /sbom/", - "interface_kind": "rest_api", - "legacy_since": "2026-08-22T17:06:38.703608Z", - "replacement_ref": "sbom-nexus:/sbom/", - "owner_component": "state-hub.sbom-compat", - "status": "legacy", - "replacement_verified": true, - "manual_hold": false, - "hold_reason": null, - "notes": null, - "retired_at": null, - "created_at": "2026-08-22T17:06:38.703608Z", - "updated_at": "2026-08-22T17:23:43.730661Z" - }, - "all_time": { - "calls": 6, - "tenant_count": 1, - "user_count": 1, - "component_count": 1, - "tenants": { - "unknown": 6 - }, - "users": { - "unknown": 6 - }, - "components": { - "unknown": 6 - } - }, - "window": { - "calls": 1, - "tenant_count": 1, - "user_count": 1, - "component_count": 1, - "tenants": { - "unknown": 1 - }, - "users": { - "unknown": 1 - }, - "components": { - "unknown": 1 - } - }, - "last_seen_at": "2026-08-31T08:18:41.571768Z", - "retirement_candidate": false, - "retirement_reason": "1 call(s) in review window" - }, - { - "interface": { - "id": "2f77ac12-8c97-4974-a2f9-2996927982d1", - "interface_key": "rest_api:GET /sbom/report/licences/", - "interface_kind": "rest_api", - "legacy_since": "2026-08-22T17:06:41.978426Z", - "replacement_ref": "sbom-nexus:/sbom/", - "owner_component": "state-hub.sbom-compat", - "status": "legacy", - "replacement_verified": true, - "manual_hold": false, - "hold_reason": null, - "notes": null, - "retired_at": null, - "created_at": "2026-08-22T17:06:41.978426Z", - "updated_at": "2026-08-22T17:23:44.794796Z" - }, - "all_time": { - "calls": 5, - "tenant_count": 1, - "user_count": 1, - "component_count": 1, - "tenants": { - "unknown": 5 - }, - "users": { - "unknown": 5 - }, - "components": { - "unknown": 5 - } - }, - "window": { - "calls": 0, - "tenant_count": 0, - "user_count": 0, - "component_count": 0, - "tenants": {}, - "users": {}, - "components": {} - }, - "last_seen_at": "2026-08-28T18:46:10.642164Z", - "retirement_candidate": true, - "retirement_reason": "no usage in review window; quiet 7d (>= 7d required for 5 all-time call(s))" - }, - { - "interface": { - "id": "b627edf5-3302-4366-ba2e-547d32f634b5", - "interface_key": "rest_api:GET /sbom/snapshots/", - "interface_kind": "rest_api", - "legacy_since": "2026-08-22T17:06:37.057774Z", - "replacement_ref": "sbom-nexus:/sbom/", - "owner_component": "state-hub.sbom-compat", - "status": "legacy", - "replacement_verified": true, - "manual_hold": false, - "hold_reason": null, - "notes": null, - "retired_at": null, - "created_at": "2026-08-22T17:06:37.057774Z", - "updated_at": "2026-08-22T17:22:15.080213Z" - }, - "all_time": { - "calls": 7, - "tenant_count": 1, - "user_count": 1, - "component_count": 1, - "tenants": { - "unknown": 7 - }, - "users": { - "unknown": 7 - }, - "components": { - "unknown": 7 - } - }, - "window": { - "calls": 0, - "tenant_count": 0, - "user_count": 0, - "component_count": 0, - "tenants": {}, - "users": {}, - "components": {} - }, - "last_seen_at": "2026-08-28T18:46:10.694185Z", - "retirement_candidate": true, - "retirement_reason": "no usage in review window; quiet 7d (>= 7d required for 7 all-time call(s))" - }, - { - "interface": { - "id": "d03ee274-cd6f-4cd5-8f22-e4d298416299", - "interface_key": "rest_api:GET /sbom/snapshots/{snapshot_id}", - "interface_kind": "rest_api", - "legacy_since": "2026-08-22T17:23:45.969876Z", - "replacement_ref": "sbom-nexus:/sbom/", - "owner_component": "state-hub.sbom-compat", - "status": "retired", - "replacement_verified": true, - "manual_hold": false, - "hold_reason": null, - "notes": "Retired by STATE-WP-0069 closeout", - "retired_at": "2026-08-31T08:55:08.470106Z", - "created_at": "2026-08-22T17:23:45.969876Z", - "updated_at": "2026-08-31T08:55:08.456139Z" - }, - "all_time": { - "calls": 1, - "tenant_count": 1, - "user_count": 1, - "component_count": 1, - "tenants": { - "unknown": 1 - }, - "users": { - "unknown": 1 - }, - "components": { - "unknown": 1 - } - }, - "window": { - "calls": 0, - "tenant_count": 0, - "user_count": 0, - "component_count": 0, - "tenants": {}, - "users": {}, - "components": {} - }, - "last_seen_at": "2026-08-22T17:23:45.967492Z", - "retirement_candidate": false, - "retirement_reason": "already retired" - }, - { - "interface": { - "id": "a6cb291e-8312-42f8-8a66-fde369482881", - "interface_key": "rest_api:GET /sbom/{repo_slug}", - "interface_kind": "rest_api", - "legacy_since": "2026-08-22T17:23:45.089542Z", - "replacement_ref": "sbom-nexus:/sbom/", - "owner_component": "state-hub.sbom-compat", - "status": "retired", - "replacement_verified": true, - "manual_hold": false, - "hold_reason": null, - "notes": "Retired by STATE-WP-0069 closeout", - "retired_at": "2026-08-31T08:55:08.754914Z", - "created_at": "2026-08-22T17:23:45.089542Z", - "updated_at": "2026-08-31T08:55:08.750826Z" - }, - "all_time": { - "calls": 1, - "tenant_count": 1, - "user_count": 1, - "component_count": 1, - "tenants": { - "unknown": 1 - }, - "users": { - "unknown": 1 - }, - "components": { - "unknown": 1 - } - }, - "window": { - "calls": 0, - "tenant_count": 0, - "user_count": 0, - "component_count": 0, - "tenants": {}, - "users": {}, - "components": {} - }, - "last_seen_at": "2026-08-22T17:23:45.670511Z", - "retirement_candidate": false, - "retirement_reason": "already retired" - }, - { - "interface": { - "id": "cad13f19-ddb1-49b9-86d0-8789b7599f3a", - "interface_key": "rest_api:GET /tasks/?workstream_id", - "interface_kind": "rest_api", - "legacy_since": "2026-08-29T10:01:31.546213Z", - "replacement_ref": "/tasks/?workplan_id=", - "owner_component": "state-hub.api", - "status": "legacy", - "replacement_verified": true, - "manual_hold": false, - "hold_reason": null, - "notes": null, - "retired_at": null, - "created_at": "2026-08-29T10:01:31.546213Z", - "updated_at": "2026-08-29T10:01:31.546213Z" - }, - "all_time": { - "calls": 11, - "tenant_count": 1, - "user_count": 1, - "component_count": 1, - "tenants": { - "unknown": 11 - }, - "users": { - "unknown": 11 - }, - "components": { - "unknown": 11 - } - }, - "window": { - "calls": 11, - "tenant_count": 1, - "user_count": 1, - "component_count": 1, - "tenants": { - "unknown": 11 - }, - "users": { - "unknown": 11 - }, - "components": { - "unknown": 11 - } - }, - "last_seen_at": "2026-09-04T17:21:29.173850Z", - "retirement_candidate": false, - "retirement_reason": "11 call(s) in review window" - }, - { - "interface": { - "id": "3e4a3d0b-08fa-45c3-91e2-4f514a914b97", - "interface_key": "rest_api:GET /workstreams/", - "interface_kind": "rest_api", - "legacy_since": "2026-06-04T00:26:14.533764Z", - "replacement_ref": "/workplans/", - "owner_component": "state-hub.api", - "status": "legacy", - "replacement_verified": true, - "manual_hold": false, - "hold_reason": null, - "notes": null, - "retired_at": null, - "created_at": "2026-06-04T00:26:14.533764Z", - "updated_at": "2026-06-04T00:26:14.533764Z" - }, - "all_time": { - "calls": 830269, - "tenant_count": 1, - "user_count": 1, - "component_count": 1, - "tenants": { - "unknown": 830269 - }, - "users": { - "unknown": 830269 - }, - "components": { - "unknown": 830269 - } - }, - "window": { - "calls": 0, - "tenant_count": 0, - "user_count": 0, - "component_count": 0, - "tenants": {}, - "users": {}, - "components": {} - }, - "last_seen_at": "2026-08-21T13:50:37.994459Z", - "retirement_candidate": false, - "retirement_reason": "quiet 14d of 60d required for 830269 all-time call(s)" - }, - { - "interface": { - "id": "e4c140ec-7479-46f9-b185-4b533f19d639", - "interface_key": "rest_api:GET /workstreams/workplan-index", - "interface_kind": "rest_api", - "legacy_since": "2026-06-04T05:20:58.321869Z", - "replacement_ref": "/workplans/index", - "owner_component": "state-hub.api", - "status": "retired", - "replacement_verified": true, - "manual_hold": false, - "hold_reason": null, - "notes": "Retired by STATE-WP-0069 closeout", - "retired_at": "2026-08-31T08:55:08.939572Z", - "created_at": "2026-06-04T05:20:58.321869Z", - "updated_at": "2026-08-31T08:55:08.933482Z" - }, - "all_time": { - "calls": 40, - "tenant_count": 1, - "user_count": 1, - "component_count": 1, - "tenants": { - "unknown": 40 - }, - "users": { - "unknown": 40 - }, - "components": { - "unknown": 40 - } - }, - "window": { - "calls": 1, - "tenant_count": 1, - "user_count": 1, - "component_count": 1, - "tenants": { - "unknown": 1 - }, - "users": { - "unknown": 1 - }, - "components": { - "unknown": 1 - } - }, - "last_seen_at": "2026-09-01T18:42:55.879795Z", - "retirement_candidate": false, - "retirement_reason": "already retired" - }, - { - "interface": { - "id": "3a00b19e-e7db-4403-98aa-a77c9ab61ecc", - "interface_key": "rest_api:GET /workstreams/{workstream_id}", - "interface_kind": "rest_api", - "legacy_since": "2026-06-04T00:25:59.014966Z", - "replacement_ref": "/workplans/{workplan_id}", - "owner_component": "state-hub.api", - "status": "legacy", - "replacement_verified": true, - "manual_hold": false, - "hold_reason": null, - "notes": null, - "retired_at": null, - "created_at": "2026-06-04T00:25:59.014966Z", - "updated_at": "2026-06-04T00:25:59.014966Z" - }, - "all_time": { - "calls": 3411477, - "tenant_count": 1, - "user_count": 1, - "component_count": 1, - "tenants": { - "unknown": 3411477 - }, - "users": { - "unknown": 3411477 - }, - "components": { - "unknown": 3411477 - } - }, - "window": { - "calls": 7, - "tenant_count": 1, - "user_count": 1, - "component_count": 1, - "tenants": { - "unknown": 7 - }, - "users": { - "unknown": 7 - }, - "components": { - "unknown": 7 - } - }, - "last_seen_at": "2026-09-03T22:02:35.348363Z", - "retirement_candidate": false, - "retirement_reason": "7 call(s) in review window" - }, - { - "interface": { - "id": "69e1a255-a8b9-4101-8a68-b1bed23abfda", - "interface_key": "rest_api:GET /workstreams/{workstream_id}/dependencies/", - "interface_kind": "rest_api", - "legacy_since": "2026-06-04T00:25:59.291135Z", - "replacement_ref": "/workplans/{workplan_id}/dependencies/", - "owner_component": "state-hub.api", - "status": "legacy", - "replacement_verified": true, - "manual_hold": false, - "hold_reason": null, - "notes": null, - "retired_at": null, - "created_at": "2026-06-04T00:25:59.291135Z", - "updated_at": "2026-06-04T00:25:59.291135Z" - }, - "all_time": { - "calls": 1643952, - "tenant_count": 1, - "user_count": 1, - "component_count": 1, - "tenants": { - "unknown": 1643952 - }, - "users": { - "unknown": 1643952 - }, - "components": { - "unknown": 1643952 - } - }, - "window": { - "calls": 0, - "tenant_count": 0, - "user_count": 0, - "component_count": 0, - "tenants": {}, - "users": {}, - "components": {} - }, - "last_seen_at": "2026-08-21T13:50:30.082480Z", - "retirement_candidate": false, - "retirement_reason": "quiet 14d of 60d required for 1643952 all-time call(s)" - }, - { - "interface": { - "id": "b1aae931-b51f-4a85-a723-865dd65f6132", - "interface_key": "rest_api:PATCH /workstreams/{workstream_id}", - "interface_kind": "rest_api", - "legacy_since": "2026-06-04T06:09:41.901035Z", - "replacement_ref": "/workplans/{workplan_id}", - "owner_component": "state-hub.api", - "status": "legacy", - "replacement_verified": true, - "manual_hold": false, - "hold_reason": null, - "notes": null, - "retired_at": null, - "created_at": "2026-06-04T06:09:41.901035Z", - "updated_at": "2026-06-04T06:09:41.901035Z" - }, - "all_time": { - "calls": 584, - "tenant_count": 1, - "user_count": 1, - "component_count": 1, - "tenants": { - "unknown": 584 - }, - "users": { - "unknown": 584 - }, - "components": { - "unknown": 584 - } - }, - "window": { - "calls": 0, - "tenant_count": 0, - "user_count": 0, - "component_count": 0, - "tenants": {}, - "users": {}, - "components": {} - }, - "last_seen_at": "2026-08-16T16:33:34.045078Z", - "retirement_candidate": false, - "retirement_reason": "quiet 19d of 30d required for 584 all-time call(s)" - }, - { - "interface": { - "id": "ed6451c9-d2cc-4486-9afe-d3852782cabc", - "interface_key": "rest_api:POST /workstreams/", - "interface_kind": "rest_api", - "legacy_since": "2026-06-04T07:40:24.168535Z", - "replacement_ref": "/workplans/", - "owner_component": "state-hub.api", - "status": "legacy", - "replacement_verified": true, - "manual_hold": false, - "hold_reason": null, - "notes": null, - "retired_at": null, - "created_at": "2026-06-04T07:40:24.168535Z", - "updated_at": "2026-06-04T07:40:24.168535Z" - }, - "all_time": { - "calls": 811, - "tenant_count": 1, - "user_count": 1, - "component_count": 1, - "tenants": { - "unknown": 811 - }, - "users": { - "unknown": 811 - }, - "components": { - "unknown": 811 - } - }, - "window": { - "calls": 0, - "tenant_count": 0, - "user_count": 0, - "component_count": 0, - "tenants": {}, - "users": {}, - "components": {} - }, - "last_seen_at": "2026-08-16T01:03:41.093965Z", - "retirement_candidate": false, - "retirement_reason": "quiet 20d of 30d required for 811 all-time call(s)" - }, - { - "interface": { - "id": "281fd706-b192-4194-8055-2d8733c115f9", - "interface_key": "rest_api:POST /workstreams/{workstream_id}/dependencies/", - "interface_kind": "rest_api", - "legacy_since": "2026-06-04T22:57:37.149207Z", - "replacement_ref": "/workplans/{workplan_id}/dependencies/", - "owner_component": "state-hub.api", - "status": "retired", - "replacement_verified": true, - "manual_hold": false, - "hold_reason": null, - "notes": "Retired by STATE-WP-0069 closeout", - "retired_at": "2026-08-31T08:55:09.130713Z", - "created_at": "2026-06-04T22:57:37.149207Z", - "updated_at": "2026-08-31T08:55:09.123888Z" - }, - "all_time": { - "calls": 4975, - "tenant_count": 1, - "user_count": 1, - "component_count": 1, - "tenants": { - "unknown": 4975 - }, - "users": { - "unknown": 4975 - }, - "components": { - "unknown": 4975 - } - }, - "window": { - "calls": 0, - "tenant_count": 0, - "user_count": 0, - "component_count": 0, - "tenants": {}, - "users": {}, - "components": {} - }, - "last_seen_at": "2026-07-07T20:31:35.389791Z", - "retirement_candidate": false, - "retirement_reason": "already retired" - } - ], - "retirement_candidates": [ - { - "interface": { - "id": "2f77ac12-8c97-4974-a2f9-2996927982d1", - "interface_key": "rest_api:GET /sbom/report/licences/", - "interface_kind": "rest_api", - "legacy_since": "2026-08-22T17:06:41.978426Z", - "replacement_ref": "sbom-nexus:/sbom/", - "owner_component": "state-hub.sbom-compat", - "status": "legacy", - "replacement_verified": true, - "manual_hold": false, - "hold_reason": null, - "notes": null, - "retired_at": null, - "created_at": "2026-08-22T17:06:41.978426Z", - "updated_at": "2026-08-22T17:23:44.794796Z" - }, - "all_time": { - "calls": 5, - "tenant_count": 1, - "user_count": 1, - "component_count": 1, - "tenants": { - "unknown": 5 - }, - "users": { - "unknown": 5 - }, - "components": { - "unknown": 5 - } - }, - "window": { - "calls": 0, - "tenant_count": 0, - "user_count": 0, - "component_count": 0, - "tenants": {}, - "users": {}, - "components": {} - }, - "last_seen_at": "2026-08-28T18:46:10.642164Z", - "retirement_candidate": true, - "retirement_reason": "no usage in review window; quiet 7d (>= 7d required for 5 all-time call(s))" - }, - { - "interface": { - "id": "b627edf5-3302-4366-ba2e-547d32f634b5", - "interface_key": "rest_api:GET /sbom/snapshots/", - "interface_kind": "rest_api", - "legacy_since": "2026-08-22T17:06:37.057774Z", - "replacement_ref": "sbom-nexus:/sbom/", - "owner_component": "state-hub.sbom-compat", - "status": "legacy", - "replacement_verified": true, - "manual_hold": false, - "hold_reason": null, - "notes": null, - "retired_at": null, - "created_at": "2026-08-22T17:06:37.057774Z", - "updated_at": "2026-08-22T17:22:15.080213Z" - }, - "all_time": { - "calls": 7, - "tenant_count": 1, - "user_count": 1, - "component_count": 1, - "tenants": { - "unknown": 7 - }, - "users": { - "unknown": 7 - }, - "components": { - "unknown": 7 - } - }, - "window": { - "calls": 0, - "tenant_count": 0, - "user_count": 0, - "component_count": 0, - "tenants": {}, - "users": {}, - "components": {} - }, - "last_seen_at": "2026-08-28T18:46:10.694185Z", - "retirement_candidate": true, - "retirement_reason": "no usage in review window; quiet 7d (>= 7d required for 7 all-time call(s))" - } - ] - }, - "retired_interfaces": [ - { - "id": "2f77ac12-8c97-4974-a2f9-2996927982d1", - "interface_key": "rest_api:GET /sbom/report/licences/", - "interface_kind": "rest_api", - "legacy_since": "2026-08-22T17:06:41.978426Z", - "replacement_ref": "sbom-nexus:/sbom/", - "owner_component": "state-hub.sbom-compat", - "status": "retired", - "replacement_verified": true, - "manual_hold": false, - "hold_reason": null, - "notes": "STATE-WP-0079-T05: user-authorized retirement 2026-09-05; fresh seven-day gate passed, replacement_verified=true; direct SBOM Nexus endpoints returned HTTP 200 from the State Hub pod. Compatibility storage/routes retained for the final cutover.", - "retired_at": "2026-09-05T08:04:48.423727Z", - "created_at": "2026-08-22T17:06:41.978426Z", - "updated_at": "2026-09-05T08:04:48.418993Z" - }, - { - "id": "b627edf5-3302-4366-ba2e-547d32f634b5", - "interface_key": "rest_api:GET /sbom/snapshots/", - "interface_kind": "rest_api", - "legacy_since": "2026-08-22T17:06:37.057774Z", - "replacement_ref": "sbom-nexus:/sbom/", - "owner_component": "state-hub.sbom-compat", - "status": "retired", - "replacement_verified": true, - "manual_hold": false, - "hold_reason": null, - "notes": "STATE-WP-0079-T05: user-authorized retirement 2026-09-05; fresh seven-day gate passed, replacement_verified=true; direct SBOM Nexus endpoints returned HTTP 200 from the State Hub pod. Compatibility storage/routes retained for the final cutover.", - "retired_at": "2026-09-05T08:04:48.506447Z", - "created_at": "2026-08-22T17:06:37.057774Z", - "updated_at": "2026-09-05T08:04:48.501706Z" - } - ], - "days": 7, - "after": { - "generated_at": "2026-09-05T08:04:48.937717Z", - "window_start": "2026-08-29T08:04:48.702204Z", - "window_end": "2026-09-05T08:04:48.702204Z", - "cadence": "weekly", - "activity_core_handoff": { - "activity_id": "statehub-legacy-interface-review", - "cadence": "weekly", - "source_endpoint": "/legacy-meter/weekly-review", - "state_owner": "state-hub", - "scheduler_owner": "activity-core" - }, - "interfaces": [ - { - "interface": { - "id": "8051fb40-66c9-4dc4-a413-13e8573e04a3", - "interface_key": "event_subject:org.statehub.workstream.completed", - "interface_kind": "event_subject", - "legacy_since": "2026-06-04T06:09:42.198193Z", - "replacement_ref": "org.statehub.workplan.completed", - "owner_component": "state-hub.events", - "status": "retired", - "replacement_verified": true, - "manual_hold": false, - "hold_reason": null, - "notes": "Retired by STATE-WP-0069 closeout", - "retired_at": "2026-08-31T08:55:06.871333Z", - "created_at": "2026-06-04T06:09:42.198193Z", - "updated_at": "2026-08-31T08:55:06.756087Z" - }, - "all_time": { - "calls": 247, - "tenant_count": 1, - "user_count": 1, - "component_count": 1, - "tenants": { - "unknown": 247 - }, - "users": { - "unknown": 247 - }, - "components": { - "state-hub.events": 247 - } - }, - "window": { - "calls": 0, - "tenant_count": 0, - "user_count": 0, - "component_count": 0, - "tenants": {}, - "users": {}, - "components": {} - }, - "last_seen_at": "2026-07-13T13:22:00.748140Z", - "retirement_candidate": false, - "retirement_reason": "already retired" - }, - { - "interface": { - "id": "cd9342fd-27e7-4a46-a1be-d41499e106a3", - "interface_key": "rest_api:DELETE /workstreams/{workstream_id}", - "interface_kind": "rest_api", - "legacy_since": "2026-06-06T17:28:13.052813Z", - "replacement_ref": "/workplans/{workplan_id}", - "owner_component": "state-hub.api", - "status": "retired", - "replacement_verified": true, - "manual_hold": false, - "hold_reason": null, - "notes": "Retired by STATE-WP-0069 closeout", - "retired_at": "2026-08-31T08:55:08.200322Z", - "created_at": "2026-06-06T17:28:13.052813Z", - "updated_at": "2026-08-31T08:55:08.089714Z" - }, - "all_time": { - "calls": 1, - "tenant_count": 1, - "user_count": 1, - "component_count": 1, - "tenants": { - "unknown": 1 - }, - "users": { - "unknown": 1 - }, - "components": { - "unknown": 1 - } - }, - "window": { - "calls": 0, - "tenant_count": 0, - "user_count": 0, - "component_count": 0, - "tenants": {}, - "users": {}, - "components": {} - }, - "last_seen_at": "2026-06-06T17:28:13.047529Z", - "retirement_candidate": false, - "retirement_reason": "already retired" - }, - { - "interface": { - "id": "d0294dce-7913-4268-94c3-1b2502aefb0f", - "interface_key": "rest_api:GET /sbom/", - "interface_kind": "rest_api", - "legacy_since": "2026-08-22T17:06:38.703608Z", - "replacement_ref": "sbom-nexus:/sbom/", - "owner_component": "state-hub.sbom-compat", - "status": "legacy", - "replacement_verified": true, - "manual_hold": false, - "hold_reason": null, - "notes": null, - "retired_at": null, - "created_at": "2026-08-22T17:06:38.703608Z", - "updated_at": "2026-08-22T17:23:43.730661Z" - }, - "all_time": { - "calls": 6, - "tenant_count": 1, - "user_count": 1, - "component_count": 1, - "tenants": { - "unknown": 6 - }, - "users": { - "unknown": 6 - }, - "components": { - "unknown": 6 - } - }, - "window": { - "calls": 1, - "tenant_count": 1, - "user_count": 1, - "component_count": 1, - "tenants": { - "unknown": 1 - }, - "users": { - "unknown": 1 - }, - "components": { - "unknown": 1 - } - }, - "last_seen_at": "2026-08-31T08:18:41.571768Z", - "retirement_candidate": false, - "retirement_reason": "1 call(s) in review window" - }, - { - "interface": { - "id": "2f77ac12-8c97-4974-a2f9-2996927982d1", - "interface_key": "rest_api:GET /sbom/report/licences/", - "interface_kind": "rest_api", - "legacy_since": "2026-08-22T17:06:41.978426Z", - "replacement_ref": "sbom-nexus:/sbom/", - "owner_component": "state-hub.sbom-compat", - "status": "retired", - "replacement_verified": true, - "manual_hold": false, - "hold_reason": null, - "notes": "STATE-WP-0079-T05: user-authorized retirement 2026-09-05; fresh seven-day gate passed, replacement_verified=true; direct SBOM Nexus endpoints returned HTTP 200 from the State Hub pod. Compatibility storage/routes retained for the final cutover.", - "retired_at": "2026-09-05T08:04:48.423727Z", - "created_at": "2026-08-22T17:06:41.978426Z", - "updated_at": "2026-09-05T08:04:48.418993Z" - }, - "all_time": { - "calls": 5, - "tenant_count": 1, - "user_count": 1, - "component_count": 1, - "tenants": { - "unknown": 5 - }, - "users": { - "unknown": 5 - }, - "components": { - "unknown": 5 - } - }, - "window": { - "calls": 0, - "tenant_count": 0, - "user_count": 0, - "component_count": 0, - "tenants": {}, - "users": {}, - "components": {} - }, - "last_seen_at": "2026-08-28T18:46:10.642164Z", - "retirement_candidate": false, - "retirement_reason": "already retired" - }, - { - "interface": { - "id": "b627edf5-3302-4366-ba2e-547d32f634b5", - "interface_key": "rest_api:GET /sbom/snapshots/", - "interface_kind": "rest_api", - "legacy_since": "2026-08-22T17:06:37.057774Z", - "replacement_ref": "sbom-nexus:/sbom/", - "owner_component": "state-hub.sbom-compat", - "status": "retired", - "replacement_verified": true, - "manual_hold": false, - "hold_reason": null, - "notes": "STATE-WP-0079-T05: user-authorized retirement 2026-09-05; fresh seven-day gate passed, replacement_verified=true; direct SBOM Nexus endpoints returned HTTP 200 from the State Hub pod. Compatibility storage/routes retained for the final cutover.", - "retired_at": "2026-09-05T08:04:48.506447Z", - "created_at": "2026-08-22T17:06:37.057774Z", - "updated_at": "2026-09-05T08:04:48.501706Z" - }, - "all_time": { - "calls": 7, - "tenant_count": 1, - "user_count": 1, - "component_count": 1, - "tenants": { - "unknown": 7 - }, - "users": { - "unknown": 7 - }, - "components": { - "unknown": 7 - } - }, - "window": { - "calls": 0, - "tenant_count": 0, - "user_count": 0, - "component_count": 0, - "tenants": {}, - "users": {}, - "components": {} - }, - "last_seen_at": "2026-08-28T18:46:10.694185Z", - "retirement_candidate": false, - "retirement_reason": "already retired" - }, - { - "interface": { - "id": "d03ee274-cd6f-4cd5-8f22-e4d298416299", - "interface_key": "rest_api:GET /sbom/snapshots/{snapshot_id}", - "interface_kind": "rest_api", - "legacy_since": "2026-08-22T17:23:45.969876Z", - "replacement_ref": "sbom-nexus:/sbom/", - "owner_component": "state-hub.sbom-compat", - "status": "retired", - "replacement_verified": true, - "manual_hold": false, - "hold_reason": null, - "notes": "Retired by STATE-WP-0069 closeout", - "retired_at": "2026-08-31T08:55:08.470106Z", - "created_at": "2026-08-22T17:23:45.969876Z", - "updated_at": "2026-08-31T08:55:08.456139Z" - }, - "all_time": { - "calls": 1, - "tenant_count": 1, - "user_count": 1, - "component_count": 1, - "tenants": { - "unknown": 1 - }, - "users": { - "unknown": 1 - }, - "components": { - "unknown": 1 - } - }, - "window": { - "calls": 0, - "tenant_count": 0, - "user_count": 0, - "component_count": 0, - "tenants": {}, - "users": {}, - "components": {} - }, - "last_seen_at": "2026-08-22T17:23:45.967492Z", - "retirement_candidate": false, - "retirement_reason": "already retired" - }, - { - "interface": { - "id": "a6cb291e-8312-42f8-8a66-fde369482881", - "interface_key": "rest_api:GET /sbom/{repo_slug}", - "interface_kind": "rest_api", - "legacy_since": "2026-08-22T17:23:45.089542Z", - "replacement_ref": "sbom-nexus:/sbom/", - "owner_component": "state-hub.sbom-compat", - "status": "retired", - "replacement_verified": true, - "manual_hold": false, - "hold_reason": null, - "notes": "Retired by STATE-WP-0069 closeout", - "retired_at": "2026-08-31T08:55:08.754914Z", - "created_at": "2026-08-22T17:23:45.089542Z", - "updated_at": "2026-08-31T08:55:08.750826Z" - }, - "all_time": { - "calls": 1, - "tenant_count": 1, - "user_count": 1, - "component_count": 1, - "tenants": { - "unknown": 1 - }, - "users": { - "unknown": 1 - }, - "components": { - "unknown": 1 - } - }, - "window": { - "calls": 0, - "tenant_count": 0, - "user_count": 0, - "component_count": 0, - "tenants": {}, - "users": {}, - "components": {} - }, - "last_seen_at": "2026-08-22T17:23:45.670511Z", - "retirement_candidate": false, - "retirement_reason": "already retired" - }, - { - "interface": { - "id": "cad13f19-ddb1-49b9-86d0-8789b7599f3a", - "interface_key": "rest_api:GET /tasks/?workstream_id", - "interface_kind": "rest_api", - "legacy_since": "2026-08-29T10:01:31.546213Z", - "replacement_ref": "/tasks/?workplan_id=", - "owner_component": "state-hub.api", - "status": "legacy", - "replacement_verified": true, - "manual_hold": false, - "hold_reason": null, - "notes": null, - "retired_at": null, - "created_at": "2026-08-29T10:01:31.546213Z", - "updated_at": "2026-08-29T10:01:31.546213Z" - }, - "all_time": { - "calls": 11, - "tenant_count": 1, - "user_count": 1, - "component_count": 1, - "tenants": { - "unknown": 11 - }, - "users": { - "unknown": 11 - }, - "components": { - "unknown": 11 - } - }, - "window": { - "calls": 11, - "tenant_count": 1, - "user_count": 1, - "component_count": 1, - "tenants": { - "unknown": 11 - }, - "users": { - "unknown": 11 - }, - "components": { - "unknown": 11 - } - }, - "last_seen_at": "2026-09-04T17:21:29.173850Z", - "retirement_candidate": false, - "retirement_reason": "11 call(s) in review window" - }, - { - "interface": { - "id": "3e4a3d0b-08fa-45c3-91e2-4f514a914b97", - "interface_key": "rest_api:GET /workstreams/", - "interface_kind": "rest_api", - "legacy_since": "2026-06-04T00:26:14.533764Z", - "replacement_ref": "/workplans/", - "owner_component": "state-hub.api", - "status": "legacy", - "replacement_verified": true, - "manual_hold": false, - "hold_reason": null, - "notes": null, - "retired_at": null, - "created_at": "2026-06-04T00:26:14.533764Z", - "updated_at": "2026-06-04T00:26:14.533764Z" - }, - "all_time": { - "calls": 830269, - "tenant_count": 1, - "user_count": 1, - "component_count": 1, - "tenants": { - "unknown": 830269 - }, - "users": { - "unknown": 830269 - }, - "components": { - "unknown": 830269 - } - }, - "window": { - "calls": 0, - "tenant_count": 0, - "user_count": 0, - "component_count": 0, - "tenants": {}, - "users": {}, - "components": {} - }, - "last_seen_at": "2026-08-21T13:50:37.994459Z", - "retirement_candidate": false, - "retirement_reason": "quiet 14d of 60d required for 830269 all-time call(s)" - }, - { - "interface": { - "id": "e4c140ec-7479-46f9-b185-4b533f19d639", - "interface_key": "rest_api:GET /workstreams/workplan-index", - "interface_kind": "rest_api", - "legacy_since": "2026-06-04T05:20:58.321869Z", - "replacement_ref": "/workplans/index", - "owner_component": "state-hub.api", - "status": "retired", - "replacement_verified": true, - "manual_hold": false, - "hold_reason": null, - "notes": "Retired by STATE-WP-0069 closeout", - "retired_at": "2026-08-31T08:55:08.939572Z", - "created_at": "2026-06-04T05:20:58.321869Z", - "updated_at": "2026-08-31T08:55:08.933482Z" - }, - "all_time": { - "calls": 40, - "tenant_count": 1, - "user_count": 1, - "component_count": 1, - "tenants": { - "unknown": 40 - }, - "users": { - "unknown": 40 - }, - "components": { - "unknown": 40 - } - }, - "window": { - "calls": 1, - "tenant_count": 1, - "user_count": 1, - "component_count": 1, - "tenants": { - "unknown": 1 - }, - "users": { - "unknown": 1 - }, - "components": { - "unknown": 1 - } - }, - "last_seen_at": "2026-09-01T18:42:55.879795Z", - "retirement_candidate": false, - "retirement_reason": "already retired" - }, - { - "interface": { - "id": "3a00b19e-e7db-4403-98aa-a77c9ab61ecc", - "interface_key": "rest_api:GET /workstreams/{workstream_id}", - "interface_kind": "rest_api", - "legacy_since": "2026-06-04T00:25:59.014966Z", - "replacement_ref": "/workplans/{workplan_id}", - "owner_component": "state-hub.api", - "status": "legacy", - "replacement_verified": true, - "manual_hold": false, - "hold_reason": null, - "notes": null, - "retired_at": null, - "created_at": "2026-06-04T00:25:59.014966Z", - "updated_at": "2026-06-04T00:25:59.014966Z" - }, - "all_time": { - "calls": 3411477, - "tenant_count": 1, - "user_count": 1, - "component_count": 1, - "tenants": { - "unknown": 3411477 - }, - "users": { - "unknown": 3411477 - }, - "components": { - "unknown": 3411477 - } - }, - "window": { - "calls": 7, - "tenant_count": 1, - "user_count": 1, - "component_count": 1, - "tenants": { - "unknown": 7 - }, - "users": { - "unknown": 7 - }, - "components": { - "unknown": 7 - } - }, - "last_seen_at": "2026-09-03T22:02:35.348363Z", - "retirement_candidate": false, - "retirement_reason": "7 call(s) in review window" - }, - { - "interface": { - "id": "69e1a255-a8b9-4101-8a68-b1bed23abfda", - "interface_key": "rest_api:GET /workstreams/{workstream_id}/dependencies/", - "interface_kind": "rest_api", - "legacy_since": "2026-06-04T00:25:59.291135Z", - "replacement_ref": "/workplans/{workplan_id}/dependencies/", - "owner_component": "state-hub.api", - "status": "legacy", - "replacement_verified": true, - "manual_hold": false, - "hold_reason": null, - "notes": null, - "retired_at": null, - "created_at": "2026-06-04T00:25:59.291135Z", - "updated_at": "2026-06-04T00:25:59.291135Z" - }, - "all_time": { - "calls": 1643952, - "tenant_count": 1, - "user_count": 1, - "component_count": 1, - "tenants": { - "unknown": 1643952 - }, - "users": { - "unknown": 1643952 - }, - "components": { - "unknown": 1643952 - } - }, - "window": { - "calls": 0, - "tenant_count": 0, - "user_count": 0, - "component_count": 0, - "tenants": {}, - "users": {}, - "components": {} - }, - "last_seen_at": "2026-08-21T13:50:30.082480Z", - "retirement_candidate": false, - "retirement_reason": "quiet 14d of 60d required for 1643952 all-time call(s)" - }, - { - "interface": { - "id": "b1aae931-b51f-4a85-a723-865dd65f6132", - "interface_key": "rest_api:PATCH /workstreams/{workstream_id}", - "interface_kind": "rest_api", - "legacy_since": "2026-06-04T06:09:41.901035Z", - "replacement_ref": "/workplans/{workplan_id}", - "owner_component": "state-hub.api", - "status": "legacy", - "replacement_verified": true, - "manual_hold": false, - "hold_reason": null, - "notes": null, - "retired_at": null, - "created_at": "2026-06-04T06:09:41.901035Z", - "updated_at": "2026-06-04T06:09:41.901035Z" - }, - "all_time": { - "calls": 584, - "tenant_count": 1, - "user_count": 1, - "component_count": 1, - "tenants": { - "unknown": 584 - }, - "users": { - "unknown": 584 - }, - "components": { - "unknown": 584 - } - }, - "window": { - "calls": 0, - "tenant_count": 0, - "user_count": 0, - "component_count": 0, - "tenants": {}, - "users": {}, - "components": {} - }, - "last_seen_at": "2026-08-16T16:33:34.045078Z", - "retirement_candidate": false, - "retirement_reason": "quiet 19d of 30d required for 584 all-time call(s)" - }, - { - "interface": { - "id": "ed6451c9-d2cc-4486-9afe-d3852782cabc", - "interface_key": "rest_api:POST /workstreams/", - "interface_kind": "rest_api", - "legacy_since": "2026-06-04T07:40:24.168535Z", - "replacement_ref": "/workplans/", - "owner_component": "state-hub.api", - "status": "legacy", - "replacement_verified": true, - "manual_hold": false, - "hold_reason": null, - "notes": null, - "retired_at": null, - "created_at": "2026-06-04T07:40:24.168535Z", - "updated_at": "2026-06-04T07:40:24.168535Z" - }, - "all_time": { - "calls": 811, - "tenant_count": 1, - "user_count": 1, - "component_count": 1, - "tenants": { - "unknown": 811 - }, - "users": { - "unknown": 811 - }, - "components": { - "unknown": 811 - } - }, - "window": { - "calls": 0, - "tenant_count": 0, - "user_count": 0, - "component_count": 0, - "tenants": {}, - "users": {}, - "components": {} - }, - "last_seen_at": "2026-08-16T01:03:41.093965Z", - "retirement_candidate": false, - "retirement_reason": "quiet 20d of 30d required for 811 all-time call(s)" - }, - { - "interface": { - "id": "281fd706-b192-4194-8055-2d8733c115f9", - "interface_key": "rest_api:POST /workstreams/{workstream_id}/dependencies/", - "interface_kind": "rest_api", - "legacy_since": "2026-06-04T22:57:37.149207Z", - "replacement_ref": "/workplans/{workplan_id}/dependencies/", - "owner_component": "state-hub.api", - "status": "retired", - "replacement_verified": true, - "manual_hold": false, - "hold_reason": null, - "notes": "Retired by STATE-WP-0069 closeout", - "retired_at": "2026-08-31T08:55:09.130713Z", - "created_at": "2026-06-04T22:57:37.149207Z", - "updated_at": "2026-08-31T08:55:09.123888Z" - }, - "all_time": { - "calls": 4975, - "tenant_count": 1, - "user_count": 1, - "component_count": 1, - "tenants": { - "unknown": 4975 - }, - "users": { - "unknown": 4975 - }, - "components": { - "unknown": 4975 - } - }, - "window": { - "calls": 0, - "tenant_count": 0, - "user_count": 0, - "component_count": 0, - "tenants": {}, - "users": {}, - "components": {} - }, - "last_seen_at": "2026-07-07T20:31:35.389791Z", - "retirement_candidate": false, - "retirement_reason": "already retired" - } - ], - "retirement_candidates": [] - } -} diff --git a/docs/retirement-cutover-slice-plan.md b/docs/retirement-cutover-slice-plan.md index 71b8257..26a4e56 100644 --- a/docs/retirement-cutover-slice-plan.md +++ b/docs/retirement-cutover-slice-plan.md @@ -1,93 +1,472 @@ # State Hub retirement — cutover slice plan -**Execution owner:** STATE-WP-0079-T04/T05 -**Re-baselined:** 2026-09-05 -**Inventory:** SHR-INV-0001, original 425-item inventory in -`prj-state-hub-retirement/inventory/`. Counts below identify historical slices; -current owner contracts take precedence over the original owner assignments. +**Workplan task:** `STATE-WP-0079-T02` +**Inventory:** `SHR-INV-0001` (`prj-state-hub-retirement/inventory/`), 425 items, v0.1.1 +**Created:** 2026-08-19 -This checklist replaces the obsolete August 19–20 readiness snapshot. That -snapshot and the original off/dual/owner proposal remain in Git history. -`RM_SLICE_*` names were proposed controls, not proof of deployed flags. Do not -execute the old workstation dual-run instructions against the cluster service: -ADR-002 forbids central services from mutating workstation checkouts. +Groups every dispositioned inventory item into an ordered cutover slice. Each +slice names its adapter flag, the owner-side API that receives the traffic, and +its rollback. Slices are the execution unit for `STATE-WP-0079-T04`. -## Evidence required to switch a slice +## Method -For each route family, identify the current caller and destination endpoint, -compare representative identities/content/counts in a read-only parity run, -record the exact deployment/source revisions, exercise rollback, and retain the -switch receipt. An owner workplan marked finished or an imported Python router -proves neither deployed endpoint availability nor data migration. Production -writer changes require a concrete recoverable cutover, within user authorization. -No new permanent receiving authority belongs in State Hub during retirement. +Slices are cut on **capability**, not on route or table, because a capability is +the smallest unit with a single owner and a coherent contract. The inventory's +`capability` field yields 51 groups; those are bundled into waves by owner, and +ordered within a wave by dependency and blast radius. -## Current route-family checklist +Two rules constrain the ordering: -| Slice / historical items | Receiver and contract evidence | Caller / route-switch evidence | Remaining gate and rollback | +1. **A slice cannot move before its owner can receive it.** Owner readiness is + the owner repo's own workplan status, not an assertion here. +2. **Read-only projections move before write paths** in the same capability, so + a failed cutover degrades to stale reads rather than lost writes. + +## Owner readiness (verified 2026-08-19) + +| Owner | Items | Gating workplan | Status | Can receive? | +| --- | --- | --- | --- | --- | +| `repo-manager` | 167 | RMGR-WP-0001/0002/0003 | `finished` | **Partial — see correction below** | +| `hub-core` | 128 | HUB-WP-0004 runtime + extension contract | `proposed` | No | +| `state-hub-until-cutover` | 55 | — (keep/retire in place) | — | n/a | +| `activity-core` | 18 | ACTIVITY-WP-0029 hub port alignment | `active` | Partial | +| `ops-hub` | 13 | OPS-WP-0003 extension contract alignment | `proposed` | No | +| `fin-hub` | 10 | FIN-WP-0003 fabric authority boundary | `proposed` | No | +| `archive` | 30 | legacy-meter evidence | see Wave E | Conditional | +| `ops-bridge` | 2 | — (`keep`) | — | n/a | +| `the-custodian` | 2 | — | — | Yes | + +Only the `repo-manager` lane is unblocked today, and **only partly** — see the +correction immediately below. Everything else is waiting on an owner-side +contract, not on State Hub. + +### Correction (2026-08-20): repo-manager readiness is per-capability + +The table above reads owner readiness off workplan status, which is too coarse. +RMGR-WP-0001/0002/0003 are `finished`, but what they delivered is **work-record +dual-run, repository observation, and scaffolding** — not a general register +surface. Verified against `repo-manager/src/repo_manager/` on 2026-08-20: + +| `rmgr` surface | Covers | Slice | +| --- | --- | --- | +| `observe`, `load_classification` | repository representation, classification | A1 (partial) | +| `reconcile`, `index_store`, `parse/workplan.py`, `task-status`, `dual_run` | work records | A2 | +| `conform`, `standards.py`, `scaffold` | standards, onboarding | A1 `repo-onboarding` (already cut over) | +| `prefix` | workplan prefix registry | A1 (partial) | + +`parse/` contains **only** `workplan.py`. A grep for `sbom`, `repo_goal`, +`contribution`, `technical_debt`, and `extension_point` across the whole source +tree returns **nothing**. + +**Consequence:** A3, A4, and A5 have no owner-side surface to receive them. + +| Slice | Items | Receivable? | +| --- | --- | --- | +| A1 repository registry | 27 | Partial — `observe`/`conform` cover representation; registry CRUD does not exist | +| A2 work records | 59 | **Yes** — this is exactly what RMGR-WP-0002/0003 proved | +| A3 registers | 49 | **No** — no register surface of any kind in repo-manager | +| A4 work + repo UI | 22 | **No** — `rmgr` is a CLI; there is no owner-side dashboard | +| A5 topic spine | 8 | **No** — no topic/classification contract beyond `observe` | + +The near-term executable surface is therefore **A1 + A2, not 165 items**, and +A2 is the only slice with a proven adapter. + +**A3 is not the low-blast-radius first cut this plan originally recommended** — +it is the least ready slice in Wave A. The recommendation is withdrawn. + +**Do not build the register surface in State Hub.** New register capability here +would be new permanent ownership in the component being retired, which +`policies/retirement-freeze.md` makes inadmissible. A3/A4/A5 need a +`repo-manager` workplan; RMGR-WP-0004 (standards conformance) and RMGR-WP-0005 +(registrar consolidation) do not cover them. + +### Owner readiness refresh (2026-08-31) + +The original readiness table is retained above as planning history. Current +workplan status changes which owners can receive a slice, but it does not count +as State Hub cutover evidence by itself: + +| Owner | Current owner evidence | State Hub cutover consequence | +| --- | --- | --- | +| `repo-manager` | RMGR-WP-0005 finished deterministic identifier migration; RMGR-WP-0008 finished register/classification surfaces | Receiving-side identity and register gates are satisfied; each State Hub writer/read switch still needs its own parity and rollback receipt. | +| `hub-core` | HUB-WP-0005 finished and its production runtime owns all declared hub-core route/writer groups with exercised rollback | Receiving runtime is available; B1-B5 are not complete until State Hub caller/route switches and counts are evidenced. | +| `activity-core` | ACTIVITY-WP-0029 finished schedule, sweep, interaction-event, and execution-boundary work | The launch-request defect is retired; remaining C-slice caller switches still require explicit evidence. | +| `ops-hub` | OPS-WP-0003 finished; owner package and implemented conformance profile pass | D1 receiving-side gate is satisfied. State Hub route/caller switch, count parity, rollback, and writer authorization remain cutover evidence. | +| `fin-hub` | FIN-WP-0003 remains `proposed`; 0/3 tasks done | D2 cannot move. Do not implement the fabric authority contract here. | +| `archive` | 2026-08-31 central meter: 6 newly retired, 9 legacy, 0 candidates | E2/E4 remain gated; live callers and volume-scaled quiet windows prohibit retirement. | + +Accordingly, `STATE-WP-0079-T04` is waiting on the missing owner workplans, +the still-unrecorded State Hub route-switch receipts, and explicit production +writer-cutover authorization. `T05` waits on fresh central meter evidence, and +`T06` cannot begin while State Hub remains the healthy, active `railiance01` +primary. + +## Adapter mechanism + +Wave A reuses the dual-run strangler proven in RMGR-WP-0002/0003 rather than +introducing a new mechanism: + +- Adapter: `api/services/repo_manager_dual_run.py` +- Existing flags: `RM_WRITEBACK`, `RM_WRITEBACK_PUSH`, `RM_RECONCILE`, + `RM_PILOT_REPOS`, `RM_METER_PATH`, `RM_DUAL_RUN_CONFIG` +- Reference: `repo-manager/docs/dual-run.md`, evidence + `repo-manager/docs/evidence/wp0002-completion.md` + +New slices add a **slice-scoped flag** of the form `RM_SLICE_` with three +states — `off` (hub only), `dual` (both, hub authoritative, divergence metered), +`owner` (owner authoritative, hub proxies). Rollback for every Wave A slice is +therefore the same operation: set the slice flag back one state. No slice +advances to `owner` until it has run a full consistency-sweep cycle at `dual` +with zero divergence. + +Waves B–D must not invent hub-side adapters ahead of their owner contract. +Per the T01 freeze rule, building an adapter for an owner that cannot yet +receive establishes new permanent ownership here — the exact thing retirement +is removing. + +--- + +## Wave A — repo-manager (167 items, executable now) + +### A1 · Repository registry — 27 items +`repository-registry` (24: 16 route, 7 mcp_tool, 1 dataset) · `repo-reconciliation` (1) +· `repo-doi` (1) · `repo-onboarding` (1) + +| | | +| --- | --- | +| Flag | `RM_SLICE_REGISTRY` | +| Owner API | `rmgr` repo registry + classification spine | +| Rollback | flag → `dual`, then `off`; hub tables retain rows throughout | + +First because every other repo-manager slice keys off repo identity, and because +`repo-onboarding` is already delegated (`STATE-WP-0080-T02`, `rmgr scaffold`), +so the slice starts partly cut over. + +### A2 · Work records — 59 items +`work-records` (20) · `work-records-workplan` (12) · `work-records-intake` (9) · +`work-records-decision` (8, move+replace) · `work-records-deps` (2) · +`work-records-task` (8, repo-manager portion) + +| | | +| --- | --- | +| Flag | `RM_SLICE_WORKRECORDS` | +| Owner API | `rmgr` file-backed work-record index + PATCH `/tasks` writeback | +| Rollback | flag → `dual`; C-15 writeback already reconciles file↔DB drift | + +Highest blast radius in the program — this is the surface every agent session +touches. Split the flag by record kind if divergence appears; do not cut the +whole slice at once. + +`work-records-task` is owner-split: the route/dataset portion is repo-manager, +the job portion is `activity-core` (Wave C1). Cut the repo-manager portion first +and leave the job dual-running. + +### A2 readiness detail (2026-08-20) + +Same check as for A3, applied one level down. The State Hub adapter +(`api/services/repo_manager_dual_run.py`) exposes exactly three operations: + +| Adapter function | Routes to | Covers | +| --- | --- | --- | +| `rm_update_task_status` | `rmgr task-status` | task status writes | +| `rm_reconcile` | `rmgr reconcile` | work-record index rebuild | +| `rm_scaffold` | `rmgr scaffold` | repo scaffolding (A1 `repo-onboarding`, already cut over) | + +There is no adapter for workplan create/update/delete, intake, decision, +dependency, or human-flag records — and no parser for them on the repo-manager +side either (`parse/` is `workplan.py` only). So A2 splits: + +| Sub-slice | Items | Receivable | +| --- | --- | --- | +| **A2a** task status + reconcile | ~6 (`update_task_status`, `bulk_update_task_statuses`, `PATCH /tasks/{id}`, `POST /tasks/bulk-status-sync`, index refresh job, `table:tasks`) | **Yes — adapter exists and was proven by RMGR-WP-0002/0003** | +| A2b workplan CRUD | ~9 routes + `table:workplans` | No adapter; repo-manager parses workplans but exposes no write path | +| A2c intake | 9 | No parser, no adapter | +| A2d decision | 8 | No parser, no adapter | +| A2e dependencies + human-flag | ~6 | No parser, no adapter | + +**A2a is the only slice in the entire plan that is executable today**, and it is +roughly 6 items, not 59. + +### Dual-run is currently off + +`rmgr dual-run-status` on 2026-08-20: + +``` +config_exists: false writeback: false reconcile: false pilot_repos: null +meter: {state-hub: 15, repo-manager: 8, total: 23} +``` + +The 23 metered mutations are the RMGR-WP-0002/0003 pilot runs. Nothing is +dual-running now — the adapter is proven but switched off, and there is no +`~/.repo-manager/dual-run.yaml`. + +**So the concrete next executable step is operational, not code:** create the +dual-run config and enable `RM_WRITEBACK` + `RM_RECONCILE`, then watch the +mutation meter for divergence. That is A2a moving from `off` to `dual`. + +**The pilot repo is already established — `repo-manager`**, per RMGR-WP-0003 and +the shipped `repo-manager/config/dual-run.pilot.example.yaml`. No new decision +is needed about which repo; the procedure is documented in +`repo-manager/docs/dual-run.md`: + +```bash +mkdir -p ~/.repo-manager +cp ~/repo-manager/config/dual-run.pilot.example.yaml ~/.repo-manager/dual-run.yaml +# then restart the State Hub API — settings are cached per process +``` + +Rollback is `rm ~/.repo-manager/dual-run.yaml` plus a restart, or setting +`writeback`/`reconcile` false. + +**Requires an operator**, for one reason only: it changes how live task writes +flow and needs a State Hub API restart to take effect. Piloting on +`repo-manager` keeps the blast radius to a single repo. + +### A3 · Registers — 49 items +`sbom-inventory` (10) · `repo-goals` (9) · `upstream-contributions` (9) · +`register-technical-debt` (9) · `register-extension-points` (6) · `register-entries` (6) + +| | | +| --- | --- | +| Flag | `RM_SLICE_REGISTERS` | +| Owner API | `rmgr register ...`; `rmgr sbom scan|licence-report` | +| Rollback | flag → `off`; retain current State Hub projection | + +**Owner ready (2026-08-21).** Finished RMGR-WP-0008 supplies the shared six-kind +register spine, governed compatibility adapter, lockfile-derived SBOM and +licence/copyleft report. Historical SBOM rows are cache provenance; rebuild +from current repository sources rather than copying them into authority. + +### A4 · Work + repo UI — 22 items +`work-coordination-ui` (14, `replace`) · `repo-ui` (8) + +| | | +| --- | --- | +| Flag | `RM_SLICE_UI` | +| Owner API | hub-core projection/query plus hub/ops UI clients | +| Rollback | remove redirect; hub pages are unchanged behind it | + +`replace`, not `move`: the contract changes. Must follow A1–A3, since the pages +render what those slices serve. RMGR-ADR-003 corrects the earlier inventory +assignment: Repo Manager owns the repository contracts, not a dashboard. A4's +UI implementation therefore rides with B5 even though these 22 inventory items +remain grouped here for traceability. + +### A5 · Topic spine — 8 items +`topic-spine` (8, `replace`) + +| | | +| --- | --- | +| Flag | `RM_SLICE_TOPICSPINE` | +| Owner API | `rmgr` topic/classification contract | +| Rollback | flag → `off` | + +The versioned Repo Manager classification contract is published and accepted by +finished HUB-WP-0004. Consumer route switching remains a State Hub cutover +action. + +--- + +## Wave B — hub-core (128 items) · HUB-WP-0004 owner gate satisfied + +HUB-WP-0004 finished 2026-08-21 and accepted the project architecture, runtime, +ports, conformance scaffold, and absorption plan. Individual production +cutovers still require their slice evidence and operator gates. + +| Slice | Capabilities | Items | +| --- | --- | --- | +| B1 catalogs | `capability-catalog` (18), `cross-domain-registry` (16) | 34 | +| B2 messaging + interface log | `agent-messaging` (11), `interface-change-log` (11) | 22 | +| B3 telemetry | `token-telemetry` (14), `third-party-software-catalog` (10), `progress-telemetry` (8) | 32 | +| B4 projections + policy | `state-projections` (9), `domain-goals` (6), `policy-integration` (2), `write-idempotency` (1), `event-bus` (1), `recently-on-scope` (1) | 20 | +| B5 hub UI | `hub-projection-ui` (14, replace), `agent-integration` (2), `dashboard` (1) | 17 | + +Order B1 → B4 → B2 → B3 → B5: catalogs and projections are read-mostly and +carry the contract; messaging and telemetry are write paths; UI last. + +## Wave C — activity-core (18 items) · ACTIVITY-WP-0029 `active` + +| Slice | Capabilities | Items | +| --- | --- | --- | +| C1 execution | `workplan-execution-queue` (7, replace), `task-flow-engine` (6, replace) | 13 | +| C2 jobs | `ops-run-projection` (1), `repo-consistency` (3), `work-records-task` activity-core portion (1) | 5 | + +Both are `replace` — schedulers move to activity-core under a different +contract. C2 must follow A2, since the consistency job writes work records. + +## Wave D — remaining owners (25 items) · fin-hub gated + +| Slice | Owner | Capabilities | Items | Gate | +| --- | --- | --- | --- | --- | +| D1 | `ops-hub` | `service-catalog` (9), `service-catalog-ui` (2) | 11 | OPS-WP-0003 `finished`; receiving contract ready, cutover receipt pending | +| D2 | `fin-hub` | `fabric-graph` (10) | 10 | FIN-WP-0003 `proposed` | +| D3 | `the-custodian` | `kaizen-agents` (2) | 2 | none — can go anytime | + +D3 is two MCP tools with no dependants; take it opportunistically. + +## Wave E — retire (42 items) + +| Slice | Capability | Items | Gate | | --- | --- | --- | --- | -| A1 registry / 27 | Repo Manager observation/scaffolding; STATE-WP-0081 and 0086 establish forge-derived projection | `rmgr sync` verified pushed commit `74a3b22` on primary/railiance01 in the preceding session | Inventory remaining registry callers per endpoint. Keep current projection while proving the owner read; do not restore checkout mutation in central | -| A2 work records / 59 | RMGR-WP-0008 implements file-backed workplan, intake, decision, dependency and task mutations; RMGR-WP-0005 identifiers finished | Repository files + `rmgr sync` are the current write convention. Two ad-hoc task-filter callers identified and guidance corrected in this review | Work-record caller inventory and per-kind writer receipts still required. Revert source commit and reconcile for a reviewed rollback; no second file authority | -| A3 registers / 49 | RMGR-WP-0008 register spine; **SBOM Nexus** is the current SBOM product owner | Live State Hub config uses Nexus for both SBOM reads/writes. Direct Nexus licence and snapshot reads return 200. Two more compatibility interfaces retired in the meter September 5 | Other registers need individual caller/parity receipts. Preserve SBOM history; remaining `/sbom/` traffic and retained compatibility handlers prevent deleting the whole router | -| A4 work/repo UI / 22 | hub-core projection + UI clients; RMGR-ADR-003 excludes a Repo Manager dashboard | No complete State Hub UI redirect receipt established | First prove backing reads; rollback redirects to the retained UI | -| A5 topic spine / 8 | Published Repo Manager classification contract, accepted by HUB-WP-0004 | No complete State Hub caller-switch receipt established | Prove deployed consumer contract and parity; retain source-backed classification projection | -| B1 catalogs / 34 | HUB-WP-0004/0005 receiving architecture and `/api/v2` absorption | Completion covers the Core Hub route groups, not every State Hub capability/registry route | Map each State Hub catalog to a deployed endpoint and migration receipt | -| B2 messaging/interface log / 22 | Shared `hub_core.routers.messages` exists; State Hub interface log is a separate family | Live Hub Core OpenAPI has **no `/messages` or `/interface-changes`**. `/api/v2/interaction-events` exists but is not asserted equivalent | **Next bounded read slice:** STATE-WP-0079-T08. Owner must expose/identify the message read contract and history projection before a parity run or switch. Retain current reads/writer | -| B3 telemetry / 32 | Shared `hub_core.routers.progress` exists; token/software catalogs need separate mappings | Live Hub Core OpenAPI has **no `/progress` or `/token-events`** | Owner runtime assembly/mapping plus historical identity/count parity; writer exclusivity and rollback receipts remain necessary | -| B4 projection/policy / 20 | HUB-WP-0004/0005; policy publication belongs to policy-nexus | State Hub still serves its projection routes; no full family receipt established | Map individual projections and policy publication; retain source/runtime boundaries and current reads | -| B5 hub UI / 17 | Hub Core runtime/console exists | Core Hub absorption does not establish replacement of State Hub dashboard pages | Prove A4/B1–B4 data contracts before redirect; retain UI rollback | -| C1 execution / 13 | ACTIVITY-WP-0029 finished; Activity Core owns scheduling/ops_run | STATE-WP-0079 records launch-request rejection (410), replacement semantics, and corrected unconsumed requests | Verify every remaining execution caller uses the owner contract. Do not revive the obsolete launch queue for rollback | -| C2 jobs / 5 | ACTIVITY-WP-0029 finished; scheduler is Activity Core, reconciliation engine is Repo Manager | Receiving/sweep handoffs recorded in owner workplan | Attach remaining per-job deployment and caller receipts; keep scheduler ownership distinct from work-record authority | -| D1 service catalog / 11 | OPS-WP-0003 finished; reviewed packages and `/api/v2` conformance gate | Owner contract completion established; State Hub family-switch receipt still missing | Compare catalog identities and UI bindings; preserve current reads until switched | -| D2 Fabric / 10 | **railiance-fabric** authority, FIN-WP-0003 consumer gate | August 31 dual-read import: 131 nodes/117 edges; green hash/count/provenance checks, rollback and roll-forward exercised | Hosted runtime/persistence/auth/freshness remains RAIL-FAB-WP-0028 (`proposed`). Keep retained import rollback; do not claim the local authority is a hosted production receiver | -| D3 kaizen / 2 | the-custodian, original two-tool disposition | No fresh removal/delegation receipt collected in this review | Locate current tools/consumers and owner contract before removal | -| E1 suggestions / 17 | Archived history in the-custodian | STATE-WP-0079 records eight read routes at 410, six MCP tools removed, dashboard removed | Completed surface removal; tables retained for final dump | -| E2 legacy workplans / 13 | Preferred `/workplans` routes and `workplan_id` parameters | Workstream REST handlers return 410 and meter rejected calls. Task query alias still accepted | Seven legacy meter records remain after today's two SBOM retirements; observe volume-scaled quiet periods and complete T07 attribution | -| E3 UI feedback / 1 | State Hub until cutover | Feedback still needed during transition | T06 zero-normal-traffic gate; do not confuse it with retired suggestions | -| E4 meter / 9 | State Hub until all other retirement evidence complete | Eight retired / seven legacy interfaces, zero current candidates after September 5 action | Retire last, after the remaining interfaces and final evidence are closed | +| E1 | `suggestion-backlog` → archive | 17 | history archived 2026-08-20; read surface + dashboard remain | +| E2 | `work-records-workplan-legacy` → archive | 13 | legacy-meter — candidate rule, see below | +| E3 | `dashboard-meta` (`/ui-feedback`) | 1 | T06 freeze window — owner is `state-hub-until-cutover` | +| E4 | `legacy-meter` itself | 9 | **last** — it is the instrument for E2 | -## What today's probes establish +E4 retires only after every other legacy surface is closed; retiring the meter +first destroys the evidence for the retirements it gates. -- Central health identifies `primary/railiance01`. -- The live State Hub configuration has `SBOM_NEXUS_READ_MODE=nexus` and - `SBOM_NEXUS_WRITE_MODE=nexus`, using the cluster SBOM Nexus service. -- Direct Nexus `/sbom/report/licences/` and `/sbom/snapshots/` returned 200 from - the State Hub pod. Their State Hub meter entries are now retired. This does - **not** delete the compatibility handlers or historical data. -- Hub Core candidate runtime OpenAPI, read from its own pod loopback, has 31 - paths and lacks the four State Hub families identified above. The State Hub - pod's probes to both Core Hub service addresses were connection-refused; - the deployments reported 1/1 ready. Transport readiness must be resolved as - part of any proxy-based pilot; this review did not diagnose its cause. -- Session trace identifies ad-hoc legacy task reads in fluid-telegram and - ops-warden. Their corrected canonical queries return 200 with 8 and 5 tasks. - No evidence identifies the other historical callers yet. +### E1 status (2026-08-20) -Evidence: `docs/evidence/STATE-WP-0079-sbom-retirement-20260905.json` and -`docs/evidence/STATE-WP-0079-caller-and-receiver-review-20260905.md`. +Already half-retired before this plan: mutations have returned HTTP 410 since +2026-07-21 (`CUST-WP-0061-T06`), pointing at `POST /intakes/`. Reads were kept +live so the historical record stayed reachable. -## Next executable work +**History is now archived** at `the-custodian/docs/archived-suggestion-backlog.md` +— all 10 suggestions, 10 notes, and 5 relevance bumps, with each entry's +migration target. Every entry was `declined` in the intake migration and none +was promoted, so nothing forward-looking is lost by removing the surface. -1. T07: observe the remaining legacy readers with component attribution. The - known caller repositories and bundled State Hub skill now prescribe canonical - reads. Preserve the quiet clocks; do not exercise legacy URLs to test them. -2. T08: obtain one **deployed message-read contract** from hub-core, including - access/transport and historical projection. Use the State Hub inbox reader as - the bounded parity client. Compare message IDs and read/archive flags against - one consistent snapshot; do not change message writes during this proof. - Only after parity and rollback evidence should a concrete reader switch run. -3. RAIL-FAB-WP-0028-T01 remains the owner decision for runtime, persistent store, - auth, backup/restore and deployment repository. Its T02–T04 deliver deployment, - freshness and final direct-consumer receipts; no new Fabric authority here. -4. Re-evaluate eligible interfaces from a fresh seven-day meter capture. The - quiet ladder is 7 days for 1–99 historical calls, 30 for 100–9,999, and 60 for - 10,000+. A new call restarts the relevant clock, including rejected requests. +**Executed 2026-08-20.** The 8 read routes now 410 with a pointer to intake and +to the archive, the 6 MCP tools are removed (not stubbed — a retired tool that +still appears in the tool list costs every agent session context on every call), +the 5 `/suggestions` write-idempotency rules are gone, and the dashboard page is +deleted with its nav entry, `reference.md` row, and `wsjf-triage.md` link +updated. `dashboard/src/docs/suggestions.md` is rewritten as the archive +pointer. Tables stay for the T06 dump. -## Freeze and infrastructure boundary +One naming trap worth recording: **`ui-feedback.md` and `todo.md` "suggestions" +are a different entity** — Shift+click dashboard feedback backed by +`technical_debt`, not the suggestion backlog. They are untouched. Anything +grepping for `suggestion` during cutover will hit them. -T06 remains blocked until move/replace families and legacy retirement complete, -followed by a fresh zero-normal-read/write window. Final dump, restore proof, -service stop and repository archive then form one separately reviewable -operation. The original schema-history/keep items and nine infrastructure -couplings (database, scheduler, connectivity) remain explicit final-window -checks; they are not route flags. Ops Bridge connectivity survives retirement. +### E3 status (2026-08-20) + +`dashboard-meta` is the `/ui-feedback` page — the feedback scratch surface just +mentioned. Its owner is `state-hub-until-cutover` and it is still in active use, +so it retires **at the T06 freeze window**, not before. Removing it now would +delete a working feedback loop during the retirement it serves. No action. + +### E2 evidence — defect found and partly fixed (2026-08-20) + +The window discrepancy flagged on 2026-08-19 was a real defect in +`scripts/capture_legacy_meter_evidence.py`, not a labelling nit. + +`_review_query` fell back to `hours=8` whenever `--days` was omitted, and +`--hours` defaulted to `8`. Every unattended capture therefore sampled an +8-hour band (06:00Z–14:00Z) while writing a file named `weekly-review` with +`cadence: weekly` in the payload. **39 of 40 captures ran this way** — only the +first, 2026-07-08, used a true 7-day window. + +Calls in the other 16 hours of each day were never sampled, so quiet-in-band +interfaces were reported as retirement candidates while still having live +callers. On the 2026-08-19 capture three candidates had recent traffic: + +| Interface | All-time calls | Last seen | +| --- | --- | --- | +| `GET /tasks/?workstream_id` | 594 | 2026-08-18 | +| `GET /progress/?workstream_id` | 2 | 2026-08-12 | +| `GET /workstreams/` | 144 086 | 2026-08-10 | + +**Fixed:** the script now defaults to `days=7`, matching the endpoint name and +the cadence label. `--hours` is retained for spot checks and documented as not +retirement evidence. Corrected capture: +`docs/evidence/legacy-meter-weekly-review-20260820.json` — 18 candidates of 20 +interfaces, `GET /tasks/?workstream_id` correctly excluded. + +**Candidate rule tightened (2026-08-20).** `_retirement_state` now requires a +quiet period scaled to all-time call volume, because a clean window only proves +silence for that window — for a heavily used interface an infrequent caller can +fall outside it entirely. `RETIREMENT_QUIET_LADDER` in +`api/services/legacy_meter.py`: + +| All-time calls | Days since `last_seen_at` required | +| --- | --- | +| 0 | none — never used | +| 1 – 99 | 7 | +| 100 – 9 999 | 30 | +| 10 000+ | 60 | + +Applied to the 2026-08-20 capture this splits the 19 legacy interfaces cleanly: + +**15 retirable** — all four `workstream` MCP tools, the `state://` resource, and +the low-volume REST aliases, plus `PATCH /workstreams/{id}` (571 calls, quiet +42d), `POST /workstreams/` (824, quiet 42d) and +`POST /workstreams/{id}/dependencies/` (4 971, quiet 49d). + +**4 held:** + +| Interface | All-time calls | Reason | +| --- | --- | --- | +| `GET /tasks/?workstream_id` | 595 | traffic inside the window | +| `GET /workstreams/` | 144 086 | quiet 9d of 60d | +| `GET /workstreams/{id}` | 511 406 | quiet 19d of 60d | +| `GET /workstreams/{id}/dependencies/` | 255 865 | quiet 42d of 60d | + +**Executed 2026-08-20:** the 15 are retired; the meter reads 16 retired / 4 +legacy with 0 outstanding candidates. Journalled at +`the-custodian/docs/retired-legacy-interfaces.md`. The four +held are the three six-figure read paths and the one with live traffic — exactly +the set where a false retirement would hurt most. They clear on their own as the +quiet counter runs, provided no new traffic arrives; the earliest, +`GET /workstreams/{id}/dependencies/`, needs 18 more silent days. + +Re-check before executing E2: the ladder is evaluated at review time, so a +capture older than the retirement decision is not evidence for it. + +## Keep — 43 items + +`schema-history` (43 migrations, `keep` until cutover) plus `ops-automation`, +`connectivity` (ops-bridge). Not slices: they persist until the T06 freeze +window and are dispositioned by the final dump and archive. + +## Coverage + +Computed against `state-hub-disposition.yaml`, not hand-counted. Every item is +assigned by `capability`; `work-records-task` splits on `owner`. + +| Wave | Slices | Items | +| --- | --- | --- | +| A repo-manager | A1 27 · A2 59 · A3 49 · A4 22 · A5 8 | 165 | +| B hub-core | B1 34 · B2 22 · B3 32 · B4 20 · B5 17 | 125 | +| C activity-core | C1 13 · C2 5 | 18 | +| D ops-hub / fin-hub / the-custodian | D1 11 · D2 10 · D3 2 | 23 | +| E retire | E1 17 · E2 13 · E3 1 · E4 9 | 40 | +| Keep | `schema-history` 43, `ops-automation` 1, `connectivity` 1 | 45 | +| Ops dependencies | see below | 9 | +| **Total** | | **425** | + +Wave A totals 165 rather than the owner table's 167, and Wave B 125 rather than +128: the difference is `ops_dependency` items, which carry no `capability` and +so attach to no capability slice. + +### Ops dependencies (9 items, no capability) + +| Owner | Disposition | Items | Handling | +| --- | --- | --- | --- | +| `hub-core` | move / replace / keep | 3 | ride with Wave B; confirm at B4 | +| `ops-hub` | replace | 2 | ride with D1 | +| `state-hub-until-cutover` | retire | 2 | T06 freeze window | +| `activity-core` | keep | 1 | keep to cutover | +| `ops-bridge` | keep | 1 | keep — external dependency, survives retirement | + +These are infrastructure couplings (DB, scheduler, tunnel), not API surface. +They cannot be strangled behind a flag and are dispositioned at the freeze +window instead. Worth an explicit owner confirmation during T04 so none is +discovered live at cutover. + +## Next actions + +1. ~~Resolve the legacy-meter window discrepancy~~ — done 2026-08-20; E1 and the + evidenced part of E2 are executed. +2. ~~Build the Repo Manager receiving surface for A3/A5 and settle A4 + ownership~~ — finished in RMGR-WP-0008. A4 belongs to hub-core projection UI, + not Repo Manager. +3. Cut **A2a** (task status + reconcile, ~6 items) — the only slice in the plan + executable today. First step is operational: create `~/.repo-manager/dual-run.yaml` + and enable writeback/reconcile for one pilot repo, then watch the mutation + meter. A2b–A2e need repo-manager parsers and adapters that do not exist. +4. HUB-WP-0004's owner-readiness gate is satisfied; advance Wave B only through + its per-slice dual-run and operator gates. +5. Do not build register, UI, or topic capability in State Hub to unblock + items 2–3 — `policies/retirement-freeze.md` makes that inadmissible. diff --git a/skills/state-hub/SKILL.md b/skills/state-hub/SKILL.md index 736cd59..6381b9b 100644 --- a/skills/state-hub/SKILL.md +++ b/skills/state-hub/SKILL.md @@ -1,6 +1,6 @@ --- name: state-hub -description: Coordinate repository-backed work through State Hub REST or optional MCP, including canonical workplan reads, inbox checks, task status sync, and progress logging. +description: Use when coordinating with Custodian State Hub: orienting with domain summaries, checking agent inbox messages, updating workplan-backed task status, recording decisions/progress, or batching task status sync through MCP/REST without re-discovering tool schemas. --- # State Hub Coordination @@ -11,32 +11,21 @@ work structure in the hub when a workplan file is the canon. ## Session Flow -1. Prefer REST/`statehub` for Codex. Verify `/state/health` identifies the expected - primary, then read `/workplans/` with repo/topic filters. MCP is opt-in; use - `get_domain_summary(domain_slug)` when enabled. +1. Orient with `get_domain_summary(domain_slug)` when working inside one domain + repo. Use `get_state_summary()` only for cross-domain/custodian-wide work. 2. Check inbox with `get_messages(to_agent=, unread_only=true)`. Mark acted-on messages with `mark_message_read(message_id)`. -3. During work, edit the workplan file first. Use `workplan_id` in API payloads - and task queries; legacy `workstream_id` is accepted only for compatibility. +3. During work, edit the workplan file first. Mirror task/workstream status to + the hub at checkpoints. 4. Prefer `bulk_update_task_statuses(...)` for checkpoint syncs with multiple task updates. Use `update_task_status(...)` for one-off changes. -5. Close with one concise progress event. After committing workplan file changes, - run `uv run --project ~/repo-manager rmgr sync --path . --push`. Reserve - `statehub fix-consistency` for a separate deep audit. +5. Close with one concise `add_progress_event(...)`, then run the repo's + `make fix-consistency REPO=` command when workplan files changed. 6. If finishing a workplan with leftovers: create **residual** work records first (intake with `origin: residual` + `origin_ref: `, or a child workplan). Residual is a role, not a kind; do not leave backlog only in finished-file prose or `SCOPE.md`. Canon: work-record-types § Residuals. -## Canonical reads and caller attribution - -Use `GET /workplans/{id}` and `GET /tasks/?workplan_id=`. -The `/workstreams/` REST routes return 410 and the `create_workstream` MCP tool -has been removed. Create repository-owned records in files before syncing. -For direct HTTP calls, send `X-StateHub-Component: ` so a remaining -legacy call can be attributed to its caller. Do not replace authoritative -`state_hub_workstream_id` frontmatter fields; those are a separate file contract. - ## High-Frequency MCP Signatures ```text @@ -44,12 +33,12 @@ get_domain_summary(domain_slug: str) -> str get_messages(to_agent?: str, from_agent?: str, unread_only: bool = false, limit: int = 20) -> str send_message(from_agent: str, to_agent: str, subject: str, body: str, thread_id?: str) -> str -create_workplan(repo_id: str, title: str, topic_id?: str, slug?: str, description?: str, owner?: str, due_date?: str, planning_priority?: str, planning_order?: int) -> str -create_task(workplan_id: str, title: str, priority: str = "medium", description?: str, assignee?: str, due_date?: str) -> str +create_workstream(topic_id: str, title: str, slug?: str, description?: str, owner?: str, due_date?: str, repo_id?: str, planning_priority?: str, planning_order?: int) -> str +create_task(workstream_id: str, title: str, priority: str = "medium", description?: str, assignee?: str, due_date?: str) -> str update_task_status(task_id: str, status: str, blocking_reason?: str, tokens_in?: int, tokens_out?: int, workplan_tokens_in?: int, workplan_tokens_out?: int, note?: str, model?: str, agent?: str, session_id?: str) -> str bulk_update_task_statuses(updates: list[dict], author?: str = "custodian", session_id?: str) -> str -add_progress_event(summary: str, event_type: str = "note", topic_id?: str, workplan_id?: str, task_id?: str, detail?: dict | str) -> str -record_decision(title: str, decision_type: str = "pending", topic_id?: str, workplan_id?: str, description?: str, rationale?: str, decided_by?: str, deadline?: str) -> str +add_progress_event(summary: str, event_type: str = "note", topic_id?: str, workstream_id?: str, task_id?: str, detail?: dict | str) -> str +record_decision(title: str, decision_type: str = "pending", topic_id?: str, workstream_id?: str, description?: str, rationale?: str, decided_by?: str, deadline?: str) -> str ``` `bulk_update_task_statuses` updates `N` task statuses in one call: diff --git a/skills/state-hub/references/tool-signatures.md b/skills/state-hub/references/tool-signatures.md index 562b954..18decfa 100644 --- a/skills/state-hub/references/tool-signatures.md +++ b/skills/state-hub/references/tool-signatures.md @@ -10,8 +10,8 @@ MCP: get_domain_summary(domain_slug) REST: GET /state/summary then filter by topic/domain when MCP is unavailable ``` -Use `get_domain_summary("infotech")` inside State Hub work. It returns the -domain topic, active workplans, blocking decisions, recent progress, repos, +Use `get_domain_summary("custodian")` inside State Hub work. It returns the +domain topic, active workstreams, blocking decisions, recent progress, repos, and compact capability hints. ## Agent Messages @@ -30,25 +30,19 @@ REST: PATCH /messages/{message_id}/read Use repo slugs as agent names. Use `broadcast` only for genuinely shared coordination. -## Workplans and Tasks +## Workstreams and Tasks ```text -MCP: create_workplan(repo_id, title, topic_id?, slug?, description?, owner?, due_date?, planning_priority?, planning_order?) -REST: POST /workplans/ +MCP: create_workstream(topic_id, title, slug?, description?, owner?, due_date?, repo_id?, planning_priority?, planning_order?) +REST: POST /workstreams/ -MCP: create_task(workplan_id, title, priority="medium", description?, assignee?, due_date?) +MCP: create_task(workstream_id, title, priority="medium", description?, assignee?, due_date?) REST: POST /tasks/ MCP: update_task_status(task_id, status, blocking_reason?, tokens_in?, tokens_out?, workplan_tokens_in?, workplan_tokens_out?, note?, model?, agent?, session_id?) REST: PATCH /tasks/{task_id} ``` -For repository-owned work, write the workplan/task files and sync with Repo -Manager; the create signatures above describe the projection API. Read using -`GET /workplans/{id}` and `GET /tasks/?workplan_id=`. Send -`X-StateHub-Component: ` on direct HTTP requests for caller attribution. -The removed workstream tools and `/workstreams/` routes are not fallbacks. - Canonical task statuses are `wait`, `todo`, `progress`, `done`, and `cancel`. Legacy aliases are accepted during migration, but do not emit new workplan files with old vocabulary. @@ -92,10 +86,10 @@ The endpoint rejects duplicate task ids with `400` and missing task ids with ## Progress and Decisions ```text -MCP: add_progress_event(summary, event_type="note", topic_id?, workplan_id?, task_id?, detail?) +MCP: add_progress_event(summary, event_type="note", topic_id?, workstream_id?, task_id?, detail?) REST: POST /progress/ -MCP: record_decision(title, decision_type="pending", topic_id?, workplan_id?, description?, rationale?, decided_by?, deadline?) +MCP: record_decision(title, decision_type="pending", topic_id?, workstream_id?, description?, rationale?, decided_by?, deadline?) REST: POST /decisions/ ``` diff --git a/workplans/STATE-WP-0079-retirement-strangler.md b/workplans/STATE-WP-0079-retirement-strangler.md index c0cceba..15ab51b 100644 --- a/workplans/STATE-WP-0079-retirement-strangler.md +++ b/workplans/STATE-WP-0079-retirement-strangler.md @@ -425,16 +425,6 @@ direct route are live owner residual `RAIL-FAB-WP-0028`. Evidence: the non-D2 repo-manager/hub-core/activity-core/ops-hub route receipts and the explicit writer-change authorization already stated above. -**Cutover re-baseline 2026-09-05.** Replaced the obsolete slice-readiness -snapshot in `docs/retirement-cutover-slice-plan.md` with a family-by-family -receiver/caller/parity/rollback checklist. Live Hub Core runtime OpenAPI lacks -`/messages`, `/progress`, `/token-events` and `/interface-changes`; its working -`/api/v2/interaction-events` is not assumed equivalent. Shared library routers -and HUB-WP-0005 completion are insufficient receiving receipts. T08 now records -the concrete first read-contract gap. State Hub-to-Core Hub service probes were -connection-refused although deployments were ready; transport is also part of -that gate. RAIL-FAB-WP-0028 remains proposed and owns hosted Fabric readiness. - ## Retire legacy surfaces ```task @@ -546,22 +536,6 @@ calendar passage alone is not retirement evidence. the existing hold; no additional retirement is justified. T04/T05/T06 remain `wait` with their existing owner and quiet-window dependencies. -**Authorized retirement and caller migration 2026-09-05.** Fresh seven-day -primary evidence made `GET /sbom/report/licences/` and `GET /sbom/snapshots/` -eligible. Verified direct Nexus endpoints (200), then marked both interfaces -retired with T05 provenance. Receipt: -`docs/evidence/STATE-WP-0079-sbom-retirement-20260905.json`. Eight retired, -seven legacy, zero remaining candidates. Compatibility handlers/history remain; -this is meter retirement, not a router deletion or application deployment. - -Session traces identified ad-hoc task-filter callers in fluid-telegram and -ops-warden. Corrected their AGENTS.md canonical-query/component-header guidance, -plus this repository's stale skill and API documentation. Canonical verification -returned 200 with 8/5 tasks. This does not explain every historical call or prove -future silence: unresolved task/workstream-detail/SBOM-index attribution is T07. -Available pod logs begin after the last calls. Evidence and limits: -`docs/evidence/STATE-WP-0079-caller-and-receiver-review-20260905.md`. - ## Stabilization window and archive prep ```task @@ -581,49 +555,6 @@ stop, or repository archive would therefore interrupt normal work and destroy the evidence needed by T05. T06 remains `wait` until T04 and T05 are done and a fresh central meter demonstrates the required zero normal read/write window. -## Attribute and finish migrating remaining legacy readers - -```task -id: STATE-WP-0079-T07 -status: wait -priority: high -state_hub_task_id: "2ac16837-454a-5a92-9385-c91cd3219aa2" -``` - -Owner: state-hub. T05 follow-up from the 2026-09-05 scan. Two ad-hoc task-query -callers were identified and their instructions corrected; the full 11 task -calls, seven workstream-detail calls and one SBOM index call remain only -partially attributed. Existing retained logs postdate these calls. Wait for -new attributed observations or recoverable historical request evidence; do not -reset the clocks with test calls. Trace remaining callers, migrate them to the -verified replacements, and attach fresh quiet-window evidence before retirement. -Use `X-StateHub-Component` for direct agent HTTP requests. No inference from -an `unknown` bucket alone is sufficient to assign an owner. - -## Prove the first deployed hub-core message-read contract - -```task -id: STATE-WP-0079-T08 -status: todo -priority: high -state_hub_task_id: "9d508739-6123-5204-b829-750b3ebf0e63" -``` - -Receiving owner: hub-core; State Hub owns source/caller evidence under T04. -The live receiver's 31-path OpenAPI has no message/progress/token/interface-log -families. Identify or assemble the owner message-read contract, auth/transport, -and historical projection in the receiving runtime. State Hub-to-owner service -probes were connection-refused in this review; diagnose the actual transport -before assuming a usable proxy path. Do not substitute `/api/v2/interaction-events` -without an explicit semantic mapping. - -Then run a bounded read-only inbox parity pilot over one consistent snapshot, -checking message IDs, ordering, read/archive flags and scope filters; record -exact revisions and rollback to the retained State Hub read. Done when receiving -readiness and parity/rollback receipts make one concrete reader switch reviewable. -Production message writers stay unchanged during this proof. Related owners: -HUB-WP-0004/0005; the full B2/B3 route migration is not implied by this task. - ## Acceptance - [x] Freeze policy documented