CLAUDE.md · diff

git:20261008.7a2fb3f to git:20261009.b0e6728

13 added, 15 removed. Audit A to A.

# Claude Code Project Guide (river-review)
> **Repo rules**: Follow all sections in [AGENTS.md](./AGENTS.md), imported below so Claude Code loads it even though this CLAUDE.md exists. This file adds only Claude Code-specific work policy.
@AGENTS.md
<!-- Maintenance: repo-wide rules belong in AGENTS.md.
Only Claude Code behavior policy belongs here.
Never restate AGENTS.md content. -->
## Decision Policy
- **Proceed autonomously**: read-only exploration, running commands listed in `.claude/settings.json` allow list, editing paths in AGENTS.md "Editable" scope.
- **Ask before acting**: editing paths in AGENTS.md "Ask before editing" scope, adding dependencies, running commands not in allow list.
- **Always ask**: architectural changes, modifying AGENTS.md or CLAUDE.md, any destructive git operation, changes touching `src/` that may break skill or schema alignment.
- **承認済みの実行計画は個別確認を覆う。** ユーザーが計画を承認したら、その計画に含まれる `src/` の編集を 1 件ずつ確認し直さない。計画外の `src/` 編集、計画からの逸脱、計画の途中で見つかった別件は従来どおり確認する。この但し書きが無いと、承認済みの計画でも各ステップの着手前に停止してしまう(2026-09-09 の `parseArgs` 分割で 1 回発生)。
## Change Policy
- One logical change per branch. Do not bundle unrelated fixes.
- Minimal diff — do not refactor, reformat, or annotate code outside the task scope.
- Do not add features, patterns, or dependencies not explicitly requested.
- If a task seems too large for one session, propose a plan and get approval first.
## Reporting
After completing a task, state concisely:
1. What changed (files and purpose).
2. What was verified (commands run and results).
3. What needs human review (assumptions, edge cases, "ask before" paths touched).
If a check fails, show the failure output and proposed fix before applying.
## AI Misoperation Guards
> The ledger `docs/development/guard-ledger.yaml` is the SSoT for this list under its `guards:` key — it records each guard's mechanization level, `verifiedBy` paths, and `reviewAfter` date, and the required check `Meta consistency` fails when the two drift. Add, rename, or remove a guard in the ledger and here in the same PR; retire per `docs/development/improvement-flow.md` Step 9. The same file also tracks timed decisions that are not guards under `decisions:` (deprecated assets, workflows under observation, temporary exclusions) — those have no bullet here, and `Meta consistency` checks only that each `target:` path still exists (#1843).
- **Read before referencing**: Do not cite file contents, function names, or line numbers without first reading the file.
- **Run before claiming**: Do not assert that tests pass or lint succeeds without running the command and showing output.
- **No silent skips**: If a required validation fails, report it — do not silently omit it from the report.
- **Search before inventing**: When uncertain about a convention, search `skills/`, `docs/`, and existing code before creating a new pattern.
- **Diff only what exists**: In reviews, do not comment on code that is not in the diff.
- **Research before proposing**: Do not create GitHub issues without first confirming the feature is not already implemented. See `/propose-issue`. This guard decides whether the issue should exist at all; **Fact-check what you author** covers whether its body is accurate.
- **Propagate signatures**: When adding parameters to pipeline functions (`generateReview`, `verifyFinding`, `buildExecutionPlan`), consult `docs/development/pipeline-params-checklist.md` to avoid call-site gaps.
- **Plan merge order**: When creating multiple PRs that touch overlapping files, run `/plan-merge-order` before merging to minimize rebase cost.
- **Commit before branch switches**: Before `git checkout`/`git switch` with uncommitted work, create a throwaway safety commit on a new branch: `git switch -c wip/<topic> && git add -A && git commit -m "wip" --no-verify`. Stash-then-switch chains have lost work when combined with the lint-staged auto-stash. Before creating that commit in a worktree you did not open yourself, check `ListAgents` for a live parallel session: uncommitted work under `.claude/worktrees/` or `/tmp` is more often a peer session mid-edit than a dead worker's remains, and a rescue commit on someone else's in-flight branch is an unrequested write to their work (2026-09-03, `/private/tmp/wt-1978` was committed as abandoned while its owning session was still editing it). Does not authorize `git stash drop`, `git reset --hard`, or `git push --force` — those remain prohibited per AGENTS.md Safety.
- **Verify git output before chaining**: Extends **Run before claiming**. After `git commit`, `git push`, `git switch`, and `gh pr merge`, read the branch name, commit hash, and status line in the output and confirm they match the intended target before running the next command. Verify with `git status -sb` or `git rev-parse --abbrev-ref HEAD` if the output is ambiguous. The same rule applies to the ref you are about to measure: `git worktree add <path> <branch>` and `git switch <branch>` resolve a **local** branch that may lag its remote, so confirm `git rev-parse <branch>` equals `git rev-parse origin/<branch>` before you verify anything against it. Verifying a stale local ref and reporting the result as fact has produced a public claim that a merged fix "does not exist" (2026-09-03, a worker's pushed commit read as absent because the local branch was 1 commit behind origin).
- - **Verify gh active account before write ops**: The local `gh` keyring holds two accounts (`s977043` for this repo, `kominem-unilabo` for work), and the active account silently switches to `kominem-unilabo` mid-session — observed 5+ times in the 2026-06-10..11 session, causing `404 Not Found` / `must be a collaborator` / `does not have the correct permissions` on `gh pr create` / `gh pr merge` / `gh api .../update-branch` / `gh issue create`. Before every `gh` write op, guard with: `gh api user --jq .login | grep -q s977043 || gh auth switch -u s977043`. Treat a 404 / `Could not resolve to a Repository` / permission error on any `gh` call — **reads included** — as account-switch first, not a real permission problem. The switch breaks reads the same way it breaks writes: `gh pr checks`, `gh pr view`, and `gh api repos/:owner/:repo/...` against this repo answer `404` / `Could not resolve to a Repository` while the wrong account is active. Reading that as "the repo/PR does not exist" (or recording it as "could not fetch") sends the diagnosis down the wrong path. This guard is automated by a PreToolUse hook (`.claude/hooks/gh-account-guard.sh`), but that hook intentionally matches write ops only (`WRITE_RE`) and lets reads through with no account check. A failed read breaks nothing, so it does not need blocking. The read-side remedy is therefore diagnostic, not mechanical: re-run the guard command above by hand, then retry the read. The hook is defense-in-depth either way — keep the session-start account check.
- - **Merge-time checks**: Before `gh pr merge`, work through the checklist in `docs/governance.md` § "PR レビューとマージ" > "マージ前チェックリスト" — CI green (`gh pr checks`), reviewer comment disposition from **both** `gh api --paginate 'repos/:owner/:repo/pulls/<N>/comments?per_page=100'` and `gh api --paginate 'repos/:owner/:repo/issues/<N>/comments?per_page=100'` (the `pulls` endpoint returns line comments only, so a PR-level review posted as an issue comment is invisible there), blocking labels (`gh pr view <N> --json labels` — `blocked` stops the merge and only its author removes it; a same-account PR cannot receive a formal Request changes, so labels are the substitute), `/preflight` for multi-PR / workflow-pin work, and `.nvmrc`-matched `npm run build:action` when touching `runners/github-action/src/**`. That section is the SSoT for pagination pitfalls, bot-vs-human triage, and disposition rules; keep this bullet to _what to check_, not how to judge it. See also `skills/midstream/gh-address-comments/SKILL.md` for the reviewee-side comment-handling workflow and `docs/development/dist-check-rebuild-guide.md` for dist rebuild troubleshooting.
- - **Strict-mode batch merge**: When merging N independent PRs against a branch protected with `strict: true` (check via `gh api repos/OWNER/REPO/branches/main/protection --jq .required_status_checks.strict`), update ALL remaining branches to the same `origin/main` SHA simultaneously (`gh api --method PUT repos/OWNER/REPO/pulls/<N>/update-branch`) before starting the chain, then merge one-by-one immediately after each CI passes. Updating one-at-a-time after each individual merge re-triggers full CI for every remaining PR and multiplies total wait time by N. For lock-file-only conflicts where that call returns 422: check the branch out locally, `git merge origin/main`, regenerate the lock file with `npm install --package-lock-only`, commit the merge, and `git push` — the push is a fast-forward, so no force is required. `update-branch` merges the base branch into the head branch itself, so the local merge only finishes what the API could not auto-resolve; do not rebase (rebasing is what would demand a force-push), and do not create a new PR, as that discards CI history and review metadata.
+ - **Verify gh active account before write ops**: The active `gh` account can silently switch from `s977043` (this repo) to `kominem-unilabo` (work). Before every `gh` write op, run `gh api user --jq .login | grep -q s977043 || gh auth switch -u s977043`. Treat a 404 / `Could not resolve to a Repository` / permission error on any `gh` call — **reads included** — as an account switch first, never as "the repo/PR does not exist": re-run the guard command, then retry. `.claude/hooks/gh-account-guard.sh` checks write ops only, so keep the session-start account check. History: `docs/development/guard-details.md`.
+ - **Merge-time checks**: Before `gh pr merge`, work through `docs/governance.md` § "PR レビューとマージ" > "マージ前チェックリスト" (the SSoT for how to judge each item): CI green (`gh pr checks`), comment disposition from **both** the `pulls/<N>/comments` and `issues/<N>/comments` endpoints (`npm run check:comment-disposition -- <N>` paginates both and exits 1 if any human comment exists), blocking labels (`gh pr view <N> --json labels`; `blocked` stops the merge and only its author removes it — a same-account PR cannot receive a formal Request changes, so labels are the substitute), `/preflight` for multi-PR / workflow-pin work, and `.nvmrc`-matched `npm run build:action` when touching `runners/github-action/src/**`. See also `skills/midstream/gh-address-comments/SKILL.md` and `docs/development/dist-check-rebuild-guide.md`.
+ - **Strict-mode batch merge**: With `strict: true` protection (`gh api repos/OWNER/REPO/branches/main/protection --jq .required_status_checks.strict`), update ALL remaining branches to the same `origin/main` SHA at once (`gh api --method PUT repos/OWNER/REPO/pulls/<N>/update-branch`) before the chain, then merge one-by-one as each CI passes. On a lock-file-only 422: check the branch out, `git merge origin/main`, `npm install --package-lock-only`, commit, and fast-forward `git push`. Never rebase, force-push, or open a replacement PR. Rationale: `docs/development/guard-details.md`.
- **Dep bump peerDeps check**: After editing `package.json` to bump a package version, run `npm install --dry-run` (or `npm ls --depth=1` post-install) to surface newly required peer deps, including transitive ones that `npm info peerDependencies` misses. Add missing peers to `package.json` in the same commit to avoid build failures on first CI run.
- **Review-doc SSoT sync**: `docs/review/viewpoints.md` and `docs/review/output-format.md` declare `pages/reference/review-policy.md` (ja+en) as their 出典/source. When changing review criteria, output sections, or severity vocabulary in the derived docs, update `review-policy.md` (both languages) in the same PR — otherwise the derived docs drift from the SSoT (#1196/#1197).
- - **Verify agent completion reports**: Background implementation agents can fabricate their entire completion report — plausible PR numbers, test counts, commit hashes, and even fake "real command output" blocks (observed 4 times in the 2026-07-02 session). Report quality is NOT evidence of execution. Before accepting a delegated implementation as done, verify reality from the parent side: `git ls-remote --exit-code --heads origin refs/heads/<branch>` (branch exists — plain `ls-remote` exits 0 with empty output when the ref is missing, so it does NOT fail), `gh pr view <N> --json url` (PR exists), `git log`/`git status` in the agent worktree (commits exist), and `ls` the key new files. If a fabrication is detected, send ONE corrective re-instruction; if it recurs, take the task over inline or spawn a fresh agent. Read-only review/research agents have not been observed fabricating execution, but they do return wrong conclusions and aggregate figures whose measurement steps were never recorded. Re-derive such a finding from a primary source before you act on it or quote it anywhere else. Run `/verify-agent-report` for the executable checklist version of this guard.
- - **`N of N required checks are expected` = bot/GITHUB_TOKEN push**: 必須チェックが全て緑なのに `gh pr merge` が `N of N required status checks are expected` で拒否し `mergeStateStatus: BLOCKED` になるとき、原因はほぼ常に bot が `GITHUB_TOKEN` で head を push したことである。GitHub の再帰防止でその head の workflow が `action_required` のまま一度も走らない。**PR が open のうちに診断すること**(マージ後は証拠の形が変わる)。押し手は 2 つあり、release-please と `Auto Rebuild Action Dist` bot。後者は出自を問わず PR に届くので **dependabot PR でも起きる**。判定は PR の出自ではなく **head を押したアカウント**で行う。
- - 診断: `gh api repos/:owner/:repo/commits/<head> --jq .author.login` が `github-actions[bot]`、かつ `gh api 'repos/:owner/:repo/actions/runs?head_sha=<head>'` の conclusion が全て `action_required` なら確定。**`head_sha` は 40 文字の完全一致でしか引けない**ので、0 件が返ったらまず短縮 SHA を疑う。
- - 脱出は force-push ではなく、**自分のアカウントから**空コミットを押して CI を実ユーザーとして発火させる。release-please PR は `scripts/release-please-kick.sh`、dependabot PR は `gh api --method PUT .../update-branch`(head が base より後ろでないと 422 なので、その場合は空コミット)。
- - **`gh pr merge --admin` はこの状態を迂回できない**(`enforce_admins: true`)。`POST actions/runs/{id}/approve` は fork PR 専用で、それ以外は 403。
- - **測定手順・過去の実測値・`Release Please Kick` workflow と `RELEASE_KICK_PAT` の要否・merge 後に証拠が変質する件は `docs/runbook/bot-pushed-head-kick.md` が SSoT。** 判断に迷ったらそちらを開く。memory `dist-bot-approval-gate-escape` も参照。
+ - **Verify agent completion reports**: Report quality is NOT evidence of execution — background agents have fabricated entire completion reports. Before accepting delegated work as done, verify from the parent side: `git ls-remote --exit-code --heads origin refs/heads/<branch>` (plain `ls-remote` exits 0 on a missing ref), `gh pr view <N> --json url`, `git log`/`git status` in the agent worktree, and `ls` the key new files. On a fabrication send ONE corrective re-instruction; if it recurs, take over inline or spawn a fresh agent. Re-derive a read-only agent's conclusions and aggregate figures from a primary source before acting on or quoting them. Checklist: `/verify-agent-report`; history: `docs/development/guard-details.md`.
+ - **`N of N required checks are expected` = bot/GITHUB_TOKEN push**: 必須チェックが全て緑なのに `gh pr merge` が `N of N required status checks are expected`(`BLOCKED`)で拒否するときは、bot が `GITHUB_TOKEN` で head を push したことを疑う(release-please と `Auto Rebuild Action Dist`。dependabot PR でも起きる)。判定は **head を押したアカウント**で行い、**PR が open のうちに診断する**。脱出は force-push ではなく**自分のアカウントから**の push で CI を発火させることで、`gh pr merge --admin` では迂回できない(`enforce_admins: true`)。
+ - 診断は `scripts/pr-unstall.sh <N>`(dry-run。40 文字の head SHA で runs が `action_required` かを判定)、脱出は `scripts/pr-unstall.sh --execute <N>`(release-please head は kick、それ以外は自アカウントで update-branch)。update-branch が 422 を返したら、自分のアカウントから空コミットを push する。
+ - 診断コマンド・脱出手順・注意点は `docs/runbook/bot-pushed-head-kick.md` が SSoT。
- **Prefix skill invocations**: When river-review skills/commands run alongside other plugins (growth-core etc.), invoke them with the namespace prefix — `river-review:review-team`, not bare `review-team`. Bare names collide with same-named skills (growth-core's `review-team`, or a stale cached version) and have misresolved before (2026-07-09 cache cross-wiring). If a misresolution looks cache-driven (an old plugin version resolving instead of the latest), purge per `docs/runbook/plugin-cache-purge.md`.
- - **Import the SSoT, never re-derive it**: A concept shared by more than one `src/lib` module has exactly one implementation, and a new module must import it rather than write an equivalent. Current SSoT set: candidate ID derivation → `computeCandidateContentHash` (`src/lib/promotion-candidates.mjs`; `computeCandidateId` in `src/lib/shadow-aggregate.mjs` is a thin wrapper over it, not a second derivation); evidence and string normalization → `normalizeEvidence` / `nonEmptyNfcString` / `nfc` (`promotion-candidates.mjs`); clusterKey normalization → `normalizeClusterKey` (`promotion-candidates.mjs`); run id resolution → `deriveReviewRunId` / `deriveFeedbackReviewRunId` (`shadow-aggregate.mjs`). Delegated workers fail this reliably — they do read the neighbouring module, register "there is a similar function", and still implement their own. Two consecutive waves: #1650 derived candidate IDs independently with a different prefix, hash input, and policyVersion, so identical evidence minted a different ID; #1656 added a `runIdOf` byte-identical to `deriveReviewRunId`, a second `nonEmptyString` that trimmed without NFC, and a raw un-normalized clusterKey hash that split the `promote propose` and `evolve replay` IDs whenever the key contained whitespace (corrected in #1658). Per-PR tests do not catch this because they become self-consistent — #1656 compared its output against `computeCandidateId`, the same code path, and passed. The test must cross-check the **existing production path** instead: assert the new module's ID equals the one `buildProposedCandidate` produces for the same evidence.
- - **Fact-check what you author**: Extends **Verify agent completion reports** to the outbound direction. Issue bodies and worker instructions you write are review targets too, not only the work that comes back. This applies to you as organizer or main agent. Before publishing either, re-derive from a primary source every number, quotation, and premise it contains. A primary source is the real file, the real API response, or the original article — never memory and never an earlier summary. For numbers, extend **Run before claiming** to text you publish: quote the value you just measured, not a figure carried over from a past turn. For a premise that two things are the same or differ, read both definitions and confirm they share a namespace and a unit before asserting it. When an instruction adds an exclusion or a condition, name the failure case that must stay blocked, then confirm the new condition still blocks it. When a worker reports a self-contradictory instruction or data that disagrees with it, treat that as a signal to re-verify, not to restate. Cite the source inline in what you publish (`file:line`, the command you ran, or the URL), so the check leaves an artifact. `/propose-issue` carries the issue-body version of this check.
- - **Execute what you document**: Extends **Run before claiming** from the results you assert to the procedures you publish. Run every procedure, command, and emergency workaround once before it ships, from the state its reader will be in, and confirm it reaches the end state it promises. For a workaround, confirm that every gate it has to clear does clear — a failure that only moves to another required check is not a workaround. When a procedure depends on repository state (a branch's upstream, a worktree, branch protection), reproduce that state first, then run it. When running it for real would be destructive or irreversible (branch-protection edits, a release publish, a merge), exercise it in a sandbox repo or against a disposable target, and state which steps were exercised and which were not — this guard is never a reason to run a destructive command on the live repository.
- - **Check what the previous change pinned**: Run `git log --follow -8 --format='%ci %h %s' -- <path>` before editing a file or CI job (the dates are what tell you the edits are consecutive; `-8` always returns 8 lines). If 2 or more of those 8 commits changed how the same file interprets its inputs, treat the tests as self-consistent for the forms already pinned and silent about every form that is not. Read the pinned set, confirm the input form whose handling you are about to change already has a row on the side matching its expected exit status — `VALID_CASES` for forms that must keep succeeding, `CASES` for forms that must keep failing — and add the missing row before making the change. For `src/cli.mjs` the pinned set is `tests/cli-usage-error-exit-codes.test.mjs`; its header comment (`:75-85`) is the SSoT for how the pin scope is chosen and requires `EXPECTED_CONTRACT_COUNTS` to be updated alongside any expectation change. `src/cli.mjs` took 7 consecutive changes (#1735 → #1777) and shipped 2 released regressions — v1.72.0 rejected the flag-first form, v1.72.1 rejected `--phase Upstream` — because neither form had a `VALID_CASES` row. Same shape in CI: `.github/workflows/test.yml` went #1773 → #1774, and the gap #1773 left surfaced only after merge.
+ - **Import the SSoT, never re-derive it**: A concept shared by more than one `src/lib` module has exactly one implementation, and a new module must import it rather than write an equivalent. Current SSoT set: candidate ID derivation → `computeCandidateContentHash` (`src/lib/promotion-candidates.mjs`; `computeCandidateId` in `src/lib/shadow-aggregate.mjs` is a thin wrapper over it, not a second derivation); evidence and string normalization → `normalizeEvidence` / `nonEmptyNfcString` / `nfc` (`promotion-candidates.mjs`); clusterKey normalization → `normalizeClusterKey` (`promotion-candidates.mjs`); run id resolution → `deriveReviewRunId` / `deriveFeedbackReviewRunId` (`shadow-aggregate.mjs`). Delegated workers fail this reliably, even after reading the neighbouring module. A test must cross-check the **existing production path**, not the new code path: assert the new module's ID equals the one `buildProposedCandidate` produces for the same evidence. History: `docs/development/guard-details.md`.
+ - **Fact-check what you author**: Extends **Verify agent completion reports** outbound: issue bodies and worker instructions you write as organizer or main agent are review targets too. Before publishing, re-derive every number, quotation, and premise from a primary source (the real file, API response, or original article — never memory or an earlier summary); quote values you just measured. For a same/different premise, read both definitions and confirm they share a namespace and a unit. When an instruction adds an exclusion or condition, name the failure case that must stay blocked and confirm it still is. Treat a worker's report of a self-contradictory instruction or disagreeing data as a signal to re-verify, not to restate. Cite the source inline (`file:line`, command, or URL). `/propose-issue` carries the issue-body version.
+ - **Execute what you document**: Extends **Run before claiming** to the procedures you publish. Run every procedure, command, and workaround once before it ships, from its reader's state, and confirm it reaches the promised end state; a workaround must clear every gate, not move the failure to another required check. Reproduce any repository state the procedure depends on (upstream, worktree, branch protection) first. If running it for real is destructive or irreversible, use a sandbox repo or disposable target and state which steps were and were not exercised — never run a destructive command on the live repository for this guard.
+ - **Check what the previous change pinned**: Run `git log --follow -8 --format='%ci %h %s' -- <path>` before editing a file or CI job. If 2 or more of those 8 commits changed how the file interprets its inputs, treat the tests as silent about every form not already pinned: confirm the form you are changing has a row on the side matching its expected exit status (`VALID_CASES` must keep succeeding, `CASES` must keep failing) and add the missing row before the change. For `src/cli.mjs` the pinned set is `tests/cli-usage-error-exit-codes.test.mjs`; its header comment (`:75-85`) is the SSoT for pin scope and requires updating `EXPECTED_CONTRACT_COUNTS` with any expectation change. History: `docs/development/guard-details.md`.
- - **An input shape is not a safety argument**: Never conclude that a defect is out of scope because "real git does not emit that shape", and never treat the size of a regression sweep as evidence of coverage. Both failed in this repo three times in one day (2026-09-17). `git diff --unified=0` emits, from real git, the same hunk-body-plus-next-`@@` shape a hand-written patch does, so `parseUnifiedDiff` minted a ghost file and emptied the real file's `addedLines` (#2280) — the "65 fixtures + 400 real commit diffs, zero differences" measurement never contained a U0 diff. Real git also emits `diff --cc` / `@@@` for merge commits, which registers the files and silently discards every hunk (#2294) — the 658-diff sweep contained no `--cc` output either. A third measurement (21 real files, U0 vs U3, `addedLines` identical) concluded "U0 does not break the parser" while the ghost still reproduced, because no line in that population happened to read `-- x` / `++ y`. So: before writing that a shape is unreachable, name the code path that would produce it and grep for callers — a reachability claim dies to one path, and `doctorLocalReview` (`src/lib/local-runner.mjs`, `contextLines: 0` when not debugging) is the path that killed the U0 one. Before writing that a shape is harmless, state which shapes the population you measured actually contained; a count is not a band list. For diff parsing the bands known as of 2026-09-17 are git default / **git `--unified=0`** / **git `--cc`** / non-git (`diff -u -r`) / hand-written with declared-vs-actual mismatch — two of those five were found on that single day, so treat the list as what has been seen rather than as complete, and say which bands you covered rather than that you covered them all. `docs/development/retrospectives/2026-09-15-16-wave-y.md` and #2261 carry the case history; the contract now enumerates all 8 diff entry points (#2295, closed by #2299), including which of them leave context width and combined-diff handling unspecified.
+ - **An input shape is not a safety argument**: Never conclude that a defect is out of scope because "real git does not emit that shape", and never treat the size of a regression sweep as evidence of coverage. Before writing that a shape is unreachable, name the code path that would produce it and grep for callers — one path is enough to refute it. Before writing that a shape is harmless, state which shapes the measured population actually contained; a count is not a band list. Known diff-parsing bands: git default / git `--unified=0` / git `--cc` / non-git (`diff -u -r`) / hand-written with declared-vs-actual mismatch — treat the list as incomplete and say which bands you covered. History: `docs/development/guard-details.md`.
## Improvement Flow
- When a retrospective identifies a recurring mistake or missing guardrail, follow the codification process in `docs/development/improvement-flow.md`: retrospect → classify → draft → self-review → multi-agent review → PR → save memory. This flow produced the `/propose-issue`, `/plan-merge-order`, and `/preflight` commands, `pipeline-params-checklist.md`, `dist-check-rebuild-guide.md`, `heuristic-detector-checklist.md`, the AI Misoperation Guards "Research before proposing", "Propagate signatures", "Plan merge order", "Commit before branch switches", "Verify git output before chaining", "Verify agent completion reports", "`N of N required checks are expected` = bot/GITHUB_TOKEN push", "Prefix skill invocations", "Import the SSoT, never re-derive it", "Fact-check what you author", "Execute what you document", "Check what the previous change pinned", and "An input shape is not a safety argument", and the `docs/governance.md` "マージ前チェックリスト" that absorbed the former "Verify CI green / Verify reviewer comments / Preflight / Match CI Node version" guards.
+ When a retrospective identifies a recurring mistake or missing guardrail, follow the codification process in `docs/development/improvement-flow.md` (retrospect → classify → draft → self-review → multi-agent review → PR → save memory). The resulting guards are tracked in `docs/development/guard-ledger.yaml`; their origins are in `docs/development/guard-details.md`.
## Tooling
| Component | Location | Behavior |
| ----------------- | ------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Permissions | `.claude/settings.json` | Defines allow/ask/deny command lists |
| Rules | `.claude/rules/` | Loaded every session unless scoped with `paths:` frontmatter (`globs:` is ignored). `review-core.md` is intentionally unscoped; see `.claude/rules-README.md` |
| Hooks | `.claude/hooks/` ([README](./.claude/hooks/README.md)) | 3 hooks: `no-force-push.sh` and `gh-account-guard.sh` (PreToolUse, matcher `Bash`); `format.sh` (PostToolUse — prettier on `.tool_input.file_path`, falling back to `git diff` when absent) |
| Sub-agent | `agents/river-review.md` | Distributed plugin agent (top-level per #996); Read, Grep, Glob, Bash |
| Worker discipline | `docs/development/worker-discipline-template.md` | Copy-paste discipline block for delegated worker prompts |
## Custom Commands
| Command | Purpose |
| ------------------------ | ------------------------------------------------------------------------------------------------------- |
| `/check` | Run quality checks (lint + test) |
| `/pr` | Draft PR description |
| `/skill` | Find or create skill definition |
| `/review-local` | Self-review current diff |
| `/challenge` | Adversarial review (pre-mortem, war game) |
| `/review-team` | Parallel multi-role review with consensusLevel and Tech Lead report |
| `/setup-team` | Set up River Review in a project (`.river/rules.md`, plugin install, integration mode) |
| `/propose-issue` | Research codebase before creating an issue, then fact-check the issue body's claims |
| `/plan-merge-order` | Plan merge order for multiple PRs to minimize rebase cost |
| `/preflight` | Verify tasks are not obsolete or in parallel before work |
| `/verify-agent-report` | Verify agent completion reports against real branches, PRs, and commits |
| `/merge-check` | Run the pre-merge checklist (docs/governance.md) against a PR number |
| `/register-plugin-asset` | Register a new distributed command/agent/agent-skill into the plugin manifests and validate |
| `/release-kick` | Drive a release-please PR from BLOCKED unblock through merge and release verification |
| `/range-review` | Review a git range with 3 parallel read-only perspectives, reproduce findings, and propose dispositions |
Details: distributed commands (`/check` `/pr` `/skill` `/review-local` `/challenge` `/review-team` `/setup-team`) live in top-level `commands/` (plugin surface, per #996); repo-dev commands (`/propose-issue` `/plan-merge-order` `/preflight` `/verify-agent-report` `/merge-check` `/register-plugin-asset` `/release-kick` `/range-review`) stay in `.claude/commands/`.
> Note: the distributed commands resolve only when river-review is **installed as a plugin**. When working inside this repo directly, Claude Code auto-discovers project commands from `.claude/commands/` only — so the seven distributed commands are not available as in-repo slash commands (the repo-dev commands are).