Skip to content

impl(aggregator+collector): complexity-weighted project visualization (rollup, hands queue, blocked weight, depth graph) #1122

Closed

Description

@dezren39

Summary

Phase B of the per-project pages: the complexity-weighted visualization from the project-structure spec (2026-10-26, lab-cluster goal workspace). The v1 pages (epic's build issue) show counts and items; this issue adds the weighted, graph-aware view — and the feed data it needs, which the aggregator does not currently ingest.

Data gap to close first

Project-pool items today carry Status/Area/Horizon/Kind only. The spec's visualization needs, per issue:

  • effort/* label (weights: xs=1, s=4, m=12, l=40; unlabeled = unsized weight, shown separately, never zero)
  • mode/* label family (online/hybrid/physical — creation of this family across the four repos is part of the cluster seeding; this issue consumes it, and must render gracefully before it exists)
  • Issue graph edges: sub-issue parents, blocked-by/blocks, epic membership

Extend the fleet-feed collector's Project section (or a companion section) to carry labels + edges for pool items, with the aggregator model/check updated in lockstep — one contract change, both sides in one PR where feasible.

Per-project section (rendered on /program/)

  1. Weighted rollup bar — total weight, weighted % done (closed weight / total), raw issue count as secondary metric
  2. Hands queue — open mode/physical + mode/hybrid weight (hands-hours waiting) vs online weight
  3. Blocked weight — weight behind an open blocker + longest dependency chain (depth)
  4. Link/depth graph — epic → issue tree; node size = weight, color = status, border = mode (solid online, dashed hybrid, thick physical); edges = parent/blocks. Server-rendered (SVG) in keeping with the aggregator's no-client-JS pattern.

Project header rolls sections up the same way (weighted progress first, counts second, deepest chain + physical weight remaining as headlines).

Acceptance

  • A project with effort/mode/graph data renders all four elements from live feed data; a project without it renders the v1 sections plus an explicit "not yet sized/ graphed" note — never a fake 0%.
  • Collector + aggregator contract change covered by tests on both sides.
  • Works at phone width (the dashboard is mobile-first).

Refs: project-structure spec §Visualization; #910 (pool), epic for per-project pages.

Activity

  1. added
    kind/featureNew feature or capability request
    app/pm-stackpm-stack (Pad/Grist) in developing-today/code
    on Oct 27, 2026
  2. developing-today commented on Oct 27, 2026

    @developing-today
    Contributor
  3. dezren39 commented on Oct 27, 2026

    @dezren39
    MemberAuthor

    Epic: #1129 — per-project status pages for all projects (generalize /program beyond pm-dashboard).

  4. dezren39 commented on Oct 27, 2026

    @dezren39
    MemberAuthor

    Agent note — design track complete (2026-10-26). Full design doc: ~/workspace/pm-stack-visualization-design-2026-10-26.md (sandbox workspace; parent agent has the file). Data contract + rendering design + build sequence + measured adoption baseline. Headlines:

    Measured baseline (live /api/projects.json, cross-checked vs GitHub search + REST APIs):

    • Pool = 188 items (all issues). Effort-labeled 120 (64%) — l=67, m=34, s=16, xs=3; unsized 68. Mode-labeled 25 (13%) — hybrid 10, online 10, physical 5. Cross-checks agree exactly (search: code-repo effort/l=70 all-states vs 67 in pool; mode/physical=5 = pool's 5).
    • effort/* and mode/* families already exist in all four repos (cluster seeding created them) — the gap is application, not creation: mode is 0% in id-train (104 items) and pm-dashboard (43); pm-dashboard is 93% unsized.
    • The graph already exists but is unattributed: epics code#1080/epic(cluster): firmware / BIOS / BMC audit & standardization #1081/epic(cluster): basement power & space #1083 hold 13 native sub-issues (code#1094–task(cluster): basement cleanup + rack layout for the first nodes #1106), all effort+mode labeled — and all 13 sit in the pool with Area=null, Status=null, invisible to the per-project pages. That's 172 weight (s×5, m×6, l×2) missing from lab-cluster's attributed 680.
    • Native blocked-by edges: zero on every sampled epic — dependencies live in epic-body prose only (epic(cluster): hardware inventory & first-node selection #1080 "gates epics 5 and 6"). Epic marking uses 3 conventions (Kind=Epic 18 vs epic label 14 vs meta/epic).

    Contract (one PR, both sides — projects.ts is shared by collector + aggregator):

    • Effort/mode need no new collection: labels already flow via PROJECT_QUERY; parse them into typed optional fields on ProjectPoolItem (raise the labels cap 20→50 against truncation).
    • Edges ride the same GraphQL query (+0 requests; REST per-issue calls measured ~2–6 s each → rejected): Issue fragment gains parent {…} (tree edge carried by the child), subIssuesSummary { total completed }, blockedBy(first:25) { nodes {…state} } (blocker state carried inline — blockers may be outside the pool), blocking(first:25) { totalCount }. All new model fields optional + fail-soft: an older feed renders honest "not yet sized/graphed" banners instead of breaking (the fix(aggregator/orchestrator): orchestration section rejected — provenance is an object, isOrchestrationSection requires a string #1110 lesson).
    • Attribution: effectiveArea = own Area, else nearest ancestor's via parentRef (cycle-guarded) — the 13 cluster children count toward lab-cluster with no Project writes. Counting rules decided in the doc (each item once by its own weight; epic subtotal separates epic-own vs children Σ; blocked = open item behind an open blocker; mode-unknown is its own bucket, never folded into online).

    Rendering: new pure src/rollup.ts; "Weight & structure" section on /program/<id> (weighted SVG rollup bar with unsized as a separate count-sized segment after a divider, hands queue, blocked weight + longest chain as linked refs, server-rendered SVG depth graph — node size=√weight, fill=status, stroke=mode solid/dashed/thick, dotted=unknown — plus an indented text-tree fallback for phone/screen-reader); /program index cards gain the spec's headlines (weighted % + coverage, deepest chain, hands weight). JSON twins gain a nullable rollup block.

    Sequence: 1) collector contract → 2) rollup math (pure, reproduces the hand-computed baselines above: 680 + 172 inherited = 852 for lab-cluster) → 3) render → 4) JSON twins → 5) adoption sweeps as separate small issues (reconciliation Area inheritance for sub-issues; effort backfill pm-dashboard 40 / id-train 25; mode backfill id-train + pm-dashboard; epic-marking convergence on 4 outliers; prose→native blocked-by conversion on the 12 cluster epics). Steps 1–4 don't wait on 5 — pages degrade honestly until the data lands.

  5. dezren39 commented on Oct 27, 2026

    @dezren39
    MemberAuthor

    Adoption step 5 filed as its own issues (from the design's baseline, 2026-10-26): #1262 sub-issue Area/Status inheritance in reconciliation · #1263 effort-label backfill (pm-dashboard/id-train) · #1264 mode-label backfill · #1265 epic-marking convergence · #1266 cluster prose dependencies → native blocked-by edges. Build steps 1–4 (collector contract, rollup math, render, JSON twins) stay on this issue and do not wait on adoption.

  6. dezren39 commented on Oct 29, 2026

    @dezren39
    MemberAuthor

    🤖 Agent note · picked up

  7. dezren39 commented on Oct 29, 2026

    @dezren39
    MemberAuthor

    🤖 Agent note · done

  8. added
    queue/queuedHas a queued task in the Supabase agent queue
    and removed
    queue/claimedQueue worker lifecycle state
    on Oct 29, 2026
  9. 6 remaining items

  10. dezren39 commented on Oct 29, 2026

    @dezren39
    MemberAuthor

    agent-note:v1 · parked · worker repo-worker-code (lane A shift), queue task 3013. Scoped fresh this shift: the surface is pm-stack/aggregator — src/sources/live.ts (collector, 1099 LOC), src/model.ts (1283), src/feed.ts (236), src/program.ts (311, the v1 per-project pages), src/projects.ts (257). Confirmed the pool path carries no effort/mode/edge data today. This is a multi-hour feature (contract change both sides + weighted SVG render + tests both sides) and has now exceeded two shift budgets unstarted; recommend the producer split it into two packets — (a) collector+model contract with tests, (b) weighted render consuming it — so each fits one shift. Resume plan is checkpointed on task 3013.

  11. added
    queue/claimedQueue worker lifecycle state
    and removed
    status/parkedDeliberately paused with a recorded resume condition
    queue/parkedQueue task is parked (waiting on CI, time, or an event)
    on Oct 29, 2026
  12. dezren39 commented on Oct 29, 2026

    @dezren39
    MemberAuthor

    🤖 Agent note · picked up

  13. dezren39 commented on Oct 29, 2026

    @dezren39
    MemberAuthor

    🤖 Agent note · handed off

    • Agent: queue worker (repo-worker-code), Lane D shift
    • Session / ID: queue task 3013
    • Found via: queue claim
    • Task: Split executed per this task's own verified checkpoint recommendation (scoped 2026-10-29T17:33Z, unstarted across two shift budgets as one multi-hour packet). Part 1 = collector + model/feed contract (pool items carry parent / blocked-by / epic edges). Part 2 = weighted render in program.ts (rollup, hands queue, blocked weight + chain, depth SVG), dependent on part 1. Part 1 is enqueued as the immediate follow-up task under the canonical fix dedupe key as soon as this task reaches its terminal state (the queue returns the live task for a duplicate key, so the enqueue must follow the completion — the follow-up task id is posted in the next note). Part 2 is staged as packet-1122-render.json in the keep-the-four-repos-healthy goal hidden_files/; the part-1 packet's acceptance requires its completer to enqueue it, so the render half cannot evaporate.
    • Expectation: impl(aggregator+collector): complexity-weighted project visualization (rollup, hands queue, blocked weight, depth graph) #1122 stays open; its acceptance is met only when BOTH parts land. Labels will mirror the part-1 task's queued state.
    • Links: split packets: packet-1122-contract.json / packet-1122-render.json (goal hidden_files)
  14. dezren39 commented on Oct 29, 2026

    @dezren39
    MemberAuthor

    🤖 Agent note · done

  15. added 2 commits that reference this issue on Oct 30, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

app/pm-stackpm-stack (Pad/Grist) in developing-today/codekind/featureNew feature or capability request

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions