Skip to content

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.