state-hub/workplans/STATE-WP-0079-retirement-strangler.md
tegwick fb363b37d3
All checks were successful
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / container-smoke (push) Successful in 1s
Build and Publish Multi-Context Image / build-and-push (push) Successful in 37s
feat(STATE-WP-0079): retire the suggestion-backlog surface (slice E1)
History is archived fleet-side, so the read surface has no remaining job.

- api/routers/suggestions.py: whole prefix 410s with a pointer to intake and
  to the archive; the router drops from 176 lines to a stub
- mcp_server: the 6 suggestion tools removed outright rather than stubbed --
  a retired tool that still appears in the tool list costs every agent
  session context on every call, which is the opposite of retiring it
- write_idempotency: 5 /suggestions rules dropped
- dashboard: suggestions.md deleted, nav entry removed, reference.md and
  wsjf-triage.md updated; docs/suggestions.md rewritten as archive pointer
- tests: two tests pinned the old read-live behaviour and now pin the
  retirement contract instead

Tables stay: they are retire/archive in SHR-INV-0001 and are captured by the
final dump at T06.

Untouched, and worth knowing during cutover: ui-feedback.md / todo.md
'suggestions' are Shift+click dashboard feedback backed by technical_debt, a
different entity that shares the word. E3 (dashboard-meta) is that page; its
owner is state-hub-until-cutover so it retires at the T06 window, not now.

Full suite 612 passed.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-20 08:11:14 +02:00

225 lines
9.3 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

