generated from coulomb/repo-seed
Add STATE-WP-0061 demand-weighted suggestion backlog workplan
Proposed plan (status: proposed) for a Suggestion entity with a persisted relevance/demand counter feeding a WSJF read-model projection. Authored during ops-warden WP-0012 triage; tracks gated needs as relevance-accruing suggestions rather than inert todo tasks. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
174
workplans/STATE-WP-0061-demand-weighted-suggestion-backlog.md
Normal file
174
workplans/STATE-WP-0061-demand-weighted-suggestion-backlog.md
Normal file
@@ -0,0 +1,174 @@
|
||||
---
|
||||
id: STATE-WP-0061
|
||||
type: workplan
|
||||
title: "Demand-weighted suggestion backlog (relevance-fed WSJF)"
|
||||
domain: custodian
|
||||
repo: state-hub
|
||||
status: proposed
|
||||
owner: codex
|
||||
topic_slug: custodian
|
||||
created: "2026-06-18"
|
||||
updated: "2026-06-18"
|
||||
---
|
||||
|
||||
# STATE-WP-0061 — Demand-weighted suggestion backlog (relevance-fed WSJF)
|
||||
|
||||
**Origin:** ops-warden WP-0012 triage (2026-06-18). Most WP-0012 tasks are gated
|
||||
on external owners shipping paths that do not exist yet. They should not sit as
|
||||
inert `todo` tasks, nor be fabricated as active entries. They should live as
|
||||
**suggestions that accrue demand pressure** every time they are needed-but-unmet,
|
||||
so in-demand work is promoted to real tasks first.
|
||||
|
||||
## Problem
|
||||
|
||||
The hub today cannot represent "a need that has been raised but not yet vetted or
|
||||
scheduled, whose urgency grows with repeated demand." Concretely:
|
||||
|
||||
- `NextStep` suggestions are **derived on the fly and never persisted**
|
||||
(`api/schemas/state.py`), so they cannot accumulate anything.
|
||||
- There is **no relevance/demand counter** on any entity.
|
||||
- There is **no suggestion → vetted requirement → task** promotion pipeline.
|
||||
`CapabilityRequest` is the closest analog but models cross-domain brokering, and
|
||||
a repeat need spawns a *new* request rather than bumping demand on an existing one.
|
||||
- The **WSJF triage is advisory** (activity-core `daily-statehub-wsjf-triage`,
|
||||
CUST-WP-0044) and consumes current summary/workplan/progress state — **no
|
||||
persisted demand signal feeds it**, and the hub holds no Cost-of-Delay / Job-Size
|
||||
data model.
|
||||
|
||||
## Approach (decided)
|
||||
|
||||
- **New `Suggestion` entity** (not an extension of `CapabilityRequest`/`TechnicalDebt`).
|
||||
Stages: `suggestion` → `requirement` (vetted + structured) → `promoted` (became a
|
||||
Task); plus terminal `declined`. Append-only `SuggestionNote` trail (mirrors
|
||||
`TDNote`) records vetting. `promoted_task_id` links the resulting `Task`.
|
||||
- **Relevance is a persisted demand counter.** It increments whenever the
|
||||
suggestion is *needed but not yet done* (defined in T3). `relevance` +
|
||||
`last_requested_at` + a `relevance_events` count drive ranking.
|
||||
- **WSJF is computed in the hub as a read-model projection** and exposed via a
|
||||
ranked endpoint; the existing activity-core daily triage **consumes** it.
|
||||
`wsjf = cost_of_delay / job_size`, where
|
||||
`cost_of_delay = base_value + (relevance_weight × relevance)` so repeated demand
|
||||
raises priority. Job size is an operator-set estimate (default medium).
|
||||
- Promotion keeps the active task backlog clean: gated needs (the WP-0012 case)
|
||||
live as relevance-accruing suggestions, **not** as inert `todo` tasks or
|
||||
fabricated active catalog entries.
|
||||
|
||||
> **Read-model boundary (ADR-001 / hub design):** suggestion writes are a new
|
||||
> sanctioned write surface alongside `resolve_decision` and `get_next_steps`.
|
||||
> `bump_relevance`, `promote_suggestion_to_task`, and vetting transitions are the
|
||||
> only writes; ranking/WSJF are pure projections. T6 records the ADR amendment.
|
||||
|
||||
## Open questions (resolve during T1/T4, do not block proposal)
|
||||
|
||||
- Exact WSJF cost-of-delay decomposition (single `base_value` vs SAFe triple of
|
||||
business-value / time-criticality / risk-reduction). Start with `base_value`
|
||||
+ relevance; leave room to split later.
|
||||
- `relevance_weight` default and whether relevance should decay over time
|
||||
(staleness) — model the field now, tune in T4.
|
||||
|
||||
---
|
||||
|
||||
## Tasks
|
||||
|
||||
### T1 — Suggestion data model + migration
|
||||
|
||||
```task
|
||||
id: STATE-WP-0061-T01
|
||||
status: todo
|
||||
priority: high
|
||||
```
|
||||
|
||||
- [ ] `api/models/suggestion.py`: `Suggestion` (id, domain_id, topic_id?,
|
||||
workstream_id?, title, description, origin, stage, relevance,
|
||||
relevance_events, last_requested_at, base_value, job_size,
|
||||
relevance_weight, promoted_task_id) + `SuggestionNote` (append-only trail).
|
||||
- [ ] `SuggestionStage` enum: `suggestion | requirement | promoted | declined`.
|
||||
- [ ] Alembic migration; register model in `api/models/__init__.py`.
|
||||
|
||||
### T2 — API + MCP sanctioned write layer
|
||||
|
||||
```task
|
||||
id: STATE-WP-0061-T02
|
||||
status: todo
|
||||
priority: high
|
||||
```
|
||||
|
||||
- [ ] REST + MCP: `create_suggestion`, `vet_suggestion` (→ requirement, with
|
||||
structured fields + note), `decline_suggestion`, `promote_suggestion_to_task`
|
||||
(creates a `Task`, sets `promoted_task_id`, stage→promoted), and `list/get`.
|
||||
- [ ] `bump_relevance(id, reason)` — sanctioned write; appends a relevance event,
|
||||
increments counter, sets `last_requested_at`.
|
||||
- [ ] Document these as sanctioned writes (alongside `resolve_decision`).
|
||||
|
||||
### T3 — Relevance emission wiring ("needed but not done")
|
||||
|
||||
```task
|
||||
id: STATE-WP-0061-T03
|
||||
status: todo
|
||||
priority: high
|
||||
```
|
||||
|
||||
- [ ] Define the demand events that bump relevance: (a) `get_next_steps` /
|
||||
dependency lookup resolves to an open suggestion/requirement; (b) a
|
||||
`CapabilityRequest` matches an unfulfilled suggestion; (c) an explicit agent
|
||||
bump when it hits a gap (the WP-0012 routing-scenario case).
|
||||
- [ ] Wire (a) and (b) in-hub; expose (c) via the MCP write from T2.
|
||||
- [ ] Idempotency/debounce so a single lookup does not double-count.
|
||||
|
||||
### T4 — WSJF projection + ranked endpoint
|
||||
|
||||
```task
|
||||
id: STATE-WP-0061-T04
|
||||
status: todo
|
||||
priority: high
|
||||
```
|
||||
|
||||
- [ ] Pure projection: `wsjf = (base_value + relevance_weight × relevance) / job_size`.
|
||||
- [ ] `GET /suggestions?rank=wsjf` returns suggestions/requirements ordered by score
|
||||
(promoted/declined excluded by default).
|
||||
- [ ] Feed the activity-core daily triage: include the ranked suggestion list in
|
||||
the `daily_triage` report input (coordinate with CUST-WP-0044 runner).
|
||||
|
||||
### T5 — Dashboard surface
|
||||
|
||||
```task
|
||||
id: STATE-WP-0061-T05
|
||||
status: todo
|
||||
priority: medium
|
||||
```
|
||||
|
||||
- [ ] `/suggestions` page: ranked table (stage, relevance, WSJF, last requested),
|
||||
with vet/promote/decline actions guarded to the sanctioned write layer.
|
||||
- [ ] Link from `/wsjf-triage`; short `src/docs/suggestions.md`.
|
||||
|
||||
### T6 — Tests, docs, ADR amendment
|
||||
|
||||
```task
|
||||
id: STATE-WP-0061-T06
|
||||
status: todo
|
||||
priority: medium
|
||||
```
|
||||
|
||||
- [ ] Tests: model + migration, relevance bump idempotency, WSJF ordering,
|
||||
promotion creates a linked task, stage transitions reject illegal moves.
|
||||
- [ ] SCOPE/INTENT note; amend the read-model ADR to list the new sanctioned writes.
|
||||
- [ ] Backfill example: register the gated WP-0012 routing scenarios as suggestions.
|
||||
|
||||
---
|
||||
|
||||
## Acceptance
|
||||
|
||||
- A need can be recorded as a `suggestion`, vetted into a `requirement`, and
|
||||
promoted into a real `Task` — with the demand trail preserved.
|
||||
- Each unmet lookup increments `relevance`; higher relevance raises WSJF, and
|
||||
`GET /suggestions?rank=wsjf` reflects the new order.
|
||||
- The daily WSJF triage report includes the ranked suggestion backlog.
|
||||
- Gated work (WP-0012-style) lives as a relevance-accruing suggestion, never as an
|
||||
inert `todo` task or a fabricated active catalog entry.
|
||||
|
||||
## See also
|
||||
|
||||
- `STATE-WP-0053` — WSJF triage review page (consumer surface)
|
||||
- `CUST-WP-0044` — activity-core daily triage runner (producer; cross-repo seam)
|
||||
- `api/models/capability_request.py`, `api/models/technical_debt.py` — prior art
|
||||
- ops-warden `WARDEN-WP-0012` — the gated-backlog case that motivated this
|
||||
Reference in New Issue
Block a user