@webpieces/rules-config 0.4.801 → 0.4.803

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.
@@ -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 agentName: string; // the agent type the subagent is spawned as (webpieces-reviewer, or the override)\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/<name>.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"]}
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 (webpieces-reviewer, or the override)\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/<name>.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.renderVerdictSchema}.\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 '## Submit your verdict',\n '',\n `Submit EXACTLY this shape through \\`${this.reviewJsonService.submitCommand(b.checklistId)}\\` —`,\n 'the JSON on stdin (a heredoc is simplest), or `--file <path>` naming a scratch file. Do NOT write',\n `\\`${b.verdictPath}\\` yourself: the bin validates the verdict, writes that file, and records that YOU`,\n 'submitted it, and `wp-finish-upsert-pr` REJECTS a verdict file written any other way. The bin also',\n 'refuses the coordinating agent, so nobody can submit this on your behalf.',\n '',\n '```',\n this.reviewJsonService.renderVerdictSchema(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, or the',\n '`review-<id>.provenance.json` wp-write-review writes beside your verdict; the tooling does.',\n ];\n }\n}\n"]}
@@ -233,6 +233,7 @@ export declare class SubagentProvenanceService {
233
233
  */
234
234
  private isReviewerRun;
235
235
  private namedVerdict;
236
+ private submittedVerdict;
236
237
  /**
237
238
  * Every `<config>/projects/&#42;/<session>/subagents` dir that exists — matching by the recorded
238
239
  * gitBranch (not by session id) is what makes provenance survive across sessions.
@@ -9,10 +9,11 @@ const inversify_1 = require("inversify");
9
9
  const claude_config_dir_1 = require("./claude-config-dir");
10
10
  const to_error_1 = require("./to-error");
11
11
  const state_dir_1 = require("./state-dir");
12
+ const review_identity_stamp_1 = require("./review-identity-stamp");
12
13
  // Outcome of a provenance check.
13
14
  exports.PROVENANCE_OK = 'ok'; // a matching reviewer subagent demonstrably ran on this branch
14
15
  exports.PROVENANCE_MISSING = 'missing'; // session known, but no matching subagent artifact found → refuse (BLOCK)
15
- exports.PROVENANCE_SKIPPED = 'skipped'; // no CLAUDE_CODE_SESSION_ID (plain terminal / CI) → warn + pass
16
+ exports.PROVENANCE_SKIPPED = 'skipped'; // no CLAUDE_CODE_SESSION_ID → transcript evidence skipped; wp-write-review provenance still enforced (#863)
16
17
  class ProvenanceResult {
17
18
  status; // PROVENANCE_OK | PROVENANCE_MISSING | PROVENANCE_SKIPPED
18
19
  detail; // human-readable explanation for the warning/error/dashboard
@@ -218,12 +219,8 @@ let SubagentProvenanceService = class SubagentProvenanceService {
218
219
  // grouping is always something the repo asked for. A run is still only credited when it is a real
219
220
  // subagent of the right type that ran on this branch.
220
221
  //
221
- // There used to be a `sharedRuns` parameter, false when `reviewerAgents` was absent, which demanded a
222
- // DISTINCT run per checklist. It went with the absent branch, and nothing was lost: a cap is a MAXIMUM,
223
- // so even a consumer setting it to their checklist count may legitimately group — the old flag could
224
- // never have enforced distinctness from the cap alone.
225
- //
226
- // Either way a run that NAMED this checklist's verdict file is preferred over one that merely ran on the
222
+ // (A removed `sharedRuns` flag once demanded a distinct run per checklist; a cap is a MAXIMUM, so it never could.)
223
+ // Either way a run that NAMED (or wp-write-review-submitted) this checklist's verdict is preferred over one that merely ran on the
227
224
  // branch, so each checklist is credited to the reviewer that actually wrote it whenever that is knowable.
228
225
  //
229
226
  // Scoped by BRANCH across ALL sessions (not the current session): once a reviewer ran on this branch in
@@ -296,7 +293,7 @@ let SubagentProvenanceService = class SubagentProvenanceService {
296
293
  const inputs = scan.inputs;
297
294
  const docPath = context.docPaths[want.checklistId] ?? '';
298
295
  const verdictPath = context.verdictPaths[want.checklistId] ?? '';
299
- return new ReviewerEvidence(want.checklistId, want.agentType, agentId, this.readDiffDir(scan, context), docPath !== '' && this.mentions(inputs, docPath), inputs.length, inputs.filter((i) => i.includes('node_modules')).length, jsonl, scan.models, verdictPath !== '' && this.mentions(inputs, verdictPath));
296
+ return new ReviewerEvidence(want.checklistId, want.agentType, agentId, this.readDiffDir(scan, context), docPath !== '' && this.mentions(inputs, docPath), inputs.length, inputs.filter((i) => i.includes('node_modules')).length, jsonl, scan.models, this.submittedVerdict(inputs, want.checklistId, verdictPath));
300
297
  }
301
298
  // The instructions file counts as "read the diff": it lives in the same per-branch dir, it is what
302
299
  // the reviewer is told to open first, and it inlines the diff paths. A reviewer that opened it and
@@ -393,7 +390,7 @@ let SubagentProvenanceService = class SubagentProvenanceService {
393
390
  return (process.env['CLAUDE_CODE_SESSION_ID'] ?? '').trim() !== '';
394
391
  }
395
392
  skipped(what) {
396
- return new ProvenanceResult(exports.PROVENANCE_SKIPPED, `CLAUDE_CODE_SESSION_ID not set — cannot verify ${what} ran (plain terminal / CI). Skipping the provenance check.`, {}, []);
393
+ return new ProvenanceResult(exports.PROVENANCE_SKIPPED, `CLAUDE_CODE_SESSION_ID not set — no Claude transcripts to verify ${what} against (Codex / terminal / CI); each verdict's wp-write-review provenance is still enforced.`, {}, []);
397
394
  }
398
395
  // The agentId of a subagent run on `branch`, searched across ALL sessions' subagent dirs
399
396
  // (branch-scoped, so a run from a prior session still counts). '' if none. `exclude` skips agentIds
@@ -453,11 +450,14 @@ let SubagentProvenanceService = class SubagentProvenanceService {
453
450
  // Did this run's transcript name the checklist's own verdict path?
454
451
  // eslint-disable-next-line @typescript-eslint/max-params
455
452
  namedVerdict(dir, agentId, checklistId, context) {
456
- const verdictPath = context.verdictPaths[checklistId] ?? '';
457
453
  const jsonl = path.join(dir, `agent-${agentId}.jsonl`);
458
- if (verdictPath === '' || !fs.existsSync(jsonl))
459
- return false;
460
- return this.mentions(this.scanTranscript(jsonl).inputs, verdictPath);
454
+ return fs.existsSync(jsonl) && this.submittedVerdict(this.scanTranscript(jsonl).inputs, checklistId, context.verdictPaths[checklistId] ?? '');
455
+ }
456
+ // Named its verdict file, or submitted it via wp-write-review (#863). Proves authorship, never branch.
457
+ submittedVerdict(inputs, checklistId, verdictPath) {
458
+ if (verdictPath !== '' && this.mentions(inputs, verdictPath))
459
+ return true;
460
+ return inputs.some((i) => review_identity_stamp_1.reviewIdentityStamps.invokedChecklists(i).includes(checklistId));
461
461
  }
462
462
  /**
463
463
  * Every `<config>/projects/&#42;/<session>/subagents` dir that exists — matching by the recorded
@@ -1 +1 @@
1
- {"version":3,"file":"subagent-provenance.js","sourceRoot":"","sources":["../../../../../packages/tooling/rules-config/src/subagent-provenance.ts"],"names":[],"mappings":"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","sourcesContent":["import { spawnSync } from 'child_process';\nimport * as fs from 'fs';\nimport * as path from 'path';\nimport { injectable, bindingScopeValues } from 'inversify';\nimport { claudeConfigDir } from './claude-config-dir';\nimport { toError } from './to-error';\nimport { dotWebpieces } from './state-dir';\n\n// Outcome of a provenance check.\nexport const PROVENANCE_OK = 'ok'; // a matching reviewer subagent demonstrably ran on this branch\nexport const PROVENANCE_MISSING = 'missing'; // session known, but no matching subagent artifact found → refuse (BLOCK)\nexport const PROVENANCE_SKIPPED = 'skipped'; // no CLAUDE_CODE_SESSION_ID (plain terminal / CI) → warn + pass\n\nexport class ProvenanceResult {\n status: string; // PROVENANCE_OK | PROVENANCE_MISSING | PROVENANCE_SKIPPED\n detail: string; // human-readable explanation for the warning/error/dashboard\n // agentIds credited, keyed by CHECKLIST ID, so an evidence pass does not re-scan to find them again. Two\n // checklists may map to the same agentId when `reviewerAgents` let one subagent cover both.\n agentIds: Record<string, string>;\n /**\n * The checklist ids that could NOT be credited — the FACT, with no remedy attached.\n *\n * Structured rather than only spelled into `detail` because the remedy depends on something this\n * service cannot see: whether that reviewer already wrote a verdict file. \"It never ran\" and \"it ran\n * and cannot be attributed\" need OPPOSITE instructions — spawn one, versus do not re-spawn, because a\n * re-spawn overwrites the verdict and is stamped identically. Handing the caller a pre-worded\n * imperative is what produced the destructive loop this field exists to end; see ProvenanceEnforcer.\n */\n missing: string[];\n\n /**\n * `agentIds` and `missing` are REQUIRED, with no defaults.\n *\n * A default on `missing` is what made the dangerous state cheap to reach: the caller BLOCKS on this\n * list, so a `PROVENANCE_MISSING` built without it would report unverified and refuse NOTHING — a\n * silent pass, one forgotten argument away. Required parameters make the omission a compile error at\n * every construction site, present and future. The remaining `missing: []` on a blocking status is\n * caught by the caller, which refuses on the STATUS and falls back to `detail`; see\n * ProvenanceEnforcer.refuse.\n */\n // eslint-disable-next-line @typescript-eslint/max-params\n constructor(status: string, detail: string, agentIds: Record<string, string>, missing: string[]) {\n this.status = status;\n this.detail = detail;\n this.agentIds = agentIds;\n this.missing = missing;\n }\n}\n\n/**\n * What ONE credited reviewer actually DID, read from its own transcript. Data-only (per CLAUDE.md).\n *\n * `verifyReviewers` answers \"did a reviewer of this type run?\" — an INTEGRITY question, and it blocks. This\n * answers \"did it look at the change?\" — a QUALITY question, and it only warns. The distinction is\n * deliberate; see {@link SubagentProvenanceService.evidenceFor}.\n */\nexport class ReviewerEvidence {\n checklistId: string; // the checklist this evidence is FOR (one subagent may appear under several)\n agentType: string;\n agentId: string;\n readDiff: boolean; // opened the materialized diff dir (or its own instructions file)\n readDoc: boolean; // opened its checklist's guidance doc\n /**\n * Named its own verdict file — `.webpieces/pr-review/<featureSlug>/review-<id>.json` — in a tool input.\n *\n * Recorded, not just consumed, because it is the field that answers \"who wrote this verdict?\" for an\n * auditor reading provenance.json later. It is also a CREDIT channel: see\n * {@link SubagentProvenanceService.creditedByWhatItTouched}.\n */\n wroteVerdict: boolean;\n toolCallCount: number;\n offRepoSearches: number; // tool calls that reached into node_modules — the archaeology signal\n /**\n * Distinct `message.model` values OBSERVED in the transcript, in first-seen order.\n *\n * The model that actually ran, never the one that was configured — and never anything the reviewer\n * says about itself. The reviewer agent's `.claude/agents/<name>.md` may declare `model:`, but that is the\n * REQUESTED value and it can silently disagree with what served the request: a repo was measured\n * running opus for a reviewer whose agent file said `model: sonnet`. Asking the model instead would\n * be worse — a model is unreliable about its own identity, naming a family instead of a version or\n * repeating whatever the system prompt implied, so a self-reported field is usually right and\n * silently wrong, which is the worst kind of telemetry because it looks authoritative.\n * `message.model` is written by the harness, so this inherits the anti-forgery property the rest of\n * this class documents.\n *\n * An ARRAY, not a string: one reviewer run can span more than one model (a fallback after a refusal,\n * a mid-run config change). Collapsing to one value forces a lossy choice at read time; recording\n * what happened lets the renderer decide.\n *\n * Token counts and cost are deliberately NOT here. Prices change, vary by platform and differ under\n * intro pricing, so a rate table in this package would rot silently — and the question this answers\n * is \"which model reviewed this?\", not \"what did it cost?\".\n */\n models: string[];\n // Absolute path of the transcript these counters were read out of, '' when it could not be resolved.\n // Carried out rather than recomputed because a reviewer subagent cannot learn its own transcript path\n // (the environment exposes the PARENT session id and no agent id), so this is the only place it is\n // known — see ReviewProvenanceService, which records it as the audit link for the verdict.\n transcriptPath: string;\n\n // eslint-disable-next-line @typescript-eslint/max-params\n constructor(checklistId: string, agentType: string, agentId: string, readDiff = false, readDoc = false, toolCallCount = 0, offRepoSearches = 0, transcriptPath = '', models: string[] = [], wroteVerdict = false) {\n this.checklistId = checklistId;\n this.agentType = agentType;\n this.agentId = agentId;\n this.readDiff = readDiff;\n this.readDoc = readDoc;\n this.wroteVerdict = wroteVerdict;\n this.toolCallCount = toolCallCount;\n this.offRepoSearches = offRepoSearches;\n this.transcriptPath = transcriptPath;\n this.models = models;\n }\n}\n\n/**\n * One pass over one transcript: the tool inputs AND the models that served it. Data-only.\n *\n * They are gathered together rather than in two passes because they come from the SAME records — the\n * inputs from `message.content[].input`, the model from `message.model` one level up — and a transcript\n * is the largest file this service opens. Two reads of it to answer two questions about the same lines\n * would be the duplicate-work trap the diff materializer documents at length.\n */\nexport class TranscriptScan {\n inputs: string[]; // every tool_use input, JSON-stringified\n models: string[]; // distinct message.model values, first-seen order\n\n constructor(inputs: string[] = [], models: string[] = []) {\n this.inputs = inputs;\n this.models = models;\n }\n}\n\n/**\n * WHERE this branch's review materials live. Data-only.\n *\n * One class for BOTH passes — crediting (`verifyReviewers`) and evidence (`evidenceFor`) — because they\n * ask their questions of the same paths. `diffDir` is the per-branch materialization\n * (`.webpieces/pr-review/<featureSlug>/diff`), which is what makes it usable as PROOF of which branch a\n * reviewer looked at: the path names the branch, it is absolute, and stage ② recreates it per run.\n */\nexport class ReviewerContext {\n branch: string;\n diffDir: string; // '' when nothing was materialized\n docPaths: Record<string, string>; // checklist id → its checklist doc path ('' when none)\n /**\n * checklist id → the absolute path of the verdict file THAT checklist must write on THIS branch\n * (`.webpieces/pr-review/<featureSlug>/review-<id>.json`). '' when unknown.\n *\n * The strongest attribution signal available, and stronger than `diffDir`: the path is\n * worktree-absolute (naming the tree), per-branch (naming the featureSlug) AND per-checklist (naming\n * the id), so a transcript containing it can only belong to a reviewer that authored that checklist's\n * verdict for that branch. `diffDir` proves the branch but not the checklist.\n */\n verdictPaths: Record<string, string>;\n\n // eslint-disable-next-line @typescript-eslint/max-params\n constructor(branch: string, diffDir = '', docPaths: Record<string, string> = {}, verdictPaths: Record<string, string> = {}) {\n this.branch = branch;\n this.diffDir = diffDir;\n this.docPaths = docPaths;\n this.verdictPaths = verdictPaths;\n }\n}\n\n/**\n * One checklist that must be credited to a reviewer run, plus the agent type the BRIEFING named. Data-only.\n *\n * The two used to be one string — a checklist's id WAS its agent type — and provenance keyed everything by\n * it. Now every checklist is reviewed by the same repo-wide agent type, so the id and the type are\n * separate facts.\n *\n * `agentType` is NOT a provenance input: nothing here matches a run on it (issue #964, see\n * {@link SubagentProvenanceService.isReviewerRun}). It is carried because it is what the BRIEFING told\n * the agent to spawn and what {@link ReviewerEvidence} reports, which are both worth recording even\n * though neither is worth gating on.\n */\nexport class ExpectedReviewer {\n checklistId: string;\n agentType: string;\n\n constructor(checklistId: string, agentType: string) {\n this.checklistId = checklistId;\n this.agentType = agentType;\n }\n}\n\n/**\n * Verifies — from the Claude Code harness's OWN artifacts, never from anything the model asserts — that\n * a real SUBAGENT actually ran on the current branch and did this checklist's work. Used to enforce that\n * every checklist was reviewed by an INDEPENDENT reviewer, rather than by the coding agent\n * self-certifying.\n *\n * The harness writes, beside each subagent transcript:\n * <config>/projects/<cwd-slug>/<sessionId>/subagents/agent-<id>.meta.json → { agentType, spawnDepth, … }\n * <config>/projects/<cwd-slug>/<sessionId>/subagents/agent-<id>.jsonl → record 0 { isSidechain, gitBranch, … }\n * `spawnDepth`/`isSidechain` are written by Claude Code, not by the model, and they are what carries the\n * anti-self-certification property. `agentType` is written there too and is deliberately NOT checked —\n * see {@link SubagentProvenanceService.isReviewerRun}. `<config>` is `$CLAUDE_CONFIG_DIR` when set, else\n * `~/.claude`; see {@link ClaudeConfigDir}, and never re-derive it here. Dirs are found by walking\n * every session, so the cwd-slug never has to be derived/guessed.\n *\n * IMPORTANT — this is NOT tamper-proof. A determined agent can `cat >` a fake agent-*.meta.json. This\n * raises the bar from \"trust the model's word\" to \"deliberate, auditable forgery outside the repo\"; it\n * is not cryptographic. Say so wherever reviewer provenance is documented.\n *\n * `@injectable(bindingScopeValues.Singleton)` so it is drawn in the DI design and injected by type.\n */\n@injectable(bindingScopeValues.Singleton)\nexport class SubagentProvenanceService {\n // cwd → the branch it is PINNED to ('' when it is not a linked worktree, or is unresolvable).\n // See branchOfCwd for why it is cached and pinnedBranch for what \"pinned\" buys.\n private readonly branchByCwd = new Map<string, string>();\n\n // transcript path → its one scan. The credit pass and the evidence pass ask different questions of\n // the same (largest) files this service opens, and the credit pass may look at candidates the\n // evidence pass then re-visits. See scanTranscript for why one pass answers both.\n private readonly scanByPath = new Map<string, TranscriptScan>();\n\n // Verify EVERY expected checklist was reviewed by a reviewer subagent that ran on `context.branch` — the\n // coding agent may not self-certify. SKIPPED (pass) without a session id.\n //\n // ONE run may cover SEVERAL checklists: `reviewerAgents` is a required config field and is a CAP, so\n // grouping is always something the repo asked for. A run is still only credited when it is a real\n // subagent of the right type that ran on this branch.\n //\n // There used to be a `sharedRuns` parameter, false when `reviewerAgents` was absent, which demanded a\n // DISTINCT run per checklist. It went with the absent branch, and nothing was lost: a cap is a MAXIMUM,\n // so even a consumer setting it to their checklist count may legitimately group — the old flag could\n // never have enforced distinctness from the cap alone.\n //\n // Either way a run that NAMED this checklist's verdict file is preferred over one that merely ran on the\n // branch, so each checklist is credited to the reviewer that actually wrote it whenever that is knowable.\n //\n // Scoped by BRANCH across ALL sessions (not the current session): once a reviewer ran on this branch in\n // any session, a later re-push in a NEW session still finds it, so the review is NOT forced to re-run.\n // That is what keeps \"review once per branch\" true across sessions. A PR opened outside the gated flow\n // still has no review-<id>.json, so wp-finish forces the review regardless of provenance.\n verifyReviewers(expected: readonly ExpectedReviewer[], context: ReviewerContext): ProvenanceResult {\n if (expected.length === 0) return new ProvenanceResult(PROVENANCE_OK, 'no reviewer subagents required', {}, []);\n if (!this.inClaudeSession()) return this.skipped('reviewer subagents');\n const dirs = this.allSubagentsDirs();\n const missing: string[] = [];\n const usedAgentIds = new Set<string>();\n const credited: Record<string, string> = {};\n for (const want of expected) {\n const agentId = this.findMatchingAgentId(dirs, want, context, new Set<string>());\n if (agentId === '') missing.push(want.checklistId);\n else {\n usedAgentIds.add(agentId);\n credited[want.checklistId] = agentId;\n }\n }\n const runs = new Set(Object.values(credited)).size;\n return missing.length === 0\n ? new ProvenanceResult(PROVENANCE_OK,\n `verified ${expected.length} checklist(s) were reviewed by ${runs} reviewer subagent run(s)`, credited, [])\n : new ProvenanceResult(PROVENANCE_MISSING,\n `${missing.length} checklist(s) could not be attributed to a reviewer subagent on this branch: ${missing.join(', ')}`,\n credited, missing);\n }\n\n /**\n * What each credited reviewer actually READ, from its own transcript.\n *\n * `verifyReviewers` proves a reviewer of the right type RAN. It cannot tell a reviewer that read the diff\n * and thought about it from one that wrote a verdict having opened nothing. This closes that gap — and\n * the motivating case is real: one reviewer spent 14 of 26 tool calls grepping `node_modules` because\n * nothing had told it where anything was, which `offRepoSearches` now makes visible.\n *\n * WARNING-ONLY by default, for three reasons, and `requireDiffEvidence` must stay opt-in until at least\n * one repo has watched it:\n * 1. The transcript layout is undocumented Claude Code internals. A format change would wedge every\n * consumer's PR with no self-service recovery — `sidechainOnBranch` is already lenient for exactly\n * this reason, and blocking on a richer read of the same files would be less safe, not more.\n * 2. A reviewer can legitimately receive the diff another way (inlined into its prompt, say).\n * 3. verifyReviewers is the INTEGRITY signal and rightly blocks; this is a QUALITY signal. Conflating\n * them would let a transcript-parsing quirk refuse a PR that a real reviewer really did review.\n *\n * Returns [] outside a Claude Code session, matching verifyReviewers's SKIP behavior.\n */\n evidenceFor(context: ReviewerContext, expected: readonly ExpectedReviewer[], agentIds: Record<string, string>): ReviewerEvidence[] {\n if (!this.inClaudeSession()) return [];\n const dirs = this.allSubagentsDirs();\n const out: ReviewerEvidence[] = [];\n for (const want of expected) {\n const agentId = agentIds[want.checklistId];\n if (agentId === undefined) continue;\n const jsonl = this.transcriptPath(dirs, agentId);\n if (jsonl === '') {\n out.push(new ReviewerEvidence(want.checklistId, want.agentType, agentId));\n continue;\n }\n out.push(this.evidenceFromTranscript(want, agentId, jsonl, context));\n }\n return out;\n }\n\n // eslint-disable-next-line @typescript-eslint/max-params\n private evidenceFromTranscript(want: ExpectedReviewer, agentId: string, jsonl: string, context: ReviewerContext): ReviewerEvidence {\n const scan = this.scanTranscript(jsonl);\n const inputs = scan.inputs;\n const docPath = context.docPaths[want.checklistId] ?? '';\n const verdictPath = context.verdictPaths[want.checklistId] ?? '';\n return new ReviewerEvidence(\n want.checklistId, want.agentType, agentId, this.readDiffDir(scan, context),\n docPath !== '' && this.mentions(inputs, docPath),\n inputs.length,\n inputs.filter((i: string): boolean => i.includes('node_modules')).length,\n jsonl,\n scan.models,\n verdictPath !== '' && this.mentions(inputs, verdictPath),\n );\n }\n\n // The instructions file counts as \"read the diff\": it lives in the same per-branch dir, it is what\n // the reviewer is told to open first, and it inlines the diff paths. A reviewer that opened it and\n // then its own diff files is the intended path; treating only the diff dir as proof would flag it.\n private readDiffDir(scan: TranscriptScan, context: ReviewerContext): boolean {\n return context.diffDir !== '' && this.mentions(scan.inputs, context.diffDir);\n }\n\n /**\n * Record this line's `message.model`, deduped, in first-seen order.\n *\n * `<synthetic>` records are SKIPPED. The harness writes them for messages no model produced (tool\n * results, injected notices); counting one would put a non-model in a field whose entire purpose is\n * \"which model reviewed this\", and it would show up on every single reviewer.\n */\n // webpieces-disable no-any-unknown -- opaque transcript record, only `model` is read and it is type-guarded below\n private collectModel(message: Record<string, unknown>, models: string[]): void {\n const model = message['model'];\n if (typeof model !== 'string' || model === '' || model === '<synthetic>') return;\n if (!models.includes(model)) models.push(model);\n }\n\n // The absolute path of agent-<id>.jsonl across all session dirs, or '' if it is not there.\n private transcriptPath(dirs: readonly string[], agentId: string): string {\n for (const dir of dirs) {\n const candidate = path.join(dir, `agent-${agentId}.jsonl`);\n if (fs.existsSync(candidate)) return candidate;\n }\n return '';\n }\n\n /**\n * ONE pass over the transcript for both answers (see {@link TranscriptScan}), CACHED per path.\n *\n * Cached because two passes now ask questions of the same file: crediting (does it name this branch's\n * verdict/diff?) and evidence (what did it read, which model served it?). Without the cache the credit\n * pass would re-read every candidate the evidence pass then re-opens — on the largest files this\n * service touches, on the path that opens a PR.\n *\n * Tool inputs are JSON-stringified rather than walked field-by-field because the shape differs per\n * tool (Read takes file_path, Bash takes command, Grep takes path) and a substring test over the\n * serialized input is both simpler and robust to a tool we have not seen.\n *\n * Best-effort, like everything else that parses this file: a format change must never wedge the\n * gate, so an unreadable transcript yields empty rather than throwing. That matters more for the\n * models than for the counters — this is quality telemetry, not an integrity check, and a missing\n * `model` field must not be able to block a PR.\n */\n private scanTranscript(jsonl: string): TranscriptScan {\n const cached = this.scanByPath.get(jsonl);\n if (cached !== undefined) return cached;\n const scan = this.readTranscript(jsonl);\n this.scanByPath.set(jsonl, scan);\n return scan;\n }\n\n private readTranscript(jsonl: string): TranscriptScan {\n const scan = new TranscriptScan();\n // webpieces-disable no-unmanaged-exceptions -- chokepoint: an unreadable transcript yields no evidence, never a crash\n // eslint-disable-next-line @webpieces/no-unmanaged-exceptions\n try {\n for (const line of fs.readFileSync(jsonl, 'utf8').split('\\n')) {\n if (line.trim() === '') continue;\n const rec = this.parseLine(line);\n const message = rec?.['message'];\n if (typeof message !== 'object' || message === null) continue;\n // webpieces-disable no-any-unknown -- opaque transcript record, narrowed by the guard above\n const msg = message as Record<string, unknown>;\n this.collectModel(msg, scan.models);\n const content = msg['content'];\n if (!Array.isArray(content)) continue;\n for (const block of content) {\n // webpieces-disable no-any-unknown -- opaque content block, only `type`/`input` are read\n const b = block as Record<string, unknown>;\n if (b['type'] === 'tool_use') scan.inputs.push(JSON.stringify(b['input'] ?? {}));\n }\n }\n } catch (err: unknown) {\n const error = toError(err);\n void error;\n }\n return scan;\n }\n\n private mentions(inputs: readonly string[], needle: string): boolean {\n return inputs.some((i: string): boolean => i.includes(needle));\n }\n\n // Are we running under Claude Code at all? (CI / plain terminal → provenance is unverifiable → SKIP.)\n private inClaudeSession(): boolean {\n return (process.env['CLAUDE_CODE_SESSION_ID'] ?? '').trim() !== '';\n }\n\n private skipped(what: string): ProvenanceResult {\n return new ProvenanceResult(PROVENANCE_SKIPPED,\n `CLAUDE_CODE_SESSION_ID not set — cannot verify ${what} ran (plain terminal / CI). Skipping the provenance check.`,\n {}, []);\n }\n\n // The agentId of a subagent run on `branch`, searched across ALL sessions' subagent dirs\n // (branch-scoped, so a run from a prior session still counts). '' if none. `exclude` skips agentIds\n // already credited to another checklist so one run can't satisfy two.\n //\n // The run is NOT matched on its agent type — see isReviewerRun for why that check was removed — so\n // several runs match and the one that NAMED this checklist's verdict file wins; the first\n // branch-matching run is the fallback, as before.\n // eslint-disable-next-line @typescript-eslint/max-params\n private findMatchingAgentId(dirs: readonly string[], want: ExpectedReviewer, context: ReviewerContext, exclude: ReadonlySet<string>): string {\n let fallback = '';\n for (const dir of dirs) {\n for (const metaFile of this.metaFiles(dir)) {\n const agentId = this.agentIdOf(metaFile);\n if (exclude.has(agentId) || !this.isReviewerRun(dir, metaFile)) continue;\n if (!this.sidechainOnBranch(dir, agentId, want.checklistId, context)) continue;\n if (this.namedVerdict(dir, agentId, want.checklistId, context)) return agentId;\n if (fallback === '') fallback = agentId;\n }\n }\n return fallback;\n }\n\n /**\n * A harness-written meta for a REAL SUBAGENT — `spawnDepth >= 1`, and nothing about its NAME.\n *\n * The agent TYPE used to be compared against the configured reviewer agent, and that check is\n * gone (issue #964). It proved nothing: `agentType` is a label on a prompt, and it does not show\n * the agent read the checklist, opened the diff, or looked at the right branch. The gates that DO\n * show those are untouched — `spawnDepth >= 1` plus `isSidechain === true` (see\n * {@link sidechainOnBranch}) are harness-written, so the main loop still cannot self-certify;\n * {@link creditedByWhatItTouched} proves the branch and the actual work; `requireDiffEvidence`\n * proves the diff was opened.\n *\n * It was also the ONLY gate with an unfixable failure mode. Claude Code snapshots agent\n * definitions per session and the refresh does not reach an already-running subagent, so a repo\n * that renames its reviewer agent mid-session leaves that subagent's registry offering only the\n * OLD names: the spawn is rejected, the agent falls back to `general-purpose`, does the real\n * review, writes every verdict — and is refused as unattributable, with no cwd, branch or respawn\n * able to change it. Measured: six checklists, six verdict files on disk, PR blocked.\n *\n * Accepted trade-off: without the name check the implementer's own subagent could in principle be\n * credited, since it touches the diff dir while running the gate. That is deliberate. The rule is\n * \"if the verdict file is there, a subagent wrote it\", and this gate's job is to catch \"no\n * subagent ran at all\" — not to adjudicate which subagent it was.\n */\n private isReviewerRun(dir: string, metaFile: string): boolean {\n const meta = this.readJson(path.join(dir, metaFile));\n if (!meta) return false;\n const spawnDepth = meta['spawnDepth'];\n return typeof spawnDepth === 'number' && spawnDepth >= 1;\n }\n\n // Did this run's transcript name the checklist's own verdict path?\n // eslint-disable-next-line @typescript-eslint/max-params\n private namedVerdict(dir: string, agentId: string, checklistId: string, context: ReviewerContext): boolean {\n const verdictPath = context.verdictPaths[checklistId] ?? '';\n const jsonl = path.join(dir, `agent-${agentId}.jsonl`);\n if (verdictPath === '' || !fs.existsSync(jsonl)) return false;\n return this.mentions(this.scanTranscript(jsonl).inputs, verdictPath);\n }\n\n /**\n * Every `<config>/projects/&#42;/<session>/subagents` dir that exists — matching by the recorded\n * gitBranch (not by session id) is what makes provenance survive across sessions.\n *\n * `<config>` comes from {@link ClaudeConfigDir.projectsRoots}, which is BOTH the configured\n * `$CLAUDE_CONFIG_DIR` tree and `~/.claude`. This used to be a hardcoded `~/.claude`, and on a\n * machine with a relocated config dir that found nothing at all — so every PR was refused with a\n * message about the reviewers' cwd, which is not what was wrong and which no agent could act on.\n */\n private allSubagentsDirs(): string[] {\n const out: string[] = [];\n for (const projects of claudeConfigDir.projectsRoots()) {\n for (const proj of this.readDir(projects)) {\n const projDir = path.join(projects, proj);\n for (const session of this.readDir(projDir)) {\n const candidate = path.join(projDir, session, 'subagents');\n if (fs.existsSync(candidate)) out.push(candidate);\n }\n }\n }\n return out;\n }\n\n private metaFiles(dir: string): string[] {\n return this.readDir(dir).filter((f: string): boolean => f.endsWith('.meta.json'));\n }\n\n // agent-<id>.meta.json → <id>\n private agentIdOf(metaFile: string): string {\n return metaFile.replace(/^agent-/, '').replace(/\\.meta\\.json$/, '');\n }\n\n /**\n * Cross-check the sibling transcript's record 0: isSidechain true (a real subagent, not the main\n * loop) and the same branch. Lenient on branch drift (a leftover …wpN suffix from a mid-flight\n * branch rename) and on a missing jsonl (meta already matched — accept, best-effort).\n *\n * WHEN `gitBranch` DISAGREES, A PINNED `cwd` DECIDES. Record 0 carries both fields, and the harness\n * can write a `gitBranch` that CONTRADICTS the record's own `cwd`: a reviewer subagent spawned into\n * a worktree on `dean/one-2406-…` was stamped `worktree-agent-a54887200e40eb956` — an unrelated,\n * still-live worktree's scaffold branch — deterministically, on four consecutive attempts, blocking\n * a PR whose required reviewer genuinely ran and genuinely passed. `stripWp` cannot bridge that, so\n * the reviewer was never credited and `wp-finish-upsert-pr` refused a legitimately-reviewed PR with\n * no in-flow recovery. A sweep of 961 record-0s on one machine found the mis-stamp is the MAJORITY\n * case among subagents in dedicated worktrees, so trusting `gitBranch` alone can never be correct.\n *\n * ─── Why ONLY a linked worktree, and never the primary clone ──────────────────────────────────\n * \"Ask git what branch the cwd is on\" is correct only when that cwd CANNOT have moved since the\n * reviewer ran. A LINKED WORKTREE is 1:1 with the agent that owns it and nothing re-checks it out;\n * the PRIMARY CLONE gets checked out constantly. Falling back on a primary-clone cwd would credit a\n * STALE reviewer, and by construction rather than by accident:\n *\n * 1. a reviewer runs in the primary clone while it is on branch A\n * 2. the clone is later checked out to branch B\n * 3. `wp-finish-upsert-pr` runs on B — `gitBranch` (stamped A) mismatches\n * 4. `git -C <clone>` now answers B, because the CLONE moved → the reviewer is credited for B\n *\n * It reviewed A. Every past reviewer run in that clone would be credited for whatever branch is\n * checked out at finish time — which in a repo with a required reviewer on every PR is not an\n * exotic sequence, it is the normal one. So the fallback is gated on `dotWebpieces.isLinkedWorktree`\n * (git's own `--git-dir != --git-common-dir` test, reused rather than re-derived), and a primary\n * clone falls through to a refusal exactly as it does today.\n *\n * That gate keeps the anti-forgery property intact: `cwd` is harness-written in the same record by\n * the same writer as `gitBranch`, so it carries the same weight — and inside a pinned worktree it is\n * the field that is CORRECT. There is deliberately no config flag and no second comparison mode:\n * ONE rule, with `gitBranch` only ever a cheap way to skip the subprocess when it already agrees.\n *\n * An UNRESOLVABLE cwd does not credit either. A reaped worktree, a deleted directory, a non-repo\n * path or a detached HEAD yields '' and falls through to a refusal. Leniency here is bounded by\n * \"git can still prove it\", never by \"we could not check, so assume yes\".\n *\n * ─── Why neither field can settle it from a PRIMARY CLONE, and what does ──────────────────────\n * Both fields above are stamped from the SPAWNING session's cwd — the Agent tool has no cwd\n * parameter, so a subagent inherits its parent's. A session rooted in the primary clone that spawns\n * a reviewer for a WORKTREE branch therefore produces `gitBranch` = the clone's branch (mismatch)\n * and `cwd` = the clone (gated off, correctly) — and NO respawn can change either stamp. That is not\n * an exotic setup: it is what the flow instructs the moment a worker agent dies mid-flow and the\n * top-level session has to take over, and it deadlocked a branch whose seven reviewers had all run.\n *\n * So the third channel is not a loosening of the cwd rule — it is a DIFFERENT question, asked of\n * evidence the reviewer cannot inherit and cannot fake by accident: {@link creditedByWhatItTouched}.\n */\n // eslint-disable-next-line @typescript-eslint/max-params\n private sidechainOnBranch(dir: string, agentId: string, checklistId: string, context: ReviewerContext): boolean {\n const jsonl = path.join(dir, `agent-${agentId}.jsonl`);\n if (!fs.existsSync(jsonl)) return true;\n const first = this.firstNonEmptyLine(jsonl);\n if (first === '') return true;\n const rec = this.parseLine(first);\n if (!rec) return true;\n if (rec['isSidechain'] !== true) return false;\n const gitBranch = rec['gitBranch'];\n // Not recorded at all → accept, as before: nothing to contradict and nothing to verify against.\n if (typeof gitBranch !== 'string' || gitBranch === '') return true;\n const want = this.stripWp(context.branch);\n if (this.stripWp(gitBranch) === want) return true;\n if (want !== '' && this.stripWp(this.branchOfCwd(rec['cwd'])) === want) return true;\n return this.creditedByWhatItTouched(jsonl, checklistId, context);\n }\n\n /**\n * Credit a reviewer for WHAT IT TOUCHED when neither harness-stamped field can settle it.\n *\n * Both paths compared here are ABSOLUTE and BRANCH-SPECIFIC — they live under\n * `<worktree>/.webpieces/pr-review/<featureSlug>/`, so the string names the tree AND the branch. A\n * reviewer that worked on a different branch cannot have them in its transcript, and a reviewer of\n * this branch that ran from a mis-stamped cwd cannot avoid having them. That is the property\n * `gitBranch` lacks — this file's own sweep of 961 record-0s found the mis-stamp is the MAJORITY\n * case among subagents in dedicated worktrees.\n *\n * Two channels, either sufficient:\n * 1. it WROTE this checklist's verdict file — proves branch AND checklist, and is the act the whole\n * gate is trying to attribute. Matched as a substring of any tool input, so a Write, an Edit and\n * a `cat > <path>` heredoc all count; the point is that the path was named, not which tool named it.\n * 2. it READ this branch's materialized diff dir — proves the branch. Kept as a second channel\n * because a reviewer whose verdict was relayed by its parent still demonstrably reviewed this\n * branch, and refusing that would re-open a narrower version of the same unrecoverable deadlock.\n *\n * Independence is NOT weakened by either: `isSidechain === true` and `spawnDepth >= 1` are checked\n * before we get here (so the main loop's own transcript can never qualify), and `verifyReviewers`\n * excludes an agentId already credited to another checklist. It remains non-tamper-proof in exactly\n * the way the class doc already states — forging this now means forging a transcript rather than a\n * meta.json, which is the same bar, not a lower one.\n */\n private creditedByWhatItTouched(jsonl: string, checklistId: string, context: ReviewerContext): boolean {\n const scan = this.scanTranscript(jsonl);\n const verdictPath = context.verdictPaths[checklistId] ?? '';\n if (verdictPath !== '' && this.mentions(scan.inputs, verdictPath)) return true;\n return this.readDiffDir(scan, context);\n }\n\n /**\n * The branch record-0's own `cwd` is PINNED to, '' when that cannot be established or is not pinned.\n *\n * Cached per cwd because `findMatchingAgentId` walks every subagent of every session on the machine\n * and several of them share a worktree — one `git` process per RECORD would put dozens of spawns on\n * the path that opens a PR.\n */\n // webpieces-disable no-any-unknown -- one opaque record field, type-guarded on the next line\n private branchOfCwd(cwd: unknown): string {\n if (typeof cwd !== 'string' || cwd === '') return '';\n const cached = this.branchByCwd.get(cwd);\n if (cached !== undefined) return cached;\n const resolved = this.pinnedBranch(cwd);\n this.branchByCwd.set(cwd, resolved);\n return resolved;\n }\n\n /**\n * The branch of `cwd` when — and only when — `cwd` is a LINKED WORKTREE. '' otherwise.\n *\n * '' for the primary clone (it moves; see sidechainOnBranch for the false-accept that closes), for a\n * reaped or deleted directory, for a non-repo path, when git is unavailable, and for a detached HEAD,\n * which `--abbrev-ref` prints as the literal `HEAD` and which names no branch.\n */\n private pinnedBranch(cwd: string): string {\n if (!fs.existsSync(cwd)) return '';\n if (!dotWebpieces.isLinkedWorktree(cwd)) return '';\n const result = spawnSync('git', ['-C', cwd, 'rev-parse', '--abbrev-ref', 'HEAD'], { encoding: 'utf8' });\n if (result.status !== 0) return '';\n const printed = (result.stdout ?? '').trim();\n return printed === 'HEAD' ? '' : printed;\n }\n\n private stripWp(branch: string): string {\n return branch.replace(/-?wp\\d+$/i, '');\n }\n\n private readDir(dir: string): string[] {\n // webpieces-disable no-unmanaged-exceptions -- chokepoint: an unreadable dir yields [] (best-effort provenance)\n // eslint-disable-next-line @webpieces/no-unmanaged-exceptions\n try {\n return fs.readdirSync(dir);\n } catch (err: unknown) {\n const error = toError(err);\n void error;\n return [];\n }\n }\n\n private firstNonEmptyLine(filePath: string): string {\n // webpieces-disable no-unmanaged-exceptions -- chokepoint: unreadable transcript → '' (best-effort)\n // eslint-disable-next-line @webpieces/no-unmanaged-exceptions\n try {\n for (const line of fs.readFileSync(filePath, 'utf8').split('\\n')) {\n if (line.trim() !== '') return line;\n }\n return '';\n } catch (err: unknown) {\n const error = toError(err);\n void error;\n return '';\n }\n }\n\n // webpieces-disable no-any-unknown -- opaque parsed JSON object, keys read by the caller\n private readJson(filePath: string): Record<string, unknown> | null {\n // webpieces-disable no-unmanaged-exceptions -- chokepoint: malformed meta.json → null (skipped)\n // eslint-disable-next-line @webpieces/no-unmanaged-exceptions\n try {\n // webpieces-disable no-any-unknown -- parsed JSON is opaque until narrowed by the caller\n return JSON.parse(fs.readFileSync(filePath, 'utf8')) as Record<string, unknown>;\n } catch (err: unknown) {\n const error = toError(err);\n void error;\n return null;\n }\n }\n\n // webpieces-disable no-any-unknown -- one opaque JSONL record, keys read by the caller\n private parseLine(line: string): Record<string, unknown> | null {\n // webpieces-disable no-unmanaged-exceptions -- chokepoint: malformed JSONL record → null\n // eslint-disable-next-line @webpieces/no-unmanaged-exceptions\n try {\n // webpieces-disable no-any-unknown -- parsed JSON is opaque until narrowed by the caller\n return JSON.parse(line) as Record<string, unknown>;\n } catch (err: unknown) {\n const error = toError(err);\n void error;\n return null;\n }\n }\n}\n"]}
1
+ {"version":3,"file":"subagent-provenance.js","sourceRoot":"","sources":["../../../../../packages/tooling/rules-config/src/subagent-provenance.ts"],"names":[],"mappings":"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","sourcesContent":["import { spawnSync } from 'child_process';\nimport * as fs from 'fs';\nimport * as path from 'path';\nimport { injectable, bindingScopeValues } from 'inversify';\nimport { claudeConfigDir } from './claude-config-dir';\nimport { toError } from './to-error';\nimport { dotWebpieces } from './state-dir';\nimport { reviewIdentityStamps } from './review-identity-stamp';\n\n// Outcome of a provenance check.\nexport const PROVENANCE_OK = 'ok'; // a matching reviewer subagent demonstrably ran on this branch\nexport const PROVENANCE_MISSING = 'missing'; // session known, but no matching subagent artifact found → refuse (BLOCK)\nexport const PROVENANCE_SKIPPED = 'skipped'; // no CLAUDE_CODE_SESSION_ID → transcript evidence skipped; wp-write-review provenance still enforced (#863)\n\nexport class ProvenanceResult {\n status: string; // PROVENANCE_OK | PROVENANCE_MISSING | PROVENANCE_SKIPPED\n detail: string; // human-readable explanation for the warning/error/dashboard\n // agentIds credited, keyed by CHECKLIST ID, so an evidence pass does not re-scan to find them again. Two\n // checklists may map to the same agentId when `reviewerAgents` let one subagent cover both.\n agentIds: Record<string, string>;\n /**\n * The checklist ids that could NOT be credited — the FACT, with no remedy attached.\n *\n * Structured rather than only spelled into `detail` because the remedy depends on something this\n * service cannot see: whether that reviewer already wrote a verdict file. \"It never ran\" and \"it ran\n * and cannot be attributed\" need OPPOSITE instructions — spawn one, versus do not re-spawn, because a\n * re-spawn overwrites the verdict and is stamped identically. Handing the caller a pre-worded\n * imperative is what produced the destructive loop this field exists to end; see ProvenanceEnforcer.\n */\n missing: string[];\n\n /**\n * `agentIds` and `missing` are REQUIRED, with no defaults.\n *\n * A default on `missing` is what made the dangerous state cheap to reach: the caller BLOCKS on this\n * list, so a `PROVENANCE_MISSING` built without it would report unverified and refuse NOTHING — a\n * silent pass, one forgotten argument away. Required parameters make the omission a compile error at\n * every construction site, present and future. The remaining `missing: []` on a blocking status is\n * caught by the caller, which refuses on the STATUS and falls back to `detail`; see\n * ProvenanceEnforcer.refuse.\n */\n // eslint-disable-next-line @typescript-eslint/max-params\n constructor(status: string, detail: string, agentIds: Record<string, string>, missing: string[]) {\n this.status = status;\n this.detail = detail;\n this.agentIds = agentIds;\n this.missing = missing;\n }\n}\n\n/**\n * What ONE credited reviewer actually DID, read from its own transcript. Data-only (per CLAUDE.md).\n *\n * `verifyReviewers` answers \"did a reviewer of this type run?\" — an INTEGRITY question, and it blocks. This\n * answers \"did it look at the change?\" — a QUALITY question, and it only warns. The distinction is\n * deliberate; see {@link SubagentProvenanceService.evidenceFor}.\n */\nexport class ReviewerEvidence {\n checklistId: string; // the checklist this evidence is FOR (one subagent may appear under several)\n agentType: string;\n agentId: string;\n readDiff: boolean; // opened the materialized diff dir (or its own instructions file)\n readDoc: boolean; // opened its checklist's guidance doc\n /**\n * Named its own verdict file — `.webpieces/pr-review/<featureSlug>/review-<id>.json` — in a tool input.\n *\n * Recorded, not just consumed, because it is the field that answers \"who wrote this verdict?\" for an\n * auditor reading provenance.json later. It is also a CREDIT channel: see\n * {@link SubagentProvenanceService.creditedByWhatItTouched}.\n */\n wroteVerdict: boolean;\n toolCallCount: number;\n offRepoSearches: number; // tool calls that reached into node_modules — the archaeology signal\n /**\n * Distinct `message.model` values OBSERVED in the transcript, in first-seen order.\n *\n * The model that actually ran, never the one that was configured — and never anything the reviewer\n * says about itself. The reviewer agent's `.claude/agents/<name>.md` may declare `model:`, but that is the\n * REQUESTED value and it can silently disagree with what served the request: a repo was measured\n * running opus for a reviewer whose agent file said `model: sonnet`. Asking the model instead would\n * be worse — a model is unreliable about its own identity, naming a family instead of a version or\n * repeating whatever the system prompt implied, so a self-reported field is usually right and\n * silently wrong, which is the worst kind of telemetry because it looks authoritative.\n * `message.model` is written by the harness, so this inherits the anti-forgery property the rest of\n * this class documents.\n *\n * An ARRAY, not a string: one reviewer run can span more than one model (a fallback after a refusal,\n * a mid-run config change). Collapsing to one value forces a lossy choice at read time; recording\n * what happened lets the renderer decide.\n *\n * Token counts and cost are deliberately NOT here. Prices change, vary by platform and differ under\n * intro pricing, so a rate table in this package would rot silently — and the question this answers\n * is \"which model reviewed this?\", not \"what did it cost?\".\n */\n models: string[];\n // Absolute path of the transcript these counters were read out of, '' when it could not be resolved.\n // Carried out rather than recomputed because a reviewer subagent cannot learn its own transcript path\n // (the environment exposes the PARENT session id and no agent id), so this is the only place it is\n // known — see ReviewProvenanceService, which records it as the audit link for the verdict.\n transcriptPath: string;\n\n // eslint-disable-next-line @typescript-eslint/max-params\n constructor(checklistId: string, agentType: string, agentId: string, readDiff = false, readDoc = false, toolCallCount = 0, offRepoSearches = 0, transcriptPath = '', models: string[] = [], wroteVerdict = false) {\n this.checklistId = checklistId;\n this.agentType = agentType;\n this.agentId = agentId;\n this.readDiff = readDiff;\n this.readDoc = readDoc;\n this.wroteVerdict = wroteVerdict;\n this.toolCallCount = toolCallCount;\n this.offRepoSearches = offRepoSearches;\n this.transcriptPath = transcriptPath;\n this.models = models;\n }\n}\n\n/**\n * One pass over one transcript: the tool inputs AND the models that served it. Data-only.\n *\n * They are gathered together rather than in two passes because they come from the SAME records — the\n * inputs from `message.content[].input`, the model from `message.model` one level up — and a transcript\n * is the largest file this service opens. Two reads of it to answer two questions about the same lines\n * would be the duplicate-work trap the diff materializer documents at length.\n */\nexport class TranscriptScan {\n inputs: string[]; // every tool_use input, JSON-stringified\n models: string[]; // distinct message.model values, first-seen order\n\n constructor(inputs: string[] = [], models: string[] = []) {\n this.inputs = inputs;\n this.models = models;\n }\n}\n\n/**\n * WHERE this branch's review materials live. Data-only.\n *\n * One class for BOTH passes — crediting (`verifyReviewers`) and evidence (`evidenceFor`) — because they\n * ask their questions of the same paths. `diffDir` is the per-branch materialization\n * (`.webpieces/pr-review/<featureSlug>/diff`), which is what makes it usable as PROOF of which branch a\n * reviewer looked at: the path names the branch, it is absolute, and stage ② recreates it per run.\n */\nexport class ReviewerContext {\n branch: string;\n diffDir: string; // '' when nothing was materialized\n docPaths: Record<string, string>; // checklist id → its checklist doc path ('' when none)\n /**\n * checklist id → the absolute path of the verdict file THAT checklist must write on THIS branch\n * (`.webpieces/pr-review/<featureSlug>/review-<id>.json`). '' when unknown.\n *\n * The strongest attribution signal available, and stronger than `diffDir`: the path is\n * worktree-absolute (naming the tree), per-branch (naming the featureSlug) AND per-checklist (naming\n * the id), so a transcript containing it can only belong to a reviewer that authored that checklist's\n * verdict for that branch. `diffDir` proves the branch but not the checklist.\n */\n verdictPaths: Record<string, string>;\n\n // eslint-disable-next-line @typescript-eslint/max-params\n constructor(branch: string, diffDir = '', docPaths: Record<string, string> = {}, verdictPaths: Record<string, string> = {}) {\n this.branch = branch;\n this.diffDir = diffDir;\n this.docPaths = docPaths;\n this.verdictPaths = verdictPaths;\n }\n}\n\n/**\n * One checklist that must be credited to a reviewer run, plus the agent type the BRIEFING named. Data-only.\n *\n * The two used to be one string — a checklist's id WAS its agent type — and provenance keyed everything by\n * it. Now every checklist is reviewed by the same repo-wide agent type, so the id and the type are\n * separate facts.\n *\n * `agentType` is NOT a provenance input: nothing here matches a run on it (issue #964, see\n * {@link SubagentProvenanceService.isReviewerRun}). It is carried because it is what the BRIEFING told\n * the agent to spawn and what {@link ReviewerEvidence} reports, which are both worth recording even\n * though neither is worth gating on.\n */\nexport class ExpectedReviewer {\n checklistId: string;\n agentType: string;\n\n constructor(checklistId: string, agentType: string) {\n this.checklistId = checklistId;\n this.agentType = agentType;\n }\n}\n\n/**\n * Verifies — from the Claude Code harness's OWN artifacts, never from anything the model asserts — that\n * a real SUBAGENT actually ran on the current branch and did this checklist's work. Used to enforce that\n * every checklist was reviewed by an INDEPENDENT reviewer, rather than by the coding agent\n * self-certifying.\n *\n * The harness writes, beside each subagent transcript:\n * <config>/projects/<cwd-slug>/<sessionId>/subagents/agent-<id>.meta.json → { agentType, spawnDepth, … }\n * <config>/projects/<cwd-slug>/<sessionId>/subagents/agent-<id>.jsonl → record 0 { isSidechain, gitBranch, … }\n * `spawnDepth`/`isSidechain` are written by Claude Code, not by the model, and they are what carries the\n * anti-self-certification property. `agentType` is written there too and is deliberately NOT checked —\n * see {@link SubagentProvenanceService.isReviewerRun}. `<config>` is `$CLAUDE_CONFIG_DIR` when set, else\n * `~/.claude`; see {@link ClaudeConfigDir}, and never re-derive it here. Dirs are found by walking\n * every session, so the cwd-slug never has to be derived/guessed.\n *\n * IMPORTANT — this is NOT tamper-proof. A determined agent can `cat >` a fake agent-*.meta.json. This\n * raises the bar from \"trust the model's word\" to \"deliberate, auditable forgery outside the repo\"; it\n * is not cryptographic. Say so wherever reviewer provenance is documented.\n *\n * `@injectable(bindingScopeValues.Singleton)` so it is drawn in the DI design and injected by type.\n */\n@injectable(bindingScopeValues.Singleton)\nexport class SubagentProvenanceService {\n // cwd → the branch it is PINNED to ('' when it is not a linked worktree, or is unresolvable).\n // See branchOfCwd for why it is cached and pinnedBranch for what \"pinned\" buys.\n private readonly branchByCwd = new Map<string, string>();\n\n // transcript path → its one scan. The credit pass and the evidence pass ask different questions of\n // the same (largest) files this service opens, and the credit pass may look at candidates the\n // evidence pass then re-visits. See scanTranscript for why one pass answers both.\n private readonly scanByPath = new Map<string, TranscriptScan>();\n\n // Verify EVERY expected checklist was reviewed by a reviewer subagent that ran on `context.branch` — the\n // coding agent may not self-certify. SKIPPED (pass) without a session id.\n //\n // ONE run may cover SEVERAL checklists: `reviewerAgents` is a required config field and is a CAP, so\n // grouping is always something the repo asked for. A run is still only credited when it is a real\n // subagent of the right type that ran on this branch.\n //\n // (A removed `sharedRuns` flag once demanded a distinct run per checklist; a cap is a MAXIMUM, so it never could.)\n // Either way a run that NAMED (or wp-write-review-submitted) this checklist's verdict is preferred over one that merely ran on the\n // branch, so each checklist is credited to the reviewer that actually wrote it whenever that is knowable.\n //\n // Scoped by BRANCH across ALL sessions (not the current session): once a reviewer ran on this branch in\n // any session, a later re-push in a NEW session still finds it, so the review is NOT forced to re-run.\n // That is what keeps \"review once per branch\" true across sessions. A PR opened outside the gated flow\n // still has no review-<id>.json, so wp-finish forces the review regardless of provenance.\n verifyReviewers(expected: readonly ExpectedReviewer[], context: ReviewerContext): ProvenanceResult {\n if (expected.length === 0) return new ProvenanceResult(PROVENANCE_OK, 'no reviewer subagents required', {}, []);\n if (!this.inClaudeSession()) return this.skipped('reviewer subagents');\n const dirs = this.allSubagentsDirs();\n const missing: string[] = [];\n const usedAgentIds = new Set<string>();\n const credited: Record<string, string> = {};\n for (const want of expected) {\n const agentId = this.findMatchingAgentId(dirs, want, context, new Set<string>());\n if (agentId === '') missing.push(want.checklistId);\n else {\n usedAgentIds.add(agentId);\n credited[want.checklistId] = agentId;\n }\n }\n const runs = new Set(Object.values(credited)).size;\n return missing.length === 0\n ? new ProvenanceResult(PROVENANCE_OK,\n `verified ${expected.length} checklist(s) were reviewed by ${runs} reviewer subagent run(s)`, credited, [])\n : new ProvenanceResult(PROVENANCE_MISSING,\n `${missing.length} checklist(s) could not be attributed to a reviewer subagent on this branch: ${missing.join(', ')}`,\n credited, missing);\n }\n\n /**\n * What each credited reviewer actually READ, from its own transcript.\n *\n * `verifyReviewers` proves a reviewer of the right type RAN. It cannot tell a reviewer that read the diff\n * and thought about it from one that wrote a verdict having opened nothing. This closes that gap — and\n * the motivating case is real: one reviewer spent 14 of 26 tool calls grepping `node_modules` because\n * nothing had told it where anything was, which `offRepoSearches` now makes visible.\n *\n * WARNING-ONLY by default, for three reasons, and `requireDiffEvidence` must stay opt-in until at least\n * one repo has watched it:\n * 1. The transcript layout is undocumented Claude Code internals. A format change would wedge every\n * consumer's PR with no self-service recovery — `sidechainOnBranch` is already lenient for exactly\n * this reason, and blocking on a richer read of the same files would be less safe, not more.\n * 2. A reviewer can legitimately receive the diff another way (inlined into its prompt, say).\n * 3. verifyReviewers is the INTEGRITY signal and rightly blocks; this is a QUALITY signal. Conflating\n * them would let a transcript-parsing quirk refuse a PR that a real reviewer really did review.\n *\n * Returns [] outside a Claude Code session, matching verifyReviewers's SKIP behavior.\n */\n evidenceFor(context: ReviewerContext, expected: readonly ExpectedReviewer[], agentIds: Record<string, string>): ReviewerEvidence[] {\n if (!this.inClaudeSession()) return [];\n const dirs = this.allSubagentsDirs();\n const out: ReviewerEvidence[] = [];\n for (const want of expected) {\n const agentId = agentIds[want.checklistId];\n if (agentId === undefined) continue;\n const jsonl = this.transcriptPath(dirs, agentId);\n if (jsonl === '') {\n out.push(new ReviewerEvidence(want.checklistId, want.agentType, agentId));\n continue;\n }\n out.push(this.evidenceFromTranscript(want, agentId, jsonl, context));\n }\n return out;\n }\n\n // eslint-disable-next-line @typescript-eslint/max-params\n private evidenceFromTranscript(want: ExpectedReviewer, agentId: string, jsonl: string, context: ReviewerContext): ReviewerEvidence {\n const scan = this.scanTranscript(jsonl);\n const inputs = scan.inputs;\n const docPath = context.docPaths[want.checklistId] ?? '';\n const verdictPath = context.verdictPaths[want.checklistId] ?? '';\n return new ReviewerEvidence(\n want.checklistId, want.agentType, agentId, this.readDiffDir(scan, context),\n docPath !== '' && this.mentions(inputs, docPath),\n inputs.length,\n inputs.filter((i: string): boolean => i.includes('node_modules')).length,\n jsonl,\n scan.models,\n this.submittedVerdict(inputs, want.checklistId, verdictPath),\n );\n }\n\n // The instructions file counts as \"read the diff\": it lives in the same per-branch dir, it is what\n // the reviewer is told to open first, and it inlines the diff paths. A reviewer that opened it and\n // then its own diff files is the intended path; treating only the diff dir as proof would flag it.\n private readDiffDir(scan: TranscriptScan, context: ReviewerContext): boolean {\n return context.diffDir !== '' && this.mentions(scan.inputs, context.diffDir);\n }\n\n /**\n * Record this line's `message.model`, deduped, in first-seen order.\n *\n * `<synthetic>` records are SKIPPED. The harness writes them for messages no model produced (tool\n * results, injected notices); counting one would put a non-model in a field whose entire purpose is\n * \"which model reviewed this\", and it would show up on every single reviewer.\n */\n // webpieces-disable no-any-unknown -- opaque transcript record, only `model` is read and it is type-guarded below\n private collectModel(message: Record<string, unknown>, models: string[]): void {\n const model = message['model'];\n if (typeof model !== 'string' || model === '' || model === '<synthetic>') return;\n if (!models.includes(model)) models.push(model);\n }\n\n // The absolute path of agent-<id>.jsonl across all session dirs, or '' if it is not there.\n private transcriptPath(dirs: readonly string[], agentId: string): string {\n for (const dir of dirs) {\n const candidate = path.join(dir, `agent-${agentId}.jsonl`);\n if (fs.existsSync(candidate)) return candidate;\n }\n return '';\n }\n\n /**\n * ONE pass over the transcript for both answers (see {@link TranscriptScan}), CACHED per path.\n *\n * Cached because two passes now ask questions of the same file: crediting (does it name this branch's\n * verdict/diff?) and evidence (what did it read, which model served it?). Without the cache the credit\n * pass would re-read every candidate the evidence pass then re-opens — on the largest files this\n * service touches, on the path that opens a PR.\n *\n * Tool inputs are JSON-stringified rather than walked field-by-field because the shape differs per\n * tool (Read takes file_path, Bash takes command, Grep takes path) and a substring test over the\n * serialized input is both simpler and robust to a tool we have not seen.\n *\n * Best-effort, like everything else that parses this file: a format change must never wedge the\n * gate, so an unreadable transcript yields empty rather than throwing. That matters more for the\n * models than for the counters — this is quality telemetry, not an integrity check, and a missing\n * `model` field must not be able to block a PR.\n */\n private scanTranscript(jsonl: string): TranscriptScan {\n const cached = this.scanByPath.get(jsonl);\n if (cached !== undefined) return cached;\n const scan = this.readTranscript(jsonl);\n this.scanByPath.set(jsonl, scan);\n return scan;\n }\n\n private readTranscript(jsonl: string): TranscriptScan {\n const scan = new TranscriptScan();\n // webpieces-disable no-unmanaged-exceptions -- chokepoint: an unreadable transcript yields no evidence, never a crash\n // eslint-disable-next-line @webpieces/no-unmanaged-exceptions\n try {\n for (const line of fs.readFileSync(jsonl, 'utf8').split('\\n')) {\n if (line.trim() === '') continue;\n const rec = this.parseLine(line);\n const message = rec?.['message'];\n if (typeof message !== 'object' || message === null) continue;\n // webpieces-disable no-any-unknown -- opaque transcript record, narrowed by the guard above\n const msg = message as Record<string, unknown>;\n this.collectModel(msg, scan.models);\n const content = msg['content'];\n if (!Array.isArray(content)) continue;\n for (const block of content) {\n // webpieces-disable no-any-unknown -- opaque content block, only `type`/`input` are read\n const b = block as Record<string, unknown>;\n if (b['type'] === 'tool_use') scan.inputs.push(JSON.stringify(b['input'] ?? {}));\n }\n }\n } catch (err: unknown) {\n const error = toError(err);\n void error;\n }\n return scan;\n }\n\n private mentions(inputs: readonly string[], needle: string): boolean {\n return inputs.some((i: string): boolean => i.includes(needle));\n }\n\n // Are we running under Claude Code at all? (CI / plain terminal → provenance is unverifiable → SKIP.)\n private inClaudeSession(): boolean {\n return (process.env['CLAUDE_CODE_SESSION_ID'] ?? '').trim() !== '';\n }\n\n private skipped(what: string): ProvenanceResult {\n return new ProvenanceResult(PROVENANCE_SKIPPED,\n `CLAUDE_CODE_SESSION_ID not set — no Claude transcripts to verify ${what} against (Codex / terminal / CI); each verdict's wp-write-review provenance is still enforced.`,\n {}, []);\n }\n\n // The agentId of a subagent run on `branch`, searched across ALL sessions' subagent dirs\n // (branch-scoped, so a run from a prior session still counts). '' if none. `exclude` skips agentIds\n // already credited to another checklist so one run can't satisfy two.\n //\n // The run is NOT matched on its agent type — see isReviewerRun for why that check was removed — so\n // several runs match and the one that NAMED this checklist's verdict file wins; the first\n // branch-matching run is the fallback, as before.\n // eslint-disable-next-line @typescript-eslint/max-params\n private findMatchingAgentId(dirs: readonly string[], want: ExpectedReviewer, context: ReviewerContext, exclude: ReadonlySet<string>): string {\n let fallback = '';\n for (const dir of dirs) {\n for (const metaFile of this.metaFiles(dir)) {\n const agentId = this.agentIdOf(metaFile);\n if (exclude.has(agentId) || !this.isReviewerRun(dir, metaFile)) continue;\n if (!this.sidechainOnBranch(dir, agentId, want.checklistId, context)) continue;\n if (this.namedVerdict(dir, agentId, want.checklistId, context)) return agentId;\n if (fallback === '') fallback = agentId;\n }\n }\n return fallback;\n }\n\n /**\n * A harness-written meta for a REAL SUBAGENT — `spawnDepth >= 1`, and nothing about its NAME.\n *\n * The agent TYPE used to be compared against the configured reviewer agent, and that check is\n * gone (issue #964). It proved nothing: `agentType` is a label on a prompt, and it does not show\n * the agent read the checklist, opened the diff, or looked at the right branch. The gates that DO\n * show those are untouched — `spawnDepth >= 1` plus `isSidechain === true` (see\n * {@link sidechainOnBranch}) are harness-written, so the main loop still cannot self-certify;\n * {@link creditedByWhatItTouched} proves the branch and the actual work; `requireDiffEvidence`\n * proves the diff was opened.\n *\n * It was also the ONLY gate with an unfixable failure mode. Claude Code snapshots agent\n * definitions per session and the refresh does not reach an already-running subagent, so a repo\n * that renames its reviewer agent mid-session leaves that subagent's registry offering only the\n * OLD names: the spawn is rejected, the agent falls back to `general-purpose`, does the real\n * review, writes every verdict — and is refused as unattributable, with no cwd, branch or respawn\n * able to change it. Measured: six checklists, six verdict files on disk, PR blocked.\n *\n * Accepted trade-off: without the name check the implementer's own subagent could in principle be\n * credited, since it touches the diff dir while running the gate. That is deliberate. The rule is\n * \"if the verdict file is there, a subagent wrote it\", and this gate's job is to catch \"no\n * subagent ran at all\" — not to adjudicate which subagent it was.\n */\n private isReviewerRun(dir: string, metaFile: string): boolean {\n const meta = this.readJson(path.join(dir, metaFile));\n if (!meta) return false;\n const spawnDepth = meta['spawnDepth'];\n return typeof spawnDepth === 'number' && spawnDepth >= 1;\n }\n\n // Did this run's transcript name the checklist's own verdict path?\n // eslint-disable-next-line @typescript-eslint/max-params\n private namedVerdict(dir: string, agentId: string, checklistId: string, context: ReviewerContext): boolean {\n const jsonl = path.join(dir, `agent-${agentId}.jsonl`);\n return fs.existsSync(jsonl) && this.submittedVerdict(this.scanTranscript(jsonl).inputs, checklistId, context.verdictPaths[checklistId] ?? '');\n }\n\n // Named its verdict file, or submitted it via wp-write-review (#863). Proves authorship, never branch.\n private submittedVerdict(inputs: readonly string[], checklistId: string, verdictPath: string): boolean {\n if (verdictPath !== '' && this.mentions(inputs, verdictPath)) return true;\n return inputs.some((i: string): boolean => reviewIdentityStamps.invokedChecklists(i).includes(checklistId));\n }\n\n /**\n * Every `<config>/projects/&#42;/<session>/subagents` dir that exists — matching by the recorded\n * gitBranch (not by session id) is what makes provenance survive across sessions.\n *\n * `<config>` comes from {@link ClaudeConfigDir.projectsRoots}, which is BOTH the configured\n * `$CLAUDE_CONFIG_DIR` tree and `~/.claude`. This used to be a hardcoded `~/.claude`, and on a\n * machine with a relocated config dir that found nothing at all — so every PR was refused with a\n * message about the reviewers' cwd, which is not what was wrong and which no agent could act on.\n */\n private allSubagentsDirs(): string[] {\n const out: string[] = [];\n for (const projects of claudeConfigDir.projectsRoots()) {\n for (const proj of this.readDir(projects)) {\n const projDir = path.join(projects, proj);\n for (const session of this.readDir(projDir)) {\n const candidate = path.join(projDir, session, 'subagents');\n if (fs.existsSync(candidate)) out.push(candidate);\n }\n }\n }\n return out;\n }\n\n private metaFiles(dir: string): string[] {\n return this.readDir(dir).filter((f: string): boolean => f.endsWith('.meta.json'));\n }\n\n // agent-<id>.meta.json → <id>\n private agentIdOf(metaFile: string): string {\n return metaFile.replace(/^agent-/, '').replace(/\\.meta\\.json$/, '');\n }\n\n /**\n * Cross-check the sibling transcript's record 0: isSidechain true (a real subagent, not the main\n * loop) and the same branch. Lenient on branch drift (a leftover …wpN suffix from a mid-flight\n * branch rename) and on a missing jsonl (meta already matched — accept, best-effort).\n *\n * WHEN `gitBranch` DISAGREES, A PINNED `cwd` DECIDES. Record 0 carries both fields, and the harness\n * can write a `gitBranch` that CONTRADICTS the record's own `cwd`: a reviewer subagent spawned into\n * a worktree on `dean/one-2406-…` was stamped `worktree-agent-a54887200e40eb956` — an unrelated,\n * still-live worktree's scaffold branch — deterministically, on four consecutive attempts, blocking\n * a PR whose required reviewer genuinely ran and genuinely passed. `stripWp` cannot bridge that, so\n * the reviewer was never credited and `wp-finish-upsert-pr` refused a legitimately-reviewed PR with\n * no in-flow recovery. A sweep of 961 record-0s on one machine found the mis-stamp is the MAJORITY\n * case among subagents in dedicated worktrees, so trusting `gitBranch` alone can never be correct.\n *\n * ─── Why ONLY a linked worktree, and never the primary clone ──────────────────────────────────\n * \"Ask git what branch the cwd is on\" is correct only when that cwd CANNOT have moved since the\n * reviewer ran. A LINKED WORKTREE is 1:1 with the agent that owns it and nothing re-checks it out;\n * the PRIMARY CLONE gets checked out constantly. Falling back on a primary-clone cwd would credit a\n * STALE reviewer, and by construction rather than by accident:\n *\n * 1. a reviewer runs in the primary clone while it is on branch A\n * 2. the clone is later checked out to branch B\n * 3. `wp-finish-upsert-pr` runs on B — `gitBranch` (stamped A) mismatches\n * 4. `git -C <clone>` now answers B, because the CLONE moved → the reviewer is credited for B\n *\n * It reviewed A. Every past reviewer run in that clone would be credited for whatever branch is\n * checked out at finish time — which in a repo with a required reviewer on every PR is not an\n * exotic sequence, it is the normal one. So the fallback is gated on `dotWebpieces.isLinkedWorktree`\n * (git's own `--git-dir != --git-common-dir` test, reused rather than re-derived), and a primary\n * clone falls through to a refusal exactly as it does today.\n *\n * That gate keeps the anti-forgery property intact: `cwd` is harness-written in the same record by\n * the same writer as `gitBranch`, so it carries the same weight — and inside a pinned worktree it is\n * the field that is CORRECT. There is deliberately no config flag and no second comparison mode:\n * ONE rule, with `gitBranch` only ever a cheap way to skip the subprocess when it already agrees.\n *\n * An UNRESOLVABLE cwd does not credit either. A reaped worktree, a deleted directory, a non-repo\n * path or a detached HEAD yields '' and falls through to a refusal. Leniency here is bounded by\n * \"git can still prove it\", never by \"we could not check, so assume yes\".\n *\n * ─── Why neither field can settle it from a PRIMARY CLONE, and what does ──────────────────────\n * Both fields above are stamped from the SPAWNING session's cwd — the Agent tool has no cwd\n * parameter, so a subagent inherits its parent's. A session rooted in the primary clone that spawns\n * a reviewer for a WORKTREE branch therefore produces `gitBranch` = the clone's branch (mismatch)\n * and `cwd` = the clone (gated off, correctly) — and NO respawn can change either stamp. That is not\n * an exotic setup: it is what the flow instructs the moment a worker agent dies mid-flow and the\n * top-level session has to take over, and it deadlocked a branch whose seven reviewers had all run.\n *\n * So the third channel is not a loosening of the cwd rule — it is a DIFFERENT question, asked of\n * evidence the reviewer cannot inherit and cannot fake by accident: {@link creditedByWhatItTouched}.\n */\n // eslint-disable-next-line @typescript-eslint/max-params\n private sidechainOnBranch(dir: string, agentId: string, checklistId: string, context: ReviewerContext): boolean {\n const jsonl = path.join(dir, `agent-${agentId}.jsonl`);\n if (!fs.existsSync(jsonl)) return true;\n const first = this.firstNonEmptyLine(jsonl);\n if (first === '') return true;\n const rec = this.parseLine(first);\n if (!rec) return true;\n if (rec['isSidechain'] !== true) return false;\n const gitBranch = rec['gitBranch'];\n // Not recorded at all → accept, as before: nothing to contradict and nothing to verify against.\n if (typeof gitBranch !== 'string' || gitBranch === '') return true;\n const want = this.stripWp(context.branch);\n if (this.stripWp(gitBranch) === want) return true;\n if (want !== '' && this.stripWp(this.branchOfCwd(rec['cwd'])) === want) return true;\n return this.creditedByWhatItTouched(jsonl, checklistId, context);\n }\n\n /**\n * Credit a reviewer for WHAT IT TOUCHED when neither harness-stamped field can settle it.\n *\n * Both paths compared here are ABSOLUTE and BRANCH-SPECIFIC — they live under\n * `<worktree>/.webpieces/pr-review/<featureSlug>/`, so the string names the tree AND the branch. A\n * reviewer that worked on a different branch cannot have them in its transcript, and a reviewer of\n * this branch that ran from a mis-stamped cwd cannot avoid having them. That is the property\n * `gitBranch` lacks — this file's own sweep of 961 record-0s found the mis-stamp is the MAJORITY\n * case among subagents in dedicated worktrees.\n *\n * Two channels, either sufficient:\n * 1. it WROTE this checklist's verdict file — proves branch AND checklist, and is the act the whole\n * gate is trying to attribute. Matched as a substring of any tool input, so a Write, an Edit and\n * a `cat > <path>` heredoc all count; the point is that the path was named, not which tool named it.\n * 2. it READ this branch's materialized diff dir — proves the branch. Kept as a second channel\n * because a reviewer whose verdict was relayed by its parent still demonstrably reviewed this\n * branch, and refusing that would re-open a narrower version of the same unrecoverable deadlock.\n *\n * Independence is NOT weakened by either: `isSidechain === true` and `spawnDepth >= 1` are checked\n * before we get here (so the main loop's own transcript can never qualify), and `verifyReviewers`\n * excludes an agentId already credited to another checklist. It remains non-tamper-proof in exactly\n * the way the class doc already states — forging this now means forging a transcript rather than a\n * meta.json, which is the same bar, not a lower one.\n */\n private creditedByWhatItTouched(jsonl: string, checklistId: string, context: ReviewerContext): boolean {\n const scan = this.scanTranscript(jsonl);\n const verdictPath = context.verdictPaths[checklistId] ?? '';\n if (verdictPath !== '' && this.mentions(scan.inputs, verdictPath)) return true;\n return this.readDiffDir(scan, context);\n }\n\n /**\n * The branch record-0's own `cwd` is PINNED to, '' when that cannot be established or is not pinned.\n *\n * Cached per cwd because `findMatchingAgentId` walks every subagent of every session on the machine\n * and several of them share a worktree — one `git` process per RECORD would put dozens of spawns on\n * the path that opens a PR.\n */\n // webpieces-disable no-any-unknown -- one opaque record field, type-guarded on the next line\n private branchOfCwd(cwd: unknown): string {\n if (typeof cwd !== 'string' || cwd === '') return '';\n const cached = this.branchByCwd.get(cwd);\n if (cached !== undefined) return cached;\n const resolved = this.pinnedBranch(cwd);\n this.branchByCwd.set(cwd, resolved);\n return resolved;\n }\n\n /**\n * The branch of `cwd` when — and only when — `cwd` is a LINKED WORKTREE. '' otherwise.\n *\n * '' for the primary clone (it moves; see sidechainOnBranch for the false-accept that closes), for a\n * reaped or deleted directory, for a non-repo path, when git is unavailable, and for a detached HEAD,\n * which `--abbrev-ref` prints as the literal `HEAD` and which names no branch.\n */\n private pinnedBranch(cwd: string): string {\n if (!fs.existsSync(cwd)) return '';\n if (!dotWebpieces.isLinkedWorktree(cwd)) return '';\n const result = spawnSync('git', ['-C', cwd, 'rev-parse', '--abbrev-ref', 'HEAD'], { encoding: 'utf8' });\n if (result.status !== 0) return '';\n const printed = (result.stdout ?? '').trim();\n return printed === 'HEAD' ? '' : printed;\n }\n\n private stripWp(branch: string): string {\n return branch.replace(/-?wp\\d+$/i, '');\n }\n\n private readDir(dir: string): string[] {\n // webpieces-disable no-unmanaged-exceptions -- chokepoint: an unreadable dir yields [] (best-effort provenance)\n // eslint-disable-next-line @webpieces/no-unmanaged-exceptions\n try {\n return fs.readdirSync(dir);\n } catch (err: unknown) {\n const error = toError(err);\n void error;\n return [];\n }\n }\n\n private firstNonEmptyLine(filePath: string): string {\n // webpieces-disable no-unmanaged-exceptions -- chokepoint: unreadable transcript → '' (best-effort)\n // eslint-disable-next-line @webpieces/no-unmanaged-exceptions\n try {\n for (const line of fs.readFileSync(filePath, 'utf8').split('\\n')) {\n if (line.trim() !== '') return line;\n }\n return '';\n } catch (err: unknown) {\n const error = toError(err);\n void error;\n return '';\n }\n }\n\n // webpieces-disable no-any-unknown -- opaque parsed JSON object, keys read by the caller\n private readJson(filePath: string): Record<string, unknown> | null {\n // webpieces-disable no-unmanaged-exceptions -- chokepoint: malformed meta.json → null (skipped)\n // eslint-disable-next-line @webpieces/no-unmanaged-exceptions\n try {\n // webpieces-disable no-any-unknown -- parsed JSON is opaque until narrowed by the caller\n return JSON.parse(fs.readFileSync(filePath, 'utf8')) as Record<string, unknown>;\n } catch (err: unknown) {\n const error = toError(err);\n void error;\n return null;\n }\n }\n\n // webpieces-disable no-any-unknown -- one opaque JSONL record, keys read by the caller\n private parseLine(line: string): Record<string, unknown> | null {\n // webpieces-disable no-unmanaged-exceptions -- chokepoint: malformed JSONL record → null\n // eslint-disable-next-line @webpieces/no-unmanaged-exceptions\n try {\n // webpieces-disable no-any-unknown -- parsed JSON is opaque until narrowed by the caller\n return JSON.parse(line) as Record<string, unknown>;\n } catch (err: unknown) {\n const error = toError(err);\n void error;\n return null;\n }\n }\n}\n"]}
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Pure renderer for ONE reviewer's verdict schema and the command that submits it. Reached only through
3
+ * ReviewJsonService.renderVerdictSchema / submitCommand — the single renderer every printed copy comes from.
4
+ */
5
+ export declare class VerdictSchemaRenderer {
6
+ /**
7
+ * THE command that submits one checklist's verdict (issue #863). The only route: `wp-write-review`
8
+ * validates the verdict and records WHO submitted it, and `wp-finish-upsert-pr` rejects a verdict file
9
+ * that did not come through it — so every message that tells anyone how a verdict gets written names
10
+ * this, and none of them names the file as something to write.
11
+ */
12
+ submitCommand(id: string): string;
13
+ render(id: string, indent: string): string;
14
+ }
@@ -0,0 +1,44 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.VerdictSchemaRenderer = void 0;
4
+ const review_json_data_1 = require("./review-json-data");
5
+ const review_identity_stamp_1 = require("./review-identity-stamp");
6
+ /**
7
+ * Pure renderer for ONE reviewer's verdict schema and the command that submits it. Reached only through
8
+ * ReviewJsonService.renderVerdictSchema / submitCommand — the single renderer every printed copy comes from.
9
+ */
10
+ class VerdictSchemaRenderer {
11
+ /**
12
+ * THE command that submits one checklist's verdict (issue #863). The only route: `wp-write-review`
13
+ * validates the verdict and records WHO submitted it, and `wp-finish-upsert-pr` rejects a verdict file
14
+ * that did not come through it — so every message that tells anyone how a verdict gets written names
15
+ * this, and none of them names the file as something to write.
16
+ */
17
+ submitCommand(id) {
18
+ return `pnpm ${review_identity_stamp_1.WRITE_REVIEW_BIN} --checklist ${id} <<'EOF' … EOF`;
19
+ }
20
+ render(id, indent) {
21
+ return [
22
+ `${indent}{ "id": "${id}", "status": "${review_json_data_1.VERDICT_GREEN} | ${review_json_data_1.VERDICT_YELLOW} | ${review_json_data_1.VERDICT_RED}", ` +
23
+ `"agent": "claude | codex | unknown", "model": "opus | sonnet | actual readable model name | unknown", ` +
24
+ `"output": "what you checked / found" }`,
25
+ `${indent}Identity fields are REQUIRED non-empty strings. Use your own harness and model, never the parent's.`,
26
+ `${indent}Use the literal "unknown" when unavailable; never guess. These are self-reported, not provenance.`,
27
+ `${indent} ${review_json_data_1.VERDICT_GREEN} → passes, nothing to flag`,
28
+ `${indent} ${review_json_data_1.VERDICT_YELLOW} → passes WITH CONCERNS; nothing is blocked and the concern is published on the PR`,
29
+ `${indent} ${review_json_data_1.VERDICT_RED} → REFUSES the PR; your "output" is printed verbatim`,
30
+ `${indent}Prefer "${review_json_data_1.VERDICT_YELLOW}" over red when the change is acceptable but worth a human's attention —`,
31
+ `${indent}a red a human then authorizes reads as a deliberately-accepted defect, a yellow reads as a note.`,
32
+ // The one sentence that stops a reviewer doing what a reviewer did once: telling the human to run
33
+ // a command, on its own authority, to get past its own finding.
34
+ `${indent}THERE IS NO "override" FIELD HERE, and you NEVER write one. A reviewer does not authorize`,
35
+ `${indent}shipping past its own finding: if this needs a human's decision, SAY SO in "output" and STOP.`,
36
+ `${indent}The coordinating agent is the one with the human, and records that decision in override-${id}.json.`,
37
+ `${indent}SUBMIT it — the reviewer itself, never the coordinating agent — with the JSON on stdin:`,
38
+ `${indent} ${this.submitCommand(id)}`,
39
+ `${indent}(or --file <path> naming a scratch file). A review-${id}.json written any other way is REJECTED.`,
40
+ ].join('\n');
41
+ }
42
+ }
43
+ exports.VerdictSchemaRenderer = VerdictSchemaRenderer;
44
+ //# sourceMappingURL=verdict-schema-renderer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"verdict-schema-renderer.js","sourceRoot":"","sources":["../../../../../packages/tooling/rules-config/src/verdict-schema-renderer.ts"],"names":[],"mappings":";;;AAAA,yDAAgF;AAChF,mEAA2D;AAE3D;;;GAGG;AACH,MAAa,qBAAqB;IAC9B;;;;;OAKG;IACH,aAAa,CAAC,EAAU;QACpB,OAAO,QAAQ,wCAAgB,gBAAgB,EAAE,gBAAgB,CAAC;IACtE,CAAC;IAED,MAAM,CAAC,EAAU,EAAE,MAAc;QAC7B,OAAO;YACH,GAAG,MAAM,YAAY,EAAE,iBAAiB,gCAAa,MAAM,iCAAc,MAAM,8BAAW,KAAK;gBAC/F,wGAAwG;gBACxG,wCAAwC;YACxC,GAAG,MAAM,qGAAqG;YAC9G,GAAG,MAAM,mGAAmG;YAC5G,GAAG,MAAM,KAAK,gCAAa,6BAA6B;YACxD,GAAG,MAAM,KAAK,iCAAc,oFAAoF;YAChH,GAAG,MAAM,KAAK,8BAAW,yDAAyD;YAClF,GAAG,MAAM,WAAW,iCAAc,0EAA0E;YAC5G,GAAG,MAAM,kGAAkG;YAC3G,kGAAkG;YAClG,gEAAgE;YAChE,GAAG,MAAM,2FAA2F;YACpG,GAAG,MAAM,+FAA+F;YACxG,GAAG,MAAM,2FAA2F,EAAE,QAAQ;YAC9G,GAAG,MAAM,yFAAyF;YAClG,GAAG,MAAM,KAAK,IAAI,CAAC,aAAa,CAAC,EAAE,CAAC,EAAE;YACtC,GAAG,MAAM,sDAAsD,EAAE,0CAA0C;SAC9G,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACjB,CAAC;CACJ;AAjCD,sDAiCC","sourcesContent":["import { VERDICT_GREEN, VERDICT_RED, VERDICT_YELLOW } from './review-json-data';\nimport { WRITE_REVIEW_BIN } from './review-identity-stamp';\n\n/**\n * Pure renderer for ONE reviewer's verdict schema and the command that submits it. Reached only through\n * ReviewJsonService.renderVerdictSchema / submitCommand — the single renderer every printed copy comes from.\n */\nexport class VerdictSchemaRenderer {\n /**\n * THE command that submits one checklist's verdict (issue #863). The only route: `wp-write-review`\n * validates the verdict and records WHO submitted it, and `wp-finish-upsert-pr` rejects a verdict file\n * that did not come through it — so every message that tells anyone how a verdict gets written names\n * this, and none of them names the file as something to write.\n */\n submitCommand(id: string): string {\n return `pnpm ${WRITE_REVIEW_BIN} --checklist ${id} <<'EOF' … EOF`;\n }\n\n render(id: string, indent: string): string {\n return [\n `${indent}{ \"id\": \"${id}\", \"status\": \"${VERDICT_GREEN} | ${VERDICT_YELLOW} | ${VERDICT_RED}\", ` +\n `\"agent\": \"claude | codex | unknown\", \"model\": \"opus | sonnet | actual readable model name | unknown\", ` +\n `\"output\": \"what you checked / found\" }`,\n `${indent}Identity fields are REQUIRED non-empty strings. Use your own harness and model, never the parent's.`,\n `${indent}Use the literal \"unknown\" when unavailable; never guess. These are self-reported, not provenance.`,\n `${indent} ${VERDICT_GREEN} → passes, nothing to flag`,\n `${indent} ${VERDICT_YELLOW} → passes WITH CONCERNS; nothing is blocked and the concern is published on the PR`,\n `${indent} ${VERDICT_RED} → REFUSES the PR; your \"output\" is printed verbatim`,\n `${indent}Prefer \"${VERDICT_YELLOW}\" over red when the change is acceptable but worth a human's attention —`,\n `${indent}a red a human then authorizes reads as a deliberately-accepted defect, a yellow reads as a note.`,\n // The one sentence that stops a reviewer doing what a reviewer did once: telling the human to run\n // a command, on its own authority, to get past its own finding.\n `${indent}THERE IS NO \"override\" FIELD HERE, and you NEVER write one. A reviewer does not authorize`,\n `${indent}shipping past its own finding: if this needs a human's decision, SAY SO in \"output\" and STOP.`,\n `${indent}The coordinating agent is the one with the human, and records that decision in override-${id}.json.`,\n `${indent}SUBMIT it — the reviewer itself, never the coordinating agent — with the JSON on stdin:`,\n `${indent} ${this.submitCommand(id)}`,\n `${indent}(or --file <path> naming a scratch file). A review-${id}.json written any other way is REJECTED.`,\n ].join('\\n');\n }\n}\n"]}