docs(STATE-WP-0079): cutover slice plan, close T02
Assign all 425 SHR-INV-0001 items to 19 slices across five waves plus Keep, each with adapter flag, owner API, and rollback. Coverage computed against the inventory rather than hand-counted. Only Wave A (repo-manager, 165 items) is executable; B/D1/D2 are gated on owner-side contracts still at proposed. Flags two findings for T04/T05: the 9 ops_dependency items cannot be strangled behind a flag, and the legacy-meter weekly review window is 8h, not a week. Also corrects the workplan status from proposed to active. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
parent
7b2b9d03d9
commit
613477b4d2
2 changed files with 268 additions and 3 deletions
249
docs/retirement-cutover-slice-plan.md
Normal file
249
docs/retirement-cutover-slice-plan.md
Normal file
|
|
@ -0,0 +1,249 @@
|
|||
# State Hub retirement — cutover slice plan
|
||||
|
||||
**Workplan task:** `STATE-WP-0079-T02`
|
||||
**Inventory:** `SHR-INV-0001` (`prj-state-hub-retirement/inventory/`), 425 items, v0.1.1
|
||||
**Created:** 2026-08-19
|
||||
|
||||
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`.
|
||||
|
||||
## Method
|
||||
|
||||
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.
|
||||
|
||||
Two rules constrain the ordering:
|
||||
|
||||
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` | **Yes** |
|
||||
| `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 fully unblocked today. **Wave A is the whole of
|
||||
the near-term executable surface**; everything else is correctly waiting on an
|
||||
owner-side contract, not on State Hub.
|
||||
|
||||
## 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_<NAME>` 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.
|
||||
|
||||
### 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 endpoints |
|
||||
| Rollback | flag → `off`; these are append-mostly, so replay is cheap |
|
||||
|
||||
Low coupling and low write volume — the natural place to prove the
|
||||
`RM_SLICE_*` pattern before A2's blast radius.
|
||||
|
||||
### A4 · Work + repo UI — 22 items
|
||||
`work-coordination-ui` (14, `replace`) · `repo-ui` (8)
|
||||
|
||||
| | |
|
||||
| --- | --- |
|
||||
| Flag | `RM_SLICE_UI` |
|
||||
| Owner API | owner-side dashboard; hub pages redirect |
|
||||
| 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.
|
||||
|
||||
### A5 · Topic spine — 8 items
|
||||
`topic-spine` (8, `replace`)
|
||||
|
||||
| | |
|
||||
| --- | --- |
|
||||
| Flag | `RM_SLICE_TOPICSPINE` |
|
||||
| Owner API | `rmgr` topic/classification contract |
|
||||
| Rollback | flag → `off` |
|
||||
|
||||
Last in Wave A: it is a `replace` under a changed contract, and A1–A4 read it.
|
||||
|
||||
---
|
||||
|
||||
## Wave B — hub-core (128 items) · gated on HUB-WP-0004
|
||||
|
||||
HUB-WP-0004 is `proposed`. **No hub-side adapter work until it is at least
|
||||
`ready`.** Slices are listed to fix scope and order, not to start.
|
||||
|
||||
| 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) · all gated
|
||||
|
||||
| Slice | Owner | Capabilities | Items | Gate |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| D1 | `ops-hub` | `service-catalog` (9), `service-catalog-ui` (2) | 11 | OPS-WP-0003 `proposed` |
|
||||
| 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 |
|
||||
| --- | --- | --- | --- |
|
||||
| E1 | `suggestion-backlog` → archive | 17 | caller check; no successor runtime |
|
||||
| E2 | `work-records-workplan-legacy` → archive | 13 | legacy-meter — see caveat below |
|
||||
| E3 | `dashboard-meta` | 1 | none |
|
||||
| E4 | `legacy-meter` itself | 9 | **last** — it is the instrument for E2 |
|
||||
|
||||
E4 retires only after every other legacy surface is closed; retiring the meter
|
||||
first destroys the evidence for the retirements it gates.
|
||||
|
||||
### Caveat on E2's evidence
|
||||
|
||||
The 2026-08-19 review (`docs/evidence/legacy-meter-weekly-review-20260819.json`)
|
||||
reports 19 retirement candidates, all `replacement_verified: true` with zero
|
||||
calls in window. But the window is `06:00Z → 14:00Z` — **8 hours, not the 7 days
|
||||
`cadence: weekly` implies**. Several candidates have very large all-time counts
|
||||
(`GET /workstreams/{id}` 511 406, `GET /workstreams/` 144 086,
|
||||
`POST /workstreams/{id}/dependencies/` 255 865).
|
||||
|
||||
An 8-hour quiet window is not sufficient evidence to retire an interface at that
|
||||
call volume. Either the window computation is a defect or the cadence label is
|
||||
wrong; either way **E2 should not proceed on the current evidence**. Resolving
|
||||
this is a prerequisite, and it is worth checking before Wave A rather than after,
|
||||
since the same meter gates T05.
|
||||
|
||||
## 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 above — it gates E2 and T05.
|
||||
2. Implement `RM_SLICE_REGISTERS` (A3) first as the pattern proof.
|
||||
3. Do not open Wave B until HUB-WP-0004 reaches `ready`.
|
||||
Loading…
Add table
Add a link
Reference in a new issue