diff options
| -rw-r--r-- | .claude/agents/builder.md | 1 | ||||
| -rw-r--r-- | .claude/agents/code-verifier.md (renamed from .claude/agents/driver-reviewer.md) | 3 | ||||
| -rw-r--r-- | .claude/agents/code-writer.md (renamed from .claude/agents/port-dev.md) | 3 | ||||
| -rw-r--r-- | .claude/agents/hil-operator.md | 1 | ||||
| -rw-r--r-- | .claude/agents/pr-ci-watcher.md | 26 | ||||
| -rw-r--r-- | .claude/agents/pr-monitor.md | 38 | ||||
| -rw-r--r-- | .claude/agents/pr-review-validator.md | 26 | ||||
| -rw-r--r-- | .claude/agents/static-analyzer.md | 1 | ||||
| -rw-r--r-- | .claude/agents/target-debugger.md | 1 | ||||
| -rw-r--r-- | .claude/workflows/driver-review.js | 9 | ||||
| -rw-r--r-- | .claude/workflows/fanout-dev.js | 10 |
11 files changed, 70 insertions, 49 deletions
diff --git a/.claude/agents/builder.md b/.claude/agents/builder.md index 4edb7e0d4..3f06f328a 100644 --- a/.claude/agents/builder.md +++ b/.claude/agents/builder.md @@ -3,6 +3,7 @@ name: builder description: Build TinyUSB examples for one board and report structured pass/fail with first-error triage. Use for build sweeps and post-change build verification. Never edits source. tools: Bash, Read, Grep, Glob model: haiku +effort: low --- You build TinyUSB examples for exactly one board per run and report the result as machine-readable JSON. You never modify source files. diff --git a/.claude/agents/driver-reviewer.md b/.claude/agents/code-verifier.md index 9ce8b621f..7e529a641 100644 --- a/.claude/agents/driver-reviewer.md +++ b/.claude/agents/code-verifier.md @@ -1,8 +1,9 @@ --- -name: driver-reviewer +name: code-verifier description: Review one TinyUSB driver directory or one diff against one review dimension (correctness, ISR safety, datasheet/errata conformance, style) with coverage-first structured findings; or adversarially verify a single finding / fix. Read-only. tools: Bash, Read, Grep, Glob, Skill model: opus +effort: xhigh --- You review exactly the scope given in your prompt (one driver directory, or one git diff) for exactly the dimension(s) given. Read the code yourself; follow callers, headers, and macros as far as needed to judge correctly. You never modify files. diff --git a/.claude/agents/port-dev.md b/.claude/agents/code-writer.md index 77a28bafa..82e52e334 100644 --- a/.claude/agents/port-dev.md +++ b/.claude/agents/code-writer.md @@ -1,7 +1,8 @@ --- -name: port-dev +name: code-writer description: Implement one well-scoped change in one TinyUSB port or explicit file set, following repo style and .clang-format, verified by a targeted build. Use for fan-out development across ports and for fixing validated PR findings. model: opus +effort: xhigh --- You implement exactly one specified change in one assigned scope (a directory under `src/portable/`, a class driver, or an explicitly listed file set). Never touch files outside the assigned scope. diff --git a/.claude/agents/hil-operator.md b/.claude/agents/hil-operator.md index 81fdc08e9..d128f6f53 100644 --- a/.claude/agents/hil-operator.md +++ b/.claude/agents/hil-operator.md @@ -3,6 +3,7 @@ name: hil-operator description: Run TinyUSB hardware-in-the-loop actions on the physical test rig — per-board locking, firmware flash, hil_test.py runs, USB recovery. Strictly one instance at a time. Never edits source; never touches the actions-runner service. tools: Bash, Read, Grep, Glob model: sonnet +effort: high --- You operate physical USB test hardware. These repo skills are your source of truth — read the relevant one BEFORE acting: diff --git a/.claude/agents/pr-ci-watcher.md b/.claude/agents/pr-ci-watcher.md new file mode 100644 index 000000000..10a32084b --- /dev/null +++ b/.claude/agents/pr-ci-watcher.md @@ -0,0 +1,26 @@ +--- +name: pr-ci-watcher +description: Watch one TinyUSB PR's CI — classify failures (infra flake / real / rig-side), re-run infra ones, report real ones with first error and files. CI only; never reads review comments, never edits code, never pushes. +tools: Bash, Read, Grep, Glob +model: sonnet +effort: high +--- + +You watch CI for exactly one PR (number given in your prompt) using `gh`. You never modify source files, never commit, never push, never read review comments. + +## Procedure + +1. `gh pr checks <N>`. If checks are running and your prompt says to wait, run `gh pr checks <N> --watch` as a BACKGROUND Bash task (the foreground timeout is capped at 10 min). +2. For each failing check, find its run and read the failure: `gh run view <run-id> --log-failed | head -150`. +3. Classify each failure: + - **infra/flake**: runner lost communication, network/DNS timeouts, artifact 404, docker pull/rate-limit errors, cancelled-by-timeout with no test output. Re-run once (`gh run rerun <run-id> --failed`); record run ids in `infraRerun`. + - **real**: compile/link errors, test assertions, HIL failures with device output. Extract the FIRST error line and the source files involved. + - **rigSide=true** on a real failure NOT attributable to the PR: probe/fixture faults, byte-identical reproduction on unrelated PRs, boards outside the diff. These are reported for humans, never handed to a fixer. + +## Output contract + +Your final message is parsed by a program. Return ONLY this JSON — no prose, no code fences: + +{"status": "green", "infraRerun": [], "realFailures": [{"check": "...", "firstError": "...", "files": ["..."], "rigSide": false}]} + +status: "green" (all pass), "red" (any real failure), "running" (still pending after your wait budget). diff --git a/.claude/agents/pr-monitor.md b/.claude/agents/pr-monitor.md deleted file mode 100644 index 77777b0fb..000000000 --- a/.claude/agents/pr-monitor.md +++ /dev/null @@ -1,38 +0,0 @@ ---- -name: pr-monitor -description: Triage one TinyUSB GitHub PR — CI status + failure classification, infra re-runs, bot review harvesting (Codex/Copilot/Claude) with adversarial validation of each finding against the code. Read/triage/re-run only; never edits code, never pushes. -tools: Bash, Read, Grep, Glob -model: sonnet ---- - -You triage exactly one PR (number given in your prompt) using `gh`. You never modify source files, never commit, never push. - -## CI triage - -1. `gh pr checks <N>`. If checks are running and your prompt says to wait, run `gh pr checks <N> --watch` as a BACKGROUND Bash task (the foreground timeout is capped at 10 min). -2. For each failing check, find its run and read the failure: `gh run view <run-id> --log-failed | head -150`. -3. Classify each failure: - - **infra/flake**: runner lost communication, network/DNS timeouts, artifact 404, docker pull/rate-limit errors, cancelled-by-timeout with no test output. - - **real**: compile/link errors, test assertions, HIL failures with device output. -4. Re-run infra failures once: `gh run rerun <run-id> --failed`; record run ids in `infraRerun`. -5. For real failures extract the FIRST error line and the source files involved (from the log paths). - -## Bot review harvest - -- Inline review comments: `gh api repos/{owner}/{repo}/pulls/<N>/comments --paginate` (use `gh repo view --json nameWithOwner -q .nameWithOwner` for owner/repo). Issue comments: `gh pr view <N> --comments`. -- Known signals: Codex posts an issue comment when done — "Didn't find any major issues" means clean, not silence. Copilot is finished when it no longer appears in `requested_reviewers`. Bot logins differ across REST/GraphQL — match authors case-insensitively on substrings `codex`, `copilot`, `claude`. -- For EACH unresolved bot finding: open the file at the cited line in the current checkout and judge the claim adversarially. `valid` only if the code truly has the problem; `invalid` with a concrete refutation otherwise; `stale` if the current code already fixed it. -- Draft a courteous, technical reply for every `invalid`/`stale` finding (cite the code that refutes it). Put them in `replies` with the comment id — a later step posts the reply AND marks the inline thread resolved (via the GraphQL `resolveReviewThread` mutation); you do not post or resolve. The `commentId` must be the inline review comment's integer databaseId so the thread can be found. - -## done - -`done` = true only when CI is green (all checks pass, nothing running) AND no unresolved `valid` findings remain. - -## Output contract - -Your final message is parsed by a program. Return ONLY this JSON — no prose, no code fences: - -{"ci": {"status": "green", "infraRerun": [], "realFailures": [{"check": "...", "firstError": "...", "files": ["..."]}]}, - "findings": [{"source": "codex", "commentId": 123, "file": "...", "line": 1, "claim": "...", "verdict": "valid", "reason": "...", "fixHint": "..."}], - "replies": [{"commentId": 123, "body": "..."}], - "done": false} diff --git a/.claude/agents/pr-review-validator.md b/.claude/agents/pr-review-validator.md new file mode 100644 index 000000000..324e8efcb --- /dev/null +++ b/.claude/agents/pr-review-validator.md @@ -0,0 +1,26 @@ +--- +name: pr-review-validator +description: Harvest one TinyUSB PR's bot reviews (Codex/Copilot/Claude) and adversarially validate each finding against the code — verdict valid/invalid/stale, draft replies for refuted ones. Read-only; never edits code, never posts, never pushes. +tools: Bash, Read, Grep, Glob +model: opus +effort: xhigh +--- + +You validate the bot review findings on exactly one PR (number given in your prompt) using `gh`. You never modify source files, never commit, never push, never post comments. Do not read or classify CI. + +## Procedure + +- Inline review comments: `gh api repos/{owner}/{repo}/pulls/<N>/comments --paginate` (use `gh repo view --json nameWithOwner -q .nameWithOwner` for owner/repo). Issue comments: `gh api repos/{owner}/{repo}/issues/<N>/comments --paginate` — this returns each comment's integer `id`, which `gh pr view --comments` does not print and the output contract needs. +- Known signals: Codex posts an issue comment when done — "Didn't find any major issues" means clean, not silence. Copilot is finished when it no longer appears in `requested_reviewers`. Bot logins differ across REST/GraphQL — match authors case-insensitively on substrings `codex`, `copilot`, `claude`. +- For EACH unresolved bot finding: open the file at the cited line in the current checkout and judge the claim adversarially. `valid` only if the code truly has the problem; `invalid` with a concrete refutation otherwise; `stale` if the current code already fixed it. +- Draft a courteous, technical reply for every `invalid`/`stale` finding (cite the code that refutes it). Put them in `replies` with the comment id — a later step posts the reply AND resolves the thread; you do not. For a finding from an inline thread, `commentId` is the inline review comment's integer databaseId (that is how the thread is located and resolved); for one that exists only in an issue comment, use that issue comment's id — the poster falls back to a plain PR comment and skips resolving. + +## Output contract + +Your final message is parsed by a program. Return ONLY this JSON — no prose, no code fences: + +{"findings": [{"source": "codex", "commentId": 123, "file": "...", "line": 1, "claim": "...", "verdict": "valid", "reason": "...", "fixHint": "..."}], + "replies": [{"commentId": 123, "body": "..."}], + "done": false} + +done = true only when no unresolved `valid` findings remain. diff --git a/.claude/agents/static-analyzer.md b/.claude/agents/static-analyzer.md index 0f0b2a6e1..e7da82192 100644 --- a/.claude/agents/static-analyzer.md +++ b/.claude/agents/static-analyzer.md @@ -3,6 +3,7 @@ name: static-analyzer description: Run PVS-Studio static analysis (SAST + MISRA C:2023/C++:2008) on TinyUSB for one board and report structured findings, gated on diagnostics in files changed vs a base ref. Read-only; never edits source. tools: Bash, Read, Grep, Glob model: sonnet +effort: medium --- You run PVS-Studio over the TinyUSB examples build for exactly one board per run and report machine-readable findings. You never modify source files. diff --git a/.claude/agents/target-debugger.md b/.claude/agents/target-debugger.md index 1b6931307..c7acca91c 100644 --- a/.claude/agents/target-debugger.md +++ b/.claude/agents/target-debugger.md @@ -2,6 +2,7 @@ name: target-debugger description: Root-cause one USB misbehavior on real HIL hardware by instrumenting the TinyUSB target — device or host stack — with TU_LOG/RTT, RAM ring-buffer trace, GDB autopsy, J-Link PC-sampling, correlated with capture from the link's other end (Linux PC host, another TinyUSB board, or a Linux gadget peer) and the wire. Long serial debug loop under one held board lock; strictly one instance. Produces a diagnosis with on-target evidence (plus a candidate fix when one emerges), never a merged patch. model: opus +effort: xhigh --- You debug one failing USB behavior on one physical board until you can name the diff --git a/.claude/workflows/driver-review.js b/.claude/workflows/driver-review.js index 255b8ac74..3d380c7e0 100644 --- a/.claude/workflows/driver-review.js +++ b/.claude/workflows/driver-review.js @@ -1,9 +1,9 @@ export const meta = { name: 'driver-review', - description: 'Review driver directories across dimensions with driver-reviewer scanners, then adversarially verify every finding; returns only confirmed findings', + description: 'Review driver directories across dimensions with code-verifier scanners, then adversarially verify every finding; returns only confirmed findings', whenToUse: 'Auditing dcd/hcd drivers for a bug class (pass question) or a full-dimension review (default dimensions)', phases: [ - { title: 'Scan', detail: 'driver-reviewer per (dir x dimension)' }, + { title: 'Scan', detail: 'code-verifier per (dir x dimension)' }, { title: 'Verify', detail: 'adversarial refutation per finding' }, ], } @@ -58,7 +58,7 @@ const results = await pipeline( p => agent( `Review ${p.dir} for exactly one dimension: ${p.dim}. Read the sources yourself. Coverage-first — report everything, a verifier filters.`, - { label: `scan:${short(p.dir)}`, phase: 'Scan', agentType: 'driver-reviewer', effort: 'xhigh', schema: FINDINGS }, + { label: `scan:${short(p.dir)}`, phase: 'Scan', agentType: 'code-verifier', schema: FINDINGS }, ), (scan, p) => { @@ -69,7 +69,8 @@ const results = await pipeline( `Adversarially verify ONE review finding about ${p.dir}.\nDimension: ${p.dim}\nFinding: ${JSON.stringify(f)}\n` + 'Read the cited code plus enough context (callers, ISR paths, macros, and the datasheet if register-related) to judge. ' + 'Try to REFUTE it; real=true only if it survives your best attempt. Return {"real": bool, "reason": string}.', - { label: `verify:${short(p.dir)}:${f.line}`, phase: 'Verify', agentType: 'driver-reviewer', effort: 'xhigh', schema: VERDICT }, + // max: one judgment-dense call per finding decides what survives - worth the top tier + { label: `verify:${short(p.dir)}:${f.line}`, phase: 'Verify', agentType: 'code-verifier', effort: 'max', schema: VERDICT }, ).then(v => v && { ...f, verdict: v }) )).then(vs => { const alive = vs.filter(Boolean) diff --git a/.claude/workflows/fanout-dev.js b/.claude/workflows/fanout-dev.js index e98a86f1d..386f6df46 100644 --- a/.claude/workflows/fanout-dev.js +++ b/.claude/workflows/fanout-dev.js @@ -1,11 +1,11 @@ export const meta = { name: 'fanout-dev', - description: 'Implement one described change across many ports/file-sets: one port-dev worker per item, independent builder verification, optional review', + description: 'Implement one described change across many ports/file-sets: one code-writer worker per item, independent builder verification, optional review', whenToUse: 'Applying a fix or pattern across multiple TinyUSB ports (e.g. the same DCD bug in several drivers)', phases: [ - { title: 'Implement', detail: 'port-dev per item (opus xhigh)' }, + { title: 'Implement', detail: 'code-writer per item (opus xhigh)' }, { title: 'Verify', detail: 'builder single-example check' }, - { title: 'Review', detail: 'optional driver-reviewer pass' }, + { title: 'Review', detail: 'optional code-verifier pass' }, ], } @@ -71,7 +71,7 @@ const results = await pipeline( : ' Pick a verification board from hw/bsp whose family uses this scope.'), { label: `dev:${short(item)}`, phase: 'Implement', - agentType: 'port-dev', effort: 'xhigh', schema: DEV, + agentType: 'code-writer', schema: DEV, ...(args.worktree ? { isolation: 'worktree' } : {}), }, ), @@ -96,7 +96,7 @@ const results = await pipeline( return agent( `Review the uncommitted change in ${item} (inspect with: git diff -- ${item}) against this task:\n${args.task}\n` + 'Dimension: does the diff correctly and completely implement the task with no unintended side effects? Coverage-first findings.', - { label: `review:${short(item)}`, phase: 'Review', agentType: 'driver-reviewer', effort: 'xhigh', schema: FINDINGS }, + { label: `review:${short(item)}`, phase: 'Review', agentType: 'code-verifier', schema: FINDINGS }, ).then(f => { // review: array = findings; null = reviewer died; absent = not requested if (!f) log(`review:${short(item)}: reviewer agent died`) |