---
id: STATE-WP-0079
type: workplan
title: "State Hub retirement strangler and disposition execution"
domain: infotech
repo: state-hub
status: active
owner: codex
topic_slug: infotech
created: "2026-08-09"
updated: "2026-08-19"
parent_project: prj-state-hub-retirement
parent_workplan: SHR-WP-0001
related:
- STATE-WP-0074
- SHR-INV-0001
- RMGR-WP-0001
- HUB-WP-0004
state_hub_workstream_id: "749beac6-3c62-4284-aab5-9ed7fce900c2"
---
# State Hub retirement strangler and disposition execution
## Goal
Execute the **keep/move/replace/retire** dispositions from
`prj-state-hub-retirement/inventory` via strangler adapters and owner handoffs,
without adding new permanent authorities here. End state: freeze window with no
normal traffic, then archive.
## Dual-run handoff (RMGR-WP-0002)
Repo Manager Stage B dual-run is available:
- Flags: `RM_WRITEBACK`, `RM_RECONCILE`, `RM_PILOT_REPOS` (see `repo-manager/docs/dual-run.md`)
- SH adapter: `api/services/repo_manager_dual_run.py` (PATCH `/tasks` + C-15 writeback + reconcile proxy)
- Evidence: `repo-manager/docs/evidence/wp0002-completion.md`
Expand pilot list here as cutover progresses; do not add new checkout mutators in State Hub.
## Freeze policy for new scope
```task
id: STATE-WP-0079-T01
status: done
priority: high
state_hub_task_id: "375c0b66-98b0-4d5b-98dd-4ad2883a4051"
```
Document and enforce: changes during retirement must preserve compatibility,
enable extraction, reduce scope, or fix operational risk — not establish new
permanent ownership (INTENT retirement status).
**Result (2026-08-20):** `policies/retirement-freeze.md`, following the existing
`policies/` convention. States the four admissible reasons, the inadmissible
case (new permanent ownership here), and the operative test — *where does this
live after cutover?* — since most inadmissible changes are otherwise good
changes. Uses `STATE-WP-0080`'s retarget as the worked example.
**Enforced by review, not by new automation.** A freeze-checker built inside
State Hub would be new permanent automation in the component being retired, so
the policy would violate itself. Gates attach to points where changes are
already reviewed: new workplan goal statements, non-trivial task starts, and
slice execution. New tables, routes, or MCP tools carry a presumption against
and are the one hard stop.
## Capability strangler plan
```task
id: STATE-WP-0079-T02
status: done
priority: high
state_hub_task_id: "595c3936-20b6-453f-92b5-84f86798054a"
```
Group SHR-INV-0001 items into cutover slices (repo/work → repo-manager;
messages/progress/projections → hub-core; catalogs → owners; retire aliases).
Per slice: adapter flag, owner API, rollback.
**Result (2026-08-19):** `docs/retirement-cutover-slice-plan.md`. All 425
inventory items assigned to 19 slices in five waves plus Keep, computed against
`state-hub-disposition.yaml` rather than hand-counted. Each slice carries an
`RM_SLICE_*` flag (off/dual/owner), owner API, and rollback; Wave A reuses the
RMGR-WP-0002/0003 dual-run adapter rather than adding a mechanism.
Owner readiness verified: only **Wave A (repo-manager, 165 items)** is
executable — RMGR-WP-0001/0002/0003 are `finished`. Wave B is gated on
HUB-WP-0004 (`proposed`), D1 on OPS-WP-0003 (`proposed`), D2 on FIN-WP-0003
(`proposed`). Recommended first cut is A3 (registers), lowest blast radius.
Two findings for T04/T05: the 9 `ops_dependency` items carry no capability and
cannot be strangled behind a flag — they resolve at the T06 freeze window; and
the legacy-meter review window is 8 hours despite `cadence: weekly`, which is
not sufficient evidence to retire high-volume `/workstreams/` interfaces (E2).
## Register CLI and GOAL.md support
```task
id: STATE-WP-0079-T03
status: done
priority: medium
state_hub_task_id: "55716f12-fb12-4a1e-a770-076c490db111"
```
Adapt `statehub register` / scaffolding so `prj-` repos with `GOAL.md` and
`repo_flavor: project` are valid without inventing durable-product `INTENT.md`
(residual from SHR-WP-0001-T01).
**Result (2026-08-19):** Implemented by `STATE-WP-0080-T01/T02`. Project
flavor is detected from classification, `GOAL.md`, or the `prj-` slug; a repo
with an existing `GOAL.md` is registered without durable scaffolding, while a
fresh project delegates scaffolding to `rmgr scaffold`. The focused State Hub
registration suite passes (`20 passed`).
## Execute move/replace slices
```task
id: STATE-WP-0079-T04
status: todo
priority: high
state_hub_task_id: "db5291f2-3801-40fa-abf2-ceb0e77687c9"
```
Implement strangler handoffs coordinated with RMGR-WP-0001 and HUB-WP-0004.
Compatibility tests for each dispositioned route family.
**Inherited (2026-08-19) from `STATE-WP-0080-T04`:** this slice now also owns
deletion of the templating path in `statehub_register.py``INTENT.md`
generation, the `AGENTS.md` / `CLAUDE.md` / `.custodian-brief.md` templates,
`project_rules/`, and bootstrap-workplan generation. The code is dead-but-present:
project repos are already routed to `rmgr scaffold`. Gate the deletion on
`RMGR-WP-0004-T06` proving byte-identical durable output and idempotent
re-scaffolding.
## Retire legacy surfaces
```task
id: STATE-WP-0079-T05
status: todo
priority: medium
state_hub_task_id: "02e508ed-3cde-4487-907e-d324a8a877d6"
```
Complete retirement of suggestions, workstream aliases, and other `retire`
inventory items once meters/callers allow. Keep historical rows archive-readable.
**Blocker identified (2026-08-20):** the legacy-meter evidence this task gates
on was being captured over an 8-hour band, not a week —
`capture_legacy_meter_evidence.py` fell back to `hours=8` whenever `--days` was
omitted, so 39 of 40 captures sampled only 06:00Z14:00Z. Interfaces called
outside that band read as unused. Three candidates on the 2026-08-19 capture had
live callers, including `GET /tasks/?workstream_id` (seen 2026-08-18).
Script default corrected to `days=7`; corrected capture
`docs/evidence/legacy-meter-weekly-review-20260820.json`.
**Candidate rule tightened (2026-08-20):** `_retirement_state` now requires a
quiet period scaled to all-time call volume (`RETIREMENT_QUIET_LADDER`: 7d under
100 calls, 30d under 10 000, 60d above). On the 2026-08-20 capture this makes 15
of 19 legacy interfaces retirable — all `workstream` MCP tools, the `state://`
resource, and the low-volume REST aliases — while holding the three six-figure
read paths (`GET /workstreams/`, `GET /workstreams/{id}`,
`GET /workstreams/{id}/dependencies/`) and `GET /tasks/?workstream_id`, which
still has live traffic. Covered by 7 new tests in `tests/test_legacy_meter.py`.
**Slice E2 executed (2026-08-20):** the 15 evidenced interfaces are retired in
the legacy meter — all four `workstream` MCP tools, the `state://` resource, and
the low-volume REST aliases including `PATCH /workstreams/{id}` (571 calls),
`POST /workstreams/` (824) and `POST /workstreams/{id}/dependencies/` (4 971).
Meter now reads 16 retired / 4 legacy, 0 outstanding candidates. Evidence:
`docs/evidence/legacy-meter-weekly-review-20260820.json`.
Retirements are journalled fleet-side at
`the-custodian/docs/retired-legacy-interfaces.md` — deliberately outside this
repo, since State Hub is being archived and the record must outlive it.
**Remaining work for this task:** the 4 held interfaces
(`GET /workstreams/`, `GET /workstreams/{id}`,
`GET /workstreams/{id}/dependencies/`, `GET /tasks/?workstream_id`) clear as
their quiet counters run; earliest is 18 more silent days. Re-capture before
deciding — the ladder evaluates at review time. **Slice E1 part-executed (2026-08-20):** `suggestion-backlog` history archived
to `the-custodian/docs/archived-suggestion-backlog.md` — 10 suggestions, 10
notes, 5 bumps, all `declined` in the 2026-07-21 intake migration, none
promoted. Mutations already 410 since `CUST-WP-0061-T06`; reads were open only
to keep that history reachable, which the archive now replaces.
**E1 removal executed the same day:** the 8 read routes 410 with a pointer to
intake and the archive, the 6 MCP tools are removed outright, the 5
`/suggestions` write-idempotency rules are dropped, and the dashboard page is
deleted with nav, `reference.md` and `wsjf-triage.md` updated;
`dashboard/src/docs/suggestions.md` is now the archive pointer. Tables remain
for the T06 dump. Two tests that pinned the old read-live behaviour were
rewritten to pin the retirement contract.
Naming trap for cutover: `ui-feedback.md` / `todo.md` "suggestions" are
Shift+click dashboard feedback backed by `technical_debt`, **not** this
capability. Untouched.
**E3 (`dashboard-meta`) is `/ui-feedback`** — that same feedback surface. Owner
is `state-hub-until-cutover` and it is still in use, so it retires at the T06
freeze window, not now.
Then `dashboard-meta` (E3, 1); `legacy-meter` itself (E4, 9) retires last,
being the instrument.
## Stabilization window and archive prep
```task
id: STATE-WP-0079-T06
status: todo
priority: high
state_hub_task_id: "d52c95c6-af3f-4b2c-804e-e07763c9a8ab"
```
With T06 gates: zero normal read/write window, final dump, backup/restore
evidence, stop service, archive repo read-only. Residuals → live owners.
## Acceptance
- [x] Freeze policy documented
- [x] Strangler plan covers all inventory capabilities
- [x] prj-/GOAL.md register path works
- [ ] Move/replace slices evidenced with tests/counts
- [ ] Retire list closed or residual-owned
- [ ] Stabilization + archive prep ready for project retirement