--- title: Suggestions --- ```js import {apiFetch, pollDelay, waitForVisible} from "./components/config.js"; const POLL = 30_000; ``` ```js const sugState = (async function*() { let failures = 0; while (true) { let data = [], ok = false; try { const r = await apiFetch("/suggestions/?rank=wsjf&limit=100"); ok = r.ok; data = ok ? await r.json() : []; } catch {} failures = ok ? 0 : failures + 1; yield {data, ok, ts: new Date()}; await waitForVisible(pollDelay({ok, base: POLL, failures})); } })(); ``` ```js const suggestions = sugState.data ?? []; const _ok = sugState.ok ?? false; const _ts = sugState.ts; ``` # Demand-Weighted Suggestions ```js import {injectTocTop} from "./components/toc-sidebar.js"; import {withDocHelp} from "./components/doc-overlay.js"; const _liveEl = html`
${_ok ? `Live · ${_ts?.toLocaleTimeString()}` : html`API offline`}
`; withDocHelp(_liveEl, "/docs/live-data"); injectTocTop("live-indicator", _liveEl); const _h1 = document.querySelector("#observablehq-main h1"); if (_h1) { _h1.style.position = "relative"; withDocHelp(_h1, "/docs/suggestions"); } display(html`

Ranked by WSJF = (base_value + relevance_weight × relevance) / job_size. Gated needs accrue relevance when unmet.

`); display(html`

Daily WSJF triage consumes this backlog in its digest.

`); ``` ```js const stageBadge = (stage) => { const colors = { suggestion: "#6b7280", requirement: "#2563eb", promoted: "#059669", declined: "#9ca3af", }; return html`${stage}`; }; const rows = suggestions.map((s) => html` ${stageBadge(s.stage)} ${s.title}${s.origin_ref ? html`
${s.origin_ref}` : ""} ${s.domain_slug || "—"} ${s.relevance} ${s.wsjf?.toFixed?.(1) ?? s.wsjf} ${s.last_requested_at ? new Date(s.last_requested_at).toLocaleString() : "—"} `); display(html`${rows.length ? rows : html``}
StageTitleDomainRelevanceWSJFLast requested
No open suggestions yet.
`); ```