You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
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:
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)
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/)
Weighted rollup bar — total weight, weighted % done (closed weight / total), raw issue count as secondary metric
Hands queue — open mode/physical + mode/hybrid weight (hands-hours waiting) vs online weight
Blocked weight — weight behind an open blocker + longest dependency chain (depth)
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.
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.
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.
Verdict — CONFIRMED at HEAD, with one part already in place: the label half of the data gap is already closed — the collector's Project-pool GraphQL read (pm-stack/aggregator/src/projects.ts) fetches labels(first: 20) per issue and ProjectPoolItem (src/model.ts) carries labels?, so effort/* and mode/* already flow into the feed when present. What does not exist: (1) edges — ProjectPoolItem has no parent/sub-issue, blocked-by/blocks, or epic-membership fields and the GraphQL query requests none; (2) the visualization itself — src/program.ts contains no weight, hands-queue, blocked-weight, depth, or SVG graph logic at all; the per-project pages are still v1 counts-and-items.
Routing: scoped implementation packet enqueued as queue task 3013 (dedupe repo-health:v1:fix:developing-today/code:issue:1122): edges in the collector + model contract in lockstep, weights xs=1/s=4/m=12/l=40 with unlabeled = unsized shown separately (never zero), the four elements server-rendered as SVG (mobile-first, no client JS), and the explicit "not yet sized/graphed" note instead of a fake 0% for projects without data.
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.
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.
Activity
developing-today commentedon Oct 27, 2026
CODE-260
dezren39 commentedon Oct 27, 2026
Epic: #1129 — per-project status pages for all projects (generalize /program beyond pm-dashboard).
dezren39 commentedon Oct 27, 2026
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):effort/l=70 all-states vs 67 in pool;mode/physical=5 = pool's 5).effort/*andmode/*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.epiclabel 14 vsmeta/epic).Contract (one PR, both sides —
projects.tsis shared by collector + aggregator):PROJECT_QUERY; parse them into typed optional fields onProjectPoolItem(raise the labels cap 20→50 against truncation).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).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);/programindex cards gain the spec's headlines (weighted % + coverage, deepest chain, hands weight). JSON twins gain a nullablerollupblock.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.
dezren39 commentedon Oct 27, 2026
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.
dezren39 commentedon Oct 29, 2026
🤖 Agent note · picked up
dezren39 commentedon Oct 29, 2026
🤖 Agent note · done
pm-stack/aggregator/src/projects.ts) fetcheslabels(first: 20)per issue andProjectPoolItem(src/model.ts) carrieslabels?, soeffort/*andmode/*already flow into the feed when present. What does not exist: (1) edges —ProjectPoolItemhas no parent/sub-issue, blocked-by/blocks, or epic-membership fields and the GraphQL query requests none; (2) the visualization itself —src/program.tscontains no weight, hands-queue, blocked-weight, depth, or SVG graph logic at all; the per-project pages are still v1 counts-and-items.repo-health:v1:fix:developing-today/code:issue:1122): edges in the collector + model contract in lockstep, weights xs=1/s=4/m=12/l=40 with unlabeled = unsized shown separately (never zero), the four elements server-rendered as SVG (mobile-first, no client JS), and the explicit "not yet sized/graphed" note instead of a fake 0% for projects without data.queue/queueduntil task 3013 lands.packet-task2404-fix1122.json(goal hidden_files)6 remaining items
dezren39 commentedon Oct 29, 2026
agent-note:v1 · parked · worker
repo-worker-code(lane A shift), queue task 3013. Scoped fresh this shift: the surface ispm-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.dezren39 commentedon Oct 29, 2026
🤖 Agent note · picked up
dezren39 commentedon Oct 29, 2026
🤖 Agent note · handed off
packet-1122-render.jsonin the keep-the-four-repos-healthy goalhidden_files/; the part-1 packet's acceptance requires its completer to enqueue it, so the render half cannot evaporate.dezren39 commentedon Oct 29, 2026
🤖 Agent note · done
packet-1122-contract.json/packet-1122-render.jsonin the keep-the-four-repos-healthy goalhidden_files/.pm-stack: Project pool graph edges contract (#2399, part 1 of #1122) (#…
Merge pull request #2831 from developing-today/queue/3573-2400-weight…