dashboard-issues¶
Provenance¶
- Source:
.spec/spexcode/spec-forge/dashboard-issues/spec.md - Source SHA-256:
a2342ea290b78ae8e889e80fbea6e8c06c1f47b665531f73da22e986ba423ab4
The dashboard surface [[spec-forge]] deferred: on each node, the open issues that work toward it.
[[links]] inverts a forge's open work into node → { issues, prs }, [[forge-cache]]'s resident ForgeCache
keeps it fresh; this node owns the display fold, on the two planes' contract:
a node defines, an issue does, so the work appears beside the node, never as node state. A node's
status stays git-derived — the two authorities never cross.
raw source¶
Surface each spec node's bound open issues on the dashboard. Backend: fold each node's open-issue
count + list into the board via a resident ForgeCache, served on the existing /api/graph nodes —
non-blocking (serve the last reconcile, refresh in the background) and silent when there's no forge/gh
(no badge, no error). Frontend: one glance badge on the tile (count, hue distinct from the status dot, like
the drift-badge), only when > 0; the issue LIST is read on demand in the focused node's [[node-popup]] Issues
tab and on [[issues-view]], not in a persistent sidebar or a card popped on the node.
The badge is WORK, distinct from the derived status dot.
expanded spec¶
Backend — a resident cache, folded into the board. A process-lifetime ForgeCache (the resident
wiring around [[forge-cache]]'s pure cache) serves the dashboard without a blocking forge call on the request
path. Its contract: a view is always instant (the last successful reconcile), and a stale read triggers
a background reconcile (a TTL backs off both success and failure). The TTL sits near the dashboard's
poll cadence (~15s), so an externally-posted issue surfaces within about one poll — "post a github issue
→ it just appears" — without re-probing a forge-less repo every poll. The board
fold goes through the unified Issue port (spec-cli's [[issues]]): each node gets its merged issue
list — this cache's forge slice AND the local store's threads ([[local-issues]]) — every item in the one
Issue shape. The graph attaches only reviewSummary.issues counts and open ids; the full merged set stays
in the server-only snapshot used by [[paged-review]] for the node-info Issues tab ([[node-popup]]) and
canonical list. This node
owns the forge slice into that fold; the merge itself is
[[issues]]'s. Closed forge issues link by the explicit Spec: marker (the transitive PR path sees only
open PRs). The slice is silent by construction: with no gh/repo/auth the reconcile throws,
is swallowed, and the cache stays empty — the fold carries the local slice alone, no error. One exception: a store-routed reply to a forge issue ([[issues]]) forces one refresh past
the TTL and AWAITS it (refreshForgeNow), so the next read carries the real read-back; the forced cycle is
a FULL re-list, never the incremental window — a since-read can lag a just-posted write, advancing the
watermark past it. Read-only throughout — the resident module never writes the forge (writes are the
[[port]] driver's) and never touches a node's git-derived status. Sibling folds ride the same pattern
(the [[eval-tab]] eval timeline); this node owns only the issues slice.
Frontend — one glance badge; rows stay on demand. When a node carries open issues, its
first row gains one badge — the count, hue distinct from the status dot and drift-badge (the three
signals never blur), absent at zero. The detail —
each issue a card (id, store, status, concern) — is read in the node-info Issues tab and the routed Issues
page; no persistent right column or card pops on the node's own hover/focus. These cards are the shared dashboard issue card:
local and forge use the same markup and truncation, their lifecycle mark consumes [[review-chrome]]'s one
issue-state mapping, and clicking either opens the internal Issues page with
that issue selected (#/issues/<issue-id>). Forge permalinks are secondary metadata in the Issues detail,
never the card's primary destination. The badge renders in the node tile
([[node-graph]]), its copy through the shared translator t ([[settings]]); each issue's id, store, and
concern remain the Issue object's data while its lifecycle label is translated by the shared visual.
The node tab requests bounded page 1 with its fixed node: query, derives summary/facets from the server
response's full-set totals, and exposes a canonical View all anchor whenever more than 25 match; it never
reconstructs the node list from graph counts or treats the current page as exhaustive.
Out of scope (future siblings): surfacing open PRs the same way; any live push of forge deltas
([[forge-cache]]'s deferred source layer). Frontend behaviour is measured by looking: the frontend-e2e eval scenario
open-count-badge-on-tile screenshots the rendered board — the ◆N badge on a tile with open issues, no
on-node popover — and files image-evidenced readings.