@openora/create 0.4.1-canary.33 → 0.4.1-canary.331
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/.tsbuildinfo +1 -1
- package/dist/generated/versions.d.ts +11 -0
- package/dist/generated/versions.d.ts.map +1 -0
- package/dist/generated/versions.js +11 -0
- package/dist/generated/versions.js.map +1 -0
- package/dist/index.js +48 -93
- package/dist/index.js.map +1 -1
- package/dist/render.d.ts +15 -0
- package/dist/render.d.ts.map +1 -0
- package/dist/render.js +125 -0
- package/dist/render.js.map +1 -0
- package/package.json +8 -6
- package/template/README.md.tpl +12 -7
- package/template/__dot__claude/settings.json.tpl +22 -12
- package/template/__dot__env.example +10 -0
- package/template/__dot__gitignore +6 -1
- package/template/__dot__rulesync/commands/adr.md +32 -0
- package/template/__dot__rulesync/commands/check.md +11 -10
- package/template/__dot__rulesync/commands/doctor.md.tpl +17 -0
- package/template/__dot__rulesync/commands/scaffold-module.md +3 -2
- package/template/__dot__rulesync/commands/scaffold-plugin.md +19 -3
- package/template/__dot__rulesync/commands/scaffold-route.md +1 -0
- package/template/__dot__rulesync/commands/start.md +2 -2
- package/template/__dot__rulesync/hooks/_shared.mjs +26 -13
- package/template/__dot__rulesync/hooks/guard-core.mjs.tpl +76 -28
- package/template/__dot__rulesync/hooks/guard-generated.mjs +16 -14
- package/template/__dot__rulesync/hooks/guard-mr.mjs +81 -0
- package/template/__dot__rulesync/hooks/guard-subagent.mjs +22 -6
- package/template/__dot__rulesync/hooks/post-edit.mjs.tpl +116 -0
- package/template/__dot__rulesync/hooks.json +27 -4
- package/template/__dot__rulesync/rules/conventions.md +114 -0
- package/template/__dot__rulesync/rules/db-conventions.md +6 -72
- package/template/__dot__rulesync/rules/e2e-conventions.md +52 -0
- package/template/__dot__rulesync/rules/frontend-conventions.md.tpl +35 -0
- package/template/__dot__rulesync/rules/oss-boundaries.md.tpl +78 -0
- package/template/__dot__rulesync/rules/overview.md +18 -73
- package/template/__dot__rulesync/skills/create-plugin/{SKILL.md → SKILL.md.tpl} +13 -24
- package/template/__dot__rulesync/skills/create-pr/SKILL.md.tpl +38 -0
- package/template/__dot__rulesync/skills/create-task/{SKILL.md → SKILL.md.tpl} +14 -22
- package/template/__dot__rulesync/skills/create-ui-module/SKILL.md.tpl +60 -0
- package/template/__dot__rulesync/skills/enhance-prompt/{SKILL.md → SKILL.md.tpl} +4 -4
- package/template/__dot__rulesync/skills/handoff/SKILL.md +95 -0
- package/template/__dot__rulesync/skills/review/SKILL.md.tpl +277 -0
- package/template/__dot__rulesync/skills/ship/SKILL.md.tpl +157 -0
- package/template/__dot__rulesync/skills/ship/handoff.md.tpl +48 -0
- package/template/__dot__rulesync/skills/ship/watch-pr.mjs +172 -0
- package/template/__dot__rulesync/skills/ui-verify/SKILL.md.tpl +120 -0
- package/template/__dot__rulesync/skills/ui-verify/layout-check.check.sh +58 -0
- package/template/__dot__rulesync/skills/ui-verify/layout-check.js +163 -0
- package/template/__dot__rulesync/subagents/builder.md.tpl +115 -0
- package/template/__dot__rulesync/subagents/compliance-reviewer.md +78 -0
- package/template/__dot__rulesync/subagents/debugger.md.tpl +86 -0
- package/template/__dot__rulesync/subagents/deployer.md.tpl +54 -0
- package/template/__dot__rulesync/subagents/expert.md +28 -34
- package/template/__dot__rulesync/subagents/planner.md.tpl +39 -0
- package/template/__dot__rulesync/subagents/quality-reviewer.md.tpl +112 -0
- package/template/__dot__rulesync/subagents/security-reviewer.md.tpl +85 -0
- package/template/__dot__rulesync/subagents/tester.md.tpl +102 -0
- package/template/__dot__rulesync/sync.json.tpl +26 -0
- package/template/apps/api/package.json.tpl +3 -4
- package/template/apps/api/src/extensions.config.ts.tpl +12 -0
- package/template/apps/api/src/main.ts.tpl +1 -4
- package/template/apps/api/src/seed.ts.tpl +8 -1
- package/template/docker-compose.yml +13 -0
- package/template/docs/agents/cross-repo.md.tpl +37 -0
- package/template/docs/agents/forge.md.tpl +54 -0
- package/template/docs/agents/issue-tracker.md.tpl +42 -0
- package/template/docs/standards/comments.md +16 -0
- package/template/docs/standards/database.md +77 -0
- package/template/docs/standards/enforcement.md +12 -0
- package/template/docs/standards/errors.md +26 -0
- package/template/docs/standards/frontend.md +60 -0
- package/template/docs/standards/functions.md +38 -0
- package/template/docs/standards/git-delivery.md +20 -0
- package/template/docs/standards/module-structure.md +37 -0
- package/template/docs/standards/testing.md +88 -0
- package/template/docs/standards/types.md +31 -0
- package/template/package.json.tpl +19 -13
- package/template/rulesync.jsonc +4 -4
- package/template/tools/oss-worktree.mjs.tpl +105 -0
- package/template/tools/review-precheck.mjs +531 -0
- package/template/tools/sync-agents.mjs +257 -0
- package/template/turbo/generators/config.ts +1 -1
- package/template/turbo.json +14 -2
- package/dist/generated/core-version.d.ts +0 -2
- package/dist/generated/core-version.d.ts.map +0 -1
- package/dist/generated/core-version.js +0 -2
- package/dist/generated/core-version.js.map +0 -1
- package/template/__dot__rulesync/hooks/post-edit.mjs +0 -57
- package/template/__dot__rulesync/skills/add-feature/SKILL.md +0 -113
- package/template/__dot__rulesync/skills/add-feature/handoff.md +0 -58
- package/template/__dot__rulesync/skills/code-review/SKILL.md +0 -111
- package/template/__dot__rulesync/skills/create-pr/SKILL.md +0 -55
- package/template/__dot__rulesync/subagents/builder.md +0 -93
- package/template/__dot__rulesync/subagents/debugger.md +0 -83
- package/template/__dot__rulesync/subagents/deployer.md +0 -66
- package/template/__dot__rulesync/subagents/qa.md +0 -88
- package/template/apps/api/src/migrate.ts.tpl +0 -46
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: create-ui-module
|
|
3
|
+
targets: ['*']
|
|
4
|
+
description: >
|
|
5
|
+
Create a frontend feature module in apps/backoffice or apps/web following the modular
|
|
6
|
+
architecture in the `frontend-conventions` rule: standard folder shape, co-located
|
|
7
|
+
locales, DI hooks, pure components, barrel entry, route wiring. Use on "create module", "new feature module",
|
|
8
|
+
"add a backoffice/web module", "/create-ui-module <app> <name>".
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
# create-ui-module ({{name}})
|
|
12
|
+
|
|
13
|
+
Applies once this repo has UI apps (`apps/web` / `apps/backoffice`); an api-only repo has no `src/modules/` to scaffold into.
|
|
14
|
+
|
|
15
|
+
Scaffold a feature module under `src/modules/<name>/` per the modular architecture in `frontend-conventions` and `docs/standards/frontend.md`. Where the repo ships a module-structure lint rule, it enforces the shape (folder structure, `use-` hook naming, kebab-case files, client-component naming). Copy an existing module in the same app as the reference.
|
|
16
|
+
|
|
17
|
+
## 1. Resolve input
|
|
18
|
+
|
|
19
|
+
`<app> <name>` from `$ARGUMENTS` (`backoffice` | `web`, kebab-case name). Ask if missing. Confirm the module doesn't exist and the concern isn't already owned by another module.
|
|
20
|
+
|
|
21
|
+
## 2. Create the shape
|
|
22
|
+
|
|
23
|
+
```
|
|
24
|
+
src/modules/<name>/
|
|
25
|
+
pages/<name>-page.tsx page entrypoint(s)
|
|
26
|
+
components/ presentational only - props in, JSX out
|
|
27
|
+
hooks/use-<x>.ts ALL logic/queries/mutations; deps passed as parameters
|
|
28
|
+
utils/ local helpers (only if needed)
|
|
29
|
+
locales/en.json translation keys
|
|
30
|
+
locales/index.ts registration (below)
|
|
31
|
+
index.ts public barrel - the ONLY entry other code may import
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
`locales/index.ts` pattern (exact):
|
|
35
|
+
|
|
36
|
+
```ts
|
|
37
|
+
import { registerTranslations } from '{{scope}}/ui';
|
|
38
|
+
import en from './en.json';
|
|
39
|
+
|
|
40
|
+
export const locales = { en };
|
|
41
|
+
export const ns = registerTranslations('<name>', locales);
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
Components use `useTranslation(ns)`; no hardcoded copy. Non-`en` files mirror `en.json` keys exactly.
|
|
45
|
+
|
|
46
|
+
## 3. Wire the route
|
|
47
|
+
|
|
48
|
+
- backoffice: `src/routes/_authed/<name>.tsx` -> `createFileRoute` with `component` imported from `@/modules/<name>`; mirror a sibling route file.
|
|
49
|
+
- web: the App Router page under `app/(shell)/<name>/` imports from `@/modules/<name>`; client components get `'use client'` line 1 + `.client.tsx` suffix.
|
|
50
|
+
|
|
51
|
+
## 4. Non-negotiables
|
|
52
|
+
|
|
53
|
+
- No cross-module imports - cross-module effects go through query cache invalidation, never a direct import.
|
|
54
|
+
- Outside code imports ONLY the barrel via `@/modules/<name>`; inside the module use relative paths.
|
|
55
|
+
- Hooks take their clients (oRPC/API) as parameters via a `use-<domain>-client-deps.ts` hook so they're testable without global mocks.
|
|
56
|
+
- Follow the `frontend-conventions` rule + `docs/standards/frontend.md` (daisyUI, theme tokens, hoisted `styles` const, React Compiler - no manual memo).
|
|
57
|
+
|
|
58
|
+
## 5. Verify
|
|
59
|
+
|
|
60
|
+
`/check` green (any structure lint runs inside `pnpm check:lint`); route renders (`pnpm dev`). Hand to `review` before an MR.
|
|
@@ -3,14 +3,14 @@ name: enhance-prompt
|
|
|
3
3
|
targets: ['*']
|
|
4
4
|
description: >
|
|
5
5
|
Normalize any raw request into a grounded, structured brief before acting. The auto pre-step
|
|
6
|
-
for orchestration skills and subagents: extract the real intent, gather scoped context (
|
|
7
|
-
|
|
6
|
+
for orchestration skills and subagents: extract the real intent, gather scoped context (Jira +
|
|
7
|
+
Confluence + Slack + roadmap + local docs), surface only blocking ambiguities, and emit
|
|
8
8
|
objective / scope / constraints / deliverables / guardrails. Routes build-type asks into
|
|
9
9
|
`enhance-intent`. Skips asks that are already precise. Use on any fuzzy, broad, or multi-part
|
|
10
10
|
request, or at the start of a skill or agent that received a raw ask.
|
|
11
11
|
---
|
|
12
12
|
|
|
13
|
-
# enhance-prompt
|
|
13
|
+
# enhance-prompt ({{name}})
|
|
14
14
|
|
|
15
15
|
Turn a raw, rambling ask into a brief a stranger could execute - before any file is touched. A one-line ask is a starting point, not a spec; a wrong reading executed confidently wastes far more than the enhancement costs.
|
|
16
16
|
|
|
@@ -27,7 +27,7 @@ Match effort to the ask: a small task gets a one-line restatement, not a full br
|
|
|
27
27
|
|
|
28
28
|
1. **Restate the intent** in one line. If your restatement might be wrong, gather context or ask - don't guess.
|
|
29
29
|
2. **Classify**: build (feature / adapter / page / route) · review or audit · debug · refactor · docs · research · ops. For a **build** ask, hand off to the `enhance-intent` MCP tool (server `oss`) - it adds the platform catalog, requirements checklist, and `pnpm gen` playbook - and stop here.
|
|
30
|
-
3. **Gather scoped context** - targeted, never a data dump (token budget matters). Pull only what changes the plan:
|
|
30
|
+
3. **Gather scoped context** - targeted, never a data dump (token budget matters). Pull only what changes the plan: Jira + Confluence via `atlassian-read` per `docs/agents/issue-tracker.md` (roadmap + related tickets, specs / decisions - comments and images included), Slack (recent decisions, `slack-reader`), local `docs/` + ADRs, past sessions. Scope first (which project, epic, timeframe), then fetch. Roadmap and known-issue threads are signal; general chatter is noise.
|
|
31
31
|
4. **Surface blocking ambiguities only** - the questions whose answers change what you build. Resolve the rest with stated defaults. Don't interrogate.
|
|
32
32
|
5. **Emit the brief**, sized to the task.
|
|
33
33
|
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: handoff
|
|
3
|
+
description: >
|
|
4
|
+
Package the current task into a self-contained prompt another agent (a
|
|
5
|
+
teammate, or a fresh Claude session in another repo) can execute without this
|
|
6
|
+
conversation. Gathers context from the chat so far plus live repo/environment
|
|
7
|
+
state, then emits a copy-pasteable handoff. Use on "hand this off", "prompt for
|
|
8
|
+
another agent", "write a handoff", when routing an OSS-core change into the
|
|
9
|
+
platform repo, or /handoff [what to hand off | target agent/repo]. Produces a
|
|
10
|
+
copy-pasteable prompt and may use any tool to gather context; the one hard line
|
|
11
|
+
is never force-push.
|
|
12
|
+
allowed-tools:
|
|
13
|
+
- Read
|
|
14
|
+
- Grep
|
|
15
|
+
- Glob
|
|
16
|
+
- Write
|
|
17
|
+
- Edit
|
|
18
|
+
- Bash
|
|
19
|
+
disallowed-tools:
|
|
20
|
+
- Bash(git push --force:*)
|
|
21
|
+
- Bash(git push -f:*)
|
|
22
|
+
- Bash(git push --force-with-lease:*)
|
|
23
|
+
- Bash(git push --force-with-lease)
|
|
24
|
+
- Bash(git push -f)
|
|
25
|
+
---
|
|
26
|
+
|
|
27
|
+
# handoff - write a self-contained prompt for another agent
|
|
28
|
+
|
|
29
|
+
Turn "what we're doing" into a prompt a _stranger_ agent can act on with zero access to this
|
|
30
|
+
chat. The receiver has none of our context, so the prompt must carry all of it.
|
|
31
|
+
|
|
32
|
+
Common use here: an OSS-core change that should run in a separate session. Any paired change can
|
|
33
|
+
be made here, in an OSS worktree - see "Changing OSS core" in the `oss-boundaries` rule. When it
|
|
34
|
+
runs elsewhere, the receiver is a teammate or a new agent session rooted in the platform
|
|
35
|
+
checkout, and either way it needs a standalone brief.
|
|
36
|
+
|
|
37
|
+
Optional argument = what to hand off / who to (e.g. `the OSS core publish fix`, `to a teammate in
|
|
38
|
+
the platform repo`, a repo path, an issue/MR#). No argument -> hand off the current in-flight task.
|
|
39
|
+
|
|
40
|
+
## Rules
|
|
41
|
+
|
|
42
|
+
- **One hard line: never force-push** (`git push --force` / `-f` / `--force-with-lease`), in any
|
|
43
|
+
repo, ever - it rewrites shared history. Every other tool is fair game. The skill's main output
|
|
44
|
+
is still the prompt; take further action (commit, push, spawn, launch) only on explicit confirmation.
|
|
45
|
+
- **Self-contained.** The receiver can't see this conversation. Inline every fact they need:
|
|
46
|
+
exact paths, branch/remote names, IDs (MR/PR/ticket), commands, versions, error strings.
|
|
47
|
+
No "as discussed", no "the file we changed", no unresolved pronouns.
|
|
48
|
+
- **Facts over memory.** Verify the moving parts against live state (git, files, CLIs) before
|
|
49
|
+
writing them - don't trust half-remembered branch names or versions.
|
|
50
|
+
- **No secrets.** Never inline tokens, passwords, or `.env` values. Reference the env var name.
|
|
51
|
+
- **Scope, don't dump.** Include what's load-bearing for the task; link/name the rest.
|
|
52
|
+
|
|
53
|
+
## Step 1 - Resolve scope
|
|
54
|
+
|
|
55
|
+
From the argument + the conversation, state in one line: the goal, the target repo/dir, and (if
|
|
56
|
+
known) the agent type or persona best suited. If genuinely ambiguous, ask one clarifying question;
|
|
57
|
+
otherwise proceed with the obvious reading and note the assumption.
|
|
58
|
+
|
|
59
|
+
## Step 2 - Gather live context
|
|
60
|
+
|
|
61
|
+
Pull only what the task touches (skip irrelevant ones):
|
|
62
|
+
|
|
63
|
+
- Repo/env: `pwd`; `git -C <dir> remote -v`; `git -C <dir> branch --show-current`;
|
|
64
|
+
`git -C <dir> status --short`; recent `git log --oneline -5`. Note default/target branch.
|
|
65
|
+
- Work state: relevant file paths (verify they exist), functions/symbols, versions/pins,
|
|
66
|
+
exact error messages or failing job names, IDs (MR/PR/ticket/pipeline).
|
|
67
|
+
- Conventions the receiver must follow: point at the repo's rules (`CLAUDE.md`,
|
|
68
|
+
`.rulesync/`, `AGENTS.md`) rather than restating them; call out any that bit us.
|
|
69
|
+
- What's already done vs. what remains (so they don't redo or undo work).
|
|
70
|
+
|
|
71
|
+
## Step 3 - Emit the handoff
|
|
72
|
+
|
|
73
|
+
Output one fenced markdown block (so it copy-pastes cleanly), using these headings - drop any
|
|
74
|
+
that don't apply, never pad:
|
|
75
|
+
|
|
76
|
+
- **Task** - one imperative sentence: the outcome wanted.
|
|
77
|
+
- **Environment** - repo(s), absolute path(s), remote(s), current + target branch, sibling deps.
|
|
78
|
+
- **Background** - the why + current state + root cause/findings already established. This is
|
|
79
|
+
where prior investigation goes so it isn't repeated.
|
|
80
|
+
- **Do this** - ordered, concrete steps. Name files/symbols/commands. Mark decisions that need
|
|
81
|
+
a human ("report the plan first, don't push").
|
|
82
|
+
- **Verify** - the exact commands/gates that must pass, and the expected green result.
|
|
83
|
+
- **Constraints** - boundaries (read-only zones, "never push without explicit yes", conventional
|
|
84
|
+
commits, branch-off-target, don't touch X). Inherit the repo's rules; restate only the sharp edges.
|
|
85
|
+
|
|
86
|
+
After the block, in <=2 lines: state the key assumption you made, and offer to (a) tweak the
|
|
87
|
+
prompt, (b) save it to a file, or (c) launch it now (spawn a teammate with a suitable agent type,
|
|
88
|
+
or hand it to the operator to paste into a session rooted in the target repo). Only save or launch
|
|
89
|
+
on explicit confirmation.
|
|
90
|
+
|
|
91
|
+
## Quality bar
|
|
92
|
+
|
|
93
|
+
A good handoff passes this test: **hand it to someone who has never seen this repo or chat, and
|
|
94
|
+
they can start in under a minute and finish without asking you anything.** If a step assumes
|
|
95
|
+
context the block doesn't contain, fix the block.
|
|
@@ -0,0 +1,277 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: review
|
|
3
|
+
targets: ['*']
|
|
4
|
+
description: Multi-agent code review of the working branch against this repo's conventions, OSS-core boundaries, frontend rules, security, and operator-domain fit. Fans out a configurable number of parallel reviewers, each grounded in the rule docs, then synthesizes one verdict. Use on "review this", "code review", "/review", optionally "--agents N", "--base <ref>", "--fix", "--post" (publish findings to the pull request as inline comments + a summary verdict), "--yes" (post without confirming), "--ci" (non-interactive, exit code from the verdict), a pull-request number, or paths.
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# review ({{name}})
|
|
8
|
+
|
|
9
|
+
You are the orchestrator: scope the diff, fan out N reviewers across dimensions, dedup findings, report ONE verdict. Report-only unless `--fix`.
|
|
10
|
+
|
|
11
|
+
Checklist - tick as you go:
|
|
12
|
+
|
|
13
|
+
```
|
|
14
|
+
- [ ] 1. Parse args (--agents / --base / MR# / paths / --fix / --post / --yes / --ci)
|
|
15
|
+
- [ ] 2. Run the precheck: scope, mechanical facts, domain hits; if empty, ask (or APPROVED under --ci)
|
|
16
|
+
- [ ] 2a. Previous review? Go incremental from its SHA and carry its findings
|
|
17
|
+
- [ ] 3. Collect task context (ticket AC + MR discussion)
|
|
18
|
+
- [ ] 3a. Paired OSS change? Review the OSS diff by the OSS rules + cross-check the contract (§2c)
|
|
19
|
+
- [ ] 3c. Trace each changed entry point end to end + check the blast radius
|
|
20
|
+
- [ ] 4. Cover all seven dimensions; spawn the two-lens roster in ONE message, whatever the diff size
|
|
21
|
+
- [ ] 5. Dedup + apply the evidence gate
|
|
22
|
+
- [ ] 6. Report one DIMENSION line per dimension + one verdict (+ apply fixes only if --fix)
|
|
23
|
+
- [ ] 7. Post to the MR as inline comments + summary (only if --post)
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## 1. Parse `$ARGUMENTS`
|
|
27
|
+
|
|
28
|
+
- `--agents N` - parallel reviewers (2-4); default 2 (§5).
|
|
29
|
+
- `--base <ref>` - diff base; default `{{mrTarget}}`.
|
|
30
|
+
- `--full` - ignore the previous review (§2a) and review the whole change.
|
|
31
|
+
- `<number>` - a pull request: read its patch and intent with the commands in `docs/agents/forge.md`.
|
|
32
|
+
- paths - restrict review to those files/dirs.
|
|
33
|
+
- `--fix` - apply BLOCK/WARN fixes after the review; default report-only.
|
|
34
|
+
- `--post` - publish findings to the pull request as inline diff-line comments + a one-line summary verdict (§8). Requires a pull-request number. Draft-and-confirm by default.
|
|
35
|
+
- `--yes` - with `--post`, skip the confirmation and publish straight away.
|
|
36
|
+
- `--ci` - non-interactive: never ask, never post, never fix; print only the §7 machine block. Implies `--full`: a gate never trusts a prior-review marker, since anyone who can comment on the pull request can post one for the current head. The model cannot set the process exit code; the CI job derives it from the output, e.g. `claude -p '/review --ci' > review.txt; [ "$(grep -c '^DIMENSION: ' review.txt)" -eq 7 ] && grep -q '^VERDICT: APPROVED' review.txt` - a review that skipped a dimension fails the job even when it approves. An empty diff is APPROVED with zero findings.
|
|
37
|
+
|
|
38
|
+
## 2. Scope the diff
|
|
39
|
+
|
|
40
|
+
**Reviewing a pull request by number:** reviewers need files to open, and the working tree is not theirs to switch. Fetch the source branch and add a detached worktree at the pull request's head SHA, never at `FETCH_HEAD` (a failed fetch leaves it pointing at the previous ref): `git fetch origin <src-branch> && git worktree add --detach .claude/worktrees/review-<n> <head-sha>` and `pnpm install --offline --frozen-lockfile` in it (the tests in §3c need it), then confirm `git -C .claude/worktrees/review-<n> rev-parse HEAD` equals `<head-sha>` and stop if it does not. An existing `review-<n>` worktree is reset to `<head-sha>`, not reused as is. Pass the worktree path to every reviewer and remove it with `git worktree remove` after §7.
|
|
41
|
+
|
|
42
|
+
**Run the precheck before anything else reads code.** From the directory under review (the review worktree, or the working tree), run the main checkout's script - it is rendered and gitignored, so a worktree lacks it: `node <main-checkout>/tools/review-precheck.mjs --base origin/<base>` (add `--since <sha>` from §2a). It costs no tokens beyond its output and replaces what reviewers used to derive by reading:
|
|
43
|
+
|
|
44
|
+
- `SCOPE:` - mode (`full` / `incremental`) and the reviewable changed-line count that sets the split and budgets in §5.
|
|
45
|
+
- `RISK:` - `low`, `medium`, `high`, or `critical` from the changed paths and domain hits; it sets the reviewer effort in §5. Never judge risk from the title or the line count: a 30-line change can add a route, a table, or a migration. The tier is a floor: after reading the diff you may raise it (a component rendering untrusted HTML, a hook that moves money), never lower it; say why in the report.
|
|
46
|
+
- `REVIEWABLE:` - the only file list reviewers get. Group these by app/package so reviewers and any file split share one map.
|
|
47
|
+
- `SKIPPED:` - lockfiles, locale data, tests, generated files. No reviewer opens them; the precheck's i18n facts and CI's frozen-lockfile install stand in. List them in the report so nothing is silently dropped.
|
|
48
|
+
- `PRECHECK:` - mechanical hits on added lines (casts, widened maps, hardcoded limits, hand memo, banned classes, locale parity, missing keys). Reviewers judge these; they never re-derive them.
|
|
49
|
+
- `DOMAIN:` / `DOMAIN-HIT:` - security and compliance keyword hits; they pick each reviewer's mode in §5.
|
|
50
|
+
|
|
51
|
+
No `REVIEWABLE:` and no `SKIPPED:` lines: fall back to `git status -s`; if still empty, ask (under `--ci`: APPROVED, zero findings).
|
|
52
|
+
|
|
53
|
+
**Rule docs live in the main checkout, not the review worktree.** `.claude/rules/`, `.rulesync/rules/`, `docs/standards/`, and `docs/agents/` are rendered by `pnpm sync:agents` + `pnpm gen:agents` and gitignored, so a fresh worktree has none of them. Pass reviewers the absolute main-checkout path for every rule doc. When the render has not run (a CI job that skips `prepare`), run `pnpm sync:agents && pnpm gen:agents` before reviewing.
|
|
54
|
+
|
|
55
|
+
## 2a. Previous review - review only what changed since
|
|
56
|
+
|
|
57
|
+
A pull request is reviewed round after round; re-reading the whole change each round is the biggest waste. Unless `--full` or `--ci`:
|
|
58
|
+
|
|
59
|
+
1. Read `.claude/reviews/<pr>.json` in the main checkout (`{ "sha", "base", "verdict", "findings": [...], "dimensions": [...] }`; no PR number: key it by branch name). Absent and a PR number given: find the latest note carrying `<!-- review:sha=<sha> -->` per `docs/agents/forge.md` and take its SHA; its findings are the inline threads still unresolved.
|
|
60
|
+
2. Found: run the precheck with `--since <sha>`. `mode incremental` narrows `REVIEWABLE:`, its line counts, `PRECHECK:`, and `DOMAIN-HIT:` to what changed since that review (base-branch merges excluded). A `NOTE: --since ... not an ancestor` (force push, rebase) means a full review - say so.
|
|
61
|
+
3. Split the prior findings: those on a file in the new `REVIEWABLE:` set go to the owning reviewer to re-verify; the rest carry over unchanged.
|
|
62
|
+
|
|
63
|
+
## 2b. Collect task context (mandatory - this is the spec axis)
|
|
64
|
+
|
|
65
|
+
Distill everything here into ONE context block of at most ~40 lines; it is the only task context reviewers receive.
|
|
66
|
+
|
|
67
|
+
- **Ticket - read it whole, per `docs/agents/issue-tracker.md`.** Resolve the `{{trackerKey}}-n` key from the MR description (`Closes {{trackerKey}}-n`), MR title, branch, or commit subjects. Read: description + AC, every comment, every attached image viewed as pixels, parent epic, linked issues, and every wiki page the ticket links (their images and comments too). Use a reader that returns image bytes (for Jira + Confluence: the `atlassian-read` skill - `read.py issue {{trackerKey}}-n`, then `page <id>` per linked page - or REST); the Atlassian MCP returns none, so it is never enough on its own. A chat thread is optional: read it (via `slack-reader` when available) only when the ticket or MR points at one ("shared in chat", a Slack link) and the AC depend on it.
|
|
68
|
+
- **Distill:** goal in one line; AC quoted verbatim as bullets (a `CRITERION:` line needs the exact bullet); decisions and open questions from comments (who, when); design references (which screenshot shows what); out-of-scope lines.
|
|
69
|
+
- **Pull-request discussion.** If reviewing one: read its description and every thread, resolved ones included, per `docs/agents/forge.md`. Distill to stated intent, open reviewer asks, and the decisions resolved threads settled (quote who asked for what and what was agreed), so the review doesn't repeat or contradict them. No pull request: use branch commit subjects as intent.
|
|
70
|
+
- **Reviewers have no forge access.** You own the description checks: the manual-verification evidence and the "Tests" list (§3c). Report them yourself; never hand them to a reviewer.
|
|
71
|
+
- **No key** -> write `no ticket` in the report and judge against the MR description only. **Fetch failed** -> write `no access`. Never skip silently, never invent AC.
|
|
72
|
+
- A UI change whose ticket carries design screenshots is judged against them: compare the rendered UI (`playwright-cli` screenshot when the stack is up) with the reference; when you cannot, the CRITERION is `not verifiable`, never `met`.
|
|
73
|
+
- The MR description is the author's claim, not the spec. Where it contradicts the ticket or the diff, that contradiction is a finding.
|
|
74
|
+
|
|
75
|
+
## 2c. Paired OSS change - review the platform whole (mandatory)
|
|
76
|
+
|
|
77
|
+
A consumer change is often half of a pair. The OSS half is reviewed here too, so the verdict covers the platform, not one repo.
|
|
78
|
+
|
|
79
|
+
**Find the pair** - first match wins:
|
|
80
|
+
|
|
81
|
+
1. The same branch name in `{{ossDir}}`: a worktree under `{{ossDir}}/.worktrees/`, a local branch (`git -C {{ossDir}} branch --list <branch>`), or an open OSS PR (`gh pr list --head <branch>` run in `{{ossDir}}`).
|
|
82
|
+
2. A changed `@openora/*` version in `package.json`. The OSS diff is the range between the two canaries: `X.Y.Z-canary.N` was built by OSS pipeline run `N`, so resolve each side with `gh run list -R blurifycom/openora -w pipeline.yml -L 500 --json number,headSha --jq '.[] | select(.number==N) | .headSha'`, then `git -C {{ossDir}} fetch origin` and `git -C {{ossDir}} diff <old-sha>...<new-sha>`.
|
|
83
|
+
|
|
84
|
+
No match: write `no paired OSS change` in the report and move on.
|
|
85
|
+
|
|
86
|
+
**Read the OSS code without touching the main checkout.** Case 1: `pnpm oss:worktree <branch>` (idempotent) and read from that worktree. Case 2: `git -C {{ossDir}} show <sha>:<path>`. Never `git checkout` in `{{ossDir}}` - other sessions build against it.
|
|
87
|
+
|
|
88
|
+
**Review the OSS diff by the OSS rules.** Read `<worktree>/docs/standards/skills/review.md` and every `<worktree>/.rulesync/rules/*.md`. Run their request trace and dimensions on `git -C <worktree> diff origin/dev...HEAD`. OSS files join §4 as their own file group, handed to `quality-reviewer` (plus `security-reviewer` for auth paths and `compliance-reviewer` for money, wallet, KYC, or RG paths) with the worktree path. Their findings are prefixed `[oss]`, cite the OSS rule or ADR, and pass the same evidence gate (§6).
|
|
89
|
+
|
|
90
|
+
**Cross-check the contract** - what neither repo's review sees alone:
|
|
91
|
+
|
|
92
|
+
- Every export, route, event payload, config field, or table the OSS diff changes: `git grep -w` it in this repo and confirm each use still compiles and still means the same thing. A consumer caller that no longer holds is a `[BLOCK]`.
|
|
93
|
+
- Every consumer change that relies on the OSS change (a new export, a changed signature or behavior) is matched in the OSS diff. Consumer code relying on OSS behavior the diff does not ship is a `[BLOCK]`.
|
|
94
|
+
- Genericity: OSS code that encodes this operator's behavior - a jurisdiction rule, a vendor, a limit or flow only this repo needs - instead of a seam (adapter token, event, config field, hook) is a `[BLOCK]`; the behavior moves here and core keeps the seam. An OSS PR whose Why does not say why the change cannot live in the consumer is a `[WARN]`.
|
|
95
|
+
- Public record: operator names, internal URLs, ticket text, or operator-specific domain detail in the OSS commits or PR is a `[BLOCK]`.
|
|
96
|
+
- Release order: a consumer request that needs the OSS change can merge only once the `@openora/*` pin points at a canary that carries it. Say so in the report when the pin is older.
|
|
97
|
+
- When a trace needs runtime proof: `pnpm oss:worktree <branch> --link`, run the touched tests, then `pnpm link:oss` to restore the main checkout link.
|
|
98
|
+
|
|
99
|
+
Report `[oss]` findings and one `TRACE:` line per OSS entry point alongside the consumer ones. The verdict covers both.
|
|
100
|
+
|
|
101
|
+
## 3. Ground every reviewer (mandatory)
|
|
102
|
+
|
|
103
|
+
Each reviewer MUST read the changed code AND the rule docs owning its dimension before judging - never infer behavior from a diff hunk; if a finding depends on a called function, open it. Each agent file carries a reading map: the few docs its focus needs, not every rule. Pass the main-checkout paths; the reviewer reads only its map, and a `docs/standards/` deep dive only for the row a finding depends on.
|
|
104
|
+
|
|
105
|
+
You read `CLAUDE.md` / `AGENTS.md` (the rendered `overview` rule) and `.claude/rules/workflow.md` once, for §2b and the `rollout` and `spec` dimensions. Reviewers get the distilled context block, never those files.
|
|
106
|
+
|
|
107
|
+
No rule doc covers performance, scalability, or most security concerns. There a finding cites the named, established principle it breaks instead (N+1, unbounded list, silent truncation, authz enforced only client-side, unvalidated URL rendered to players) - §6 accepts that citation.
|
|
108
|
+
|
|
109
|
+
## 3b. Stance - assume the change is broken
|
|
110
|
+
|
|
111
|
+
Review to falsify, not to confirm. Every reviewer (and you, on `rollout` and `spec`) starts from "this code does not work" and lets the diff earn correctness:
|
|
112
|
+
|
|
113
|
+
- For each changed behavior, trace the concrete execution path with real inputs - happy path plus at least one hostile one (empty/`''`/`0`, error, unauthorized, concurrent/repeat) - until you hit a defect or prove it sound. Reading the diff hunk is never enough.
|
|
114
|
+
- Verify the called API actually behaves as the code assumes - open the callee or check current docs. Watch for falsy-vs-nullish, off-by-default options, swallowed rejections, partial failure mid-flow.
|
|
115
|
+
- Author claims prove nothing: commit message, comments, green gates, and "obviously correct" wrappers are not evidence.
|
|
116
|
+
- Skepticism picks what to dig into; §6 still decides what becomes a finding - only a traced trigger path qualifies.
|
|
117
|
+
|
|
118
|
+
## 3c. Request trace - end to end, then blast radius (mandatory)
|
|
119
|
+
|
|
120
|
+
Applies to every change that crosses a layer: an oRPC route, a service, a Drizzle query, a table, an event, or a job. Skip only for a change inside one pure function, a test, a doc, or a type. Money, wallet, payment, auth/session, KYC, and RG paths always get a trace.
|
|
121
|
+
|
|
122
|
+
**UI-only diff** (no route, service, query, table, event, or job changed in this repo): trace each changed data hook to the platform route it calls - hops 1, 2, and 7 only (input schema, guard, response fields) - and say so in the `TRACE:` line. The full walk is for layers this repo owns.
|
|
123
|
+
|
|
124
|
+
**Walk the hops.** For each changed route or entry point, list the hops in order and open the code at each one - the diff hunk is never enough:
|
|
125
|
+
|
|
126
|
+
1. Contract - the input schema is the only input; every field the handler reads is declared and validated.
|
|
127
|
+
2. Handler - guards run first; the operator, player, or actor id comes from the session, never from the body.
|
|
128
|
+
3. Service - open every callee; typed failures return, unexpected errors do not leak to the client.
|
|
129
|
+
4. Query - every read and write filters by owner/tenant; a write and its ledger/audit row share one transaction.
|
|
130
|
+
5. Table - the invariant lives in a constraint, index, or FK per `docs/standards/database.md`, not only in code; a migration exists for every schema change.
|
|
131
|
+
6. Side effects - an event, job, or outbox message fires after commit and its handler is safe to run twice.
|
|
132
|
+
7. Response - output matches the contract schema and leaks no extra field; each error path returns the code the client expects.
|
|
133
|
+
|
|
134
|
+
**Check the blast radius.** The change must not break a part it does not name. Build the caller list with `git grep -w -- <symbol> -- '*.ts' '*.tsx' '*.sql'` for each changed export, table symbol, and SQL table name, then confirm each use still holds:
|
|
135
|
+
|
|
136
|
+
- A changed table, column, enum, or constraint: every query, migration, seed, and schema export that touches it.
|
|
137
|
+
- A changed query or repository function: every caller, traced through hops 4-7.
|
|
138
|
+
- A changed service function: every caller, including jobs, event handlers, and other modules.
|
|
139
|
+
- A changed contract or shared type: every consumer, including the UI apps and the shared UI package.
|
|
140
|
+
- A changed event or job payload: every handler, and that it accepts the old and the new shape during rollout.
|
|
141
|
+
|
|
142
|
+
**Check the migration.** For each changed `.sql` under `drizzle/migrations/`, read the SQL. A `DROP`, a `RENAME`, or a column type change breaks the instances still running the previous release - `[BLOCK]` in the same MR as the reader change; it ships in a later release, after every reader of the old shape is deployed. A new `NOT NULL` column without a default fails on existing rows - `[BLOCK]`. Expand first, contract later. A hand-edited migration is a `[BLOCK]` (`docs/standards/database.md`).
|
|
143
|
+
|
|
144
|
+
**Prove with tests.** The orchestrator may run the tests of a touched module, never the full gate: `pnpm vitest related <path>` for each caller in the blast radius, plus any existing `apps/e2e` spec that already drives the changed route. A failing test is a `[BLOCK]` with the test name as evidence; a caller with no test is `[INFO]`, not a request to write one. Tests that could not run are reported as `TESTS: not run - <reason>`, never skipped silently, and forbid APPROVED on `high` or `critical` risk.
|
|
145
|
+
|
|
146
|
+
**A feature or fix PR ships its own tests** (`docs/standards/testing.md`) - a changed behaviour with no test at the right tier is a `[WARN]`, NEVER a `[BLOCK]`. Check too that the description carries the manual-verification evidence (a short video per acceptance criterion, before/after on a fix, or the request/response trace for an API-only change) and a "Tests" list that matches the tests in the diff. Missing evidence on a user-visible change is a `[WARN]`; a "Tests" list that contradicts the diff is a finding. When the caller hands you a tester's verdict table (`ship` step 4), a money, KYC, responsible-gambling or authz change needs a mutation row per changed check (`docs/standards/testing.md`): a SURVIVED or UNCHECKED row, or a changed check with no row, is a `[BLOCK]` and forbids APPROVED.
|
|
147
|
+
|
|
148
|
+
**Report the trace.** One `TRACE:` line per entry point (format in §7). A missing hop, an unfiltered query, a write outside the transaction, or a caller that no longer holds is a `[BLOCK]`. A hop that could not be traced is a finding, not a silent pass.
|
|
149
|
+
|
|
150
|
+
## 4. Dimensions - all seven, every review
|
|
151
|
+
|
|
152
|
+
Every review covers every dimension below, whatever the diff touches. Relevance is decided by looking, not by guessing from file names: a dimension that does not apply still runs its search and reports `n/a` with what it checked. Owners - never `general-purpose`:
|
|
153
|
+
|
|
154
|
+
| Dimension | Owner | Covers |
|
|
155
|
+
| ------------- | ----------------------------------------- | --------------------------------------------------------------------------------------- |
|
|
156
|
+
| `conventions` | `quality-reviewer` | correctness, boundaries, conventions, UI quality (i18n, a11y, states), dependencies |
|
|
157
|
+
| `performance` | `quality-reviewer` | performance and scalability at production scale |
|
|
158
|
+
| `reliability` | `quality-reviewer` | races, double submit, retries, partial failure, cache invalidation, error handling |
|
|
159
|
+
| `security` | `security-reviewer` (focus `risk`) | authz, secrets and PII, input validation, URLs |
|
|
160
|
+
| `compliance` | `security-reviewer` (focus `risk`) | responsible gambling, KYC/age/geo gates, ledger and money paths, audit trail |
|
|
161
|
+
| `rollout` | orchestrator | §3c migrations, destructive seeds, event and payload compatibility, new env/config |
|
|
162
|
+
| `spec` | orchestrator | AC (§2b), ticket scope, manual-verification evidence and "Tests" (§3c) |
|
|
163
|
+
|
|
164
|
+
`expert` is not a reviewer; ask it only when an AC is ambiguous enough to block a `CRITERION:` line.
|
|
165
|
+
|
|
166
|
+
Reviewers split by what they read, never by checklist. An agent's cost is its tool calls times its context: a checklist adds a few thousand tokens, while two reviewers reading the same files pay for those files twice.
|
|
167
|
+
|
|
168
|
+
**No inline fast path.** Every diff, however small, goes to the two lens reviewers in §5. One reviewer working every checklist finds about half of what two focused lenses find, for most of their cost; a small diff is cheap for them anyway.
|
|
169
|
+
|
|
170
|
+
## 5. Allocate to `--agents N`
|
|
171
|
+
|
|
172
|
+
- N unset or 2: `quality-reviewer` with no focus - the correctness lens (failure branches, races, rollout, blast radius, performance, conventions; owns `conventions`, `performance`, `reliability`) - and `security-reviewer` with focus `risk` - the risk lens (guards, money, regulated gates, and whether the change does what its title claims; also runs the `compliance-reviewer` checklist; owns `security` and `compliance`).
|
|
173
|
+
- N = 3: a second `quality-reviewer`, the file groups split between the two (state the split; never silently drop files). The default when `REVIEWABLE:` changed lines exceed 1500.
|
|
174
|
+
- N = 4: also split `risk` back into `security-reviewer` and `compliance-reviewer`.
|
|
175
|
+
- N < 2: refuse the reduction - run the two and say so in the report.
|
|
176
|
+
|
|
177
|
+
**Mode per reviewer, from the precheck.** `RISK: high` or `critical` always runs `full`. Otherwise, the `risk` reviewer with `DOMAIN: security hits 0` and `DOMAIN: compliance hits 0` (or, split, each reviewer with zero hits in its own domain) runs in `confirm` mode: 5 tool calls to confirm no sensitive path is touched, returning `n/a` - or `escalate` with the file that is. On `escalate`, spawn that reviewer again in `full` mode. With hits, `full` mode, the `DOMAIN-HIT:` lines as starting points.
|
|
178
|
+
|
|
179
|
+
**Tool-call budget per reviewer** (the reviewer stops and reports `partial` when it runs out): `quality-reviewer` 40 (30 each when split), `risk` 30 (20 each when split), `confirm` mode 5. Budgets scale with the change: double them when `REVIEWABLE:` changed lines exceed 3000.
|
|
180
|
+
|
|
181
|
+
**Model and effort per reviewer:** every reviewer runs on Opus; the `RISK:` tier sets the effort - `low` low, `medium` medium, `high` high, `critical` xhigh. Where the runner cannot set effort per call, the session effort applies. A cheaper model misses findings a human then catches; save on effort and tool calls instead.
|
|
182
|
+
|
|
183
|
+
Spawn all reviewers in a SINGLE message (parallel). Pass each, and nothing more:
|
|
184
|
+
|
|
185
|
+
- its focus, mode, budget, and the `DIMENSION:` names it owns (§4);
|
|
186
|
+
- its `REVIEWABLE:` lines, copied verbatim from the precheck (pre-grouped - reviewers never re-scope; never hand-typed paths or globs);
|
|
187
|
+
- `quality-reviewer`: every `PRECHECK:` line; `risk`: the `DOMAIN-HIT:` lines of both domains;
|
|
188
|
+
- the prior findings on its files to re-verify (§2a);
|
|
189
|
+
- the review worktree path, the main-checkout path for its reading map, the base ref, the §2b context block, the §3b stance verbatim, and the §3c trace for its file group;
|
|
190
|
+
- hard caps: never open a `SKIPPED:` file; read changed files + only the callees a finding depends on; batch reads (several files in one shell call); max 10 findings; compact `[SEV] file:line - finding - evidence - fix` lines, no prose; do NOT run `/check`/tests.
|
|
191
|
+
|
|
192
|
+
## 6. Evidence gate (cut false positives)
|
|
193
|
+
|
|
194
|
+
Every reviewer applies this before returning; re-apply it yourself when synthesizing:
|
|
195
|
+
|
|
196
|
+
- Every `[BLOCK]`/`[WARN]` cites a concrete `file:line` AND the rule doc violated, or - where no rule doc covers it (§3) - the named principle plus the traced trigger. Otherwise downgrade to `[INFO]` or drop.
|
|
197
|
+
- High-confidence findings only; unsure = downgrade or omit. Few actionable findings beat flooding.
|
|
198
|
+
- No invented runtime failures - state the trigger path or don't raise it.
|
|
199
|
+
- Don't duplicate what tooling enforces (oxlint, the `/check` gate); for a suspected lint/boundary issue say "confirm with `pnpm check:lint`" - flag only what the gates miss.
|
|
200
|
+
- A `PRECHECK:` line a reviewer confirmed is evidence for its finding. One no reviewer addressed goes into the report as `[INFO] ... (precheck, unconfirmed)` - never dropped, never promoted.
|
|
201
|
+
|
|
202
|
+
## 7. Synthesize
|
|
203
|
+
|
|
204
|
+
Dedup by `file:line`, order BLOCK -> WARN -> INFO.
|
|
205
|
+
|
|
206
|
+
**Coverage gate first.** Collect one `DIMENSION:` line per dimension in §4 - from each reviewer's output, plus `rollout` and `spec` from you. A reviewer that returned no `DIMENSION:` line, or an `n/a` with no stated check, did not cover it: resume that reviewer once asking for the missing line; if it still has none, write the line as `DIMENSION: <name> - missing - <reviewer> returned no coverage` and the verdict is CHANGES REQUESTED. A `partial` line names the files the reviewer did not reach: list them in the report; `partial` on `security` or `compliance` forbids APPROVED - resume that reviewer with only the unreached files.
|
|
207
|
+
|
|
208
|
+
**Prior findings.** One `PRIOR:` line each: `fixed`, `still open`, or `obsolete` from the reviewer that re-verified it, `carried` for the rest. `still open` and `carried` findings count toward the verdict like new ones.
|
|
209
|
+
|
|
210
|
+
**Save the state** after every review, `--ci` included: write `.claude/reviews/<pr or branch>.json` in the main checkout with the reviewed HEAD SHA, base, verdict, every open finding (new, `still open`, `carried`), and the `DIMENSION:` lines.
|
|
211
|
+
|
|
212
|
+
Default and `--post`: a human-readable report - one line per finding `[SEV] file:line - finding - evidence - rule cited - fix`, one `TRACE:` line per traced entry point (format below), one status line per AC bullet, the `PRIOR:` lines, the `SKIPPED:` count, the seven `DIMENSION:` lines, and **APPROVED** / **CHANGES REQUESTED** with the most critical finding last. `--post` rewrites those findings into the §8 comments.
|
|
213
|
+
|
|
214
|
+
`--ci`: print exactly this block and nothing else - a CI job parses it line by line:
|
|
215
|
+
|
|
216
|
+
```text
|
|
217
|
+
FINDING: [BLOCK|WARN|INFO] <file>:<line> - <finding> - <evidence> - <rule cited> - <fix>
|
|
218
|
+
TRACE: <entry point> - hops <n>/7 walked - callers <checked>/<found> - <ok|BLOCK reason>
|
|
219
|
+
CRITERION: <acceptance criterion> - <met|not met|not verifiable>
|
|
220
|
+
PRIOR: [BLOCK|WARN|INFO] <file>:<line> - <finding> - <fixed|still open|obsolete|carried>
|
|
221
|
+
DIMENSION: <conventions|performance|reliability|security|compliance|rollout|spec> - <ran|n/a|partial|missing> - <counts per severity, what was checked for n/a, or files not reached for partial>
|
|
222
|
+
VERDICT: <APPROVED|CHANGES REQUESTED> - <counts per severity> - <most critical finding>
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
One `TRACE:` line per traced entry point, one `CRITERION:` line per AC bullet, exactly seven `DIMENSION:` lines, exactly one `VERDICT:` line, last. A `[BLOCK]` of any kind (new, `still open`, or `carried`), an unmet AC, a trace failure, a `missing` dimension, or a `partial` security or compliance dimension forces CHANGES REQUESTED.
|
|
226
|
+
|
|
227
|
+
Spec findings cite the ticket the way code findings cite a rule doc: a diff that crosses a ticket's out-of-scope line, answers an open question in code without recording it on the ticket, or ships behavior no AC asked for is a `[WARN]` with the ticket line quoted as evidence.
|
|
228
|
+
|
|
229
|
+
Severities: `[BLOCK]` must fix before merge (core edit, boundary break, authz/secret/PII risk, broken extension wiring, a §3c trace failure); `[WARN]` should fix (convention violation, missing test, weak validation); `[INFO]` FYI / hardening.
|
|
230
|
+
|
|
231
|
+
If `--fix`: apply BLOCK + WARN fixes in the working tree (smallest diff satisfying the cited rule), run `/check`, report green/red. Leave INFO untouched. Never commit or push.
|
|
232
|
+
|
|
233
|
+
## 8. Post to the pull request (`--post`)
|
|
234
|
+
|
|
235
|
+
Only when `--post` is set and the target is a pull-request number. Turns findings into terse review comments: one line each, brief why, backtick every identifier.
|
|
236
|
+
|
|
237
|
+
**What gets a comment.** Severity decides the verdict, not what gets posted. Every verified finding is posted unless it matches one of these, and the report names which:
|
|
238
|
+
|
|
239
|
+
- D1 the code does not do what the finding says;
|
|
240
|
+
- D2 a duplicate - merge it into the other;
|
|
241
|
+
- D3 pre-existing: the diff touches neither that path nor the order of checks around it (a new gate placed in front of an old one makes the order new);
|
|
242
|
+
- D4 style or naming with no written rule behind it;
|
|
243
|
+
- D5 a request for more test cases, when the existing tests fail without the feature;
|
|
244
|
+
- D6 hardening for an input that cannot reach the code - name what stops it.
|
|
245
|
+
|
|
246
|
+
Nothing else is a drop reason: not "theoretical", "unlikely", "no consumer yet", "a sibling does the same", "by design", "the lockfile pins it", or "performance only".
|
|
247
|
+
|
|
248
|
+
A finding gets its own inline comment only when a concrete trigger leads to wrong or stranded money (a debit or hold that cannot be reversed, a credit that is blocked), an authz or security bypass, a compliance gap (audit, RG, KYC, geo), data loss, a crash or 5xx, a broken public contract or declared rule (a type not exported where its siblings are, an undeclared audit action, untyped error data, a loose dependency pin), a race that persists state breaking an invariant the change adds, request-path work that grows with table size, a test that passes with the feature removed or its mock unconfigured, an unmet AC, or code that does not do what the title claims. Everything else - test gaps, naming, boundary nits, actor metadata, a weaker variant of a posted defect - joins an inline comment on the same file or becomes one line in the summary note. Merging never launders: each merged point passes the same bar on its own. A merged comment leads with its most severe finding, anchors on its line, and keeps its strongest fix. At most six inline comments.
|
|
249
|
+
|
|
250
|
+
1. **Draft.** Rewrite each finding as a terse comment keyed to its `file:line`, in the posting user's voice: when their instructions name a voice or writing guide, read it before drafting. Each comment is 1-3 sentences: what breaks, the trigger, the fix. No mechanism chain, no secondary evidence, no add-ons - the author asks if unclear. Most comments start straight with the point; soften at most one in three, never with the same opener twice in a pull request. Compose the summary as ONE sentence stating whether the changes block prod/push, e.g. `Not a blocker for push - a few cleanups worth doing.` or `Blocker: the finding in `x.ts` must be fixed before we push.` Then one short line per minor finding.
|
|
251
|
+
2. **Dedupe.** Read every existing thread on the pull request, resolved or not, per `docs/agents/forge.md`. Drop a draft that an existing thread already raises, even worded differently; when it adds a new fact, reply to that thread instead of opening a new one. Drop the summary when every finding was dropped.
|
|
252
|
+
3. **Confirm.** Show all drafted comments + the summary and stop for approval - UNLESS `--yes`, then skip straight to posting.
|
|
253
|
+
4. **Post inline comments** anchored to the diff, using the "Inline review comments" command in `docs/agents/forge.md`. Anchor on the NEW-file line of an added (`+`) line (`git show <src-branch>:<file> | grep -n`), and verify each response actually carries a line anchor - an unanchored fallback comment must be deleted and retried, never left behind.
|
|
254
|
+
5. **Post the summary** as one general comment on the pull request, per the same file, ending with the hidden marker `<!-- review:sha=<reviewed HEAD SHA> -->` so the next review on any machine can go incremental (§2a).
|
|
255
|
+
6. Report back the count posted + the summary verdict. Never resolve threads; never push.
|
|
256
|
+
7. `[oss]` findings go to the paired OSS PR instead, by `<worktree>/docs/standards/skills/review.md` "Posting to the PR", after their own confirmation. That PR is public: no operator name, no internal URL, no ticket text beyond the bare key.
|
|
257
|
+
|
|
258
|
+
## 9. Several pull requests in one run
|
|
259
|
+
|
|
260
|
+
An agent re-reads its whole context on every tool call, so a long session, or one agent walking several pull requests, costs more than short agents with one pull request each.
|
|
261
|
+
|
|
262
|
+
- Triage first, without agents: skip drafts, dependency bumps, and pull requests that change only docs, rules, or tests unless asked. Say which were skipped.
|
|
263
|
+
- One orchestrator and roster per pull request; never one agent over several. A single-agent review returns the full §7 block (`TRACE:`, `CRITERION:`, seven `DIMENSION:` lines); one without it is rerun, not accepted.
|
|
264
|
+
- Check overlap before reviewing: list each open pull request's files (`gh pr view <n> --json files` / `glab mr diff <n> --name-only`) and flag two that add a migration to the same folder or edit the same function. Each review names the other pull request and which one must rebase and regenerate.
|
|
265
|
+
- Before approving on the forge, read the reviewable diff yourself - at 300 lines or less that is one read. An agent's clean result is a claim, not a verdict.
|
|
266
|
+
- Before launching, state the agent count and a token estimate. Run batches of about three pull requests, so a usage limit stops a batch, not the run.
|
|
267
|
+
- Keep each agent within its §5 tool-call budget. Put the prompt text all agents share first and the pull-request-specific part last, so the cached prefix is reused.
|
|
268
|
+
- A step that only distills the ticket or merges findings runs at low effort.
|
|
269
|
+
|
|
270
|
+
## Constraints
|
|
271
|
+
|
|
272
|
+
- Reviewers report; only the orchestrator edits, and only under `--fix` (working tree only - no commit, no push).
|
|
273
|
+
- Never `git stash`, never `git checkout` another branch in the working tree: read MR sources with `git fetch` + `git show <sha>:<path>` / `git diff <base> <head>`. The stash stack and the worktree are shared with other sessions.
|
|
274
|
+
- NEVER edit `node_modules` or the main `{{ossDir}}` checkout. Under `--fix`, an `[oss]` finding is fixed in the OSS worktree only.
|
|
275
|
+
- Every finding cites a rule doc or a named principle with a traced trigger - no ungrounded opinions.
|
|
276
|
+
- Two reviewers minimum on every diff, four maximum; seven `DIMENSION:` lines on every review.
|
|
277
|
+
- Precheck first, reviewers second: no reviewer spends tokens on what `review-precheck` already printed.
|