@webpieces/rules-config 0.4.775 → 0.4.776

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.
Files changed (43) hide show
  1. package/package.json +1 -1
  2. package/src/checklist-config.d.ts +37 -6
  3. package/src/checklist-config.js +55 -19
  4. package/src/checklist-config.js.map +1 -1
  5. package/src/checklist-docs-validator.d.ts +2 -2
  6. package/src/checklist-docs-validator.js +2 -2
  7. package/src/checklist-docs-validator.js.map +1 -1
  8. package/src/checklist-instructions.d.ts +11 -0
  9. package/src/checklist-instructions.js +43 -11
  10. package/src/checklist-instructions.js.map +1 -1
  11. package/src/checklist-validator.d.ts +13 -12
  12. package/src/checklist-validator.js +46 -34
  13. package/src/checklist-validator.js.map +1 -1
  14. package/src/constants.d.ts +6 -0
  15. package/src/constants.js +7 -1
  16. package/src/constants.js.map +1 -1
  17. package/src/index.d.ts +3 -3
  18. package/src/index.js +11 -6
  19. package/src/index.js.map +1 -1
  20. package/src/pr-gate-config.d.ts +9 -1
  21. package/src/pr-gate-config.js +15 -4
  22. package/src/pr-gate-config.js.map +1 -1
  23. package/src/pr-gate-section-validators.d.ts +17 -3
  24. package/src/pr-gate-section-validators.js +91 -30
  25. package/src/pr-gate-section-validators.js.map +1 -1
  26. package/src/retired-config-keys.js +8 -0
  27. package/src/retired-config-keys.js.map +1 -1
  28. package/src/review-json-data.d.ts +3 -2
  29. package/src/review-json-data.js +4 -4
  30. package/src/review-json-data.js.map +1 -1
  31. package/src/review-json.js +3 -3
  32. package/src/review-json.js.map +1 -1
  33. package/src/review-provenance.js +2 -2
  34. package/src/review-provenance.js.map +1 -1
  35. package/src/reviewer-instructions.d.ts +13 -9
  36. package/src/reviewer-instructions.js +27 -16
  37. package/src/reviewer-instructions.js.map +1 -1
  38. package/src/subagent-provenance.d.ts +30 -15
  39. package/src/subagent-provenance.js +100 -50
  40. package/src/subagent-provenance.js.map +1 -1
  41. package/src/validate-config.js +5 -2
  42. package/src/validate-config.js.map +1 -1
  43. package/templates/webpieces.review-checklists.md +50 -27
@@ -51,7 +51,7 @@ exports.BriefedFile = BriefedFile;
51
51
  * remove. Data-only.
52
52
  */
