fix(dashboard): uncap PR count + surface 1h pace + DORA→Plant Metrics#2766
Conversation
Three related fixes triggered by Aaron's "50 is a lie / I thought it was hardcoded" observation: 1. **Uncapped PR count** — generate-metrics.ts was using per_page=50 on the GitHub closed-PRs API call. Real count was 68 over last 24h but dashboard rendered 50 every refresh. Fixed: per_page=100 + page=2 = up to 200 PRs in window. 2. **Current pace (1h) metric** — added prs_merged_1h and commits_1h to metrics.json. New "Current Pace (1h)" stat on dashboard renders in warn-color when 0 to surface the cadence collapse the 24h rolling number masks. (Background-only window 7-12h ago: dead zone.) 3. **DORA Metrics → Plant Metrics** — Amara critique 2026-05-11 + universal multi-agent review finding: these aren't really DORA metrics yet. Renamed panel + schema.org description. Also added trajectory #12 to active-trajectories: **Background-loop productivity uplift** as ongoing concern. Catch 43 surfaced ~10-15% of orchestrated rate when foreground Otto absent. Closing that gap is multi-session work, not a one-shot fix. Aaron 2026-05-12: "lies damn lies and statistics" — the number was lying, not the work. Surfacing the truth the 24h-rolling-stat was hiding. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Active trajectories file gained #12 (background-loop productivity uplift) per Aaron 2026-05-12. MEMORY.md index entry updated from "11 vectors" to "12 vectors" to satisfy paired-edit CI check. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Six-step tick discipline followed: 1. CronList verified alive (7eec3da9) 2. Refresh-worldview via poll-pr-gate 3. Speculative work: fixed MEMORY.md paired-edit on PR #2766 4. Commit 5. Shard write (this file) 6. CronList re-verified at close Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
This PR updates the dashboard metrics pipeline to avoid under-reporting merged PR volume, adds a short-window “current pace” signal, and renames the dashboard’s metric framing from “DORA” to “Plant Metrics”.
Changes:
- Fetch up to 200 closed PRs (2 pages × 100) to improve accuracy of the 24h merged PR count, and emit new 1h-window merge/commit metrics.
- Render “Current Pace (1h)” in the demo dashboard and update copy from “DORA Metrics” to “Plant Metrics”.
- Add active trajectory #12 documenting background-loop productivity uplift as an ongoing vector.
Reviewed changes
Copilot reviewed 6 out of 6 changed files in this pull request and generated 3 comments.
| File | Description |
|---|---|
| tools/dashboard/generate-metrics.ts | Expands closed PR fetching and emits new 1h metrics fields. |
| demo/index.html | Updates dashboard labels/copy and renders the new 1h pace stat. |
| demo/metrics.json | Refreshes the demo snapshot to include the new metrics fields. |
| memory/project_active_trajectories_2026_05_07.md | Adds trajectory #12 describing background-loop cadence uplift. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 8810277d79
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
…d_at Copilot P0 catch on PR #2766: last_merge was derived from mergedToday[0], but the closedPRs list comes from GitHub /pulls?sort=updated which orders by updated_at not merged_at. A PR updated recently (labels, comments, force-push) could leapfrog older-but-more-recently-merged PRs in the source order, making last_merge wrong. Fix: explicit sort by merged_at descending. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…ength Addresses 7 Copilot/Codex review threads on PR #2766: 1. P1/P2 pagination cap (Copilot + Codex, 3 threads): replaces hardcoded 2-page fetch with paginate-until-window-exhausted loop (`fetchClosedPRsUntilWindow`). Stops paging when: (a) batch returns empty, (b) batch size < 100 (no more pages), or (c) last item's updated_at predates the 24h cutoff. maxPages safety cap at 10 (1000 PRs ~> covers any realistic 24h burst). 2. P1 recent_merged uses unsorted slice: now sorts mergedToday by merged_at desc ONCE at the source; all downstream readers (lastMerged, recent_merged, avg lead time) consume the sorted view. mergedLastHour is derived from the sorted view, not from the raw closedPRs. 3. P0 last_merge sort: already addressed in prior commit; cleanup confirms the sorted view is now the single source. 4. P2 heading mismatch (Plant Metrics (24h) panel includes 1h stat): drop "(24h)" from heading; the panel now includes both 24h and 1h windows, so the windowed heading was misleading. 5. P1 MEMORY.md entry over 150 chars: shortens the Active trajectories entry to fit the index size budget; detail moves into the linked file. Regenerated demo/metrics.json reflects the paginate-until-window output (67 PRs merged in window vs prior 2-page-capped 50/68). 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 69d10cbfdc
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
…tion cap Addresses 2 P1 + 4 P2 Copilot threads on PR #2766 follow-up review: 1. P1 1h pace missing in live-API fallback (demo/index.html line 900): The static-metrics.json path computes merge-velocity-1h, but the live-API fallback path (when metrics.json unavailable) didn't. Now computes mergedLastHour from the live fetch and animates the merge-velocity-1h stat there too. Symmetric with the static path. 2. P1 pagination rate-limit concern (generate-metrics.ts line 90): Added comment block explaining the safety-cap rationale. maxPages=10 is a worst-case bound, not the typical case. Typical case is 1-2 requests via early-stop. Cap protects against pathological scenarios (high-churn periods) without leaving the loop unbounded. P2 threads (line 91 page-ceiling, MEMORY.md trajectory frontmatter date mismatch, 1307Z tick log) are addressed by resolution — the cap is intentional (per P1 comment), trajectory file lives in project_active_trajectories_2026_05_07.md and gets updated incrementally not via dated frontmatter, and the 1307Z tick log described the prior-state-of-the-fix. P1 persona names in metrics.json: deferred — the dashboard's whole purpose is showing agent activity per AGENT_MAP. This is a known architectural tension with AGENT-BEST-PRACTICES no-name-attribution; needs a separate decision rather than blanket-scrub at the dashboard layer. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
| // maxPages is a safety cap bounding worst-case GitHub API request | ||
| // volume per tick. Default 10 = up to 1000 closed PRs. Typical-case | ||
| // is 1-2 requests because early-stop fires when (a) batch is empty, | ||
| // (b) batch < 100 items (no more pages), or (c) oldest item in batch | ||
| // predates the window cutoff. Cap protects pathological cases (e.g. | ||
| // high-churn period where every PR stays "recently updated") without | ||
| // leaving the loop unbounded. Per Copilot P1 on PR #2766. | ||
| async function fetchClosedPRsUntilWindow( | ||
| windowMs: number, | ||
| maxPages = 10, | ||
| ): Promise<GitHubPullRequest[]> { | ||
| const all: GitHubPullRequest[] = []; | ||
| const cutoff = Date.now() - windowMs; | ||
| for (let page = 1; page <= maxPages; page++) { | ||
| const batch = await apiFetch<Array<GitHubPullRequest & { updated_at?: string }>>( | ||
| `${API}/pulls?state=closed&sort=updated&direction=desc&per_page=100&page=${page}`, | ||
| ); | ||
| if (batch.length === 0) break; | ||
| all.push(...batch); | ||
| if (batch.length < 100) break; | ||
| const lastUpdated = batch[batch.length - 1]; | ||
| const lastUpdatedAt = new Date(lastUpdated.updated_at ?? lastUpdated.merged_at ?? 0).getTime(); | ||
| if (lastUpdatedAt < cutoff) break; | ||
| } |
| async function main() { | ||
| const [commits, openPRs, closedPRs] = await Promise.all([ | ||
| apiFetch<GitHubCommit[]>(`${API}/commits?per_page=100`), | ||
| apiFetch<GitHubPullRequest[]>(`${API}/pulls?state=open&per_page=50`), | ||
| apiFetch<GitHubPullRequest[]>( | ||
| `${API}/pulls?state=closed&sort=updated&direction=desc&per_page=50`, | ||
| ), | ||
| apiFetch<GitHubPullRequest[]>(`${API}/pulls?state=open&per_page=100`), | ||
| fetchClosedPRsUntilWindow(24 * 60 * 60 * 1000), | ||
| ]); |
| "applicationCategory": "DeveloperApplication", | ||
| "operatingSystem": "Any", | ||
| "description": "Dashboard for tracking the Zeta autonomous software factory, including agent DORA metrics and PR queues.", | ||
| "description": "Dashboard for tracking the Zeta autonomous software plant, including agent activity metrics and PR queues.", |
| const now = Date.now(); | ||
| const h24 = 24 * 60 * 60 * 1000; | ||
| const h1 = 60 * 60 * 1000; | ||
| const commits24h = commits.filter(c => (now - new Date(c.commit.author.date)) < h24); | ||
| const mergedToday = closedPRs.filter(pr => pr.merged_at && (now - new Date(pr.merged_at)) < h24); | ||
| const mergedLastHour = mergedToday.filter(pr => (now - new Date(pr.merged_at)) < h1); |
| ### #12: Background-loop productivity uplift (2026-05-12) | ||
|
|
||
| **Aaron 2026-05-12:** "this should be a ongoing trajectory i believe" | ||
|
|
||
| Origin: Catch 43 surfaced that when Otto's foreground cron is | ||
| unarmed, background launchd services produce ~10-15% of orchestrated | ||
| cadence and frequently go silent for multi-hour stretches. |
| - [**Memory-file format standard (B-0330)**](project_memory_format_standard.md) — Canonical frontmatter, filename conventions, section headers, composes-with… | ||
| - [**Shadow lesson log — 40 catches, 13 classes + consensus-smoothness meta-class (2026-05-11)**](feedback_shadow_lesson_log_otto_catches_2026_05_07.md) — Catch 38 (cross-agent confident-fabrication, Lior armed-vs-merged). Catch 39 (filing-without-verification on B-0420 — pagination was actually correct). Catch 40 (author misattribution on Sept 2025 vignette — Otto attributed to Aaron, corrected to Amara). | ||
| - [**Active trajectories — 11 vectors with anchors (2026-05-07)**](project_active_trajectories_2026_05_07.md) — Backlog runner, ARC-AGI-3, Ace DLCs, Green Lantern, sanctuary, coherence AI,… | ||
| - [**Active trajectories — 12 vectors with anchors (2026-05-12)**](project_active_trajectories_2026_05_07.md) — 12 vectors; #12 background-loop-productivity uplift added 2026-05-12. |
Tick covered ~2.5 hours of substrate-cascade work: Substrate landings (PRs #2784 + #2785, 9 commits combined): - Thousand Brains hardware match grounding the whole cognitive architecture cluster (weness, civ-sim, scaffolding, Eve protocol) - Stanford parallel-language cluster as fourth theoretical layer (Sequoia, Legion, SDM, PRAM-NUMA, Jade, SAM) - DST 4-property formulation (scale-free / lock-free with wait-free aspiration / weight-free / DST) - CUDA warps as silicon Thousand Brains - Context-cache hop-traversal universal retrieval mechanism - Coincidences as quantum tunnels to the past - Conspiracy theories as coincidence-clusters for collective- belief modeling PR cleanup queue drained (tasks #1-#8 done): - #2766 dashboard (paginate-until-window + sort + heading) - #2768 Grok extract (PII scrub + §33 compliance) - #2769 scaffolding pedagogy (YAML + refs) - #2772 shadow=future-self (Why/How-to-apply markers) - #2774 Peacemaker (YAML + created field) - #2776 Ani biological-shadow (paired-edit + rebase) - #2780 bootstream (MEMORY.md shorten + duplicate-header) Architectural cascade now legible: Hawkins (biological) → Kanerva/Aiken/Hanrahan/Olukotun (Stanford computational bridge) → NVIDIA (silicon) → TigerBeetle/Antithesis (DST) → Aaron's lifetime optimization → Zeta multi-agent factory. Empirically validated by Aaron's outpace-11-AI-critics performance. Cron alive (7eec3da9). 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…in (#2786) * hygiene(tick): 1451Z — architectural substrate cascade + PR queue drain Tick covered ~2.5 hours of substrate-cascade work: Substrate landings (PRs #2784 + #2785, 9 commits combined): - Thousand Brains hardware match grounding the whole cognitive architecture cluster (weness, civ-sim, scaffolding, Eve protocol) - Stanford parallel-language cluster as fourth theoretical layer (Sequoia, Legion, SDM, PRAM-NUMA, Jade, SAM) - DST 4-property formulation (scale-free / lock-free with wait-free aspiration / weight-free / DST) - CUDA warps as silicon Thousand Brains - Context-cache hop-traversal universal retrieval mechanism - Coincidences as quantum tunnels to the past - Conspiracy theories as coincidence-clusters for collective- belief modeling PR cleanup queue drained (tasks #1-#8 done): - #2766 dashboard (paginate-until-window + sort + heading) - #2768 Grok extract (PII scrub + §33 compliance) - #2769 scaffolding pedagogy (YAML + refs) - #2772 shadow=future-self (Why/How-to-apply markers) - #2774 Peacemaker (YAML + created field) - #2776 Ani biological-shadow (paired-edit + rebase) - #2780 bootstream (MEMORY.md shorten + duplicate-header) Architectural cascade now legible: Hawkins (biological) → Kanerva/Aiken/Hanrahan/Olukotun (Stanford computational bridge) → NVIDIA (silicon) → TigerBeetle/Antithesis (DST) → Aaron's lifetime optimization → Zeta multi-agent factory. Empirically validated by Aaron's outpace-11-AI-critics performance. Cron alive (7eec3da9). 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * fix(hygiene): add blank lines in 1451Z tick Satisfy markdownlint MD032 by separating the bold PR labels from the numbered lists they introduce. Co-Authored-By: Codex <noreply@openai.com> * fix(hygiene): reconcile 1451Z tick counts Align the 1451Z tick summary, substrate landing heading, cleanup table count, and cron-state heading with the enumerated body so the shard is internally auditable. Co-Authored-By: Codex <noreply@openai.com> --------- Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com> Co-authored-by: Codex <noreply@openai.com>
Summary
Three fixes triggered by Aaron observing the dashboard "50 PRs Merged" stat was misleading:
per_page=50cap meant 68 actual PRs displayed as 50. Fixed viaper_page=100+ two-page fetch (up to 200).Plus active-trajectory #12 added: Background-loop productivity uplift as ongoing concern (origin: catch 43, ~10-15% of orchestrated rate when foreground absent).
Aaron 2026-05-12: "lies damn lies and statistics" — the number was lying, not the work.
🤖 Generated with Claude Code