Repository navigation
Score persona eval sets weekly at parity tier — add the cadence, preserve the daily triage run #1702
Description
Decision
Persona eval sets are scored at parity tier on a WEEKLY cadence (maintainer decision, 2026-09-07).
Correcting the cost basis this decision was first framed against
An earlier estimate described parity as costing ~$158/yr for qa-lead by changing a daily run.
That figure was wrong and is retracted. Verified against main:
.github/workflows/skill-eval-report.ymlrunscron: '51 7 * * *'(daily) but scores
triageonly —SKILL: ${{ inputs.skill || 'triage' }}, and nothing overrides the default on
the scheduled path.- No persona is scored on any cron today. Every qa-lead scoring run to date has been a manual
workflow_dispatch. - Parity itself is not on
mainyet:"engine": "persona"lives in unmerged PR feat: implement issue #1686 — Persona eval harness scores the wrong model and the wrong context shape — a scored promotion gate built on it measures neither the shipped persona nor the case #1696 (issue Persona eval harness scores the wrong model and the wrong context shape — a scored promotion gate built on it measures neither the shipped persona nor the case #1686).
Onmain, all threescorer.jsonfiles (deep-review,qa-lead,solution-architect) declare no
engine and therefore default to the Haiku-tierrun_triage.
So this is net-new recurring spend, not a saving. Corrected figures, on the same assumptions the
eval-cost-estimate.sh script uses (6 held-out cases; 12k/1.2k engine tokens, 3k/300 judge tokens per
case; Opus $5/$25 per Mtok vs Haiku $1/$5):
| Scope | Weekly | (daily, for reference) | (on-demand ~12/yr) |
|---|---|---|---|
| qa-lead only | ~$22/yr | ~$158/yr | ~$5/yr |
| all 9 personas | ~$202/yr | ~$1,419/yr | ~$47/yr |
Weekly was chosen deliberately as a regression tripwire: cheap enough to run unattended, frequent
enough to catch a prompt or vendored-framework change that degrades advice quality between promotion
decisions. The existing daily triage run is unaffected and stays as-is — it is Haiku-tier and cheap.
Acceptance Criteria
- Persona eval sets are scored weekly, at the tier their
scorer.jsondeclares. A skill with
"engine": "persona"is scored at parity; a skill without it keepsrun_triage. No skill is
silently upgraded — the declaration remains the only thing that selects the tier (Persona eval harness scores the wrong model and the wrong context shape — a scored promotion gate built on it measures neither the shipped persona nor the case #1686 AC Go-live improvements for PR review agent #2). - The existing daily
triagerun is preserved unchanged (cron: '51 7 * * *', Haiku). This
story adds a persona cadence; it does not repurpose or degrade the existing one. - The weekly run discovers which skills to score from their
scorer.json(engine == "persona"),
rather than hardcodingqa-lead. Adding a persona to the parity cadence must require no edit to
this workflow — the same derive-don't-enumerate rule as the<id>:hands-offlabel family (fix(pr-review-sweep): dispatch with GH_PAT_WORKFLOWS, not the bot comment PAT #756). - Weekly runs are off-peak and do not contend with the existing daily report — pick a distinct
day+hour and state it, per AGENTS.md "Scheduled workflows". - The run is report-only and non-blocking, exactly like the current
skill-eval-reportpath: a
held-out regression is a::warning::and a published report, never a failed required check. It
must not become a merge gate by accident. - The report records which tier each skill was scored at, so a number is never ambiguous about what
produced it (Persona eval harness scores the wrong model and the wrong context shape — a scored promotion gate built on it measures neither the shipped persona nor the case #1686 AC test issue from agent #1). - Cost is re-stated at implementation time using
scripts/evals/eval-cost-estimate.sh(added by
Persona eval harness scores the wrong model and the wrong context shape — a scored promotion gate built on it measures neither the shipped persona nor the case #1686) rather than the estimates above, and the actual per-run figure is recorded in the PR. If the
real cost diverges materially from ~$22/yr for one persona, say so rather than proceeding silently.
Tasks / Subtasks
- Add the weekly persona-parity schedule, deriving the skill list from
scorer.json. (AC: test issue from agent #1, Add @claude delegation, auto-merge, and rebase handling #3, Optimize review: small-PR and incremental fast paths #4) - Preserve the daily
triagepath untouched. (AC: Go-live improvements for PR review agent #2) - Surface the scored tier in the report output. (AC: feat: feature ideation framework — adversarial proposer/challenger/synthesizer #6)
- Keep the path report-only/non-blocking. (AC: feat: add Copilot engine support via REVIEW_ENGINE toggle #5)
- Run
eval-cost-estimate.shand record real figures in the PR. (AC: Workflow should skip no-op PRs in MAX_PRS count #7)
Dev Notes
- Blocked by Persona eval harness scores the wrong model and the wrong context shape — a scored promotion gate built on it measures neither the shipped persona nor the case #1686. Parity (
run_persona, theenginefield inscorer.json) does not exist on
mainyet — it is in PR feat: implement issue #1686 — Persona eval harness scores the wrong model and the wrong context shape — a scored promotion gate built on it measures neither the shipped persona nor the case #1696. Implementing this first would wire a cadence for a tier that has no
implementation. - Do not add a new workflow file if the existing
skill-eval-report.ymlcan carry a second
schedule entry; AGENTS.md discourages new cron surface, and this initiative has already added
observability rather than new scheduled workloads elsewhere. - No new count-based breakers or budget machinery. The existing automation budget and runaway
detector remain the ceiling; this is a scheduled report, not an agent action loop. - Note for whoever implements: the current scheduled path scores exactly one skill. Scoring N skills in
one run needs a loop or a matrix — keep the per-skill report artifact shape (eval-report.jsonper
skill) so existing consumers and theskill-eval-report-<skill>artifact naming still work.
References
.github/workflows/skill-eval-report.yml(cron: '51 7 * * *',SKILLdefaulttriage)scripts/evals/run-eval.sh,scripts/evals/eval-cost-estimate.sh(Persona eval harness scores the wrong model and the wrong context shape — a scored promotion gate built on it measures neither the shipped persona nor the case #1686)evals/<skill>/scorer.json— theenginedeclaration that selects the tier- Persona eval harness scores the wrong model and the wrong context shape — a scored promotion gate built on it measures neither the shipped persona nor the case #1686 / PR feat: implement issue #1686 — Persona eval harness scores the wrong model and the wrong context shape — a scored promotion gate built on it measures neither the shipped persona nor the case #1696 (engine parity — the hard dependency), [qa-lead S2] Make the qa-lead eval set scorable and capture a first held-out baseline #1645 / PR feat: implement issue #1645 — [qa-lead S2] Make the qa-lead eval set scorable and capture a first held-out baseline #1656 (per-skill judge)
- Epic: Persona framework — post-rollout hardening & follow-ups #1318 (persona post-rollout tracker — scored eval-gate follow-up)
- AGENTS.md — "Scheduled workflows", "Cost reporting"
Delivery brief — 2026-09-13 (read this section first; implement it, do not re-ask)
"Blocked by #1686" (Dev Notes) is discharged. #1686 is closed, PR #1696 merged 2026-09-08, and scripts/evals/eval-cost-estimate.sh exists on main. Parity is live: on main, every evals/*/scorer.json except deep-review declares "engine": "persona". Discovery (AC #3) therefore yields nine skills: business-analyst, dev-lead, devops-lead, pr-review, qa-lead, scrum-master, security-lead, solution-architect, sre-lead. That matches the "all 9 personas" row of the cost table.
Two hazards the description does not mention
- Concurrency will cancel runs.
skill-eval-report.ymlhasconcurrency: { group: skill-eval-report, cancel-in-progress: true }. As written, the weekly run and the daily triage run cancel each other, and a per-skill matrix in that one group cancels its own siblings. Key the group by event and skill, e.g.skill-eval-report-${{ github.event_name }}-${{ matrix.skill || inputs.skill || 'triage' }}, so AC Go-live improvements for PR review agent #2 (daily run unchanged in behaviour) actually holds. - Most of the nine skills' case sets fail
case.schema.jsontoday. [qa-lead S8] Fleet-wide: 11 of 12 eval sets fail case.schema.json and CI never notices #1651 owns that, and it is in flight in parallel. One skill erroring must not abort the rest: usefail-fast: false, and record the failure as that skill's row in the report (AC feat: add Copilot engine support via REVIEW_ENGINE toggle #5 report-only). Do not edit anything underevals/*/cases.jsonlorevals/case.schema.jsonin this PR.
Pre-answered decisions
- Keep one workflow file: add a second
scheduleentry toskill-eval-report.yml(Dev Notes). - Weekly slot:
23 9 * * 0(Sunday 09:23 UTC). It is distinct from the daily 07:51 run and fromapply-repo-settings(Monday 06:17). State it in the header comment (AC Optimize review: small-PR and incremental fast paths #4). - Tell the two schedules apart with
github.event.schedule: the daily cron keepsSKILL=triage, and the weekly cron runs the discovered matrix. - Keep the
skill-eval-report-<skill>artifact naming andeval-report.jsonper skill. - The
timeout-minutes: 20is per job; with a matrix it applies per skill, which is fine.
Budget guard
- Schedule, discovery job, matrix, concurrency fix and
fail-fast: false(AC test issue from agent #1–feat: add Copilot engine support via REVIEW_ENGINE toggle #5), with a bats or unit test proving that discovery derives the list fromscorer.json. - Tier recorded in the report output (AC feat: feature ideation framework — adversarial proposer/challenger/synthesizer #6).
- Run
eval-cost-estimate.shand paste the figure into the PR description (AC Workflow should skip no-op PRs in MAX_PRS count #7). Do not dispatch real parity scoring runs to verify; the estimate script is the required evidence.
If you run low on budget, stop after step 1 or 2 with a green PR and list what remains. A timed-out run that loses the work is worse than a partial.
Activity
don-petry commentedon Sep 13, 2026
Dev-Lead Implementation Plan
Issue: #1702 — Score persona eval sets weekly at parity tier — add the cadence, preserve the daily triage run
Scope
Add a weekly persona-parity cadence to
skill-eval-report.ymlthat discovers the skills to score fromevals/*/scorer.json(engine == "persona"), scores each at its declared tier over afail-fast: falsematrix, records the scored tier in the report, and stays report-only/non-blocking — while leaving the existing dailytriagerun (51 7 * * *) behaviourally unchanged.Implementation Checklist
scripts/evals/discover-parity-skills.sh— new: emit a JSON array of skills whosescorer.jsondeclaresengine == "persona"(derive, don't enumerate; AC Add @claude delegation, auto-merge, and rebase handling #3). HonorsEVALS_DIRoverride..github/workflows/skill-eval-report.yml:scheduleentry23 9 * * 0(Sunday 09:23 UTC), documented in the header (AC Optimize review: small-PR and incremental fast paths #4). Keep daily51 7 * * *(AC Go-live improvements for PR review agent #2).discoverjob: weekly cron → run discovery script; daily cron / dispatch →[triage](or dispatched skill). Outputs the matrix.eval-reportjob depends ondiscover,strategy.matrix.skillfrom discovery,fail-fast: false(AC test issue from agent #1, feat: add Copilot engine support via REVIEW_ENGINE toggle #5).skill-eval-report-${{ github.event_name }}-${{ matrix.skill }}so daily & weekly (and matrix siblings) don't cancel (AC Go-live improvements for PR review agent #2).SKILL: ${{ matrix.skill }}; preserveskill-eval-report-<skill>artifact + per-skilleval-report.json.engine_tier(AC feat: feature ideation framework — adversarial proposer/challenger/synthesizer #6).Tests to Write
tests/test_discover_parity_skills.bats— discovery derives the list fromscorer.json(persona included, triage/deep-review excluded; fixture EVALS_DIR).tests/test_skill_eval_report.bats— weekly cron present, daily cron preserved, matrix +fail-fast: false, concurrency keyed by event+skill, tier surfaced.tests/test_discover_parity_skills.batsinlint.ymlbats list.Cost Evidence (AC #7)
scripts/evals/eval-cost-estimate.shfor one persona and record the per-run figure in the PR (no live parity scoring dispatched).Test Command
scripts/run-bats.sh tests/test_discover_parity_skills.bats tests/test_skill_eval_report.batsandbash .dev-lead/scripts/dev-lead-lint.shdon-petry commentedon Sep 13, 2026
Dev-Lead: Progress (in progress — not yet durable)
Plan Execution (intended)
scripts/evals/discover-parity-skills.sh— emits a JSON array of skills whoseevals/<skill>/scorer.jsondeclares"engine": "persona"(derive-don't-enumerate, AC Add @claude delegation, auto-merge, and rebase handling #3). HonorsEVALS_DIR.skill-eval-report.yml: added the weekly23 9 * * 0(Sun 09:23 UTC) schedule alongside the untouched daily51 7 * * *; newdiscoverjob resolves the matrix (weekly → discovered personas; daily cron / dispatch → single skill viagithub.event.schedule);eval-reportnow runs astrategy.matrix.skillwithfail-fast: false; concurrency moved to job level and keyedskill-eval-report-${{ github.event_name }}-${{ matrix.skill }}so daily/weekly/siblings never cancel; step summary now records the scoredtier+ observedmodel(AC feat: feature ideation framework — adversarial proposer/challenger/synthesizer #6). Report-only/non-blocking preserved (continue-on-error). Per-skilleval-report.json+skill-eval-report-<skill>artifact naming unchanged.tests/test_discover_parity_skills.bats; extendedtests/test_skill_eval_report.bats; registered the new file inlint.yml.evals/*/cases.jsonl,evals/case.schema.json, or anyscorer.json(per delivery brief).Cost evidence (AC #7) — from
scripts/evals/eval-cost-estimate.sh, no live scoring dispatchedAssumptions are the script defaults (12k/1.2k engine, 3k/300 judge tokens per case; Opus $5/$25 vs Haiku $1/$5 per Mtok).
Divergence note (AC #7): qa-lead alone is ~$0.85/run → ~$44/yr, ~2× the issue's
$22/yr framing. The gap is purely held-out case count: the estimate assumed 6 cases; qa-lead now has 9 (and pr-review 12, solution-architect 8). The all-9 total ($231/yr) is in line with the issue's ~$202/yr "all personas" row given those larger case sets. Still trivially cheap for an unattended weekly regression tripwire — no concern, flagged rather than proceeding silently.Local check output (provisional — not the pushed run)
Notes
deep-review(no engine) stays Haiku-tier and is correctly excluded — no skill silently upgraded (AC test issue from agent #1).[]→ zero matrix jobs, never a crash.don-petry commentedon Sep 13, 2026
Dev-Lead: Implementation Complete — PR #1814
The implementation for issue #1702 is durable: commits are pushed and a pull request is open. This record is backed by verifiable artifacts you can confirm in one click.
5c1102376463a4f490e2ec6976d2021846391fb3Review happens on the PR. Acceptance criteria and test results are evidenced by the PR's diff and CI checks — not asserted here. If a later stage fails, this claim is retracted in place.
feat: implement issue #1702 — Score persona eval sets weekly at parit…