Skip to content

feat(compliance): fire badge issuance on owner_test runs (closes #4376)#4391

Open
bokelley wants to merge 2 commits into
mainfrom
claude/issue-4376-badge-issuance-owner-test
Open

feat(compliance): fire badge issuance on owner_test runs (closes #4376)#4391
bokelley wants to merge 2 commits into
mainfrom
claude/issue-4376-badge-issuance-owner-test

Conversation

@bokelley
Copy link
Copy Markdown
Contributor

Summary

  • Extract the per-version badge fan-out (membership-org resolution + processAgentBadges loop across SUPPORTED_BADGE_VERSIONS) from compliance-heartbeat.ts into a shared runBadgeFanOut() helper in services/badge-issuance.ts.
  • Call the helper from the two owner-driven test paths immediately after recordComplianceRun():
    • member-tools.ts evaluate_agent_quality (full comply) for an agent owner — fires badges off the canonical write so an owner who just fixed compliance sees the badge update on the next page load.
    • registry-api.ts POST /registry/agents/:encodedUrl/storyboard/:storyboardId/run (single storyboard) — same effect for in-place storyboard re-runs from the dashboard.
  • Verification-change Slack notifications stay scoped to heartbeat — owner runs already deliver the result via chat / HTTP response.

Why the helper reads getStoryboardStatuses() instead of trusting the run's own inputs

The single-storyboard endpoint (storyboard/:storyboardId/run) supplies only one storyboard status in dbInput. If the helper used those inputs verbatim, deriveVerificationStatus() would treat every other declared specialism as "failing" (its storyboard would be absent from the status map) and degrade unrelated badges as a side effect. Loading the merged latest state from agent_storyboard_status after recordComplianceRun() returns the correct picture for both partial owner runs and full heartbeat runs.

Test plan

  • npx vitest run tests/unit/badge-fan-out.test.ts tests/unit/badge-issuance.test.ts — 17 tests pass.
    • New tests: no-op on empty specialisms, full-status load for partial runs, membership-lapse revoke path, per-version aggregation contract.
  • npx tsc --noEmit -p server/tsconfig.json clean.
  • After merge: spot-check a heartbeat run still emits the verification-change Slack DM (no behavior change there — same code path, just goes through the helper).

Closes #4376.

🤖 Generated with Claude Code

bokelley and others added 2 commits May 11, 2026 08:06
Extract the per-version badge fan-out from compliance-heartbeat.ts into
a shared runBadgeFanOut() helper and call it from both owner-driven test
paths so an owner who just fixed a compliance issue sees their badge
update on the next page load instead of waiting up to a heartbeat cycle.

The helper loads the latest per-storyboard statuses from
agent_storyboard_status (not just what this run touched), which is
required for the single-storyboard run path so a partial test doesn't
degrade badges for storyboards it didn't touch.

Verification-change Slack notifications stay scoped to heartbeat — owner
runs already deliver the result via chat or HTTP response.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 (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.

compliance: fire processAgentBadges on owner_test transitions (skip Slack notify)

1 participant