feat(design-review): close design-reviewer loop on area:dashboard PRs #160
No reviewers
Labels
No labels
area:agents
area:dashboard
area:database
area:design
area:design-review
area:flows
area:infra
area:meta
area:security
area:sessions
area:webhook
area:workdir
security
type:bug
type:chore
type:meta
type:user-story
No milestone
No project
No assignees
2 participants
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
charles/claude-hooks!160
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "boss/155"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Summary
Closes #155 (M17-4).
reviewerForPr(author, labels)replacesreviewerForAuthorin the CI gate (decidePostCiAction) and the changes-requested round-cap. Label match beats author mapping: adev-authored PR witharea:dashboardnow routes todesign-reviewerthe same way adesigner-authored PR does.handleReviewRequested/handleChangesRequestedhand the mergedPR labels ∪ linked-issue labelsset to the pool scheduler so the match-labels tier triggers.types.design-reviewerinconfig/agents.jsongrowsdefault_match_labels: ["area:dashboard"]. The seed path uses it on first boot; a newapplyDefaultMatchLabelsmigration at startup upgrades any pre-existing<type>-defaultrow whosematch_labelsis stillNULL(idempotent, leaves operator-edited rows alone).skills/design-review.mdis rewritten for the PR path: read the diff, comparedashboard.htmlchanges to any Penpot frame linked in the PR body, walk every#abcdef/#abchex literal in the diff and flag anything missing fromdesign/tokens.json, ship the verdict throughmcp__forgejo__create_pull_review(APPROVED / REQUEST_CHANGES — a plain issue comment would stall the PR per #111). The legacy Penpot issue-scoped workflow stays in the same file under a second section; the skill branches on whetherget_pull_request_by_indexreturns a PR or 404s into an issue.design-reviewjoinsreviewinSTATELESS_SKILLSso each dispatch reads the current state fresh.Design review flowsection + CLAUDE.mdLabel routingupdate cover the two triggers, the pool-seeding contract, and thecreate_pull_reviewvs.create_issue_commentrule.Test plan
bun x tsc --noEmit— cleanbun x biome check src/— cleanbun test— 574 / 574 pass (new coverage:reviewerForPrlabel-wins cases inwebhook-routing.test.ts; design-reviewer /area:dashboardpool selection inpool.test.ts;default_match_labelsseed +applyDefaultMatchLabelsmigration idempotency + operator-override survival indb.test.tsandwebhook-config.test.ts)decidePostCiActionpicksdesign-revieweron CI green, the skill reads the diff, and acreate_pull_reviewlands (not a plain comment).🤖 Generated with Claude Code
CI still pending at review time (run #1751, sha
d23ac23). Stepping off the review request — will be re-dispatched automatically when CI completes.d23ac239b45cfc08160eDesign review — PR #160
Round: 1 (no prior reviews by reviewer)
CI: green (run #1756, sha
5cfc081, 3m22s)Routing (webhook-routing.ts + webhook-ci.ts)
reviewerForPr(author, labels) correctly gives label match priority over author mapping in both decidePostCiAction (CI gate) and handleChangesRequested (round-cap). The staleReview and reviewerInRequestedList checks in decidePostCiAction now both use the label-aware result, so bounce and skip paths stay coherent. No issues.
Pool seeding + migration (db.ts, webhook-config.ts, config/agents.json)
applyDefaultMatchLabels correctly guards on match_labels IS NULL — operator-edited rows survive the migration. Idempotent on every restart. seedDefaultAgents correctly accepts the initial match_labels per type so fresh deployments get it too. config/agents.json has default_match_labels: [area:dashboard] on design-reviewer. All correct.
handleReviewRequested label-aware dispatch (webhook-handlers.ts)
fetchPrDispatchLabels merges PR labels and linked-issue labels before the dispatchByType call. area:dashboard on the PR selects the design-reviewer-default pool member; area:security on the linked issue selects the security-specialised reviewer. Both sources needed, both wired correctly.
STATELESS_SKILLS (webhook-handlers.ts line 130)
design-review added alongside review. The check STATELESS_SKILLS.has(base) receives the already-resolved skill name from skillForAgent(agent.type, review) which returns design-review for design-reviewer. Correct chain.
skills/design-review.md
Well-structured dual-context skill: context detection via get_pull_request_by_index before branching. PR path covers round check, CI check, layout/Penpot comparison, token-taxonomy hex walk, accessibility spot-checks, verdict via create_pull_review only. Legacy issue path preserved and clearly separated. Pending-CI carve-out documented. Never use state COMMENT rule is explicit.
forgejo-api.ts
PullRequestDetail now includes labels and body fields — needed so decidePostCiAction can read PR labels without an extra API call and fetchPrDispatchLabels can parse the body for Closes #N linkage. Typed as optional to match existing null-safe call patterns. Clean.
Tests
574/574 passing. New coverage: reviewerForPr label-wins, design-reviewer pool selection, applyDefaultMatchLabels idempotency and operator-override survival.
Acceptance criteria
APPROVED — implementation is correct, complete, and CI is green.
Design review — PR #160
Round: 1 (no prior reviews by reviewer)
CI: green (run #1756, sha
5cfc081, 3m22s)Routing (webhook-routing.ts + webhook-ci.ts)
reviewerForPr(author, labels) correctly gives label match priority over author mapping in both decidePostCiAction (CI gate) and handleChangesRequested (round-cap). The staleReview and reviewerInRequestedList checks in decidePostCiAction now both use the label-aware result, so bounce and skip paths stay coherent. No issues.
Pool seeding + migration (db.ts, webhook-config.ts, config/agents.json)
applyDefaultMatchLabels correctly guards on match_labels IS NULL — operator-edited rows survive the migration. Idempotent on every restart. seedDefaultAgents correctly accepts the initial match_labels per type so fresh deployments get it too. config/agents.json has default_match_labels: [area:dashboard] on design-reviewer. All correct.
handleReviewRequested label-aware dispatch (webhook-handlers.ts)
fetchPrDispatchLabels merges PR labels and linked-issue labels before the dispatchByType call. area:dashboard on the PR selects the design-reviewer-default pool member; area:security on the linked issue selects the security-specialised reviewer. Both sources needed, both wired correctly.
STATELESS_SKILLS (webhook-handlers.ts line 130)
design-review added alongside review. The check STATELESS_SKILLS.has(base) receives the already-resolved skill name from skillForAgent(agent.type, review) which returns design-review for design-reviewer. Correct chain.
skills/design-review.md
Well-structured dual-context skill: context detection via get_pull_request_by_index before branching. PR path covers round check, CI check, layout/Penpot comparison, token-taxonomy hex walk, accessibility spot-checks, verdict via create_pull_review only. Legacy issue path preserved and clearly separated. Pending-CI carve-out documented. Never use state COMMENT rule is explicit.
forgejo-api.ts
PullRequestDetail now includes labels and body fields — needed so decidePostCiAction can read PR labels without an extra API call and fetchPrDispatchLabels can parse the body for Closes #N linkage. Typed as optional to match existing null-safe call patterns. Clean.
Tests
574/574 passing. New coverage: reviewerForPr label-wins, design-reviewer pool selection, applyDefaultMatchLabels idempotency and operator-override survival.
Acceptance criteria
APPROVED — implementation is correct, complete, and CI is green.
Design review — PR #160
Round: 1 (no prior reviews by reviewer)
CI: ✅ green (run #1756, sha
5cfc081, 3m22s)Routing (
webhook-routing.ts+webhook-ci.ts)reviewerForPr(author, labels)correctly gives label match priority over author mapping in bothdecidePostCiAction(CI gate) andhandleChangesRequested(round-cap). ThestaleReviewandreviewerInRequestedListchecks indecidePostCiActionnow both use the label-aware result, so bounce and skip paths stay coherent. No issues.Pool seeding + migration (
db.ts,webhook-config.ts,config/agents.json)applyDefaultMatchLabelscorrectly guards onmatch_labels IS NULL— operator-edited rows survive the migration. Idempotent on every restart.seedDefaultAgentscorrectly accepts the initialmatch_labelsper type so fresh deployments get it too.config/agents.jsonhasdefault_match_labels: ["area:dashboard"]ondesign-reviewer. All correct.handleReviewRequestedlabel-aware dispatch (webhook-handlers.ts)fetchPrDispatchLabelsmerges PR labels and linked-issue labels before thedispatchByTypecall.area:dashboardon the PR selects thedesign-reviewer-defaultpool member;area:securityon the linked issue selects the security-specialised reviewer. Both sources needed, both wired correctly.STATELESS_SKILLS(webhook-handlers.tsline 130)"design-review"added alongside"review". The checkSTATELESS_SKILLS.has(base)receives the already-resolved skill name fromskillForAgent(agent.type, "review")which returns"design-review"fordesign-reviewer. Correct chain.skills/design-review.mdWell-structured dual-context skill: context detection via
get_pull_request_by_indexbefore branching. PR path covers round check, CI check, layout/Penpot comparison, token-taxonomy hex walk, accessibility spot-checks, verdict viacreate_pull_reviewonly. Legacy issue path preserved and clearly separated. Pending-CI carve-out documented. "Never usestate: "COMMENT"" rule is explicit.forgejo-api.tsPullRequestDetailnow includeslabels?andbody?fields — needed sodecidePostCiActioncan read PR labels without an extra API call andfetchPrDispatchLabelscan parse the body forCloses #Nlinkage. Typed as optional to match existing null-safe call patterns. Clean.Tests
574/574 passing. New coverage:
reviewerForPrlabel-wins, design-reviewer pool selection,applyDefaultMatchLabelsidempotency and operator-override survival.Acceptance criteria
design-reviewerdispatched onarea:dashboardPRs regardless of authorarea:dashboardmatch_labels seeded ondesign-reviewer-default(first-boot + migration)skills/design-review.mddocuments PR diff review + hex token-taxonomy checkcreate_pull_reviewenforced in skill; plain comment explicitly forbiddenAPPROVED — implementation is correct, complete, and CI is green.