Skip to content

feat: implement issue #747 — [Phase 1] Make the Skill Eval Report visible — surface regression/error outcomes (no longer silent)#754

Merged
don-petry merged 7 commits into
mainfrom
dev-lead/issue-747-20260615-0027
Jun 15, 2026
Merged

feat: implement issue #747 — [Phase 1] Make the Skill Eval Report visible — surface regression/error outcomes (no longer silent)#754
don-petry merged 7 commits into
mainfrom
dev-lead/issue-747-20260615-0027

Conversation

@don-petry

Copy link
Copy Markdown
Collaborator

Closes #747

Implemented by dev-lead agent. Please review.

…ible — surface regression/error outcomes (no longer silent)
@don-petry
don-petry requested a review from a team as a code owner June 15, 2026 00:38
@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.
To continue using code reviews, you can upgrade your account or add credits to your account and enable them for code reviews in your settings.

@coderabbitai

coderabbitai Bot commented Jun 15, 2026

Copy link
Copy Markdown

Warning

Review limit reached

@don-petry, we couldn't start this review because you've reached your PR review rate limit.

More reviews will be available in 23 minutes and 30 seconds. Learn how PR review limits work.

Your organization has used up its prepaid credits, and credit purchases are no longer available. Enable the review add-on in the billing tab to keep reviews running — you're only billed for reviews past your plan's rate limits ($0.25/file).

⌛ How to resolve this issue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans include higher PR review limits than trial, open-source, and free plans. In all cases, reviews become available again over time. During sustained high-volume PR review activity, CodeRabbit may temporarily slow when the next review becomes available.

Please see our Fair Usage Limits Policy for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 98cc78db-bd87-4802-a826-0f64c9d845ee

📥 Commits

Reviewing files that changed from the base of the PR and between ecc9e25 and 669fd6c.

📒 Files selected for processing (5)
  • .github/workflows/lint.yml
  • .github/workflows/skill-eval-report.yml
  • scripts/evals/notify-eval-health.sh
  • tests/test_eval_health_notify.bats
  • tests/test_skill_eval_report.bats
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch dev-lead/issue-747-20260615-0027

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@don-petry

Copy link
Copy Markdown
Collaborator Author

Dev-Lead — review-changes (no-changes)

No changes were needed for this PR.

@don-petry
don-petry enabled auto-merge (squash) June 15, 2026 00:39

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces a new bash script notify-eval-health.sh along with comprehensive BATS tests to manage and de-duplicate GitHub tracking issues for daily Skill Eval outcomes. The script handles pass, regression, and error outcomes, updating or closing tracking issues accordingly. The review feedback highlights a robustness issue where the script could crash under set -e if the report JSON is valid but incomplete (e.g., missing .failed or .cases keys), and provides a code suggestion to safely default these values in jq.

Comment thread scripts/evals/notify-eval-health.sh
@don-petry
don-petry disabled auto-merge June 15, 2026 00:40
coderabbitai[bot]
coderabbitai Bot previously approved these changes Jun 15, 2026
@don-petry

Copy link
Copy Markdown
Collaborator Author

Dev-Lead — fix-bot-comment (applied)

Changes committed and pushed.

@don-petry

Copy link
Copy Markdown
Collaborator Author

Dev-Lead — review-changes (applied)

Changes committed and pushed.

@don-petry
don-petry enabled auto-merge (squash) June 15, 2026 00:50
@don-petry
don-petry disabled auto-merge June 15, 2026 00:50
@don-petry

Copy link
Copy Markdown
Collaborator Author

Dev-Lead — review-changes (no-changes)

No changes were needed for this PR.

@don-petry
don-petry enabled auto-merge (squash) June 15, 2026 00:52
@don-petry
don-petry disabled auto-merge June 15, 2026 11:28
@don-petry

Copy link
Copy Markdown
Collaborator Author

Dev-Lead — review-changes (no-changes)

No changes were needed for this PR.

@don-petry
don-petry enabled auto-merge (squash) June 15, 2026 11:28
@don-petry
don-petry disabled auto-merge June 15, 2026 11:39
@don-petry

