Overview
Development speed tracks test speed, and today knowing what is slow takes a manual archaeology session over CI job logs. This task builds the standing surface: a ⏱ Performance section on the Heart board showing run times of the testing/integration infrastructure (PR smoke gates, unit-test gates, weekly Workspace Smoke, Nightly Release), with history to flag drops, kill-timer/hang events surfaced, and the NO_RUN census with reasons — every actionable row carrying its own one-tap Claude prompt. The Brain board consumes the published block verbatim as a headline row (the existing heart_blockers contract).
Full design rationale with receipts: PyAutoMind/docs/pyautoheart/test_performance_board_assessment.md. Mind prompt: active/test_performance_board.md.
Plan
- Add two cloud-safe Heart checks: ci_timing (Actions-API wall-clock scrape of the tracked gates — durations, queue delay, conclusion mix, cancelled/timed-out disambiguation) and no_run_census (parse each workspace's
config/build/no_run.yaml; SLOW/NEEDS_FIX/permanent tiers, marker age, unmeasured-SLOW flagging).
- History via the self-carrying published-artifact roll-forward (previous
board.json fetched at render, today appended, capped) — no commit noise.
- Two new dashboard sections + an additive
performance block in board.json (schema v2 stays additive); rows carry their own /bug prompts.
- Wire both checks into
heart-health.yml's daily cloud run (not the <30s tick).
- Brain board: a "⏱ Test performance" section consuming the published block verbatim; hang events count as attention in the verdict.
- Advisory only: the GREEN/STALE/YELLOW/RED readiness verdict is untouched.
Detailed implementation plan
Affected Repositories
- PyAutoHeart (primary)
- PyAutoBrain (board consumer)
- PyAutoMind (prompt lifecycle + assessment doc, already pushed)
Branch Survey
| Repository |
Current Branch |
Dirty? |
| ./PyAutoHeart |
main → claude/test-performance-dashboard-y3fdy7 |
clean |
| ./PyAutoBrain |
claude/test-performance-dashboard-y3fdy7 (= main) |
clean |
| ./PyAutoMind |
claude/test-performance-dashboard-y3fdy7 |
pushed |
Branch: claude/test-performance-dashboard-y3fdy7 (all three repos)
Implementation Steps
heart/checks/ci_timing.{sh,py} — per polled repo, gh api repos/<owner>/<name>/actions/runs?per_page=50 (PR runs included); durations from run_started_at→updated_at (never created_at); success-only medians per required workflow (+ performance: extra_workflows in config/repos.yaml: Workspace Smoke, Nightly Release); cancelled runs disambiguated (superseded-by-newer-same-branch = benign; on main or successorless = suspect event; timed_out always an event); per-repo sidecars + an aggregate $HEART_STATE_DIR/ci_timing.json that rolls history forward from the previously published board.json (dedupe by date, capped).
heart/checks/no_run_census.{sh,py} — contents-API fetch of config/build/no_run.yaml per workspace-group repo; line-based parse (comments carry the markers; a bare off entry must not crash as a YAML boolean); SLOW rows flagged measured: false when the reason carries no real seconds figure (a bare "1800s cap" mention is not a measurement); 404 recorded honestly as present: false.
heart/state.py — aggregate the two new global keys.
heart/dashboard.py — "CI wall-clock" and "NO_RUN census" sections (cloud-observed, not in LOCAL_ONLY_FAMILIES; events → FAIL state, drift → WARN, both advisory); Board.performance emitted in to_dict as the performance block; sparkline helper for gate history.
config/repos.yaml — performance: block + thresholds: ci_timing: {yellow_factor: 1.5, min_delta_s: 120, history_cap: 30} (drift flags only on ratio AND absolute floor — the profiling-conductor doctrine).
.github/workflows/heart-health.yml — run both checks in the cloud-safe step.
- PyAutoBrain
board/_board.py — one Heart board.json read serves blockers + performance; ⏱ Test performance section rendering flagged rows' prompts verbatim; events counted as attention.
- Tests both sides (stdlib+PyYAML, hermetic fixtures, tenant-firewall-clean).
Key Files
heart/checks/ci_status.{sh,py} — the API-safe check shape being mirrored
heart/dashboard.py — the one unified renderer (sections, blockers, html 📋 buttons)
.github/workflows/heart-health.yml — the daily cloud render + Pages publish
PyAutoBrain/board/_board.py — fetch_heart_blockers consumer contract + _row chips
Out of scope (phased separately)
- Phase 0 prerequisite (separate PR):
draft/bug/pyautoheart/script_timing_baselines_orphaned_and_window_filled.md — orphaned slugs / single-observation windows in script_timing.
- Phase 2 (PyAutoHands): per-script
smoke_timings.json from the delegated runner — the standing dataset answering item 4 of draft/research/ci/smoke_timing_and_profiling.md.
Original Prompt
Click to expand starting prompt
Test-performance section on the Heart board — run times, hangs, NO_RUN, with one-tap fix prompts
Type: feature / Target: pyautoheart / Repos: @PyAutoHeart @PyAutoHands @PyAutoBrain
Difficulty: large / Autonomy: supervised / Priority: high / Filed: 2026-08-24
Development speed tracks test speed, and today knowing what is slow takes a manual archaeology session over CI job logs. Build the standing surface: a ⏱ Performance section on the Heart board that always shows the run times of the testing/integration infrastructure — PR smoke gates (*_workspace_test, normal workspaces, HowTo), unit-test gates, weekly workspace-smoke, the nightly release driver, import time — with enough history to flag drops, kill-timer/hang events surfaced, the NO_RUN census with reasons, and a one-tap Claude prompt on every row so "speed this up" is a paste.
Full design rationale, data-plane analysis, chip payloads, and the trap list: docs/pyautoheart/test_performance_board_assessment.md in PyAutoMind.
Acceptance:
- The Heart board page shows, per tracked gate: latest duration, p50/max over the window, trend sparkline, conclusion mix, coverage count — refreshed on the Heart's existing render cadence with no commit noise.
- A hang/kill event (per-script TIMEOUT, unexplained
cancelled, aborted summary) appears within one render, red, with a /bug … — <run url> chip.
- Every SLOW/NEEDS_FIX
no_run.yaml entry is listed with marker age, reason, and a re-measure-first fix chip; unmeasured SLOW markers are visibly flagged.
- The Brain board carries the headline row consuming the published block verbatim.
- Nothing gates: readiness verdict and
badge.json message shape unchanged.
Overview
Development speed tracks test speed, and today knowing what is slow takes a manual archaeology session over CI job logs. This task builds the standing surface: a ⏱ Performance section on the Heart board showing run times of the testing/integration infrastructure (PR smoke gates, unit-test gates, weekly Workspace Smoke, Nightly Release), with history to flag drops, kill-timer/hang events surfaced, and the NO_RUN census with reasons — every actionable row carrying its own one-tap Claude prompt. The Brain board consumes the published block verbatim as a headline row (the existing
heart_blockerscontract).Full design rationale with receipts:
PyAutoMind/docs/pyautoheart/test_performance_board_assessment.md. Mind prompt:active/test_performance_board.md.Plan
config/build/no_run.yaml; SLOW/NEEDS_FIX/permanent tiers, marker age, unmeasured-SLOW flagging).board.jsonfetched at render, today appended, capped) — no commit noise.performanceblock inboard.json(schema v2 stays additive); rows carry their own/bugprompts.heart-health.yml's daily cloud run (not the <30s tick).Detailed implementation plan
Affected Repositories
Branch Survey
claude/test-performance-dashboard-y3fdy7claude/test-performance-dashboard-y3fdy7(= main)claude/test-performance-dashboard-y3fdy7Branch:
claude/test-performance-dashboard-y3fdy7(all three repos)Implementation Steps
heart/checks/ci_timing.{sh,py}— per polled repo,gh api repos/<owner>/<name>/actions/runs?per_page=50(PR runs included); durations fromrun_started_at→updated_at(nevercreated_at); success-only medians per required workflow (+performance: extra_workflowsinconfig/repos.yaml: Workspace Smoke, Nightly Release); cancelled runs disambiguated (superseded-by-newer-same-branch = benign; on main or successorless = suspect event;timed_outalways an event); per-repo sidecars + an aggregate$HEART_STATE_DIR/ci_timing.jsonthat rolls history forward from the previously publishedboard.json(dedupe by date, capped).heart/checks/no_run_census.{sh,py}— contents-API fetch ofconfig/build/no_run.yamlper workspace-group repo; line-based parse (comments carry the markers; a bareoffentry must not crash as a YAML boolean); SLOW rows flaggedmeasured: falsewhen the reason carries no real seconds figure (a bare "1800s cap" mention is not a measurement); 404 recorded honestly aspresent: false.heart/state.py— aggregate the two new global keys.heart/dashboard.py— "CI wall-clock" and "NO_RUN census" sections (cloud-observed, not inLOCAL_ONLY_FAMILIES; events → FAIL state, drift → WARN, both advisory);Board.performanceemitted into_dictas theperformanceblock; sparkline helper for gate history.config/repos.yaml—performance:block +thresholds: ci_timing: {yellow_factor: 1.5, min_delta_s: 120, history_cap: 30}(drift flags only on ratio AND absolute floor — the profiling-conductor doctrine)..github/workflows/heart-health.yml— run both checks in the cloud-safe step.board/_board.py— one Heartboard.jsonread serves blockers + performance;⏱ Test performancesection rendering flagged rows' prompts verbatim; events counted as attention.Key Files
heart/checks/ci_status.{sh,py}— the API-safe check shape being mirroredheart/dashboard.py— the one unified renderer (sections, blockers, html 📋 buttons).github/workflows/heart-health.yml— the daily cloud render + Pages publishPyAutoBrain/board/_board.py—fetch_heart_blockersconsumer contract +_rowchipsOut of scope (phased separately)
draft/bug/pyautoheart/script_timing_baselines_orphaned_and_window_filled.md— orphaned slugs / single-observation windows inscript_timing.smoke_timings.jsonfrom the delegated runner — the standing dataset answering item 4 ofdraft/research/ci/smoke_timing_and_profiling.md.Original Prompt
Click to expand starting prompt
Test-performance section on the Heart board — run times, hangs, NO_RUN, with one-tap fix prompts
Type: feature / Target: pyautoheart / Repos: @PyAutoHeart @PyAutoHands @PyAutoBrain
Difficulty: large / Autonomy: supervised / Priority: high / Filed: 2026-08-24
Development speed tracks test speed, and today knowing what is slow takes a manual archaeology session over CI job logs. Build the standing surface: a ⏱ Performance section on the Heart board that always shows the run times of the testing/integration infrastructure — PR smoke gates (
*_workspace_test, normal workspaces, HowTo), unit-test gates, weeklyworkspace-smoke, the nightly release driver, import time — with enough history to flag drops, kill-timer/hang events surfaced, the NO_RUN census with reasons, and a one-tap Claude prompt on every row so "speed this up" is a paste.Full design rationale, data-plane analysis, chip payloads, and the trap list:
docs/pyautoheart/test_performance_board_assessment.mdin PyAutoMind.Acceptance:
cancelled, aborted summary) appears within one render, red, with a/bug … — <run url>chip.no_run.yamlentry is listed with marker age, reason, and a re-measure-first fix chip; unmeasured SLOW markers are visibly flagged.badge.jsonmessage shape unchanged.