state-hub/workplans/STATE-WP-0079-retirement-strangler.md
tegwick 93e95f93e7
All checks were successful
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / container-smoke (push) Successful in 2s
Build and Publish Multi-Context Image / build-and-push (push) Successful in 28s
feat(legacy-meter): scale retirement quiet period to call volume
A clean review window only proves an interface was silent for that window.
For a heavily used interface that is weak evidence -- an infrequent caller
can fall outside the window entirely, so the interface reads as retirable
while still having consumers.

_retirement_state now also requires silence since last_seen_at, scaled by
all-time volume (RETIREMENT_QUIET_LADDER): 7d under 100 calls, 30d under
10k, 60d above. Existing guards (retired / manual hold / replacement ref /
replacement verified / in-window traffic) still take precedence.

On the 2026-08-20 capture this makes 15 of 19 legacy interfaces retirable
and holds 4: the three six-figure /workstreams/ read paths, and
GET /tasks/?workstream_id which still has live traffic.

Unblocks the bulk of Wave E2 in the cutover slice plan. 7 new tests.

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

177 lines
6.6 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: todo
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).
## 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`.
**Remaining work for this task:** execute the retirement of the 15 evidenced
interfaces, then re-review the 4 held ones as their quiet counters run. The
ladder is evaluated at review time, so re-capture before deciding. See
`docs/retirement-cutover-slice-plan.md` § E2.
## 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
- [ ] 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