Files
state-hub/workplans/STATE-WP-0061-demand-weighted-suggestion-backlog.md
tegwick 044141de48 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>
2026-06-19 15:58:36 +02:00

7.0 KiB
Raw Blame History

id, type, title, domain, repo, status, owner, topic_slug, created, updated
id type title domain repo status owner topic_slug created updated
STATE-WP-0061 workplan Demand-weighted suggestion backlog (relevance-fed WSJF) custodian state-hub proposed codex custodian 2026-06-18 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: suggestionrequirement (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

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

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")

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

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

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

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