go-to-k/cdkd/.claude/skills/verify-pr/SKILL.md
verify-pr
Comprehensive PR readiness check before merge. Run quality checks, tests, CI, documentation, AWS resource cleanup, and code review.
- Source repository stars
- 116
- Declared platforms
- 0
- Static risk flags
- 2
- Last source update
- 2026-08-24
- Source checked
- 2026-08-25
Decision brief
What it does: where it fits
Heavy pre-merge gate. Run this before creating or merging a pull request — NOT before every commit. Per-commit verification is handled by /check (enforced by a PreToolUse hook that blocks git commit without a fresh marker).
Not for
- Tasks that require unconfirmed production actions or broad system permissions.
- Environments where the pinned source and install steps cannot be inspected.
Compatibility matrix
Platform support, with evidence labels
| Platform | Status | Evidence | What to check |
|---|---|---|---|
| Codex | Not declared | No explicit evidence | Portability before use |
| Claude Code | Not declared | No explicit evidence | Portability before use |
| Cursor | Not declared | No explicit evidence | Portability before use |
| Gemini CLI | Not declared | No explicit evidence | Portability before use |
Installation
Inspect first. Install second.
The source command is displayed only when detected. A safe inspection prompt is always available so your agent can explain every action before execution.
npx skills add https://github.com/go-to-k/cdkd --skill ".claude/skills/verify-pr"Inspect the Agent Skill "verify-pr" from https://github.com/go-to-k/cdkd/blob/b54756192def581a75194260c921821c8098328e/.claude/skills/verify-pr/SKILL.md at commit b54756192def581a75194260c921821c8098328e. List every install step, command, network request, credential, file read/write, external action, and rollback step. Explain whether it fits my task. Do not install or execute anything until I approve.
Workflow
What the source asks the agent to do
- 01
Final Step
After all checks pass, record THREE markers via markgate so the gate hooks allow the next git commit, gh pr create, and gh pr merge. /verify-pr is a superset of /check (code correctness) and /check-docs (docs consistency), and adds live-test + retrospective + scope-match on top…
After all checks pass, record THREE markers via markgate so the gate hooks allow the next git commit, gh pr create, and gh pr merge. /verify-pr is a superset of /check (code correctness) and /check-docs (docs consistenc…The verify-pr marker is the one consulted by .claude/hooks/verify-pr-gate.sh to allow gh pr create and gh pr merge. It is intentionally settable ONLY by this skill — running it by hand from a shell to bypass the gate de…Then, if there are uncommitted changes (e.g., lint fixes, doc updates made during this run), commit them and push to the remote. This ensures the remote branch is always up to date when reporting "PR is ready to merge." - 02
Checklist
Run each check and report pass/fail:
Worktree pre-flight: confirm nodemodules/ exists in the cwd:Code qualityvp run typecheck passes - 03
Output
Present results as a table:
A check that is merely pending (CI still running, an integ in flight, a reviewer agent not back yet) is WAITING, not a failure and not a stop. Say what you are waiting on, the signal that will re-invoke you (gh pr check…A check that legitimately cannot pass (no AWS credentials for the live-test, a decision only the maintainer can make) is not WAITING either — there is no signal coming. Either resolve it, or ask through the AskUserQuest…Report STOPPED only when the PR is merged (or the user explicitly owns the next step) and nothing is pending.
Permission review
Static risk signals and limitations
Runs scripts
The documentation asks the agent to run terminal commands or scripts.
git status --short docs/ src/provisioning/property-coverage.generated.ts \Runs scripts
The documentation asks the agent to run terminal commands or scripts.
For each user-visible change in the diff (CLI command, output format, flag, error message), run the actual command path against a real or fixture input and confirm the output matches the spec / CDK CLI parity claim:Writes files
The documentation asks the agent to create, modify, or delete local files.
**Title check**: read `gh pr view <PR> --json title -q .title` and confirm it still describes the union of commits on the branch. If a later commit added a separate concern (e.g. an unrelated fix, an opportunistic refactor), broaden the titWrites files
The documentation asks the agent to create, modify, or delete local files.
# Write desired body to a file (avoids shell escaping issues with backticks)Evidence record
Why each signal appears
| Signal | Value | Evidence type | Meaning |
|---|---|---|---|
| Quality score | 91/100 | Computed | Documentation, specificity, maintenance, and trust rules |
| Repository stars | 116 | Source | Repository attention, not individual Skill quality |
| Compatibility | 0 platforms | Source | Declared in the catalog source record |
| Usage guide | automated source guide | Editorial | Generated or reviewed according to the visible evidence level |
Pinned source
Provenance and original SKILL.md
- Repository
- go-to-k/cdkd
- Skill path
- .claude/skills/verify-pr/SKILL.md
- Commit
- b54756192def581a75194260c921821c8098328e
- License
- Apache-2.0
- Collected
- 2026-08-25
- Default branch
- main
View the original SKILL.md
PR Readiness Verification
Heavy pre-merge gate. Run this before creating or merging a pull request — NOT before every commit. Per-commit verification is handled by /check (enforced by a PreToolUse hook that blocks git commit without a fresh marker).
Checklist
Run each check and report pass/fail:
-
Worktree pre-flight: confirm
node_modules/exists in the cwd:[ -d node_modules ] || pnpm installgit worktree adddoes NOT copynode_modules, so a fresh worktree'svp run typecheck/lint/buildandvp run testall fail withtsc: command not found/Cannot find package 'vitest'etc. — but the failure is easy to miss when the output is piped totail(the exit code reflectstail, notvp, and the failure line gets buried). If the pre-flight skips by way of an existingnode_modules, confirm it is not stale by spot-checkingpnpm-lock.yamlmtime ≤node_modules/.modules.yamlmtime. Do not start step 1 until this passes, or every quality check below silently no-ops while looking green. -
Code quality
vp run typecheckpassesvp run lintpasses (runlint:fixfirst if needed)vp run buildsucceeds- When piping any of the above to
tail/head/grepfor log truncation, check the actual output content forError/Command failedmarkers —$?after a pipeline reflects the LAST stage (usually 0), NOT the build tool's exit. The same applies to background-task completion notifications: the framework'sexit code 0is the chained command's exit, not the pipeline head. When in doubt, capture the result without piping:vp run X > /tmp/out 2>&1; rc=$?; tail -3 /tmp/out; echo "[rc=$rc]".
-
Tests
vp run test- all unit tests pass- Every scope / diff check in this skill uses
origin/main...HEAD, notmain...HEAD. The gate hooks derive their scope fromorigin/mainand theinteg-destroydigest is pinned tomerge-base(origin/main, HEAD), so a localmainthat has not been fetched makes this skill and the hook that blocks the merge disagree about what the branch touched. - Report test count (files and tests)
- Test coverage check: compare
git diff origin/main...HEADforsrc/changes vstests/changes. If new logic was added or modified insrc/but no corresponding test files were added or updated, flag as fail and add the missing tests before proceeding
-
CI status
- If PR number is not provided as argument, auto-detect via
gh pr view --json number -q .number - If no PR exists for current branch, use the
AskUserQuestiontool to ask for the PR number - FIRST:
gh pr view <PR> --json mergeStateStatus,mergeable -q '"mergeable=\(.mergeable) state=\(.mergeStateStatus)"'— when this returnsmergeable=CONFLICTING state=DIRTY, the CI workflow will NEVER fire on the PR no matter how long you wait (empirically observed PR #404 — wasted ~70 min thinking GitHub Actions was broken). Close+reopen, empty commits, andgit push --force-with-leaseof unchanged content all fail to re-trigger. Resolution:git fetch origin main && git rebase origin/main, resolve conflicts,git push --force-with-lease— CI fires within ~30s of the push. See memoryfeedback_pr_conflict_blocks_ci.mdfor the full diagnostic checklist. - Only after
mergeStateStatusisCLEAN/UNSTABLE/BLOCKED/BEHIND:gh pr checks <PR-number>- all checks pass - If checks are pending, wait and recheck
- If PR number is not provided as argument, auto-detect via
-
Working tree
git status- clean (no uncommitted changes)- Branch is up to date with remote
-
Documentation consistency
-
Invoke
/check-docsskill logic: verify docs match code changes -
Check for stale references to removed code
-
Generated-artifact freshness: CI carries a staleness guard per generated artifact — it runs the generator and fails if the working tree changes. There are NINE of them, and this step used to name only four, so the list drifted every time one was added. Do NOT re-list them here; regenerate everything in one shot:
# Regenerates every artifact CI guards (offline static analysis, seconds # each). Unconditional on purpose: the old per-matrix `git diff` triggers # were themselves the drift, since each new matrix needed a new trigger. vp run gen:all-matrices # `--check` is offline (~0.5s) and verifies the cached # docs/_generated/provider-coverage.json matches register-providers.ts # under the current Tier classification. It is a CRITIC, not a generator, # so it is not part of the aggregate. If it fails, run # `vp run audit:coverage:regenerate` (heavy: ~15 min, needs AWS creds with # cloudformation:ListTypes + DescribeType) and commit the regenerated # cache. /verify-pr does NOT auto-run :regenerate — it needs AWS # credentials this skill cannot assume are present, so it is gated on the # critic FAILING rather than skipped for speed. vp run audit:coverage:check # Anything dirty here was stale before you ran the above. git status --short docs/ src/provisioning/property-coverage.generated.ts \ src/provisioning/unsupported-types.generated.tsIf
git statusreports anything dirty, the contributor forgot to regenerate after their code change. Stage it, add it to the PR, and re-run/check-docsto refresh the docs marker.tests/unit/scripts/matrix-regen-coverage.test.tspinsgen:all-matricesagainst the guards actually present in.github/workflows/ci.ymlin BOTH directions, so a new CI guard cannot be added without landing in the aggregate, and a removed one cannot linger. That test is what makes this step non-drifting; keep pointing at the aggregate rather than re-listing.History, because the same round-trip has now happened four times: PR #548 hit two matrices in succession; PR #1104 hit
cli-flag-coverage(added to CI by #1072 without updating this step); PR #1231 merged a flag-only diff that staledcli-flag-coveragewith no fixture change and turned main'scheck-build-testred until #1232; and PR #1416 hithandled-property-wiring(added by #1414), which is staled by an ordinary private-method rename inside a provider — a refactor nobody associates with a generated file (issue #1417). Theprovider-integ-gate.shPreToolUse hook blocksgit commitwhen a newregistry.register('AWS::Foo::Bar', ...)is added without integ coverage (literal type id,Cfn<Type>(L1 class, or// allow-no-integ: <rationale>carve-out) — but it does not enforce that the matrix snapshots themselves are regenerated. This step closes that gap.
-
-
Leftover resources
-
Resolve account ID via
aws sts get-caller-identity --query Account --output text -
aws s3 ls s3://cdkd-state-{accountId}-us-east-1/stacks/ --region us-east-1— no leftover state -
For deletion-touching PRs (any change under
src/provisioning/providers/**,src/cli/commands/destroy.ts,src/analyzer/dag-builder.ts,IMPLICIT_DELETE_DEPENDENCIES, etc.): theinteg-destroymarkgate gate physically blocksgh pr mergewhen its marker is stale (see.claude/hooks/integ-destroy-gate.sh). This step verifies the gate state explicitly so failures surface here rather than at merge time:mise exec -- markgate verify integ-destroyRead the exit code, do not just test for non-zero. The gate runs markgate 0.4's
hash: diffmode, which has three outcomes, and two of them have opposite remedies:- exit 1 — the marker is genuinely stale (this branch changed in-scope code, or the 14d TTL expired). Run
/run-integ <relevant-test>(e.g.bench-cdk-sample) and confirm it reports 0 errors / 0 orphans; the skill itself then callsmarkgate set integ-destroy. - exit 2 — markgate could not EVALUATE the gate:
origin/mainunresolvable (never fetched, shallow clone) or no delta against the merge base./run-integcannot fix this —markgate setfails on the identical condition, so running one burns a real-AWS run and leaves the gate blocked anyway. The remedy isgit fetch origin(or--unshallow, or committing the branch's work).markgate statusalso errors here and prints nostate:line, so the usual staleness reason comes back empty.
CI is necessary but not sufficient — it does not exercise real-AWS destroy. The gate is the structural enforcement of that fact.
- exit 1 — the marker is genuinely stale (this branch changed in-scope code, or the 14d TTL expired). Run
-
CROSS-CUTTING CHECK (load-bearing): the
integ-destroymarker accepts ANY clean real-AWS destroy. A narrow feature-specific integ (e.g.import-value-strong-ref's 2-stack S3+SSM fixture) IS sufficient to flip the marker, but it does NOT exercise the broad deploy / destroy code paths a cross-cutting change touches. When the PR diff touches ANY of:src/deployment/deploy-engine.tssrc/deployment/intrinsic-function-resolver.tssrc/cli/commands/destroy-runner.tssrc/cli/commands/destroy.tssrc/cli/commands/deploy.tssrc/analyzer/dag-builder.tssrc/analyzer/template-parser.tssrc/provisioning/register-providers.tssrc/deployment/retry.tssrc/deployment/retryable-errors.tssrc/deployment/rollback-executor.ts
...you MUST run a broad integ in addition to whatever feature-specific integ the change came with. (Both lists in this step — the paths above and the test names below — are duplicated across several files and are fenced against the hook by
tests/unit/scripts/cross-cutting-list-sync.test.ts, so editing one copy alone fails CI rather than drifting silently.) The canonical broad set (keep in sync with.claude/hooks/integ-broad-gate.sh,.claude/skills/run-integ/SKILL.mdstep 11,.markgate.ymlinteg-broad gate, CLAUDE.md "integ-broad" entry):bench-cdk-sample(39-resource VPC+NAT+CF+Lambda+SQS)lambdamicroservicesdrift-revertdrift-revert-vpcmulti-stack-depsmulti-resourceremove-protectionexport
These exercise multi-resource VPC / Lambda / IAM / CFn-Custom paths that narrow integs leave uncovered. Cross-cutting code paths affect EVERY user's deploy/destroy, not just the feature you added — broad integs are the only structural defense against shipping a regression that only surfaces in production on stacks unlike your fixture. Bypassing this is the PR #348 trap from 2026-05-13 (Issue #343 shipped without bench-cdk-sample validation; surfaced post-merge as an incident).
# Detection: only fires when the diff actually touches cross-cutting code. if git diff origin/main...HEAD --name-only | grep -qE '^src/deployment/(deploy-engine|intrinsic-function-resolver|retry|retryable-errors|rollback-executor)\.ts$|^src/cli/commands/(destroy-runner|destroy|deploy)\.ts$|^src/analyzer/(dag-builder|template-parser)\.ts$|^src/provisioning/register-providers\.ts$'; then echo "Cross-cutting code touched — broad integ required (bench-cdk-sample / lambda / microservices / drift-revert)." # Then run the broad integ via /run-integ and confirm 0 errors / 0 orphans. fiThe narrow feature integ stays valuable for testing the FEATURE; the broad integ is the regression backstop. Both must pass; both refresh the same
integ-destroymarker. -
For local-execution-touching PRs (any change under
src/local/**,src/cli/commands/local-*.ts,tests/integration/local-*/**): theinteg-localmarkgate gate physically blocksgh pr mergewhen its marker is stale (see.claude/hooks/integ-local-gate.sh). The merge-time gate has a known blind spot: it reads the local working tree digest, and whengh pr mergeruns from a parent worktree still on pre-PRmain, the digest matches the old content and the gate passes silently — so an unverified local-execution change can reach main via the merge-from-parent path./verify-prruns in the PR's own worktree (post-PR content), so verifying the marker here closes that gap structurally:# Only check when the PR diff actually touches the gate scope. # Mirrors how `gh pr merge` is checked, but in the worktree that has the PR's content. if git diff origin/main...HEAD --name-only | grep -qE '^src/local/|^src/cli/commands/local-|^tests/integration/local-'; then mise exec -- markgate verify integ-local fiIf this exits non-zero (digest differs OR expired by TTL), run
/run-integ local-<test>against a test that exercises the changed surface —local-start-apifor HTTP-server / route-discovery / authorizer / container-pool changes,local-invokefor Lambda-runtime / ZIP-asset changes,local-run-taskfor ECS changes,local-invoke-containerfor container-Lambda changes,local-invoke-layersfor Lambda Layers changes. The integ skill callsmarkgate set integ-localitself when the Docker-side check passes. As withinteg-destroy, CI is necessary but not sufficient — it does not exercise Docker-based local execution. -
For each region this PR may have created resources in (typically
us-east-1), spot-check the most failure-prone resource types — VPCs (describe-vpcs --filters "Name=tag:Name,Values=Cdkd*/Vpc"), Lambda hyperplane ENIs (describe-network-interfaces --filters "Name=description,Values=AWS Lambda VPC ENI-*"), CloudFront Distributions, NAT Gateways. Any match against a stack name in this PR's diff = orphan, must be cleaned up before merge.
-
-
No stale references
- Grep for removed imports, old module names, or deprecated references in source files
- Check
src/index.tsexports are consistent
-
Code review
-
First, run
/review-pr <N>to get a size-appropriate review plan. The skill outputs one of:- inline spot-check (small PR, < 300 LOC OR < 5 files, no security-sensitive paths) — read the diff yourself in this step; no sub-agent dispatch.
- 1 reviewer (medium PR, 300-1000 LOC) — dispatch a single
pr-code-revieweragent (the skill emits a ready-to-paste Agent call). - 3-axis parallel (large PR ≥ 1000 LOC OR security-sensitive paths) — dispatch all three of
pr-spec-reviewer/pr-code-reviewer/pr-test-reviewerin parallel (single message, three Agent tool calls). - security add-on (additive, ANY tier incl.
inline) — when the PR touches a security / process-launch surface or is a security fix,/review-prALSO emits apr-security-reviewerdispatch. Add it to the same parallel batch; its blockers block the merge like any other reviewer's.
The skill applies bias factors (security surfaces bump up; pure-infra / docs / tests-only bump down) and appends the security reviewer on top of the tier when a security surface / fix is involved. Trust the recommendation; override only when you have a concrete reason (note the reason here).
-
Synthesize the reviewer reports (or your inline read) into a pass / issues-found verdict. Any blocker → fix-back loop before continuing.
-
Then re-review the FIX DELTA, not just re-run the tier heuristic. The fixes are code no reviewer has seen, written under the momentum of agreeing with a finding, and they land in the exact spot a reviewer just proved is subtle. Dispatch a second round scoped to what changed since the first, telling the reviewers the original design was already accepted so they spend their pass on the delta. This is not belt-and-braces: on 2026-08-19 (PR #2044) round 1 asked for the give-up summary to be deferred into its
tryand for a new retry class to be reported; round 2 found that the fix for the second one reintroduced the first one's bug one line away (an unguarded$metadataread on a path where nothing had read the field yet) and, separately, printed a new default-levelwarnon graceful-degradation paths that had been silent. A test reviewer in the same round found eight surviving mutants in branches that round 1's fixes had introduced. Neither defect existed when the first round ran, so no amount of rigor there could have caught them. -
Corollary for the mutation probes this repo relies on: enumerate the branches the diff ADDS and probe each one, rather than probing the headline change. A new
if, a new token in a rendered string, a new early return and a new gate condition are four probes, not one — and every fix round adds more of them. -
git diff origin/main...HEAD— confirm the diff is what you reviewed (no last-minute commits slipped through). -
For each change: is it correct? complete? necessary?
-
Check for:
- Logic errors or unhandled edge cases
- Unnecessary changes (reverted code still in diff, dead code, unrelated changes)
- Inconsistencies between changed files
-
Verify all callers of changed functions handle the new behavior
-
Verify type definitions are consistent with implementation
-
Shared-utility regression check: if any file under
src/utils/**(or another widely-imported module) changed, list every importer (grep -rl "from '\.\./.*utils/<file>'" src tests) and walk through each one to confirm the new behavior is correct for them. A change to a shared helper is only "done" when every caller has been considered. -
Internal-interface contract change check: if the diff changes the semantics of arguments an interface receives — even if the type signature is unchanged — list every implementer and walk through each one. Examples that count as a contract change:
provider.update'snewPropertiesshifting from "full desired state" to "partial / overlay / etc."; an intrinsic resolver's input format changing; a state schema field's invariant changing. The risk is implementers that silently treat the old shape's invariants as load-bearing (e.g.SNSTopicProvider.updatetreatingnewProps[K] === undefinedas "remove K from AWS"). PR #161 hit this — the first-pass design ("drifted-only partial newProperties") had to be reworked after audit foundSNSTopicProviderandIAMRoleProvider.updateManagedPolicieswould silently clear non-drifted attrs. Audit BEFORE writing tests against the new design, not after — discovering the breaks via tests-after-design forces a design rework and invalidates the tests already written.# For provider interface changes: grep -rln "implements ResourceProvider" src/provisioning/providers/ # For each implementer, read the body of the affected method and write # down what it assumes about the argument's shape — truthy gates, # diff-based "absent = remove" semantics, JSON.parse on stringly-typed # input, etc. The new contract must preserve every assumption that # is load-bearing, OR every implementer must be updated in the same PR.See
feedback_internal_contract_audit_first.mdfor the full pattern.
-
-
Live-test changed behavior
- Unit tests verify code correctness; this step verifies feature correctness against the runtime the user actually sees.
- Build the latest source:
vp run build - For each user-visible change in the diff (CLI command, output format, flag, error message), run the actual command path against a real or fixture input and confirm the output matches the spec / CDK CLI parity claim:
- CLI surface change → run
node dist/cli.js <subcommand> <args>againsttests/integration/<example>/cdk.outor a real state bucket; verify each output mode (--long/--json/ patterns / etc.). - State-touching change → exercise it against a real / test state bucket (e.g.
cdkd-state-test). - Non-CLI library change → run a minimal repro that imports the new code path.
- CLI surface change → run
- "Tests passed" is not "feature works." Always run the actual command before declaring done. If you cannot live-test (no real-AWS credentials, no fixture available), say so explicitly rather than skip silently — the gate exits non-zero in that case so a reviewer can decide whether to accept the trade-off.
-
Retrospective + rules update
- Walk back over the session that produced this PR. For each surprise, friction, or correction the user had to make, ask: "is this a one-off, or a pattern that will recur?"
- For each pattern, propose where it should be reflected so it doesn't recur:
- Hook — pattern can be detected mechanically (e.g. fragile shell pattern, deprecated tool, marker-gated step). Strongest enforcement.
- Skill / marker — pattern is a checklist that must be done before some action. Use the
/check+check-gate//check-docs+check-gate//verify-pr+verify-pr-gate//run-integ+integ-destroy-gatetemplate. - Memory — pattern is judgmental ("prefer X when Y") and not mechanically detectable. Weakest enforcement; honest about its limits.
- Surface the proposals out loud (in chat, or in this PR's body) before merging. If the user agrees, write them in the same PR for code/skill/hook artifacts; memory entries are local to
~/.claude/projects/.../memory/so they land regardless of PR boundaries. - The retrospective is itself one of the items the
verify-prmarker covers — skipping this step means the marker is set on incomplete work.
-
Residual review-nit sweep (mandatory — added 2026-05-22 after a multi-PR session left ~9 reviewer-flagged nits unfiled when the parent declared "session complete")
- For every
/review-prreviewer agent output during this session (including re-reviews after fix-back), walk the reviewer's "Minor / Nit / Informational" section. - For EACH item there, confirm ONE of the following is true BEFORE setting the
verify-prmarker (these are the same three buckets as CLAUDE.md's "Remaining work" taxonomy — Fixed here / TODO / Won't-do):-
(a) Fixed in this PR — point at the fix commit / file:line that resolves the nit.
-
(b) TODO (issue #N) — a GitHub issue exists AND this PR's body references it (e.g. "minor follow-ups in (#515)"). This is the only bucket that leaves future work. The issue body MUST carry the four classification lines, one field per line (see CLAUDE.md → "The four TODO fields"):
Session-fit: now (do it in this session) | next (not this session) — <reason> Severity: high | medium | low — <what stays broken while it is undone> Effort: small (S) | medium (M) | large (L) — <which verification cycle it drags> Estimate: <duration, e.g. ~1-3 h -- never a bare letter> — <what eats the time>The reviewer agents grade on a DIFFERENT scale — translate, do not copy.
.claude/agents/pr-*-reviewer.mdreportblocker/minor/nit;Severitytakeshigh/medium/low. This step is exactly where a reviewer's word gets carried into an issue body, so map it:nit->low,minor->medium. There is deliberately noblockerarm: this step walks only the "Minor / Nit / Informational" section, and a blocker is resolved by step 8's fix-back loop before you ever get here. If one reaches this step, the steps are being run out of order — go back to step 8 rather than grading it. And re-read the mapped value against the Severity scale rather than trusting it: reviewer severity grades how bad the FINDING is, whileSeveritygrades what stays broken for a USER, and the two come apart on internal-consistency nits.This step is the deferral moment, so it is where the call gets made — not at wrap time, by which point the evidence for it (which files were open, which verification cycle was already paid for) is gone. A
nowitem must be fixed before the marker is set, or re-classified tonextwith the reason recorded; you cannot setverify-prover an opennow. -
(c) Won't-do (decided + recorded) — the PR body or a comment names the nit and explains why shipping as-is is the right call. Requires no future action.
-
- If NONE of (a) / (b) / (c) is true for any nit, file a bundled follow-up issue NOW (one issue per session, listing every uncovered nit) and update the PR body to reference it. Do not set the
verify-prmarker until every reviewer-flagged item is on one of those three paths. - Also walk the session transcript for surfaced memory-rule candidates (surprising traps, repeated friction, "I should remember this for next time" moments). Each MUST be either written as a memory file in
~/.claude/projects/-Users-goto-pc-github-cdkd/memory/(with a MEMORY.md index entry) OR explicitly de-prioritized in the chat / PR body. - Auto-close audit (added 2026-05-22 — counter-trap to the closing-paren disambig convention in memory
feedback_pr_body_no_hash_for_item_numbers.md):- Read the PR body (
gh pr view <PR> --json body -q .body). For every(#N)parens-form reference, check whether it's adjacent to a close keyword (closes/fixes/resolves, case-insensitive). - If yes: the merge will NOT auto-close the target issue. Either rewrite to parens-free
Closes #N(auto-close fires), OR add a manualgh issue close <N>step to the merge sequence and note it in the PR body. - The mechanical
closes-paren-form-gate.shhook ALREADY blocksgh pr mergefor theCloses (#N)pattern — this skill step is the human-readable backup that catches the issue BEFORE the merge attempt.
- Read the PR body (
- This step is the structural enforcement of memory
feedback_session_completion_audit_required.md— claiming "session complete" / "nothing remaining" without running this sweep is the exact violation that surfaced this rule.
- For every
-
PR title + body freshness (skip if no PR exists yet —
/create-prwill write them from scratch)- When a PR has follow-up commits after creation, both the title and body authored at PR-create time often go stale: the title was scoped to the first commit's intent only, and the body may mention reverted features, removed checks, or wrong rationale. Detect and fix both.
- Title check: read
gh pr view <PR> --json title -q .titleand confirm it still describes the union of commits on the branch. If a later commit added a separate concern (e.g. an unrelated fix, an opportunistic refactor), broaden the title. Update viagh api -X PATCH repos/{owner}/{repo}/pulls/{number} -f title="..."(NOTgh pr edit --title, which currently fails silently due to GraphQL Projects-classic deprecation — see hookgh-pr-edit-deprecation-gate.sh). - Body freshness commands:
gh pr view <PR> --json commits -q '.commits | length'— commit count on the PRgit log main..HEAD --oneline | wc -l— commit count locally- If they match and >1, the PR has been iterated on; the initial body is almost certainly stale
- Read the current body (
gh pr view <PR> --json body -q .body) and compare against the actual final diff (git diff origin/main...HEAD). Flag any of:- Bullets describing behavior that was reverted in a later commit
- Bullets describing checks/validations the code no longer performs
- File:line citations that no longer exist
- Wording that contradicts the current README.md / CLAUDE.md
- Stale numeric claims ("N tests pass" when the count has since changed)
- If stale, rewrite the body and patch via:
# Write desired body to a file (avoids shell escaping issues with backticks) cat > /tmp/pr-body.md <<'EOF' ## Summary ... ## Test plan ... EOF gh api repos/{owner}/{repo}/pulls/{number} -X PATCH --field "body=@/tmp/pr-body.md" -q '.html_url'Note:
gh pr edit --bodymay fail with "Projects (classic) is being deprecated" — fall back to thegh api PATCHform above.
- Verify with
gh pr view <PR> --json body -q .body | head -5that backticks and special chars rendered correctly.
Output
Present results as a table:
| Check | Result |
|---|---|
| typecheck | pass/fail |
| lint | pass/fail |
| build | pass/fail |
| tests (N files, M tests) | pass/fail |
| test coverage for changes | pass/fail |
| CI | pass/fail |
| working tree | clean/dirty |
| docs consistency | pass/fail |
| leftover resources | none/found |
| integ-destroy marker (deletion-touching PRs only) | fresh/stale/n-a |
| integ-broad marker (cross-cutting deploy/destroy PRs only) | fresh/stale/n-a |
| integ-local marker (local-execution-touching PRs only) | fresh/stale/n-a |
| code review (incl. shared-utility callers) | pass/issues found |
| live-test changed behavior | pass/skipped/issues found |
| retrospective + rule proposals | done/skipped |
| residual review-nit sweep (fixed / TODO-issue / won't-do) | N items / 0 unhandled |
every TODO carries Session-fit / Severity / Effort / Estimate | N classified / 0 open now |
auto-close audit (no Closes (#N) in body) | clean / N traps fixed |
| PR title + body freshness | up-to-date/stale (updated)/n-a (no PR yet) |
If all pass, confirm "PR is ready to merge." If any fail, list the issues to fix.
Then add the State line CLAUDE.md's wrap-report rule requires — this skill's report is the single most common place it is needed, because "ready to merge" is almost never the end of the turn:
- A check that is merely pending (CI still running, an integ in flight, a reviewer agent not back yet) is WAITING, not a failure and not a stop. Say what you are waiting on, the signal that will re-invoke you (
gh pr checks <N> --watch, a background-task completion notification), and that you will merge once it is green. Do not hand the user a "ready to merge" verdict and then go quiet — that reads as STOPPED and leaves them unsure whether to intervene. - A check that legitimately cannot pass (no AWS credentials for the live-test, a decision only the maintainer can make) is not WAITING either — there is no signal coming. Either resolve it, or ask through the
AskUserQuestiontool so the run continues from the answer. Never end the turn with the question in prose. - Report STOPPED only when the PR is merged (or the user explicitly owns the next step) and nothing is pending.
Final Step
After all checks pass, record THREE markers via markgate so the gate hooks allow the next git commit, gh pr create, and gh pr merge. /verify-pr is a superset of /check (code correctness) and /check-docs (docs consistency), and adds live-test + retrospective + scope-match on top — so its success implies all three. cdkd pins markgate via mise, so use mise exec to avoid PATH issues when shims aren't active:
mise exec -- markgate set check
mise exec -- markgate set docs
mise exec -- markgate set verify-pr
The verify-pr marker is the one consulted by .claude/hooks/verify-pr-gate.sh to allow gh pr create and gh pr merge. It is intentionally settable ONLY by this skill — running it by hand from a shell to bypass the gate defeats the whole point. If a check legitimately cannot pass right now (e.g. the live-test cannot run because the user lacks AWS credentials), say so explicitly in the report and DO NOT set the marker — the gate exits non-zero so the human can decide whether to override.
Then, if there are uncommitted changes (e.g., lint fixes, doc updates made during this run), commit them and push to the remote. This ensures the remote branch is always up to date when reporting "PR is ready to merge."
Skip the marker + commit step if any check failed.
Frequently asked questions
What to verify before installation and use
What does the verify-pr source document cover?
Heavy pre-merge gate. Run this before creating or merging a pull request — NOT before every commit. Per-commit verification is handled by /check (enforced by a PreToolUse hook that blocks git commit without a fresh marker).
How do I install verify-pr?
The source record exposes this install command: npx skills add https://github.com/go-to-k/cdkd --skill ".claude/skills/verify-pr". Inspect the command and pinned source before running it.
Which permission-related actions were detected?
Static rules flagged exec-script, write-files in the source; the page lists the matching lines and excerpts.
Alternatives
Compare before choosing
Jamie-BitFlight/claude_skills
python3-development
Use when building Python 3.11+ CLI apps (Typer/Rich), writing pytest test suites, fixing ruff linting or ty/mypy type errors, configuring pyproject.toml, creating portable scripts, or reviewing Python code. Activates on all Python implementation tasks — routes to specialist agents for CLI architecture, test design, packaging, and code review. Authoritative reference for modern Python 3.11-3.14 patterns and TDD workflows.
Jamie-BitFlight/claude_skills
complete-implementation
Use when all tasks for a feature are marked COMPLETE — runs holistic quality gates including code review, feature verification, integration check, documentation drift audit and update, and context refinement. Creates follow-up plans when issues are found.
th3vib3coder/vibe-science
vibe-science
Scientific research engine for hypothesis testing, literature gap analysis, experimental validation, and data-driven discovery. Enforces adversarial review (Reviewer 2), 32 quality gates, tree search over hypotheses, confounder harness for quantitative claims, and serendipity detection. TRIGGER when: user asks to analyze scientific data, test hypotheses, validate findings, search for research gaps, design experiments, or investigate results. DO NOT TRIGGER when: pure code review, documentation w
PramodDutta/qaskills
Code Review Excellence
Master code review best practices with constructive feedback patterns, quality assurance standards, review checklists, security considerations, and collaborative improvement techniques for high-quality software delivery.