Copy link
Copy Markdown
Collaborator Author

Dev-Lead — fix-bot-comment (no-changes)

Agent reasoning
  - `.cases` access safely filters with `select(type == "array") // []` to prevent iteration errors on null/missing values
  - The fix is in place and the review thread is already resolved with don-petry's fix reply [replied + thread resolved]
**Files changed:** 
- `.github/workflows/lint.yml`
- `.github/workflows/skill-eval-report.yml`
- `scripts/evals/notify-eval-health.sh`
- `tests/test_eval_health_notify.bats`
- `tests/test_skill_eval_report.bats`
**Skipped (informational):** 0
The PR is ready for merge — all issues are addressed and no Tier 1 blockers remain.

@don-petry
don-petry enabled auto-merge (squash) June 15, 2026 11:40

@donpetry-bot donpetry-bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Automated review — APPROVED ✓

Risk: MEDIUM
Reviewed commit: c622d1437ae6703ab2b1609d44ebae95e912a326
Review mode: triage-approved (single reviewer)

Summary

Phase-1 visibility layer for the daily Skill Eval Report (#747): a new offline-tested notifier (notify-eval-health.sh) opens/updates/closes a single de-duplicated eval-health tracking issue on regression/error and stays silent on healthy passes, plus a least-privilege issues:write grant and notify step wired into skill-eval-report.yml. Confirms the triage low-risk assessment.

Linked issue analysis

Closes #747. All acceptance criteria are satisfied: (1) regression/error produces a visible, de-duplicated tracking issue (not just an Actions annotation); (2) healthy pass with no open issue makes zero noise; (3) workflow stays non-blocking — no gating added; (4) least-privilege: only issues:write added, contents:read retained for checkout, with tests asserting no contents:write / write-all; (5) an offline stub test (tests/test_eval_health_notify.bats, no network) covers open/update/close + de-dupe and is wired into lint.yml.

Findings

No blocking findings.

  • Security: workflow triggers only on schedule + workflow_dispatch (no pull_request_target), top-level permissions: {}, job re-grants only issues:write. Notify-step env uses trusted GitHub context (github.token, github.repository, steps.eval.outputs.outcome validated by the script's case guard) — no untrusted-input injection surface. Script quotes variables, uses mktemp + --body-file, and ignores label-create failures idempotently.
  • Resolved review thread: gemini-code-assist flagged a potential jq crash on a valid-but-incomplete report under set -e. Fixed in notify-eval-health.sh via // defaults (.score // "N/A", .failed // "0", etc.) and a guarded array iteration (.cases | select(type == "array") // []). Thread is resolved.
  • Idempotency/de-dupe: lookup keys on a stable per-skill title scoped by the eval-health label and open state; verified by tests for create-once, update-in-place, recovery-close, and no-op-on-healthy.

CI status

All required checks green. SUCCESS: Lint, shellcheck/ShellCheck, bats, unit-tests, CodeQL (actions + python), agent-shield/AgentShield, Agent Security Scan, Secret scan (gitleaks), SonarCloud, validate-agent-profiles, gh-aw-compile, review, CodeRabbit. Benign SKIPPED: dependency-audit ecosystem jobs, dependabot-automerge, dev-lead/ci-relay. No failing checks.


Reviewed automatically by the PR-review agent (single-reviewer mode: fable 5). Reply if you need a human review.

@don-petry
don-petry disabled auto-merge June 15, 2026 11:48
@don-petry

Copy link
Copy Markdown
Collaborator Author

Dev-Lead — waiting on PR blockers (intent: review-changes)

PR: #754
No changes were committed, but the PR still has blocking checks or reviews (failing or cancelled checks, or changes-requested reviews). The retry cron will re-attempt automatically. Next attempt after: 2026-06-15T12:19:31Z

@don-petry

Copy link
Copy Markdown
Collaborator Author

Note

@don-petry I reviewed this PR and no code changes were needed, but it still has blocking checks or reviews (failing or cancelled checks, or changes-requested reviews), so I cannot mark it done yet. I'll re-check automatically.
Next attempt after: 2026-06-15T12:19:31Z

@don-petry
don-petry enabled auto-merge (squash) June 15, 2026 11:49
@sonarqubecloud

Copy link
Copy Markdown

@don-petry
don-petry merged commit 5fd164e into main Jun 15, 2026
26 of 28 checks passed
@don-petry
don-petry deleted the dev-lead/issue-747-20260615-0027 branch June 15, 2026 12:06

@donpetry-bot donpetry-bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Automated review — APPROVED ✓

Risk: MEDIUM
Reviewed commit: 669fd6c47fab4c98ad351718f08eb7c86d0dd552
Review mode: triage-approved (single reviewer)

Summary

Phase-1 visibility layer for the daily Skill Eval Report (#747): a new offline-tested notifier (scripts/evals/notify-eval-health.sh) opens/updates/closes a single de-duplicated eval-health tracking issue on regression/error and stays silent on healthy passes, plus a least-privilege issues:write grant and an always() notify step wired into skill-eval-report.yml. Confirms the triage low-risk assessment; the prior bot approval at c622d14 still holds since the only intervening commits are merge-from-main (no change to the PR's own 5 files).

Linked issue analysis

Closes #747. Acceptance criteria satisfied: (1) regression/error produces a visible, de-duplicated tracking issue rather than just an Actions annotation; (2) a healthy pass with no open issue makes zero noise, and a pass after a prior open issue comments + closes it (recovery); (3) the workflow stays non-blocking — no gating added, notify step is report-only; (4) least-privilege — only issues:write is added while contents:read is retained for checkout, with tests asserting no contents:write and no write-all; (5) an offline stub test (tests/test_eval_health_notify.bats, no network) covers open/update/close + de-dupe and is wired into lint.yml.

Findings

No blocking findings.

  • Security: skill-eval-report.yml triggers on schedule + workflow_dispatch only (no pull_request_target). Notify-step env uses trusted GitHub context (github.token, github.repository, github.run_id) and steps.eval.outputs.outcome, which the script validates via an explicit case guard before use — no untrusted-input injection surface. The script runs set -euo pipefail, quotes variables, uses mktemp + --body-file, and idempotently ignores label-create failures.
  • Resolved review thread: gemini-code-assist flagged a high-priority jq crash under set -e on a valid-but-incomplete report (missing .failed/.cases). The current head fixes it via jq // defaults (.score // "N/A", .failed // "0", etc.) and a guarded array iteration ((.cases | select(type == "array") // [])). Verified resolved at the reviewed SHA.
  • Idempotency/de-dupe: lookup keys on a stable per-skill title scoped by the eval-health label and open state; bats tests verify create-once, update-in-place, recovery-close, and no-op-on-healthy.
  • SonarCloud Quality Gate passed (0 new issues, 0 security hotspots).

CI status

All required checks green. SUCCESS: Lint, shellcheck/ShellCheck, bats, unit-tests, validate-agent-profiles, gh-aw-compile, Compile agentic workflows, CodeQL (actions + python), agent-shield/AgentShield, Agent Security Scan, Secret scan (gitleaks), holdout-guard, SonarCloud + SonarCloud Code Analysis, CodeRabbit. Benign SKIPPED: dependency-audit ecosystem jobs (npm/pnpm/pip/cargo/go), dependabot-automerge. CANCELLED: dev-lead/dispatch and dev-lead/ci-relay — these are the Dev-Lead Agent's own concurrency-cancelled jobs (known-benign per #608/#609), not real CI failures. review/review is this in-progress run. No failing checks.


Reviewed automatically by the PR-review agent (single-reviewer mode: fable 5). Reply if you need a human review.

don-petry added a commit that referenced this pull request Jul 18, 2026
Two regressions from the review-agent's push (b6f12fa):

1. It DELETED the CRLF test that Gemini specifically requested and that guards
   the '\r'-stripping fix. Restored — without it, a future revert of the strip
   would pass CI silently.

2. It changed the prompt to `gh api "$COMMENT_URL"` (correct target: an API url),
   but the router (#754, merged) currently sends `.html_url` — and `gh api`
   cannot fetch a github.com browser url, so the comment-body read fails. The
   prompt already degrades gracefully ("if that fails, proceed from the item"),
   so the soak still works; but the contract must be made real.

   The fix is in the ROUTER, not here: it should send the comment's `.url` (API)
   not `.html_url`. Companion PR on petry-projects/.github does that. Documented
   the contract in the prompt so the two sides agree.

Verification
- bats tests/persona_runner.bats: 22/22 (CRLF test back).
- shellcheck --severity=warning -x: clean.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
don-petry added a commit that referenced this pull request Jul 18, 2026
* feat(personas): the persona runtime — dispatch side of the mention framework

Closes the loop the router opened. petry-projects/.github#754 detects an
`@petry-projects/<role>` mention and fires a `persona-mention`
repository_dispatch at this repo; nothing listened. This is what listens.

Architecture: ONE runner, single-homed

The runner is NOT fanned out to the fleet. Every mention across every repo funnels
through the router's dispatch to THIS repo, so the runner lives only here and is
called locally (uses: ./). That is why it needs no channel tag or canary
registration — unlike the router (`persona-mention`), which IS consumed by fleet
repos and rolls out through the rings. One runner serves every persona,
convention-driven (prompts/<id>/advisory.md), never one workflow per persona
(§4.1: per-agent workflows are the drift the framework exists to prevent).

The recursion marker is closed from BOTH sides

The router skips any comment carrying '<!-- persona:'. This runner's prompt and
its pr_comment_has_marker guard REQUIRE every advisory's first line to be
'<!-- persona:<id> -->'. So a persona's own comment can never re-summon it or any
persona named in the thread — the .github-private#860 failure (1,481 acks in
4.5h), closed from the writing side.

Contents
- prompts/qa-lead/advisory.md — qa-lead's advisory behaviour: read the vendored
  bmad-tea skill by path, assess test-risk (risk vs value, no manufactured risk),
  post ONE advisory comment. Advisory only — no writes, no PRs, no labels.
- scripts/lib/persona-runner.sh — the pure core: payload re-validation (this
  runner is a SEPARATE trust boundary — a repository_dispatch can be sent by
  anything with a token, so a malformed persona id must never reach a path
  interpolation), advisory-prompt resolution by convention, and the shared marker.
- .github/workflows/persona-runner-reusable.yml — the runtime: resolve prompt →
  install claude-code → run headless → the prompt posts one marked comment. PAT
  (not github.token) because the item lives in a DIFFERENT repo. Rate-limit is a
  soft skip, matching ci-failure-analyst.
- .github/workflows/persona-runner.yml — thin caller: maps the dispatch payload to
  the reusable's inputs, nothing else.
- tests/persona_runner.bats — 15 tests, weighted to the marker and payload
  re-validation (path traversal, bad ids, missing prompt → rc 3 not a crash).
- lint.yml — wires the suite into CI (a bats suite with no runner is unenforced).

A persona with no prompts/<id>/advisory.md yet is a clean no-op ("no runtime
wired"), not a failure — a persona may declare an address before its runtime
exists.

NOT wired live here. persona-runner-reusable.yml is workflow_call-only, so per
the org standard it must be set disabled_manually after merge (GitHub ignores the
flag for workflow_call). And no mention reaches it until the router release is cut
and .github-private adopts the `persona-mention` stub — the `next`-ring
enablement, which follows in sequence. This PR is the runtime; turning it on is
the next step.

Verification
- bats tests/persona_runner.bats: 15/15.
- shellcheck --severity=warning -x scripts/lib/persona-runner.sh: clean.
- actionlint (CI's ignores) on both workflows: clean.
- prompts/** is a markdownlint ignore (agent instructions, not prose).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* fix(reviews): address review comments [skip ci-relay]

* fix(personas): make the recursion marker MECHANICALLY enforced (review)

Copilot's most important finding: the agent posted its OWN comment, so the
marker was only prompt-REQUESTED, not enforced. An agent that forgot it would
post an unmarked comment → self-summon → #860 (1,481 acks in 4.5h). My
"closed from both sides" claim was false. Restructured, not patched.

Read/write split

- The AGENT now runs with github.token, which reads the PUBLIC source repo but
  CANNOT post to it (scoped to THIS repo). It PRINTS the advisory between
  sentinels; it never receives GH_PAT_WORKFLOWS.
- The WORKFLOW extracts the body, guarantees the marker (pr_ensure_marker —
  prepends if the agent omitted it), and is the ONLY writer, using the PAT.

So an agent that forgets the marker cannot post an unmarked comment because it
cannot post at all. The guard is now mechanical. New helpers pr_extract_advisory
/ pr_ensure_marker, tested to the invariant "the posted body always starts with
the marker".

Other review fixes

- Gemini (high): pr_comment_has_marker kept the trailing '\r' from GitHub's CRLF
  bodies, so the guard silently never matched. Strip it; CRLF test added.
- Copilot: resolve step conflated rc 2 (malformed/hostile id) with rc 3 (no
  runtime). Now rc 2 FAILS loudly, rc 3 is the benign skip.
- Copilot: concurrency group keyed only on item_number, which is empty for
  discussions → all discussion mentions for one persona+repo collapsed into one
  group. Added comment_url to the key.
- Copilot: prompt used $COMMENT_URL (an html_url) with `gh api`, referenced an
  undefined $BODY, and put a parenthetical on the marker line. Rewritten: the
  agent derives the API url, prints between sentinels (no self-post, no $BODY),
  and the marker is alone on the first body line.
- Gemini: `head -400` → `head -n 400 || true` (POSIX + no SIGPIPE under pipefail).

Discussion posting is explicitly a no-op-with-notice for now (the issue-comments
endpoint doesn't serve discussions); wired when the discussion path lands.

Verification
- bats tests/persona_runner.bats: 21/21 (15 + 6: CRLF, sentinel extraction x2,
  marker-prepend, unchanged-when-present, and the post-body invariant).
- shellcheck --severity=warning -x scripts/lib/persona-runner.sh: clean.
- actionlint (CI ignores) on both workflows: clean.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* fix(reviews): address review comments [skip ci-relay]

* fix(personas): restore the CRLF test; pin the COMMENT_URL contract

Two regressions from the review-agent's push (b6f12fa):

1. It DELETED the CRLF test that Gemini specifically requested and that guards
   the '\r'-stripping fix. Restored — without it, a future revert of the strip
   would pass CI silently.

2. It changed the prompt to `gh api "$COMMENT_URL"` (correct target: an API url),
   but the router (#754, merged) currently sends `.html_url` — and `gh api`
   cannot fetch a github.com browser url, so the comment-body read fails. The
   prompt already degrades gracefully ("if that fails, proceed from the item"),
   so the soak still works; but the contract must be made real.

   The fix is in the ROUTER, not here: it should send the comment's `.url` (API)
   not `.html_url`. Companion PR on petry-projects/.github does that. Documented
   the contract in the prompt so the two sides agree.

Verification
- bats tests/persona_runner.bats: 22/22 (CRLF test back).
- shellcheck --severity=warning -x: clean.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-authored-by: donpetry-bot <281750570+donpetry-bot@users.noreply.github.com>
don-petry added a commit that referenced this pull request Jul 18, 2026
Registering `persona-mention` in canary-rings.json (#754) is not enough to cut
its release: cut-release.sh keeps its OWN hardcoded agent allowlist (valid_agent
/ cross_repo_agent), and the router was absent from it — so
`cut-release.sh persona-mention 1.0.0 --channel next` failed with "unknown
agent". This is the two-registry drift the framework fights, in the release
tooling.

persona-mention is a cross-repo agent exactly like pr-review-mention: its
reusable lives in petry-projects/.github, this repo holds only the caller stub,
so its release/channel tags resolve against .github (CROSS_REPO_TARGET). Added it
beside pr-review-mention in cross_repo_agent(), the usage comment, and the
unknown-agent error string.

Verification
- bats tests/test_cut_release.bats: 61/61 (2 new: valid_agent + cross_repo_agent
  accept persona-mention).
- shellcheck --severity=warning -x scripts/cut-release.sh: clean.

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Phase 1] Make the Skill Eval Report visible — surface regression/error outcomes (no longer silent)

2 participants