53
53
  class ReviewerBriefing {
54
- subagent;
54
+ agentName; // the agent type the subagent is spawned as (commands.pr-gate.reviewerAgentName)
55
55
  docPath; // the checklist's guidance doc ('' when the checklist has none)
56
56
  repoRoot;
57
57
  diffDir; // '' when nothing was materialized
@@ -76,7 +76,7 @@ class ReviewerBriefing {
76
76
  hashForkPoint;
77
77
  hashFeatureHead;
78
78
  hashMainHead;
79
- ownAgentFileInDiff; // ABSOLUTE path when this diff edits THIS reviewer's own agent file; '' otherwise
79
+ ownAgentFileInDiff; // ABSOLUTE path when this diff edits the reviewer agent's own file; '' otherwise
80
80
  // From the checklist's config `required`. Carried so the stage-② report can group the spawn blocks
81
81
  // (must run) apart from the ones the human is merely OFFERED, without a second lookup that could
82
82
  // disagree with the scan. The reviewer's OWN instructions do not mention it: a reviewer that has been
@@ -84,8 +84,8 @@ class ReviewerBriefing {
84
84
  // grade itself softer.
85
85
  required;
86
86
  // eslint-disable-next-line @typescript-eslint/max-params
87
- constructor(subagent, checklistId, repoRoot) {
88
- this.subagent = subagent;
87
+ constructor(agentName, checklistId, repoRoot) {
88
+ this.agentName = agentName;
89
89
  this.checklistId = checklistId;
90
90
  this.repoRoot = repoRoot;
91
91
  this.docPath = '';
@@ -123,7 +123,8 @@ exports.READ_TRUNCATION_LINES = 2000;
123
123
  exports.ALL_DIFF_ONE_READ_LINES = 1500;
124
124
  /**
125
125
  * Renders the per-reviewer instructions file that `wp-review-upsert-pr` writes to
126
- * `.webpieces/pr-review/<feature>/instructions/<subagent>.instructions.md`.
126
+ * `.webpieces/pr-review/<feature>/instructions/<checklistId>.instructions.md` — ONE PER CHECKLIST, so a
127
+ * subagent covering several checklists (`commands.pr-gate.reviewerAgents`) is simply handed several files.
127
128
  *
128
129
  * WHY this file exists, measured rather than assumed: a reviewer subagent on consumer-monorepo2 spent **14 of its
129
130
  * 26 tool calls** rediscovering context the tooling already had — three separate greps into
@@ -131,8 +132,9 @@ exports.ALL_DIFF_ONE_READ_LINES = 1500;
131
132
  * re-derivation of the dependency graph. It did not over-review; it was under-supplied. Everything below is
132
133
  * chosen to delete a specific one of those calls.
133
134
  *
134
- * It is GENERATED per run, and the registered `.claude/agents/<subagent>.md` is a thin stub that points
135
- * here, because content a human maintains goes stale and a reviewer follows the stale copy. The verdict
135
+ * It is GENERATED per run, and the reviewer agent (`.claude/agents/<reviewerAgentName>.md`, by default the
136
+ * webpieces-owned `webpieces-reviewer.md`) is checklist-agnostic and points here, because content a human
137
+ * maintains goes stale and a reviewer follows the stale copy. The verdict
136
138
  * schema in particular comes from {@link ReviewJsonService.verdictSchemaFor}.
137
139
  *
138
140
  * `@injectable(bindingScopeValues.Singleton)` so it is injected by type and drawn in the DI design.
@@ -146,13 +148,13 @@ let ReviewerInstructionsService = class ReviewerInstructionsService {
146
148
  instructionsDirFor(repoRoot, featureName) {
147
149
  return path.join(this.reviewJsonService.prDirFor(repoRoot, featureName), 'instructions');
148
150
  }
149
- /** The file name for a reviewer's generated instructions. */
150
- fileNameFor(subagent) {
151
- return `${subagent}.instructions.md`;
151
+ /** The file name for one checklist's generated instructions. */
152
+ fileNameFor(checklistId) {
153
+ return `${checklistId}.instructions.md`;
152
154
  }
153
- /** Absolute path of one reviewer's generated instructions file. */
154
- pathFor(repoRoot, featureName, subagent) {
155
- return path.join(this.instructionsDirFor(repoRoot, featureName), this.fileNameFor(subagent));
155
+ /** Absolute path of one checklist's generated instructions file. */
156
+ pathFor(repoRoot, featureName, checklistId) {
157
+ return path.join(this.instructionsDirFor(repoRoot, featureName), this.fileNameFor(checklistId));
156
158
  }
157
159
  render(briefing) {
158
160
  return [
@@ -167,10 +169,15 @@ let ReviewerInstructionsService = class ReviewerInstructionsService {
167
169
  }
168
170
  identity(b) {
169
171
  return [
170
- `# You are \`${b.subagent}\``,
172
+ `# Checklist \`${b.checklistId}\` — reviewed by a \`${b.agentName}\` subagent`,
171
173
  '',
172
- 'Review as YOURSELF, against your own checklist — not as a general code reviewer.',
173
- 'You may not write another reviewer\'s verdict file.',
174
+ 'Review this diff against THIS checklist only — not as a general code reviewer — and only over the',
175
+ 'files in scope below. If you were handed several of these files, review each checklist separately',
176
+ 'and write each one its own verdict. Never write a verdict for a checklist you were not handed.',
177
+ '',
178
+ `Your agent definition is \`${this.agentFileFor(b)}\`. If your harness did not load it for you`,
179
+ '(Codex spawns a generic subagent), read it before anything else — it is the one canonical',
180
+ 'definition of how a reviewer works here.',
174
181
  '',
175
182
  '"You may not review your own authorship" means: you did not write this diff, so review it — but if',
176
183
  'the diff CHANGES YOU, say so in `output` rather than pretending the conflict is not there.',
@@ -181,6 +188,10 @@ let ReviewerInstructionsService = class ReviewerInstructionsService {
181
188
  '',
182
189
  ];
183
190
  }
191
+ /** The absolute path of the reviewer agent's committed definition (`.claude/agents/<agentName>.md`). */
192
+ agentFileFor(b) {
193
+ return path.join(b.repoRoot, '.claude', 'agents', `${b.agentName}.md`);
194
+ }
184
195
  /**
185
196
  * Every PR that edits the review gate hits this: on the measured run, 5 of 8 changed files were the
186
197
  * reviewer agent files themselves, two reviewers reviewed their OWN definition, and neither flagged it —
@@ -1 +1 @@
1
- {"version":3,"file":"reviewer-instructions.js","sourceRoot":"","sources":["../../../../../packages/tooling/rules-config/src/reviewer-instructions.ts"],"names":[],"mappings":"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","sourcesContent":["import * as path from 'path';\nimport { injectable, bindingScopeValues } from 'inversify';\nimport { ReviewJsonService } from './review-json';\n\n/** One pre-resolved place a reviewer would otherwise have to go hunting for. Data-only (per CLAUDE.md). */\nexport class ContextEntry {\n label: string;\n path: string; // ABSOLUTE, or '' when it could not be resolved\n note: string; // '(not installed)' / '(configured but missing)' — never silently dropped\n\n constructor(label: string, entryPath: string, note = '') {\n this.label = label;\n this.path = entryPath;\n this.note = note;\n }\n}\n\n/**\n * One reviewer's matched file, the extracted diff for it, AND the absolute path of the file itself.\n *\n * `sourcePath` exists because of a measured 0/4: four reviewers on one PR read the diff and not one opened a\n * single full source file. The instructions handed them an absolute path per diff and only a parent DIRECTORY\n * per source, so reading the diff was a paste and reading the source was \"join this dir to that filename\n * yourself\". Identical affordance, or the cheaper one wins every time. Data-only.\n */\nexport class BriefedFile {\n file: string; // repo-relative source path\n diffPath: string; // ABSOLUTE path of the extracted .diff\n sourcePath: string; // ABSOLUTE path of the file itself; '' for a deleted file, which has no after-state\n status: string; // 'M' | 'A' | 'D' | 'U' (untracked) | 'X' (excluded by config)\n diffBytes: number;\n truncated: boolean;\n\n // eslint-disable-next-line @typescript-eslint/max-params\n constructor(file: string, diffPath: string, sourcePath = '', status = 'M', diffBytes = 0, truncated = false) {\n this.file = file;\n this.diffPath = diffPath;\n this.sourcePath = sourcePath;\n this.status = status;\n this.diffBytes = diffBytes;\n this.truncated = truncated;\n }\n}\n\n/**\n * Everything ONE reviewer needs, with every path already resolved to an ABSOLUTE one.\n *\n * Absolute is not fussiness: a subagent's working directory is not guaranteed to be the repo root, and a\n * relative path that fails to resolve turns into a search, which is the cost this whole class exists to\n * remove. Data-only.\n */\nexport class ReviewerBriefing {\n subagent: string;\n docPath: string; // the checklist's guidance doc ('' when the checklist has none)\n repoRoot: string;\n diffDir: string; // '' when nothing was materialized\n allDiffPath: string;\n manifestPath: string;\n myFiles: BriefedFile[]; // ONLY this reviewer's matched files\n matchedPatterns: string[]; // [] ⇒ patternless: the whole diff is in scope\n sourceDirs: string[]; // deduped ABSOLUTE parent dirs of myFiles\n contextEntries: ContextEntry[];\n verdictPath: string; // ABSOLUTE review-<id>.json\n checklistId: string;\n fileDiffCommand: string;\n dirty: boolean;\n // Facts ABOUT the manifest, surfaced inline so a reviewer learns the diff is complete without opening it.\n changedFileCount: number;\n truncatedCount: number;\n excludedCount: number;\n allDiffLines: number;\n allDiffBytes: number;\n // The three shas, by the names DiffManifest already uses. Printing two bare shas told a reviewer nothing\n // about WHAT the diff is taken against; C beside A makes \"main has moved since the fork\" self-evident.\n hashForkPoint: string;\n hashFeatureHead: string;\n hashMainHead: string;\n ownAgentFileInDiff: string; // ABSOLUTE path when this diff edits THIS reviewer's own agent file; '' otherwise\n // From the checklist's config `required`. Carried so the stage-② report can group the spawn blocks\n // (must run) apart from the ones the human is merely OFFERED, without a second lookup that could\n // disagree with the scan. The reviewer's OWN instructions do not mention it: a reviewer that has been\n // spawned reviews the same way either way, and telling an optional one it was optional invites it to\n // grade itself softer.\n required: boolean;\n\n // eslint-disable-next-line @typescript-eslint/max-params\n constructor(subagent: string, checklistId: string, repoRoot: string) {\n this.subagent = subagent;\n this.checklistId = checklistId;\n this.repoRoot = repoRoot;\n this.docPath = '';\n this.diffDir = '';\n this.allDiffPath = '';\n this.manifestPath = '';\n this.myFiles = [];\n this.matchedPatterns = [];\n this.sourceDirs = [];\n this.contextEntries = [];\n this.verdictPath = '';\n this.fileDiffCommand = '';\n this.dirty = false;\n this.changedFileCount = 0;\n this.truncatedCount = 0;\n this.excludedCount = 0;\n this.allDiffLines = 0;\n this.allDiffBytes = 0;\n this.hashForkPoint = '';\n this.hashFeatureHead = '';\n this.hashMainHead = '';\n this.ownAgentFileInDiff = '';\n // Fails CLOSED, like RequiredChecklist.required: a briefing built without the flag being copied is\n // treated as a blocking reviewer, never as a skippable one.\n this.required = true;\n }\n}\n\n/**\n * The Read tool truncates at roughly this many lines, silently. Any path this file prints alongside a bigger\n * line count has to say so, or a reviewer reviews a fraction of a change and reports on all of it.\n */\nexport const READ_TRUNCATION_LINES = 2000;\n\n/** Comfortably under {@link READ_TRUNCATION_LINES} — the size at which ALL.diff really is one clean Read. */\nexport const ALL_DIFF_ONE_READ_LINES = 1500;\n\n/**\n * Renders the per-reviewer instructions file that `wp-review-upsert-pr` writes to\n * `.webpieces/pr-review/<feature>/instructions/<subagent>.instructions.md`.\n *\n * WHY this file exists, measured rather than assumed: a reviewer subagent on consumer-monorepo2 spent **14 of its\n * 26 tool calls** rediscovering context the tooling already had — three separate greps into\n * `node_modules/@webpieces` to locate a scanner, a hunt through terraform for queue names, and a\n * re-derivation of the dependency graph. It did not over-review; it was under-supplied. Everything below is\n * chosen to delete a specific one of those calls.\n *\n * It is GENERATED per run, and the registered `.claude/agents/<subagent>.md` is a thin stub that points\n * here, because content a human maintains goes stale and a reviewer follows the stale copy. The verdict\n * schema in particular comes from {@link ReviewJsonService.verdictSchemaFor}.\n *\n * `@injectable(bindingScopeValues.Singleton)` so it is injected by type and drawn in the DI design.\n */\n@injectable(bindingScopeValues.Singleton)\nexport class ReviewerInstructionsService {\n constructor(private readonly reviewJsonService: ReviewJsonService) {}\n\n /** The dir holding this branch's generated instructions, beside its review.json. */\n instructionsDirFor(repoRoot: string, featureName: string): string {\n return path.join(this.reviewJsonService.prDirFor(repoRoot, featureName), 'instructions');\n }\n\n /** The file name for a reviewer's generated instructions. */\n fileNameFor(subagent: string): string {\n return `${subagent}.instructions.md`;\n }\n\n /** Absolute path of one reviewer's generated instructions file. */\n pathFor(repoRoot: string, featureName: string, subagent: string): string {\n return path.join(this.instructionsDirFor(repoRoot, featureName), this.fileNameFor(subagent));\n }\n\n render(briefing: ReviewerBriefing): string {\n return [\n ...this.identity(briefing),\n ...this.checklistSection(briefing),\n ...this.diffSection(briefing),\n ...this.sourceSection(briefing),\n ...this.contextSection(briefing),\n ...this.verdictSection(briefing),\n ...this.budgetSection(),\n ].join('\\n') + '\\n';\n }\n\n private identity(b: ReviewerBriefing): string[] {\n return [\n `# You are \\`${b.subagent}\\``,\n '',\n 'Review as YOURSELF, against your own checklist — not as a general code reviewer.',\n 'You may not write another reviewer\\'s verdict file.',\n '',\n '\"You may not review your own authorship\" means: you did not write this diff, so review it — but if',\n 'the diff CHANGES YOU, say so in `output` rather than pretending the conflict is not there.',\n ...this.selfEditWarning(b),\n '',\n '_Generated per run by `wp-review-upsert-pr`. Everything below is already resolved for you; the',\n 'paths are absolute because your working directory is not guaranteed to be the repo root._',\n '',\n ];\n }\n\n /**\n * Every PR that edits the review gate hits this: on the measured run, 5 of 8 changed files were the\n * reviewer agent files themselves, two reviewers reviewed their OWN definition, and neither flagged it —\n * neither had any guidance to. Detected by the tooling rather than left to the reviewer to notice.\n */\n private selfEditWarning(b: ReviewerBriefing): string[] {\n if (b.ownAgentFileInDiff === '') return [];\n return [\n '',\n `⚠️ THIS DIFF MODIFIES YOUR OWN AGENT FILE: \\`${b.ownAgentFileInDiff}\\``,\n 'You are reviewing a change to your own definition. Review it anyway — and state that fact in',\n '`output`, so a human reading your verdict knows the reviewer and the reviewed were the same thing.',\n ];\n }\n\n private checklistSection(b: ReviewerBriefing): string[] {\n if (b.docPath === '') {\n return ['## Your checklist', '', 'This checklist has no guidance doc — judge the diff on your own standards.', ''];\n }\n return ['## Your checklist', '', `Read this FIRST: \\`${b.docPath}\\``, ''];\n }\n\n /**\n * The change itself. The MANIFEST leads, and the per-file table with it; `ALL.diff` is demoted to one\n * option among several, recommended only where it is actually the right read.\n *\n * That ordering is the fix for a measured 4/4 failure. `ALL.diff` used to be bolded, first, and framed as\n * \"everything\", with the manifest one unbolded line below it called a \"path map\" — which reads like a\n * lookup aid, not something to open. All four reviewers on that PR read `ALL.diff`, none opened the\n * manifest, and none could therefore have established that the combined view was complete. Reviewers did\n * exactly what the emphasis told them to; so the emphasis moved.\n */\n private diffSection(b: ReviewerBriefing): string[] {\n const lines = ['## The change you are reviewing', ''];\n if (b.dirty) {\n lines.push('> ⚠️ This diff INCLUDES uncommitted and untracked work, so it is not what a');\n lines.push('> commit-to-commit range would show. Judge it anyway — it is what your checklist matched.');\n lines.push('');\n }\n lines.push(...this.manifestLines(b), ...this.basisLines(b), ...this.myFilesTable(b), ...this.allDiffLines(b));\n if (b.fileDiffCommand !== '') {\n lines.push(`Reproduce any single file: \\`${b.fileDiffCommand}\\``);\n lines.push('');\n }\n lines.push('Path matching is COARSE. Judge the change, not the path — if a matched file turns out to be');\n lines.push('irrelevant to your checklist, say so in one sentence and move on.');\n lines.push('');\n return lines;\n }\n\n /**\n * The manifest, named as the authority AND with its own headline facts inlined. Inlining them is the\n * point: a reviewer that never opens the manifest still learns whether anything was truncated or\n * excluded, which is the one thing it could not otherwise have known it was missing.\n */\n private manifestLines(b: ReviewerBriefing): string[] {\n if (b.manifestPath === '') return [];\n const warn = b.truncatedCount + b.excludedCount > 0 ? ' ⚠️ NOT everything is materialized — see the table.' : '';\n return [\n `**Path map — AUTHORITATIVE. Read this first:** \\`${b.manifestPath}\\``,\n ` ${b.changedFileCount} file(s) · ${b.truncatedCount} truncated · ${b.excludedCount} excluded${warn}`,\n ' Per file it carries: `status` (M/A/D/U/X), `bytes`, `file`/`fileAbs`, `diffFile`/`diffAbs`, and the',\n ' three shas below. It is the only place that records what was truncated or left out.',\n '',\n ];\n }\n\n /**\n * What the diff is taken AGAINST. Two bare shas in a `git diff` command said nothing about this, so a\n * reviewer could not tell a fork-point diff from a diff against main's current tip — and therefore could\n * not tell that anything merged to main since the fork is simply absent from what it is judging.\n * Rendering C beside A makes \"main has moved\" self-evident exactly when it has.\n */\n private basisLines(b: ReviewerBriefing): string[] {\n if (b.hashForkPoint === '') return [];\n const sameAsFork = b.hashMainHead === b.hashForkPoint;\n const cNote = b.hashMainHead === '' ? '(unresolved)'\n : sameAsFork ? `${b.hashMainHead} ← same as A, so main has not moved since the fork`\n : `${b.hashMainHead} ← main HAS MOVED since the fork`;\n return [\n 'This diff is **fork-point → feature-head**, NOT a diff against main\\'s current tip:',\n '```',\n `fork point (A) ${b.hashForkPoint}`,\n `feature head (B) ${b.hashFeatureHead}`,\n `main head (C) ${cNote}`,\n '```',\n 'Anything merged to main after A is NOT in this diff.',\n '',\n ];\n }\n\n /**\n * Source and diff get IDENTICAL affordance — an absolute path each, in adjacent columns. The previous\n * table gave an absolute path for the diff and nothing for the source, and the source went unread 4/4.\n */\n private myFilesTable(b: ReviewerBriefing): string[] {\n if (b.myFiles.length === 0) return ['_No files matched your patterns._', ''];\n const why = b.matchedPatterns.length === 0\n ? `**In scope: ALL ${b.myFiles.length} changed file(s)** — your checklist has no \\`patterns\\`, so the whole diff is yours.`\n : `**In scope: ${b.myFiles.length} file(s)** matching ${b.matchedPatterns.map((p: string): string => `\\`${p}\\``).join(', ')}:`;\n const rows = b.myFiles.map((f: BriefedFile): string => this.fileRow(f));\n return [why, '', '| file | status | its diff | full source |', '|---|---|---|---|', ...rows, ''];\n }\n\n /**\n * One row. A truncated or excluded diff is flagged HERE, in the row, not left as a field inside a file the\n * reviewer has to think to open — and an oversized diff states the line count that makes a single Read\n * come back silently incomplete.\n */\n private fileRow(f: BriefedFile): string {\n const flags: string[] = [];\n if (f.truncated) flags.push('⚠️ diff TRUNCATED — read the source');\n if (f.status === 'X') flags.push('⚠️ EXCLUDED, not materialized — read the source');\n const status = [`\\`${f.status}\\``, ...flags].join(' ');\n const source = f.sourcePath === '' ? '_deleted — no file on disk_' : `\\`${f.sourcePath}\\``;\n return `| \\`${f.file}\\` | ${status} | \\`${f.diffPath}\\` (${f.diffBytes} bytes) | ${source} |`;\n }\n\n /**\n * `ALL.diff`, recommended ONLY where it is the right read. It is kept — for a patternless reviewer on a\n * small diff it is genuinely one Read instead of N, which is why all four used it — but the blanket\n * \"everything on this branch\" line was wrong in two different ways at once: it invited a pattern-scoped\n * reviewer to spend its budget on files it was explicitly not asked about, and it pointed a reviewer on a\n * large PR at a file that cannot survive one Read.\n */\n private allDiffLines(b: ReviewerBriefing): string[] {\n if (b.allDiffPath === '') return [];\n const size = b.allDiffLines === 0 ? '' : ` — ${b.allDiffLines} lines / ${b.allDiffBytes} bytes`;\n if (b.matchedPatterns.length > 0) {\n return [`The whole branch${size}, for CROSS-FILE CONTEXT if you need it: \\`${b.allDiffPath}\\``,\n 'Your own files above are what you are reviewing; the rest of the branch is someone else\\'s checklist.', ''];\n }\n if (b.allDiffLines > ALL_DIFF_ONE_READ_LINES) {\n return [`⚠️ The combined diff is ${b.allDiffLines} lines and will NOT survive a single Read (the Read tool`,\n `truncates at ~${READ_TRUNCATION_LINES} lines, silently). Read the per-file diffs above instead, or page it:`,\n `\\`${b.allDiffPath}\\``, ''];\n }\n return [`Whole-branch diff${size} — convenient at this size, but the per-file table above is authoritative:`,\n `\\`${b.allDiffPath}\\``, ''];\n }\n\n /**\n * The rule that used to say \"when you need to\", and lost 4/4 to the more emphatic budget section 40 lines\n * later. \"When you need to\" delegates the judgment to a reviewer that, by construction, does not yet know\n * what it is missing. It has no opt-out now.\n */\n private sourceSection(b: ReviewerBriefing): string[] {\n const lines = ['## Read the full source — every file, every time', '', `Repo root: \\`${b.repoRoot}\\``, ''];\n lines.push('**READ THE FULL SOURCE OF EVERY FILE IN YOUR TABLE.** Not \"if you need to\" — every time.');\n lines.push('A hunk shows what changed; only the whole file shows what it changed INTO, and a change that');\n lines.push('looks fine in isolation can still be wrong in place.');\n lines.push('');\n lines.push('The `full source` column above is the path. For files marked `A` (added) you have already done');\n lines.push('this: an add-diff IS the complete file, byte for byte, so its diff and its source are the same');\n lines.push('text. For `M` (modified) and `D` (deleted) files the diff is a fragment — open the file.');\n lines.push('');\n if (b.sourceDirs.length > 0) {\n lines.push('The neighbouring code lives under:');\n for (const dir of b.sourceDirs) lines.push(`- \\`${dir}\\``);\n lines.push('');\n }\n return lines;\n }\n\n /**\n * The section that deletes the `node_modules` greps. Entries come from config, because the tooling\n * cannot guess that a repo keeps its queue names in terraform — but it CAN resolve where a package\n * installed to, and it must never drop an entry silently: a missing path is stated as missing.\n */\n private contextSection(b: ReviewerBriefing): string[] {\n // Emitting NOTHING made the section this class exists for look like a feature that does not exist.\n // One line naming the config keys costs nothing and is the only hint a repo will ever get.\n if (b.contextEntries.length === 0) {\n return ['## Pre-resolved context', '',\n '_None configured for this repo. If you find yourself hunting for the same path on every review,',\n 'it belongs in `pr-gate.reviewContext` / `pr-gate.reviewContextPackages` in `webpieces.config.json`._',\n ''];\n }\n const lines = ['## Pre-resolved context (do not go hunting for these)', ''];\n for (const entry of b.contextEntries) {\n const suffix = entry.note === '' ? '' : ` ${entry.note}`;\n lines.push(`- **${entry.label}** — \\`${entry.path === '' ? entry.note : entry.path}\\`${entry.path === '' ? '' : suffix}`);\n }\n lines.push('');\n return lines;\n }\n\n /**\n * The verdict shape, GENERATED — never restated in a hand-maintained file. `id` is pre-filled with this\n * reviewer's own checklist id so there is nothing to substitute and nothing to get wrong.\n */\n private verdictSection(b: ReviewerBriefing): string[] {\n return [\n '## Write your verdict',\n '',\n `Write EXACTLY this shape, to EXACTLY this file: \\`${b.verdictPath}\\``,\n '',\n '```',\n this.reviewJsonService.verdictSchemaFor(b.checklistId, '', ''),\n '```',\n '',\n ];\n }\n\n /**\n * The anti-hunting rule, with the changed files carved out explicitly.\n *\n * It used to read as \"stay inside what you were given\" and, being the LAST thing in the file, it beat\n * the source-reading instruction 4 times out of 4. It never distinguished HUNTING — greps into\n * `node_modules`, re-deriving the dependency graph — from OPENING A FILE IT WAS EXPLICITLY HANDED. The\n * distinction is now stated, because where two instructions conflict the later and more emphatic one wins.\n */\n private budgetSection(): string[] {\n return [\n '## Budget',\n '',\n 'Do NOT search `node_modules`, do NOT re-derive the dependency graph, and do NOT hunt the repo for',\n 'infrastructure config. That is hunting, and it is what wastes a review budget — those paths are',\n 'either given above or were not configured.',\n '',\n 'Reading the full text of a file that is IN your table is NOT hunting — it is the review. Budget for',\n 'it: read the diff to see what changed, and the source to judge whether it is right in place.',\n '',\n 'If something you genuinely need is missing, name it in `output` and give your verdict on what you',\n 'could actually see.',\n '',\n 'Open your diff files before writing a verdict. `wp-finish-upsert-pr` reads your own transcript and',\n 'reports a verdict written without opening the diff. It also records the path of that transcript,',\n 'beside what you were offered and what you read, in `provenance.json` next to your verdict file —',\n 'so the review is auditable after the fact. You do not write that file; the tooling does.',\n ];\n }\n}\n"]}
1
+ {"version":3,"file":"reviewer-instructions.js","sourceRoot":"","sources":["../../../../../packages/tooling/rules-config/src/reviewer-instructions.ts"],"names":[],"mappings":"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","sourcesContent":["import * as path from 'path';\nimport { injectable, bindingScopeValues } from 'inversify';\nimport { ReviewJsonService } from './review-json';\n\n/** One pre-resolved place a reviewer would otherwise have to go hunting for. Data-only (per CLAUDE.md). */\nexport class ContextEntry {\n label: string;\n path: string; // ABSOLUTE, or '' when it could not be resolved\n note: string; // '(not installed)' / '(configured but missing)' — never silently dropped\n\n constructor(label: string, entryPath: string, note = '') {\n this.label = label;\n this.path = entryPath;\n this.note = note;\n }\n}\n\n/**\n * One reviewer's matched file, the extracted diff for it, AND the absolute path of the file itself.\n *\n * `sourcePath` exists because of a measured 0/4: four reviewers on one PR read the diff and not one opened a\n * single full source file. The instructions handed them an absolute path per diff and only a parent DIRECTORY\n * per source, so reading the diff was a paste and reading the source was \"join this dir to that filename\n * yourself\". Identical affordance, or the cheaper one wins every time. Data-only.\n */\nexport class BriefedFile {\n file: string; // repo-relative source path\n diffPath: string; // ABSOLUTE path of the extracted .diff\n sourcePath: string; // ABSOLUTE path of the file itself; '' for a deleted file, which has no after-state\n status: string; // 'M' | 'A' | 'D' | 'U' (untracked) | 'X' (excluded by config)\n diffBytes: number;\n truncated: boolean;\n\n // eslint-disable-next-line @typescript-eslint/max-params\n constructor(file: string, diffPath: string, sourcePath = '', status = 'M', diffBytes = 0, truncated = false) {\n this.file = file;\n this.diffPath = diffPath;\n this.sourcePath = sourcePath;\n this.status = status;\n this.diffBytes = diffBytes;\n this.truncated = truncated;\n }\n}\n\n/**\n * Everything ONE reviewer needs, with every path already resolved to an ABSOLUTE one.\n *\n * Absolute is not fussiness: a subagent's working directory is not guaranteed to be the repo root, and a\n * relative path that fails to resolve turns into a search, which is the cost this whole class exists to\n * remove. Data-only.\n */\nexport class ReviewerBriefing {\n agentName: string; // the agent type the subagent is spawned as (commands.pr-gate.reviewerAgentName)\n docPath: string; // the checklist's guidance doc ('' when the checklist has none)\n repoRoot: string;\n diffDir: string; // '' when nothing was materialized\n allDiffPath: string;\n manifestPath: string;\n myFiles: BriefedFile[]; // ONLY this reviewer's matched files\n matchedPatterns: string[]; // [] ⇒ patternless: the whole diff is in scope\n sourceDirs: string[]; // deduped ABSOLUTE parent dirs of myFiles\n contextEntries: ContextEntry[];\n verdictPath: string; // ABSOLUTE review-<id>.json\n checklistId: string;\n fileDiffCommand: string;\n dirty: boolean;\n // Facts ABOUT the manifest, surfaced inline so a reviewer learns the diff is complete without opening it.\n changedFileCount: number;\n truncatedCount: number;\n excludedCount: number;\n allDiffLines: number;\n allDiffBytes: number;\n // The three shas, by the names DiffManifest already uses. Printing two bare shas told a reviewer nothing\n // about WHAT the diff is taken against; C beside A makes \"main has moved since the fork\" self-evident.\n hashForkPoint: string;\n hashFeatureHead: string;\n hashMainHead: string;\n ownAgentFileInDiff: string; // ABSOLUTE path when this diff edits the reviewer agent's own file; '' otherwise\n // From the checklist's config `required`. Carried so the stage-② report can group the spawn blocks\n // (must run) apart from the ones the human is merely OFFERED, without a second lookup that could\n // disagree with the scan. The reviewer's OWN instructions do not mention it: a reviewer that has been\n // spawned reviews the same way either way, and telling an optional one it was optional invites it to\n // grade itself softer.\n required: boolean;\n\n // eslint-disable-next-line @typescript-eslint/max-params\n constructor(agentName: string, checklistId: string, repoRoot: string) {\n this.agentName = agentName;\n this.checklistId = checklistId;\n this.repoRoot = repoRoot;\n this.docPath = '';\n this.diffDir = '';\n this.allDiffPath = '';\n this.manifestPath = '';\n this.myFiles = [];\n this.matchedPatterns = [];\n this.sourceDirs = [];\n this.contextEntries = [];\n this.verdictPath = '';\n this.fileDiffCommand = '';\n this.dirty = false;\n this.changedFileCount = 0;\n this.truncatedCount = 0;\n this.excludedCount = 0;\n this.allDiffLines = 0;\n this.allDiffBytes = 0;\n this.hashForkPoint = '';\n this.hashFeatureHead = '';\n this.hashMainHead = '';\n this.ownAgentFileInDiff = '';\n // Fails CLOSED, like RequiredChecklist.required: a briefing built without the flag being copied is\n // treated as a blocking reviewer, never as a skippable one.\n this.required = true;\n }\n}\n\n/**\n * The Read tool truncates at roughly this many lines, silently. Any path this file prints alongside a bigger\n * line count has to say so, or a reviewer reviews a fraction of a change and reports on all of it.\n */\nexport const READ_TRUNCATION_LINES = 2000;\n\n/** Comfortably under {@link READ_TRUNCATION_LINES} — the size at which ALL.diff really is one clean Read. */\nexport const ALL_DIFF_ONE_READ_LINES = 1500;\n\n/**\n * Renders the per-reviewer instructions file that `wp-review-upsert-pr` writes to\n * `.webpieces/pr-review/<feature>/instructions/<checklistId>.instructions.md` — ONE PER CHECKLIST, so a\n * subagent covering several checklists (`commands.pr-gate.reviewerAgents`) is simply handed several files.\n *\n * WHY this file exists, measured rather than assumed: a reviewer subagent on consumer-monorepo2 spent **14 of its\n * 26 tool calls** rediscovering context the tooling already had — three separate greps into\n * `node_modules/@webpieces` to locate a scanner, a hunt through terraform for queue names, and a\n * re-derivation of the dependency graph. It did not over-review; it was under-supplied. Everything below is\n * chosen to delete a specific one of those calls.\n *\n * It is GENERATED per run, and the reviewer agent (`.claude/agents/<reviewerAgentName>.md`, by default the\n * webpieces-owned `webpieces-reviewer.md`) is checklist-agnostic and points here, because content a human\n * maintains goes stale and a reviewer follows the stale copy. The verdict\n * schema in particular comes from {@link ReviewJsonService.verdictSchemaFor}.\n *\n * `@injectable(bindingScopeValues.Singleton)` so it is injected by type and drawn in the DI design.\n */\n@injectable(bindingScopeValues.Singleton)\nexport class ReviewerInstructionsService {\n constructor(private readonly reviewJsonService: ReviewJsonService) {}\n\n /** The dir holding this branch's generated instructions, beside its review.json. */\n instructionsDirFor(repoRoot: string, featureName: string): string {\n return path.join(this.reviewJsonService.prDirFor(repoRoot, featureName), 'instructions');\n }\n\n /** The file name for one checklist's generated instructions. */\n fileNameFor(checklistId: string): string {\n return `${checklistId}.instructions.md`;\n }\n\n /** Absolute path of one checklist's generated instructions file. */\n pathFor(repoRoot: string, featureName: string, checklistId: string): string {\n return path.join(this.instructionsDirFor(repoRoot, featureName), this.fileNameFor(checklistId));\n }\n\n render(briefing: ReviewerBriefing): string {\n return [\n ...this.identity(briefing),\n ...this.checklistSection(briefing),\n ...this.diffSection(briefing),\n ...this.sourceSection(briefing),\n ...this.contextSection(briefing),\n ...this.verdictSection(briefing),\n ...this.budgetSection(),\n ].join('\\n') + '\\n';\n }\n\n private identity(b: ReviewerBriefing): string[] {\n return [\n `# Checklist \\`${b.checklistId}\\` — reviewed by a \\`${b.agentName}\\` subagent`,\n '',\n 'Review this diff against THIS checklist only — not as a general code reviewer — and only over the',\n 'files in scope below. If you were handed several of these files, review each checklist separately',\n 'and write each one its own verdict. Never write a verdict for a checklist you were not handed.',\n '',\n `Your agent definition is \\`${this.agentFileFor(b)}\\`. If your harness did not load it for you`,\n '(Codex spawns a generic subagent), read it before anything else — it is the one canonical',\n 'definition of how a reviewer works here.',\n '',\n '\"You may not review your own authorship\" means: you did not write this diff, so review it — but if',\n 'the diff CHANGES YOU, say so in `output` rather than pretending the conflict is not there.',\n ...this.selfEditWarning(b),\n '',\n '_Generated per run by `wp-review-upsert-pr`. Everything below is already resolved for you; the',\n 'paths are absolute because your working directory is not guaranteed to be the repo root._',\n '',\n ];\n }\n\n /** The absolute path of the reviewer agent's committed definition (`.claude/agents/<agentName>.md`). */\n agentFileFor(b: ReviewerBriefing): string {\n return path.join(b.repoRoot, '.claude', 'agents', `${b.agentName}.md`);\n }\n\n /**\n * Every PR that edits the review gate hits this: on the measured run, 5 of 8 changed files were the\n * reviewer agent files themselves, two reviewers reviewed their OWN definition, and neither flagged it —\n * neither had any guidance to. Detected by the tooling rather than left to the reviewer to notice.\n */\n private selfEditWarning(b: ReviewerBriefing): string[] {\n if (b.ownAgentFileInDiff === '') return [];\n return [\n '',\n `⚠️ THIS DIFF MODIFIES YOUR OWN AGENT FILE: \\`${b.ownAgentFileInDiff}\\``,\n 'You are reviewing a change to your own definition. Review it anyway — and state that fact in',\n '`output`, so a human reading your verdict knows the reviewer and the reviewed were the same thing.',\n ];\n }\n\n private checklistSection(b: ReviewerBriefing): string[] {\n if (b.docPath === '') {\n return ['## Your checklist', '', 'This checklist has no guidance doc — judge the diff on your own standards.', ''];\n }\n return ['## Your checklist', '', `Read this FIRST: \\`${b.docPath}\\``, ''];\n }\n\n /**\n * The change itself. The MANIFEST leads, and the per-file table with it; `ALL.diff` is demoted to one\n * option among several, recommended only where it is actually the right read.\n *\n * That ordering is the fix for a measured 4/4 failure. `ALL.diff` used to be bolded, first, and framed as\n * \"everything\", with the manifest one unbolded line below it called a \"path map\" — which reads like a\n * lookup aid, not something to open. All four reviewers on that PR read `ALL.diff`, none opened the\n * manifest, and none could therefore have established that the combined view was complete. Reviewers did\n * exactly what the emphasis told them to; so the emphasis moved.\n */\n private diffSection(b: ReviewerBriefing): string[] {\n const lines = ['## The change you are reviewing', ''];\n if (b.dirty) {\n lines.push('> ⚠️ This diff INCLUDES uncommitted and untracked work, so it is not what a');\n lines.push('> commit-to-commit range would show. Judge it anyway — it is what your checklist matched.');\n lines.push('');\n }\n lines.push(...this.manifestLines(b), ...this.basisLines(b), ...this.myFilesTable(b), ...this.allDiffLines(b));\n if (b.fileDiffCommand !== '') {\n lines.push(`Reproduce any single file: \\`${b.fileDiffCommand}\\``);\n lines.push('');\n }\n lines.push('Path matching is COARSE. Judge the change, not the path — if a matched file turns out to be');\n lines.push('irrelevant to your checklist, say so in one sentence and move on.');\n lines.push('');\n return lines;\n }\n\n /**\n * The manifest, named as the authority AND with its own headline facts inlined. Inlining them is the\n * point: a reviewer that never opens the manifest still learns whether anything was truncated or\n * excluded, which is the one thing it could not otherwise have known it was missing.\n */\n private manifestLines(b: ReviewerBriefing): string[] {\n if (b.manifestPath === '') return [];\n const warn = b.truncatedCount + b.excludedCount > 0 ? ' ⚠️ NOT everything is materialized — see the table.' : '';\n return [\n `**Path map — AUTHORITATIVE. Read this first:** \\`${b.manifestPath}\\``,\n ` ${b.changedFileCount} file(s) · ${b.truncatedCount} truncated · ${b.excludedCount} excluded${warn}`,\n ' Per file it carries: `status` (M/A/D/U/X), `bytes`, `file`/`fileAbs`, `diffFile`/`diffAbs`, and the',\n ' three shas below. It is the only place that records what was truncated or left out.',\n '',\n ];\n }\n\n /**\n * What the diff is taken AGAINST. Two bare shas in a `git diff` command said nothing about this, so a\n * reviewer could not tell a fork-point diff from a diff against main's current tip — and therefore could\n * not tell that anything merged to main since the fork is simply absent from what it is judging.\n * Rendering C beside A makes \"main has moved\" self-evident exactly when it has.\n */\n private basisLines(b: ReviewerBriefing): string[] {\n if (b.hashForkPoint === '') return [];\n const sameAsFork = b.hashMainHead === b.hashForkPoint;\n const cNote = b.hashMainHead === '' ? '(unresolved)'\n : sameAsFork ? `${b.hashMainHead} ← same as A, so main has not moved since the fork`\n : `${b.hashMainHead} ← main HAS MOVED since the fork`;\n return [\n 'This diff is **fork-point → feature-head**, NOT a diff against main\\'s current tip:',\n '```',\n `fork point (A) ${b.hashForkPoint}`,\n `feature head (B) ${b.hashFeatureHead}`,\n `main head (C) ${cNote}`,\n '```',\n 'Anything merged to main after A is NOT in this diff.',\n '',\n ];\n }\n\n /**\n * Source and diff get IDENTICAL affordance — an absolute path each, in adjacent columns. The previous\n * table gave an absolute path for the diff and nothing for the source, and the source went unread 4/4.\n */\n private myFilesTable(b: ReviewerBriefing): string[] {\n if (b.myFiles.length === 0) return ['_No files matched your patterns._', ''];\n const why = b.matchedPatterns.length === 0\n ? `**In scope: ALL ${b.myFiles.length} changed file(s)** — your checklist has no \\`patterns\\`, so the whole diff is yours.`\n : `**In scope: ${b.myFiles.length} file(s)** matching ${b.matchedPatterns.map((p: string): string => `\\`${p}\\``).join(', ')}:`;\n const rows = b.myFiles.map((f: BriefedFile): string => this.fileRow(f));\n return [why, '', '| file | status | its diff | full source |', '|---|---|---|---|', ...rows, ''];\n }\n\n /**\n * One row. A truncated or excluded diff is flagged HERE, in the row, not left as a field inside a file the\n * reviewer has to think to open — and an oversized diff states the line count that makes a single Read\n * come back silently incomplete.\n */\n private fileRow(f: BriefedFile): string {\n const flags: string[] = [];\n if (f.truncated) flags.push('⚠️ diff TRUNCATED — read the source');\n if (f.status === 'X') flags.push('⚠️ EXCLUDED, not materialized — read the source');\n const status = [`\\`${f.status}\\``, ...flags].join(' ');\n const source = f.sourcePath === '' ? '_deleted — no file on disk_' : `\\`${f.sourcePath}\\``;\n return `| \\`${f.file}\\` | ${status} | \\`${f.diffPath}\\` (${f.diffBytes} bytes) | ${source} |`;\n }\n\n /**\n * `ALL.diff`, recommended ONLY where it is the right read. It is kept — for a patternless reviewer on a\n * small diff it is genuinely one Read instead of N, which is why all four used it — but the blanket\n * \"everything on this branch\" line was wrong in two different ways at once: it invited a pattern-scoped\n * reviewer to spend its budget on files it was explicitly not asked about, and it pointed a reviewer on a\n * large PR at a file that cannot survive one Read.\n */\n private allDiffLines(b: ReviewerBriefing): string[] {\n if (b.allDiffPath === '') return [];\n const size = b.allDiffLines === 0 ? '' : ` — ${b.allDiffLines} lines / ${b.allDiffBytes} bytes`;\n if (b.matchedPatterns.length > 0) {\n return [`The whole branch${size}, for CROSS-FILE CONTEXT if you need it: \\`${b.allDiffPath}\\``,\n 'Your own files above are what you are reviewing; the rest of the branch is someone else\\'s checklist.', ''];\n }\n if (b.allDiffLines > ALL_DIFF_ONE_READ_LINES) {\n return [`⚠️ The combined diff is ${b.allDiffLines} lines and will NOT survive a single Read (the Read tool`,\n `truncates at ~${READ_TRUNCATION_LINES} lines, silently). Read the per-file diffs above instead, or page it:`,\n `\\`${b.allDiffPath}\\``, ''];\n }\n return [`Whole-branch diff${size} — convenient at this size, but the per-file table above is authoritative:`,\n `\\`${b.allDiffPath}\\``, ''];\n }\n\n /**\n * The rule that used to say \"when you need to\", and lost 4/4 to the more emphatic budget section 40 lines\n * later. \"When you need to\" delegates the judgment to a reviewer that, by construction, does not yet know\n * what it is missing. It has no opt-out now.\n */\n private sourceSection(b: ReviewerBriefing): string[] {\n const lines = ['## Read the full source — every file, every time', '', `Repo root: \\`${b.repoRoot}\\``, ''];\n lines.push('**READ THE FULL SOURCE OF EVERY FILE IN YOUR TABLE.** Not \"if you need to\" — every time.');\n lines.push('A hunk shows what changed; only the whole file shows what it changed INTO, and a change that');\n lines.push('looks fine in isolation can still be wrong in place.');\n lines.push('');\n lines.push('The `full source` column above is the path. For files marked `A` (added) you have already done');\n lines.push('this: an add-diff IS the complete file, byte for byte, so its diff and its source are the same');\n lines.push('text. For `M` (modified) and `D` (deleted) files the diff is a fragment — open the file.');\n lines.push('');\n if (b.sourceDirs.length > 0) {\n lines.push('The neighbouring code lives under:');\n for (const dir of b.sourceDirs) lines.push(`- \\`${dir}\\``);\n lines.push('');\n }\n return lines;\n }\n\n /**\n * The section that deletes the `node_modules` greps. Entries come from config, because the tooling\n * cannot guess that a repo keeps its queue names in terraform — but it CAN resolve where a package\n * installed to, and it must never drop an entry silently: a missing path is stated as missing.\n */\n private contextSection(b: ReviewerBriefing): string[] {\n // Emitting NOTHING made the section this class exists for look like a feature that does not exist.\n // One line naming the config keys costs nothing and is the only hint a repo will ever get.\n if (b.contextEntries.length === 0) {\n return ['## Pre-resolved context', '',\n '_None configured for this repo. If you find yourself hunting for the same path on every review,',\n 'it belongs in `pr-gate.reviewContext` / `pr-gate.reviewContextPackages` in `webpieces.config.json`._',\n ''];\n }\n const lines = ['## Pre-resolved context (do not go hunting for these)', ''];\n for (const entry of b.contextEntries) {\n const suffix = entry.note === '' ? '' : ` ${entry.note}`;\n lines.push(`- **${entry.label}** — \\`${entry.path === '' ? entry.note : entry.path}\\`${entry.path === '' ? '' : suffix}`);\n }\n lines.push('');\n return lines;\n }\n\n /**\n * The verdict shape, GENERATED — never restated in a hand-maintained file. `id` is pre-filled with this\n * reviewer's own checklist id so there is nothing to substitute and nothing to get wrong.\n */\n private verdictSection(b: ReviewerBriefing): string[] {\n return [\n '## Write your verdict',\n '',\n `Write EXACTLY this shape, to EXACTLY this file: \\`${b.verdictPath}\\``,\n '',\n '```',\n this.reviewJsonService.verdictSchemaFor(b.checklistId, '', ''),\n '```',\n '',\n ];\n }\n\n /**\n * The anti-hunting rule, with the changed files carved out explicitly.\n *\n * It used to read as \"stay inside what you were given\" and, being the LAST thing in the file, it beat\n * the source-reading instruction 4 times out of 4. It never distinguished HUNTING — greps into\n * `node_modules`, re-deriving the dependency graph — from OPENING A FILE IT WAS EXPLICITLY HANDED. The\n * distinction is now stated, because where two instructions conflict the later and more emphatic one wins.\n */\n private budgetSection(): string[] {\n return [\n '## Budget',\n '',\n 'Do NOT search `node_modules`, do NOT re-derive the dependency graph, and do NOT hunt the repo for',\n 'infrastructure config. That is hunting, and it is what wastes a review budget — those paths are',\n 'either given above or were not configured.',\n '',\n 'Reading the full text of a file that is IN your table is NOT hunting — it is the review. Budget for',\n 'it: read the diff to see what changed, and the source to judge whether it is right in place.',\n '',\n 'If something you genuinely need is missing, name it in `output` and give your verdict on what you',\n 'could actually see.',\n '',\n 'Open your diff files before writing a verdict. `wp-finish-upsert-pr` reads your own transcript and',\n 'reports a verdict written without opening the diff. It also records the path of that transcript,',\n 'beside what you were offered and what you read, in `provenance.json` next to your verdict file —',\n 'so the review is auditable after the fact. You do not write that file; the tooling does.',\n ];\n }\n}\n"]}
@@ -6,7 +6,7 @@ export declare class ProvenanceResult {
6
6
  detail: string;
7
7
  agentIds: Record<string, string>;
8
8
  /**
9
- * The agentTypes that could NOT be credited — the FACT, with no remedy attached.
9
+ * The checklist ids that could NOT be credited — the FACT, with no remedy attached.
10
10
  *
11
11
  * Structured rather than only spelled into `detail` because the remedy depends on something this
12
12
  * service cannot see: whether that reviewer already wrote a verdict file. "It never ran" and "it ran
@@ -30,11 +30,12 @@ export declare class ProvenanceResult {
30
30
  /**
31
31
  * What ONE credited reviewer actually DID, read from its own transcript. Data-only (per CLAUDE.md).
32
32
  *
33
- * `verifyDistinct` answers "did a reviewer of this type run?" — an INTEGRITY question, and it blocks. This
33
+ * `verifyReviewers` answers "did a reviewer of this type run?" — an INTEGRITY question, and it blocks. This
34
34
  * answers "did it look at the change?" — a QUALITY question, and it only warns. The distinction is
35
35
  * deliberate; see {@link SubagentProvenanceService.evidenceFor}.
36
36
  */
37
37
  export declare class ReviewerEvidence {
38
+ checklistId: string;
38
39
  agentType: string;
39
40
  agentId: string;
40
41
  readDiff: boolean;
@@ -53,7 +54,7 @@ export declare class ReviewerEvidence {
53
54
  * Distinct `message.model` values OBSERVED in the transcript, in first-seen order.
54
55
  *
55
56
  * The model that actually ran, never the one that was configured — and never anything the reviewer
56
- * says about itself. A checklist's `.claude/agents/<subagent>.md` declares `model:`, but that is the
57
+ * says about itself. The reviewer agent's `.claude/agents/<name>.md` may declare `model:`, but that is the
57
58
  * REQUESTED value and it can silently disagree with what served the request: a repo was measured
58
59
  * running opus for a reviewer whose agent file said `model: sonnet`. Asking the model instead would
59
60
  * be worse — a model is unreliable about its own identity, naming a family instead of a version or
@@ -72,7 +73,7 @@ export declare class ReviewerEvidence {
72
73
  */
73
74
  models: string[];
74
75
  transcriptPath: string;
75
- constructor(agentType: string, agentId: string, readDiff?: boolean, readDoc?: boolean, toolCallCount?: number, offRepoSearches?: number, transcriptPath?: string, models?: string[], wroteVerdict?: boolean);
76
+ constructor(checklistId: string, agentType: string, agentId: string, readDiff?: boolean, readDoc?: boolean, toolCallCount?: number, offRepoSearches?: number, transcriptPath?: string, models?: string[], wroteVerdict?: boolean);
76
77
  }
77
78
  /**
78
79
  * One pass over one transcript: the tool inputs AND the models that served it. Data-only.
@@ -90,7 +91,7 @@ export declare class TranscriptScan {
90
91
  /**
91
92
  * WHERE this branch's review materials live. Data-only.
92
93
  *
93
- * One class for BOTH passes — crediting (`verifyDistinct`) and evidence (`evidenceFor`) — because they
94
+ * One class for BOTH passes — crediting (`verifyReviewers`) and evidence (`evidenceFor`) — because they
94
95
  * ask their questions of the same paths. `diffDir` is the per-branch materialization
95
96
  * (`.webpieces/pr-review/<featureSlug>/diff`), which is what makes it usable as PROOF of which branch a
96
97
  * reviewer looked at: the path names the branch, it is absolute, and stage ② recreates it per run.
@@ -100,7 +101,7 @@ export declare class ReviewerContext {
100
101
  diffDir: string;
101
102
  docPaths: Record<string, string>;
102
103
  /**
103
- * agentType → the absolute path of the verdict file THAT checklist must write on THIS branch
104
+ * checklist id → the absolute path of the verdict file THAT checklist must write on THIS branch
104
105
  * (`.webpieces/pr-review/<featureSlug>/review-<id>.json`). '' when unknown.
105
106
  *
106
107
  * The strongest attribution signal available, and stronger than `diffDir`: the path is
@@ -111,11 +112,23 @@ export declare class ReviewerContext {
111
112
  verdictPaths: Record<string, string>;
112
113
  constructor(branch: string, diffDir?: string, docPaths?: Record<string, string>, verdictPaths?: Record<string, string>);
113
114
  }
115
+ /**
116
+ * One checklist that must be credited to a reviewer run, and the agent type that run must carry. Data-only.
117
+ *
118
+ * The two used to be one string — a checklist's id WAS its agent type — and provenance keyed everything by
119
+ * it. Now every checklist is reviewed by the same repo-wide agent type, so the id and the type are
120
+ * separate facts and a run is matched on the type but credited to the id.
121
+ */
122
+ export declare class ExpectedReviewer {
123
+ checklistId: string;
124
+ agentType: string;
125
+ constructor(checklistId: string, agentType: string);
126
+ }
114
127
  /**
115
128
  * Verifies — from the Claude Code harness's OWN artifacts, never from anything the model asserts — that
116
129
  * a subagent of a given `agentType` actually ran during the current session on the current branch. Used
117
- * to enforce a checklist's optional `subagent:` field: that an INDEPENDENT reviewer looked, rather than
118
- * the coding agent self-certifying.
130
+ * to enforce that every checklist was reviewed by a `reviewerAgentName` subagent: that an INDEPENDENT
131
+ * reviewer looked, rather than the coding agent self-certifying.
119
132
  *
120
133
  * The harness writes, beside each subagent transcript:
121
134
  * ~/.claude/projects/<cwd-slug>/<sessionId>/subagents/agent-<id>.meta.json → { agentType, spawnDepth, … }
@@ -126,18 +139,18 @@ export declare class ReviewerContext {
126
139
  *
127
140
  * IMPORTANT — this is NOT tamper-proof. A determined agent can `cat >` a fake agent-*.meta.json. This
128
141
  * raises the bar from "trust the model's word" to "deliberate, auditable forgery outside the repo"; it
129
- * is not cryptographic. Say so wherever `subagent:` is documented.
142
+ * is not cryptographic. Say so wherever reviewer provenance is documented.
130
143
  *
131
144
  * `@injectable(bindingScopeValues.Singleton)` so it is drawn in the DI design and injected by type.
132
145
  */
133
146
  export declare class SubagentProvenanceService {
134
147
  private readonly branchByCwd;
135
148
  private readonly scanByPath;
136
- verifyDistinct(expectedAgentTypes: readonly string[], context: ReviewerContext): ProvenanceResult;
149
+ verifyReviewers(expected: readonly ExpectedReviewer[], context: ReviewerContext, sharedRuns: boolean): ProvenanceResult;
137
150
  /**
138
151
  * What each credited reviewer actually READ, from its own transcript.
139
152
  *
140
- * `verifyDistinct` proves a reviewer of the right type RAN. It cannot tell a reviewer that read the diff
153
+ * `verifyReviewers` proves a reviewer of the right type RAN. It cannot tell a reviewer that read the diff
141
154
  * and thought about it from one that wrote a verdict having opened nothing. This closes that gap — and
142
155
  * the motivating case is real: one reviewer spent 14 of 26 tool calls grepping `node_modules` because
143
156
  * nothing had told it where anything was, which `offRepoSearches` now makes visible.
@@ -148,12 +161,12 @@ export declare class SubagentProvenanceService {
148
161
  * consumer's PR with no self-service recovery — `sidechainOnBranch` is already lenient for exactly
149
162
  * this reason, and blocking on a richer read of the same files would be less safe, not more.
150
163
  * 2. A reviewer can legitimately receive the diff another way (inlined into its prompt, say).
151
- * 3. verifyDistinct is the INTEGRITY signal and rightly blocks; this is a QUALITY signal. Conflating
164
+ * 3. verifyReviewers is the INTEGRITY signal and rightly blocks; this is a QUALITY signal. Conflating
152
165
  * them would let a transcript-parsing quirk refuse a PR that a real reviewer really did review.
153
166
  *
154
- * Returns [] outside a Claude Code session, matching verifyDistinct's SKIP behavior.
167
+ * Returns [] outside a Claude Code session, matching verifyReviewers's SKIP behavior.
155
168
  */
156
- evidenceFor(context: ReviewerContext, agentIds: Record<string, string>): ReviewerEvidence[];
169
+ evidenceFor(context: ReviewerContext, expected: readonly ExpectedReviewer[], agentIds: Record<string, string>): ReviewerEvidence[];
157
170
  private evidenceFromTranscript;
158
171
  private readDiffDir;
159
172
  /**
@@ -188,6 +201,8 @@ export declare class SubagentProvenanceService {
188
201
  private inClaudeSession;
189
202
  private skipped;
190
203
  private findMatchingAgentId;
204
+ private isReviewerRun;
205
+ private namedVerdict;
191
206
  private allSubagentsDirs;
192
207
  private metaFiles;
193
208
  private agentIdOf;
@@ -262,7 +277,7 @@ export declare class SubagentProvenanceService {
262
277
  * branch, and refusing that would re-open a narrower version of the same unrecoverable deadlock.
263
278
  *
264
279
  * Independence is NOT weakened by either: `isSidechain === true` and `spawnDepth >= 1` are checked
265
- * before we get here (so the main loop's own transcript can never qualify), and `verifyDistinct`
280
+ * before we get here (so the main loop's own transcript can never qualify), and `verifyReviewers`
266
281
  * excludes an agentId already credited to another checklist. It remains non-tamper-proof in exactly
267
282
  * the way the class doc already states — forging this now means forging a transcript rather than a
268
283
  * meta.json, which is the same bar, not a lower one.