@webpieces/rules-config 0.4.779 → 0.4.781

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":"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 * as os from 'os';\nimport { injectable, bindingScopeValues } from 'inversify';\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, and the agent type that run must carry. 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 and a run is matched on the type but credited to the id.\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 subagent of a given `agentType` actually ran during the current session on the current branch. Used\n * to enforce that every checklist was reviewed by a `reviewerAgentName` subagent: that an INDEPENDENT\n * reviewer looked, rather than the coding agent self-certifying.\n *\n * The harness writes, beside each subagent transcript:\n * ~/.claude/projects/<cwd-slug>/<sessionId>/subagents/agent-<id>.meta.json → { agentType, spawnDepth, … }\n * ~/.claude/projects/<cwd-slug>/<sessionId>/subagents/agent-<id>.jsonl → record 0 { isSidechain, gitBranch, … }\n * `agentType`/`spawnDepth`/`isSidechain` are written by Claude Code, not by the model. We locate the dir\n * by the unique sessionId (globbing `projects/&#42;/<sessionId>/subagents`), so the cwd-slug never has to be\n * 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 // `sharedRuns` false (no `reviewerAgents` configured): each checklist needs a DISTINCT run, so one\n // reviewer may not stand in for several. `sharedRuns` true (`reviewerAgents` set): one run may cover\n // several checklists, because that grouping is exactly what the repo asked for; a run is still only\n // credited when it is a real subagent of the right type on this branch.\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, sharedRuns: boolean): 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 exclude = sharedRuns ? new Set<string>() : usedAgentIds;\n const agentId = this.findMatchingAgentId(dirs, want, context, exclude);\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 matching subagent run for `want.agentType` on `branch`, searched across ALL sessions'\n // subagent dirs (branch-scoped, so a run from a prior session still counts). '' if none. `exclude`\n // skips agentIds already credited to another checklist so one run can't satisfy two.\n //\n // Now that every checklist shares ONE agent type, several runs match, so the one that NAMED this\n // checklist's verdict file wins; the first 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, want.agentType)) 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 // A harness-written meta for a real subagent (spawnDepth >= 1) of the wanted type.\n private isReviewerRun(dir: string, metaFile: string, agentType: string): boolean {\n const meta = this.readJson(path.join(dir, metaFile));\n if (!meta || meta['agentType'] !== agentType) 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 // Every `projects/*/<session>/subagents` dir that exists — matching by the recorded gitBranch (not by\n // session id) is what makes provenance survive across sessions.\n private allSubagentsDirs(): string[] {\n const projects = path.join(os.homedir(), '.claude', 'projects');\n if (!fs.existsSync(projects)) return [];\n const out: string[] = [];\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 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 * as os from 'os';\nimport { injectable, bindingScopeValues } from 'inversify';\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, and the agent type that run must carry. 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 and a run is matched on the type but credited to the id.\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 subagent of a given `agentType` actually ran during the current session on the current branch. Used\n * to enforce that every checklist was reviewed by a subagent of the repo reviewer-agent type: that an INDEPENDENT\n * reviewer looked, rather than the coding agent self-certifying.\n *\n * The harness writes, beside each subagent transcript:\n * ~/.claude/projects/<cwd-slug>/<sessionId>/subagents/agent-<id>.meta.json → { agentType, spawnDepth, … }\n * ~/.claude/projects/<cwd-slug>/<sessionId>/subagents/agent-<id>.jsonl → record 0 { isSidechain, gitBranch, … }\n * `agentType`/`spawnDepth`/`isSidechain` are written by Claude Code, not by the model. We locate the dir\n * by the unique sessionId (globbing `projects/&#42;/<sessionId>/subagents`), so the cwd-slug never has to be\n * 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 // `sharedRuns` false (no `reviewerAgents` configured): each checklist needs a DISTINCT run, so one\n // reviewer may not stand in for several. `sharedRuns` true (`reviewerAgents` set): one run may cover\n // several checklists, because that grouping is exactly what the repo asked for; a run is still only\n // credited when it is a real subagent of the right type on this branch.\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, sharedRuns: boolean): 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 exclude = sharedRuns ? new Set<string>() : usedAgentIds;\n const agentId = this.findMatchingAgentId(dirs, want, context, exclude);\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 matching subagent run for `want.agentType` on `branch`, searched across ALL sessions'\n // subagent dirs (branch-scoped, so a run from a prior session still counts). '' if none. `exclude`\n // skips agentIds already credited to another checklist so one run can't satisfy two.\n //\n // Now that every checklist shares ONE agent type, several runs match, so the one that NAMED this\n // checklist's verdict file wins; the first 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, want.agentType)) 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 // A harness-written meta for a real subagent (spawnDepth >= 1) of the wanted type.\n private isReviewerRun(dir: string, metaFile: string, agentType: string): boolean {\n const meta = this.readJson(path.join(dir, metaFile));\n if (!meta || meta['agentType'] !== agentType) 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 // Every `projects/*/<session>/subagents` dir that exists — matching by the recorded gitBranch (not by\n // session id) is what makes provenance survive across sessions.\n private allSubagentsDirs(): string[] {\n const projects = path.join(os.homedir(), '.claude', 'projects');\n if (!fs.existsSync(projects)) return [];\n const out: string[] = [];\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 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"]}
@@ -295,7 +295,6 @@ function prGateExample() {
295
295
  ` "gates": [\n` +
296
296
  ` { "name": "API Changed", "patterns": ["libraries/apis/**", "**/*Api.ts"], "warningColor": "yellow" }\n` +
297
297
  ` ],\n` +
298
- ` "reviewerAgentName": "webpieces-reviewer",\n` +
299
298
  ` "reviewerAgents": 1, // OPTIONAL — the most reviewer subagents per round; omit for one per checklist\n` +
300
299
  ` "checklists": [ // OPTIONAL — per-area review, each against its own doc\n` +
301
300
  ` { "id": "db-migrations", "doc": ".claude/review/db-migrations.md", "patterns": ["**/*.sql"], "required": true }\n` +
@@ -1 +1 @@
1
- {"version":3,"file":"validate-config.js","sourceRoot":"","sources":["../../../../../packages/tooling/rules-config/src/validate-config.ts"],"names":[],"mappings":"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","sourcesContent":["import * as fs from 'fs';\nimport * as path from 'path';\nimport { FieldDef } from './field-def';\n// Imported, never re-typed: the banner offers the bulk migrator only for errors it actually covers, and\n// this marker is how it recognizes a placement error. See config-error-banner.ts.\nimport { SECTION_PLACEMENT_MARKER } from './config-error-banner';\nimport { sectionForRule, isHookGuard } from './sections';\nimport { RULE_SCHEMAS, allRuleNames } from './rule-schemas';\nimport { recommendedSeedModeFor, isGradualMode } from './seed-entry';\nimport { MODIFIED_CODE_MODES } from './rule-configs';\nimport {\n validateChecklistsSection, validateDevDeploySection, validateLandPrSection, validateNoGateSaltRationale,\n validateReviewerAgentKeys,\n} from './pr-gate-section-validators';\nimport { retiredEntry, retiredKeyError, retiredRuleFor } from './retired-config-keys';\nimport { PRUNE_UNKNOWN_COMMAND } from './constants';\n\n// Re-exported so the isolated validate-checklist-docs target keeps importing it from here.\nexport { validateChecklistsSection };\n// Re-exported from their new homes: this module was the historical entry point for both.\nexport { allRuleNames } from './rule-schemas';\nexport { recommendedSeedMode, recommendedSeedModeFor, seedEntryForRule } from './seed-entry';\nimport { DEFAULT_MATCH_RULES } from './match-rules-config';\nimport { toError } from './to-error';\n\n/**\n * The longest a `turnOffRuleUntilEpoch` may reach into the future: ONE WEEK. Poke it again next week to\n * extend — that weekly re-set IS the intended workflow, not a workaround: it is what makes a rule that is\n * off on purpose stay a decision somebody keeps making, instead of one nobody remembers.\n *\n * DELIBERATELY ASYMMETRIC with turnOffRuleWhileOnBranch, which has NO cap and must not get one. The epoch\n * hatch is REPO-WIDE while it lasts, so a long window shelters every unrelated change that lands inside it\n * (a fleet repo was found with max-file-lines/max-method-lines switched off until 2026-10-01 — 43 days\n * out, six times this cap). The branch hatch fires only on ONE exact branch name — a big refactor\n * legitimately runs 35+ days, and capping that would only interrupt the one branch that opted in.\n */\nexport const MAX_TURN_OFF_EPOCH_DAYS = 7;\n\nconst SECONDS_PER_DAY = 24 * 60 * 60;\n\n/**\n * Reject a `turnOffRuleUntilEpoch` more than MAX_TURN_OFF_EPOCH_DAYS into the future.\n *\n * A PAST epoch is always valid: it is inert (it skips nothing), and every existing config is full of them.\n * The BOUNDARY is inclusive — exactly MAX_TURN_OFF_EPOCH_DAYS out is accepted, only strictly beyond it is\n * refused — so a config written as \"now + 7 days\" is never rejected by the second it took to save.\n */\n// webpieces-disable no-function-outside-class -- module-scope validator helper, matching every other check in this file\nfunction epochCapError(label: string, value: number): string | null {\n const maxEpoch = Math.floor(Date.now() / 1000) + MAX_TURN_OFF_EPOCH_DAYS * SECONDS_PER_DAY;\n if (value <= maxEpoch) return null;\n const daysOut = Math.round((value - Date.now() / 1000) / SECONDS_PER_DAY);\n const maxDate = new Date(maxEpoch * 1000).toISOString().split('T')[0];\n return (\n `${label} \"turnOffRuleUntilEpoch\": ${value} is ${daysOut} days in the future — the maximum is ` +\n `${MAX_TURN_OFF_EPOCH_DAYS} days. A rule switched off for longer than that is off for work nobody ` +\n `had in mind when it was written, because this hatch is REPO-WIDE while it lasts.\\n` +\n ` CURE: set it to at most ${maxEpoch} (${maxDate}), then re-set it WEEKLY for as long as you ` +\n `still need it — that renewal is the intended workflow, not a workaround. If the rule is off for ` +\n `ONE branch's work, use \"turnOffRuleWhileOnBranch\": \"<exact branch name>\" instead; that one has ` +\n `no cap.`\n );\n}\n\nfunction valueHint(def: FieldDef, key?: string): string {\n // The two universal escape hatches, REQUIRED on every rule so they're always visible. Spell out the\n // \"off\" value so a fresh config seeds them in the active/no-op state (0 / null), not a placeholder.\n if (key === 'turnOffRuleUntilEpoch') return '0 (0 = active; future unix-epoch seconds = temporarily off)';\n if (key === 'turnOffRuleWhileOnBranch') return 'null (null = always on; an EXACT branch name — no globs — disables the rule while that branch is checked out)';\n return def.enumValues\n ? `\"${def.enumValues.join(' | ')}\"`\n : def.type === 'string[]' ? '[\"<string>\", ...]'\n : def.type === 'number' ? '<number>'\n : def.type === 'boolean' ? '<boolean>'\n : '\"<string>\"';\n}\n\n/** A rollout hint for the copy-paste snippet: recommend the narrowest gradual mode the rule supports. */\nfunction rolloutTip(schema: Record<string, FieldDef>): string {\n const modes = schema['mode']?.enumValues ?? [];\n // Same source of truth as the seeder; only a GRADUAL recommendation gets the rollout prose, so a\n // rule whose recommendation falls through to ON/RUN_EVERY_TIME/OFF prints no tip (as before).\n const recommended = recommendedSeedModeFor(modes);\n if (!isGradualMode(recommended)) return '';\n const optOut = modes.includes('OFF') ? ' Set \"mode\": \"OFF\" to opt out entirely.' : '';\n return (\n `\\n\\n💡 Recommended: start with \"mode\": \"${recommended}\" — it enforces only on what you ` +\n `actually change, so the rule rolls out gradually (existing code stays grandfathered until ` +\n `you next touch that project/file/method).${optOut}`\n );\n}\n\nfunction missingRuleSnippet(ruleName: string, schema: Record<string, FieldDef>): string {\n // Required fields go in the copy-paste entry. The two universal escape hatches\n // (turnOffRuleUntilEpoch / turnOffRuleWhileOnBranch) are now REQUIRED, so they land in that block —\n // which is the whole point: every seeded rule shows both hatches. Optional fields are listed separately.\n const fields = Object.keys(schema);\n const required = fields.filter(f => !schema[f].optional);\n const optional = fields.filter(f => schema[f].optional);\n\n const requiredLines = required.map(f => ` \"${f}\": ${valueHint(schema[f], f)}`);\n const section = sectionForRule(ruleName);\n let out =\n `[${ruleName}] Not configured in webpieces.config.json. Add this entry to the \"${section}\" section\\n` +\n `(choose values appropriate for your project):\\n\\n` +\n ` \"${ruleName}\": {\\n${requiredLines.join(',\\n')}\\n }`;\n\n if (optional.length > 0) {\n const optionalLines = optional.map(f => ` \"${f}\": ${valueHint(schema[f], f)}`);\n out +=\n `\\n\\nOptional fields you may add to this rule (omit if not needed):\\n` +\n `${optionalLines.join(',\\n')}`;\n }\n out += rolloutTip(schema);\n return out;\n}\n\n/**\n * A config key under rules/hookGuards that the RUNNING validator has no schema for (and no rulesDir is set\n * to supply custom rules). THE FALLBACK: it fires for any name the table in retired-config-keys.ts does not\n * know, which very much includes RETIRED names on a tree whose validator predates the retirement — the\n * ordinary linked-worktree layout, where the worktree is on one release and the parent checkout that\n * supplies the hook's resolution is on an older one. So this text has to be useful with NO table entry.\n *\n * DELETION LEADS, and it is not a hedge. A key the running validator has no schema for controls nothing:\n * every code path that would read it is keyed off the schema. Leaving it is dead config that reads as live\n * config, and for a retired key deleting it is the entire fix.\n *\n * This message used to lead with `pnpm install` instead, on the theory that the key might be valid and the\n * validator merely stale. Two things are wrong with that. First, it CONTRADICTED the banner this error is\n * printed inside, which states outright that `pnpm install` cannot help — one output, two opposite orders.\n * Second, the premise is already handled upstream: the shim's version-drift guard compares the pin against\n * the installed version and denies every tool call BEFORE exec'ing this validator, with its own message and\n * its own cure. If this text is on screen, that guard found no drift. The pin therefore appears here only as\n * a secondary note, so a valid-but-newer key is never dropped without the reader being told the case exists.\n */\nfunction unknownRuleError(ruleName: string): string {\n return (\n `[${ruleName}] Unknown rule — the running @webpieces validator has no schema for it, and no ` +\n `\"rulesDir\" is configured to supply custom rules. A key no validator knows controls NOTHING, so ` +\n `DELETE the \"${ruleName}\" key from webpieces.config.json — run \\`${PRUNE_UNKNOWN_COMMAND}\\` to ` +\n `strip it (and every other unknown key) mechanically. It may be RETIRED: a newer release can move ` +\n `a setting out of this file entirely, in which case deleting the key here is the WHOLE fix. ` +\n `MACHINE-LOCAL settings in particular now live in ~/.webpieces/config.json under \"experimental\" — ` +\n `an optional file tracked by no repo, whose absence is the default behaviour — so if ` +\n `\"${ruleName}\" is one of those, delete it here and set it there. Secondary, and rare: a key is ` +\n `valid-but-unlearned when package.json pins an @webpieces OLDER than this config was written for, ` +\n `and the version-drift guard reports THAT separately with its own cure (bump the pin) before this ` +\n `validator ever runs — so it is not what you are looking at.`\n );\n}\n\n// Fields we DELETED from a rule's schema, keyed by \"<rule>.<field>\". The generic unknown-field error\n// (\"Unknown field ... Valid fields: [...]\") is correct but doesn't say WHY the field vanished, so an AI\n// might re-add it. These hints explain the removal so the only action left is to delete the key.\nconst RETIRED_FIELD_HINTS: Record<string, string> = {\n 'runtime-architecture.servicePaths':\n 'This field was removed — it was never read. The runtime graph is derived automatically from ' +\n 'architecture/dependencies.json (apiRelations + project roles). Delete it.',\n 'runtime-architecture.apiProjectPaths':\n 'This field was removed — it was never read. The runtime graph is derived automatically from ' +\n 'architecture/dependencies.json, so there is NO list of api libs to maintain. Delete it (do not ' +\n 'enumerate api libs and do not replace it with a glob).',\n 'runtime-architecture.allowedCycles':\n 'This field was removed — a runtime cycle is not allowable at all any more. Levelling now FAILS ' +\n 'on any cycle, because CD deploys services in dependency order and a cycle has no such order. ' +\n 'Delete the key. If a cycle genuinely cannot be broken yet, declare it PER EDGE with a ' +\n '`cutLegacyCycle:<targetService>` nx tag on the CALLING project, which admits the debt where ' +\n '`grep -rn cutLegacyCycle` can enumerate it — there is no config key for it.',\n // The two per-guard command strings, deleted as SECOND SPELLINGS of commands.guardHints. They were\n // read at the point of use, so they BEAT the commands section — which made guardHintsWhy's promise\n // (\"rename a gated command here and every guard message follows\") false for any repo that set them.\n // Keyed on the new policy key, since that is the entry a consumer's field now sits inside.\n 'pr-lifecycle-guard.upsertPrCommand':\n 'This field was removed. The command the push/PR-creation block prints lives in ONE place: ' +\n '\"commands\": { \"guardHints\": { \"prCreationOrPush\": <value> } }. Move your value there and delete ' +\n 'this key.',\n 'pr-lifecycle-guard.mergeCompleteCommand':\n 'This field was removed. The command the unfinished-merge block prints lives in ONE place: ' +\n '\"commands\": { \"guardHints\": { \"mergeInProgress\": <value> } }. Move your value there and delete ' +\n 'this key.',\n};\n\n// Universal field renames (apply to EVERY rule/guard AND every match-rule, unlike the per-rule\n// RETIRED_FIELD_HINTS). When an entry still uses the old escape-hatch name, the generic unknown-field\n// error is replaced with a precise \"renamed to X — rename it\" instruction so the fix is mechanical.\nconst RENAMED_FIELD_ALIASES: Record<string, string> = {\n ignoreModifiedUntilEpoch: 'turnOffRuleUntilEpoch',\n ignoreRuleWhileOnBranch: 'turnOffRuleWhileOnBranch',\n};\n\n\n// The renamed-field message shared by keyed rules and match-rules.\n// webpieces-disable no-function-outside-class -- module-level config validator, matches the rest of this file\nfunction renamedFieldError(scope: string, oldKey: string, newKey: string): string {\n return `${scope} Unknown field \"${oldKey}\" — it was renamed to \"${newKey}\". Rename it (the value carries over unchanged; for the branch hatch, use null when there is no branch).`;\n}\n\n/**\n * Field-level errors for ONE configured rule entry: unknown/renamed/retired keys, type and enum\n * mismatches, and the two-week cap on turnOffRuleUntilEpoch.\n *\n * Extracted out of validateWebpiecesConfig purely so that function stays inside max-method-lines; it is\n * the same checks in the same order.\n */\n// webpieces-disable no-any-unknown -- one config entry as opaque JSON; every field is typed-checked below\n// webpieces-disable no-function-outside-class -- module-scope validator helper, matching every other check in this file\nfunction fieldErrors(ruleName: string, entry: Record<string, unknown>, schema: Record<string, FieldDef>): string[] {\n const errors: string[] = [];\n for (const [key, value] of Object.entries(entry)) {\n const fieldDef = schema[key];\n if (!fieldDef) {\n const renamedTo = RENAMED_FIELD_ALIASES[key];\n if (renamedTo) {\n errors.push(renamedFieldError(`[${ruleName}]`, key, renamedTo));\n continue;\n }\n const retiredHint = RETIRED_FIELD_HINTS[`${ruleName}.${key}`];\n const suffix = retiredHint ? ` ${retiredHint}` : '';\n errors.push(`[${ruleName}] Unknown field \"${key}\". Valid fields: [${Object.keys(schema).join(', ')}].${suffix}`);\n continue;\n }\n // A nullable field (e.g. turnOffRuleWhileOnBranch) accepts JSON null in addition to its type.\n if (value === null && fieldDef.nullable) continue;\n if (fieldDef.type === 'string[]') {\n if (!Array.isArray(value) || !value.every(v => typeof v === 'string'))\n errors.push(`[${ruleName}] \"${key}\" must be string[], got ${typeof value}.`);\n } else if (typeof value !== fieldDef.type) {\n errors.push(`[${ruleName}] \"${key}\" must be ${fieldDef.type}, got ${typeof value}.`);\n } else if (fieldDef.enumValues && !fieldDef.enumValues.includes(value as string)) {\n errors.push(`[${ruleName}] \"${key}\" = \"${value}\" is not valid. Must be one of: ${fieldDef.enumValues.join(', ')}.`);\n } else if (key === 'turnOffRuleUntilEpoch') {\n const capError = epochCapError(`[${ruleName}]`, value as number);\n if (capError) errors.push(capError);\n } else if (ruleName === 'branch-state-guard' && key === 'maxCommitsBehind'\n && (!Number.isInteger(value) || (value as number) < 0)) {\n errors.push('[branch-state-guard] \"maxCommitsBehind\" must be a non-negative integer.');\n }\n }\n return errors;\n}\n\n// webpieces-disable no-any-unknown -- rawRules values are opaque JSON; each field is validated individually\nexport function validateWebpiecesConfig(\n rawRules: Record<string, Record<string, unknown>>,\n hasCustomRulesDir: boolean = false,\n): string[] {\n const errors: string[] = [];\n\n // Check field-level correctness for rules that are present\n for (const [ruleName, entry] of Object.entries(rawRules)) {\n const schema = RULE_SCHEMAS[ruleName];\n if (!schema) {\n // A name we KNOW is retired beats the generic unknown-rule message, because only the table\n // knows WHERE the setting went — a rename carries its value over, and a bare \"delete it\"\n // would throw that value away. It fires even when a rulesDir is set, because a custom rule\n // must not reuse a retired name.\n const retired = retiredRuleFor(ruleName);\n if (retired) {\n errors.push(retiredKeyError(retired));\n continue;\n }\n // No built-in schema. With no rulesDir there are no custom rules, so this key is a\n // dead/typo'd entry — tell the AI to remove it (a removed rule like no-shell-substitution\n // lingers here otherwise). With a rulesDir it may be a legitimate custom rule → skip.\n if (!hasCustomRulesDir) errors.push(unknownRuleError(ruleName));\n continue;\n }\n errors.push(...fieldErrors(ruleName, entry, schema));\n // Required fields must actually be present. Until now the loop above only checked\n // fields that WERE present, so an entry like `{}` (or one missing `mode` /\n // `turnOffRuleUntilEpoch`) slipped through. Every non-optional schema field is mandatory.\n for (const [key, fieldDef] of Object.entries(schema)) {\n if (!fieldDef.optional && !(key in entry)) {\n errors.push(`[${ruleName}] Missing required field \"${key}\". Add ${key}: ${valueHint(fieldDef, key)}.`);\n }\n }\n }\n\n // Every built-in rule must be explicitly configured — no silent defaults.\n // When a new rule is added to the framework, this check surfaces it immediately\n // with a ready-to-copy snippet so AI can configure it in one pass.\n for (const [ruleName, schema] of Object.entries(RULE_SCHEMAS)) {\n if (!(ruleName in rawRules)) {\n errors.push(missingRuleSnippet(ruleName, schema));\n }\n }\n\n return errors;\n}\n\nconst PR_GATE_MODES = ['ON', 'OFF'] as const;\n// Optional — omitted means DETECT. Kept inline (like prGateExample) to avoid a load-config ↔\n// pr-gate-config import cycle; the canonical list + semantics live in pr-gate-config.ts.\nconst PR_GATE_MERGE_MODES = ['AUTO', 'NONE'] as const;\n\n// Spelled out because the choice is a POLICY decision with a consequence the chooser cannot see:\n// only the AUTO path can put the compact risk/flags body in main's history, because a UI merge is\n// composed from the repo's squash_merge_commit_title/message settings, which the tooling pins.\nconst MERGE_MODE_HELP = (\n `Must be one of: ${PR_GATE_MERGE_MODES.join(', ')}.\\n` +\n ` \"AUTO\" — wp-finish-upsert-pr lands the PR: it squash-merges when mergeable, else enables\\n` +\n ` GitHub auto-merge, both with an explicit --subject/--body-file so main's history\\n` +\n ` gets the PR title + the compact risk/flags body. Needs allow_auto_merge on the repo\\n` +\n ` (gh api repos/{owner}/{repo} --jq .allow_auto_merge).\\n` +\n ` \"NONE\" — wp-finish-upsert-pr only opens/updates the PR; a human merges it, and that still\\n` +\n ` lands the compact body: the PR DESCRIPTION *is* that body, and stage \\u2462 keeps the repo's\\n` +\n ` squash_merge_commit_title/message pinned to PR_TITLE/PR_BODY so a UI merge copies it\\n` +\n ` verbatim (SquashSettingsEnforcer). Nothing to set by hand.`\n);\n\n// Copy-paste example for the top-level `pr-gate` block (sibling of `rules`). Kept inline rather\n// than imported from pr-gate-config.ts to avoid a load-config ↔ pr-gate-config import cycle.\nfunction prGateExample(): string {\n return (\n ` \"pr-gate\": {\\n` +\n ` \"mode\": \"ON\",\\n` +\n ` \"buildCommand\": \"<command CI runs to validate a PR, e.g. pnpm nx affected --target=ci --base=$(git merge-base origin/main HEAD)>\",\\n` +\n ` \"gates\": [\\n` +\n ` { \"name\": \"API Changed\", \"patterns\": [\"libraries/apis/**\", \"**/*Api.ts\"], \"warningColor\": \"yellow\" }\\n` +\n ` ],\\n` +\n ` \"reviewerAgentName\": \"webpieces-reviewer\",\\n` +\n ` \"reviewerAgents\": 1, // OPTIONAL — the most reviewer subagents per round; omit for one per checklist\\n` +\n ` \"checklists\": [ // OPTIONAL — per-area review, each against its own doc\\n` +\n ` { \"id\": \"db-migrations\", \"doc\": \".claude/review/db-migrations.md\", \"patterns\": [\"**/*.sql\"], \"required\": true }\\n` +\n ` ]\\n` +\n ` }`\n );\n}\n\n// The `gates` array: dashboard-only warning flags. Extracted from validatePrGateSection to keep that\n// method inside the length limit.\n// webpieces-disable no-any-unknown -- `value` is the opaque consumer `gates` value until narrowed here\n// webpieces-disable no-function-outside-class -- module-level config validator, matches the rest of this file\nfunction validateGatesSection(value: unknown): string[] {\n if (!Array.isArray(value)) {\n return [`[pr-gate] \"gates\" must be an array of { name, patterns, warningColor, disabled? }.`];\n }\n const errors: string[] = [];\n for (let i = 0; i < value.length; i += 1) {\n errors.push(...validateGate(value[i], i));\n }\n return errors;\n}\n\n// webpieces-disable no-any-unknown -- one gate entry from opaque consumer JSON, validated field-by-field\nfunction validateGate(gate: unknown, index: number): string[] {\n if (typeof gate !== 'object' || gate === null) {\n return [`[pr-gate] gates[${index}] must be an object { name, patterns, warningColor, disabled? }.`];\n }\n // webpieces-disable no-any-unknown -- narrowing one opaque gate object from consumer JSON\n const g = gate as Record<string, unknown>;\n const errors: string[] = [];\n if (typeof g['name'] !== 'string') errors.push(`[pr-gate] gates[${index}].name must be a string.`);\n if (!Array.isArray(g['patterns']) || !g['patterns'].every(p => typeof p === 'string'))\n errors.push(`[pr-gate] gates[${index}].patterns must be string[].`);\n if (g['warningColor'] === undefined)\n errors.push(`[pr-gate] gates[${index}].warningColor is required — set it to \"yellow\" or \"red\" (green is implicit when nothing matches).`);\n else if (g['warningColor'] !== 'yellow' && g['warningColor'] !== 'red')\n errors.push(`[pr-gate] gates[${index}].warningColor must be \"yellow\" or \"red\" (green is implicit when nothing matches).`);\n if (g['disabled'] !== undefined && typeof g['disabled'] !== 'boolean')\n errors.push(`[pr-gate] gates[${index}].disabled must be a boolean (example/inactive gate kept in the file).`);\n return errors;\n}\n\n/**\n * Validate the top-level `pr-gate` section. It is REQUIRED (a client that opts out sets mode \"OFF\").\n * `buildCommand` is required unless mode is \"OFF\". Returns human-readable, copy-paste-friendly errors\n * — never throws. The pr-gate block lives outside the FieldDef-driven `rules` schema because its\n * nested `gates`/`checklists` arrays can't be expressed there, so they get structural validation here.\n * `repoRoot` (when known) lets the `checklists[].docs` existence check run.\n */\n// webpieces-disable no-any-unknown -- `section` is opaque consumer JSON until narrowed below\n// webpieces-disable no-function-outside-class -- module-level config validator, matches the rest of this file\nexport function validatePrGateSection(section: unknown, repoRoot?: string): string[] {\n if (section === undefined || section === null) {\n return [\n `[pr-gate] Not configured in webpieces.config.json. Add this block under the \"commands\" ` +\n `section (set \"mode\": \"OFF\" to opt out):\\n\\n${prGateExample()}`,\n ];\n }\n if (typeof section !== 'object' || Array.isArray(section)) {\n return [`[pr-gate] Must be an object. Example:\\n\\n${prGateExample()}`];\n }\n // webpieces-disable no-any-unknown -- narrowing the opaque pr-gate section from consumer JSON\n const s = section as Record<string, unknown>;\n const errors: string[] = [];\n\n if (!('mode' in s)) {\n errors.push(`[pr-gate] Missing required field \"mode\". Must be one of: ${PR_GATE_MODES.join(', ')}.`);\n } else if (typeof s['mode'] !== 'string' || !PR_GATE_MODES.includes(s['mode'] as typeof PR_GATE_MODES[number])) {\n errors.push(`[pr-gate] \"mode\" = \"${String(s['mode'])}\" is not valid. Must be one of: ${PR_GATE_MODES.join(', ')}.`);\n }\n\n // buildCommand and mergeMode are both required whenever the gate is active (mode !== OFF). There\n // is deliberately NO default for mergeMode: whether the tooling may land your PRs is a policy\n // decision, and either guess is wrong for somebody.\n if (s['mode'] !== 'OFF') {\n const cmd = s['buildCommand'];\n if (typeof cmd !== 'string' || cmd.trim() === '') {\n errors.push(\n `[pr-gate] Missing required field \"buildCommand\" — the command CI runs to validate a PR. ` +\n `Add e.g. \"buildCommand\": \"pnpm nx affected --target=ci --base=$(git merge-base origin/main HEAD)\".`,\n );\n }\n const mm = s['mergeMode'];\n if (!('mergeMode' in s)) {\n errors.push(`[pr-gate] Missing required field \"mergeMode\". ${MERGE_MODE_HELP}`);\n } else if (typeof mm !== 'string' || !PR_GATE_MERGE_MODES.includes(mm as typeof PR_GATE_MERGE_MODES[number])) {\n errors.push(`[pr-gate] \"mergeMode\" = \"${String(mm)}\" is not valid. ${MERGE_MODE_HELP}`);\n }\n errors.push(...validateReviewerAgentKeys(s, repoRoot));\n }\n\n if ('gates' in s) errors.push(...validateGatesSection(s['gates']));\n\n // Optional extension point: company review checklists, as an ARRAY right here in the config. Absent ⇒\n // none. The removed { doc } manifest shape is rejected with the exact migration edit.\n if ('checklists' in s) errors.push(...validateChecklistsSection(s['checklists'], repoRoot));\n\n // Optional server-token salt. Absent ⇒ no token minted, CI enforcement is a no-op. Present ⇒ must be\n // a non-empty string (an empty salt would mint a token anyone can forge from a known-empty secret).\n if ('gateSalt' in s) {\n const salt = s['gateSalt'];\n if (typeof salt !== 'string' || salt.trim() === '') {\n errors.push(`[pr-gate] \"gateSalt\" must be a non-empty string — it is the shared secret the gate token is HMAC'd with. Omit the key entirely to disable server-side token enforcement.`);\n }\n }\n\n // Optional: what happens to the LOCAL branch once its PR lands. Absent ⇒ \"archive-tag\".\n if ('landPr' in s) errors.push(...validateLandPrSection(s['landPr']));\n\n // Optional: where wp-push-dev publishes the disposable copy. Absent ⇒ \"dev-include\" / \"dev\".\n if ('devDeploy' in s) errors.push(...validateDevDeploySection(s['devDeploy']));\n\n errors.push(...validateNoGateSaltRationale(s));\n\n // Optional: publish reviewer output as a PR comment (defaults true). Must be a boolean when present.\n if ('checklistComments' in s && typeof s['checklistComments'] !== 'boolean') {\n errors.push(`[pr-gate] \"checklistComments\" must be a boolean (defaults to true; set false to keep the PR body-only).`);\n }\n\n return errors;\n}\n\nfunction excludePathsExample(): string {\n return '\"excludePaths\": [\"repositories/**\"]';\n}\n\n// A glob list: must be a string[] (may be empty). `key` names it for the error.\n// webpieces-disable no-any-unknown -- `value` is opaque consumer JSON until narrowed here\nfunction validateExcludeList(value: unknown, key: string): string[] {\n if (!(Array.isArray(value) && value.every(p => typeof p === 'string'))) {\n return [`[excludePaths] \"${key}\" must be a string[] of glob paths (use [] for none).`];\n }\n return [];\n}\n\n/**\n * Validate the REQUIRED top-level `excludePaths` block: ONE glob list suppressing hook enforcement per\n * file path, for code-style rules and file-scoped guards alike. Required so every client upgrading is\n * forced to declare it (as [] to keep today's behavior, or with real paths). Returns copy-paste\n * friendly errors and never throws — same contract as validatePrGateSection.\n *\n * The two-list object form `{ \"rules\": [...], \"guards\": [...] }` is RETIRED, not tolerated. It used to be\n * accepted and silently unioned, which is why this repo's own config sat on the dead shape for releases: an\n * accepted shape is never migrated. Rejecting it cannot wedge a consumer — editing webpieces.config.json is\n * always permitted, even while it is invalid. See retired-config-keys.ts.\n */\n// webpieces-disable no-any-unknown -- `section` is opaque consumer JSON until narrowed below\nexport function validateExcludePaths(section: unknown): string[] {\n if (section === undefined || section === null) {\n return [\n `[excludePaths] Not configured in webpieces.config.json. Add this REQUIRED block ` +\n `(use an empty array to keep enforcing everywhere):\\n\\n ${excludePathsExample()}`,\n ];\n }\n if (Array.isArray(section)) return validateExcludeList(section, 'excludePaths');\n if (typeof section !== 'object') {\n return [`[excludePaths] Must be a string[] of glob paths. Example:\\n\\n ${excludePathsExample()}`];\n }\n // webpieces-disable no-any-unknown -- narrowing the opaque excludePaths section from consumer JSON\n const s = section as Record<string, unknown>;\n // The retired two-list object. One table row owns the message for either key present.\n const retired = retiredEntry('rules', '[excludePaths]');\n if (retired && (s['rules'] !== undefined || s['guards'] !== undefined)) {\n return [`${retiredKeyError(retired)}\\n\\n ${excludePathsExample()}`];\n }\n return [`[excludePaths] Must be a string[] of glob paths. Example:\\n\\n ${excludePathsExample()}`];\n}\n\n// ---------------------------------------------------------------------------\n// match-rules — a new top-level ARRAY section (parallel to pr-gate/excludePaths). Each entry is a\n// client-authored content guard (raw-regex patterns + message + scoping). Validated structurally here\n// the same way pr-gate's `gates` are, because an array of objects can't be expressed in FieldDef schema.\n// ---------------------------------------------------------------------------\n\nfunction matchRulesExample(): string {\n return `\"match-rules\": ${JSON.stringify(DEFAULT_MATCH_RULES, null, 4)}`;\n}\n\n// webpieces-disable no-any-unknown -- generic type guard over an opaque JSON value\nfunction isStringArray(value: unknown): value is string[] {\n return Array.isArray(value) && value.every(v => typeof v === 'string');\n}\n\n// Compile a pattern to validate it; returns the error message, or undefined when it compiles.\nfunction regexError(pattern: string): string | undefined {\n // eslint-disable-next-line @webpieces/no-unmanaged-exceptions\n try {\n // Constructed only to validate the syntax; the object is intentionally discarded.\n void new RegExp(pattern);\n return undefined;\n } catch (err: unknown) {\n const error = toError(err);\n return error.message;\n }\n}\n\n// One entry of the match-rules array, validated field-by-field (see validateGate for the pattern).\n// webpieces-disable no-any-unknown -- one match-rule entry from opaque consumer JSON, validated field-by-field\nfunction validateMatchRule(entry: unknown, index: number): string[] {\n if (typeof entry !== 'object' || entry === null || Array.isArray(entry)) {\n return [`[match-rules] entry[${index}] must be an object { name, patterns, mainMessage, mode, turnOffRuleUntilEpoch, turnOffRuleWhileOnBranch, ... }.`];\n }\n // webpieces-disable no-any-unknown -- narrowing one opaque match-rule entry from consumer JSON\n const e = entry as Record<string, unknown>;\n const label = typeof e['name'] === 'string' ? `\"${e['name']}\"` : `entry[${index}]`;\n const errors: string[] = [];\n\n if (typeof e['name'] !== 'string' || e['name'].trim() === '')\n errors.push(`[match-rules] entry[${index}].name must be a non-empty string (it is the disable token and report label).`);\n\n if (!isStringArray(e['patterns']) || e['patterns'].length === 0) {\n errors.push(`[match-rules] ${label}.patterns must be a non-empty string[] of regexes.`);\n } else {\n e['patterns'].forEach((p: string, pi: number) => {\n const rxErr = regexError(p);\n if (rxErr) errors.push(`[match-rules] ${label}.patterns[${pi}] is not a valid regex: ${rxErr}`);\n });\n }\n\n if (typeof e['mainMessage'] !== 'string' || e['mainMessage'].trim() === '')\n errors.push(`[match-rules] ${label}.mainMessage must be a non-empty string.`);\n\n if (typeof e['mode'] !== 'string' || !MODIFIED_CODE_MODES.includes(e['mode'] as typeof MODIFIED_CODE_MODES[number]))\n errors.push(`[match-rules] ${label}.mode must be one of: ${MODIFIED_CODE_MODES.join(', ')}.`);\n\n // Both escape hatches are REQUIRED on every match-rule too (same as keyed rules), so they are always\n // visible. turnOffRuleUntilEpoch: number (0 = active; a future unix-epoch in seconds = temporarily\n // off). turnOffRuleWhileOnBranch: string | null (null = always on; an EXACT branch name — matched\n // with ===, never as a glob — disables the rule while that branch is checked out).\n if (typeof e['turnOffRuleUntilEpoch'] !== 'number') {\n errors.push(`[match-rules] ${label}.turnOffRuleUntilEpoch must be a number (0 = active; future unix-epoch seconds = temporarily off).`);\n } else {\n const capError = epochCapError(`[match-rules] ${label}`, e['turnOffRuleUntilEpoch']);\n if (capError) errors.push(capError);\n }\n if (!(e['turnOffRuleWhileOnBranch'] === null || typeof e['turnOffRuleWhileOnBranch'] === 'string'))\n errors.push(`[match-rules] ${label}.turnOffRuleWhileOnBranch must be a string or null (null = no branch / always on; a string is an EXACT branch name, globs are not supported).`);\n\n // The old escape-hatch names were renamed — flag them precisely.\n for (const oldKey of Object.keys(RENAMED_FIELD_ALIASES)) {\n if (oldKey in e) errors.push(renamedFieldError(`[match-rules] ${label}`, oldKey, RENAMED_FIELD_ALIASES[oldKey]));\n }\n\n if (e['options'] !== undefined && !isStringArray(e['options']))\n errors.push(`[match-rules] ${label}.options must be a string[] (omit if not needed).`);\n if (e['allowedPaths'] !== undefined && !isStringArray(e['allowedPaths']))\n errors.push(`[match-rules] ${label}.allowedPaths must be a string[] of globs (omit if not needed).`);\n if (e['disableAllowed'] !== undefined && typeof e['disableAllowed'] !== 'boolean')\n errors.push(`[match-rules] ${label}.disableAllowed must be a boolean.`);\n\n return errors;\n}\n\n/**\n * Validate the REQUIRED top-level `match-rules` array (client-authored content guards). MISSING →\n * one error printing the ready-to-paste `no-fetch` example (add at least this; more can follow).\n * Present-but-`[]` → allowed (a conscious opt-out, matching pr-gate mode:OFF / excludePaths []).\n * Otherwise every entry is validated field-by-field (each regex compile-checked) plus name\n * uniqueness. Copy-paste-friendly errors; never throws — same contract as validatePrGateSection.\n */\n// webpieces-disable no-any-unknown -- `section` is opaque consumer JSON until narrowed below\nexport function validateMatchRulesSection(section: unknown): string[] {\n if (section === undefined || section === null) {\n return [\n `[match-rules] Not configured in webpieces.config.json. Add this REQUIRED top-level array — ` +\n `seed it with the no-fetch guard below (you can add more entries: no-moment, no-lodash-chain, …):\\n\\n${matchRulesExample()}`,\n ];\n }\n if (!Array.isArray(section)) {\n return [`[match-rules] Must be an array of content-guard objects. Example:\\n\\n${matchRulesExample()}`];\n }\n\n const errors: string[] = [];\n const seen = new Set<string>();\n for (let i = 0; i < section.length; i += 1) {\n errors.push(...validateMatchRule(section[i], i));\n // webpieces-disable no-any-unknown -- reading the name off an opaque entry only to dedupe\n const name = (section[i] as Record<string, unknown> | null)?.['name'];\n if (typeof name === 'string') {\n if (seen.has(name)) errors.push(`[match-rules] duplicate entry name \"${name}\" — each match-rule name must be unique.`);\n seen.add(name);\n }\n }\n return errors;\n}\n\n/**\n * Enforce that each built-in lives in its correct section: code rules under `rules`, bash guards\n * under `hookGuards`. A guard left in `rules` (or a rule placed in `hookGuards`) is reported with a\n * \"move it\" message so the split stays clean. Unknown/custom names are ignored (they may be custom\n * rules from rulesDir). Presence (\"every built-in must be configured\") is checked separately by\n * validateWebpiecesConfig against the merged map.\n */\n// webpieces-disable no-any-unknown -- section maps are opaque consumer JSON\nexport function validateSectionPlacement(\n rulesSection: Record<string, Record<string, unknown>>,\n hookGuardsSection: Record<string, Record<string, unknown>>,\n): string[] {\n const errors: string[] = [];\n for (const name of Object.keys(rulesSection)) {\n if (isHookGuard(name)) {\n errors.push(\n `[${name}] is a hook guard and ${SECTION_PLACEMENT_MARKER} \"hookGuards\" section, not \"rules\". ` +\n `Move it.`,\n );\n }\n }\n for (const name of Object.keys(hookGuardsSection)) {\n // Only flag KNOWN code rules misplaced into hookGuards; unknown names may be custom rules.\n if (!isHookGuard(name) && RULE_SCHEMAS[name]) {\n errors.push(\n `[${name}] is a code rule and ${SECTION_PLACEMENT_MARKER} \"rules\" section, not \"hookGuards\". ` +\n `Move it.`,\n );\n }\n }\n return errors;\n}\n"]}
1
+ {"version":3,"file":"validate-config.js","sourceRoot":"","sources":["../../../../../packages/tooling/rules-config/src/validate-config.ts"],"names":[],"mappings":"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","sourcesContent":["import * as fs from 'fs';\nimport * as path from 'path';\nimport { FieldDef } from './field-def';\n// Imported, never re-typed: the banner offers the bulk migrator only for errors it actually covers, and\n// this marker is how it recognizes a placement error. See config-error-banner.ts.\nimport { SECTION_PLACEMENT_MARKER } from './config-error-banner';\nimport { sectionForRule, isHookGuard } from './sections';\nimport { RULE_SCHEMAS, allRuleNames } from './rule-schemas';\nimport { recommendedSeedModeFor, isGradualMode } from './seed-entry';\nimport { MODIFIED_CODE_MODES } from './rule-configs';\nimport {\n validateChecklistsSection, validateDevDeploySection, validateLandPrSection, validateNoGateSaltRationale,\n validateReviewerAgentKeys,\n} from './pr-gate-section-validators';\nimport { retiredEntry, retiredKeyError, retiredRuleFor } from './retired-config-keys';\nimport { PRUNE_UNKNOWN_COMMAND } from './constants';\n\n// Re-exported so the isolated validate-checklist-docs target keeps importing it from here.\nexport { validateChecklistsSection };\n// Re-exported from their new homes: this module was the historical entry point for both.\nexport { allRuleNames } from './rule-schemas';\nexport { recommendedSeedMode, recommendedSeedModeFor, seedEntryForRule } from './seed-entry';\nimport { DEFAULT_MATCH_RULES } from './match-rules-config';\nimport { toError } from './to-error';\n\n/**\n * The longest a `turnOffRuleUntilEpoch` may reach into the future: ONE WEEK. Poke it again next week to\n * extend — that weekly re-set IS the intended workflow, not a workaround: it is what makes a rule that is\n * off on purpose stay a decision somebody keeps making, instead of one nobody remembers.\n *\n * DELIBERATELY ASYMMETRIC with turnOffRuleWhileOnBranch, which has NO cap and must not get one. The epoch\n * hatch is REPO-WIDE while it lasts, so a long window shelters every unrelated change that lands inside it\n * (a fleet repo was found with max-file-lines/max-method-lines switched off until 2026-10-01 — 43 days\n * out, six times this cap). The branch hatch fires only on ONE exact branch name — a big refactor\n * legitimately runs 35+ days, and capping that would only interrupt the one branch that opted in.\n */\nexport const MAX_TURN_OFF_EPOCH_DAYS = 7;\n\nconst SECONDS_PER_DAY = 24 * 60 * 60;\n\n/**\n * Reject a `turnOffRuleUntilEpoch` more than MAX_TURN_OFF_EPOCH_DAYS into the future.\n *\n * A PAST epoch is always valid: it is inert (it skips nothing), and every existing config is full of them.\n * The BOUNDARY is inclusive — exactly MAX_TURN_OFF_EPOCH_DAYS out is accepted, only strictly beyond it is\n * refused — so a config written as \"now + 7 days\" is never rejected by the second it took to save.\n */\n// webpieces-disable no-function-outside-class -- module-scope validator helper, matching every other check in this file\nfunction epochCapError(label: string, value: number): string | null {\n const maxEpoch = Math.floor(Date.now() / 1000) + MAX_TURN_OFF_EPOCH_DAYS * SECONDS_PER_DAY;\n if (value <= maxEpoch) return null;\n const daysOut = Math.round((value - Date.now() / 1000) / SECONDS_PER_DAY);\n const maxDate = new Date(maxEpoch * 1000).toISOString().split('T')[0];\n return (\n `${label} \"turnOffRuleUntilEpoch\": ${value} is ${daysOut} days in the future — the maximum is ` +\n `${MAX_TURN_OFF_EPOCH_DAYS} days. A rule switched off for longer than that is off for work nobody ` +\n `had in mind when it was written, because this hatch is REPO-WIDE while it lasts.\\n` +\n ` CURE: set it to at most ${maxEpoch} (${maxDate}), then re-set it WEEKLY for as long as you ` +\n `still need it — that renewal is the intended workflow, not a workaround. If the rule is off for ` +\n `ONE branch's work, use \"turnOffRuleWhileOnBranch\": \"<exact branch name>\" instead; that one has ` +\n `no cap.`\n );\n}\n\nfunction valueHint(def: FieldDef, key?: string): string {\n // The two universal escape hatches, REQUIRED on every rule so they're always visible. Spell out the\n // \"off\" value so a fresh config seeds them in the active/no-op state (0 / null), not a placeholder.\n if (key === 'turnOffRuleUntilEpoch') return '0 (0 = active; future unix-epoch seconds = temporarily off)';\n if (key === 'turnOffRuleWhileOnBranch') return 'null (null = always on; an EXACT branch name — no globs — disables the rule while that branch is checked out)';\n return def.enumValues\n ? `\"${def.enumValues.join(' | ')}\"`\n : def.type === 'string[]' ? '[\"<string>\", ...]'\n : def.type === 'number' ? '<number>'\n : def.type === 'boolean' ? '<boolean>'\n : '\"<string>\"';\n}\n\n/** A rollout hint for the copy-paste snippet: recommend the narrowest gradual mode the rule supports. */\nfunction rolloutTip(schema: Record<string, FieldDef>): string {\n const modes = schema['mode']?.enumValues ?? [];\n // Same source of truth as the seeder; only a GRADUAL recommendation gets the rollout prose, so a\n // rule whose recommendation falls through to ON/RUN_EVERY_TIME/OFF prints no tip (as before).\n const recommended = recommendedSeedModeFor(modes);\n if (!isGradualMode(recommended)) return '';\n const optOut = modes.includes('OFF') ? ' Set \"mode\": \"OFF\" to opt out entirely.' : '';\n return (\n `\\n\\n💡 Recommended: start with \"mode\": \"${recommended}\" — it enforces only on what you ` +\n `actually change, so the rule rolls out gradually (existing code stays grandfathered until ` +\n `you next touch that project/file/method).${optOut}`\n );\n}\n\nfunction missingRuleSnippet(ruleName: string, schema: Record<string, FieldDef>): string {\n // Required fields go in the copy-paste entry. The two universal escape hatches\n // (turnOffRuleUntilEpoch / turnOffRuleWhileOnBranch) are now REQUIRED, so they land in that block —\n // which is the whole point: every seeded rule shows both hatches. Optional fields are listed separately.\n const fields = Object.keys(schema);\n const required = fields.filter(f => !schema[f].optional);\n const optional = fields.filter(f => schema[f].optional);\n\n const requiredLines = required.map(f => ` \"${f}\": ${valueHint(schema[f], f)}`);\n const section = sectionForRule(ruleName);\n let out =\n `[${ruleName}] Not configured in webpieces.config.json. Add this entry to the \"${section}\" section\\n` +\n `(choose values appropriate for your project):\\n\\n` +\n ` \"${ruleName}\": {\\n${requiredLines.join(',\\n')}\\n }`;\n\n if (optional.length > 0) {\n const optionalLines = optional.map(f => ` \"${f}\": ${valueHint(schema[f], f)}`);\n out +=\n `\\n\\nOptional fields you may add to this rule (omit if not needed):\\n` +\n `${optionalLines.join(',\\n')}`;\n }\n out += rolloutTip(schema);\n return out;\n}\n\n/**\n * A config key under rules/hookGuards that the RUNNING validator has no schema for (and no rulesDir is set\n * to supply custom rules). THE FALLBACK: it fires for any name the table in retired-config-keys.ts does not\n * know, which very much includes RETIRED names on a tree whose validator predates the retirement — the\n * ordinary linked-worktree layout, where the worktree is on one release and the parent checkout that\n * supplies the hook's resolution is on an older one. So this text has to be useful with NO table entry.\n *\n * DELETION LEADS, and it is not a hedge. A key the running validator has no schema for controls nothing:\n * every code path that would read it is keyed off the schema. Leaving it is dead config that reads as live\n * config, and for a retired key deleting it is the entire fix.\n *\n * This message used to lead with `pnpm install` instead, on the theory that the key might be valid and the\n * validator merely stale. Two things are wrong with that. First, it CONTRADICTED the banner this error is\n * printed inside, which states outright that `pnpm install` cannot help — one output, two opposite orders.\n * Second, the premise is already handled upstream: the shim's version-drift guard compares the pin against\n * the installed version and denies every tool call BEFORE exec'ing this validator, with its own message and\n * its own cure. If this text is on screen, that guard found no drift. The pin therefore appears here only as\n * a secondary note, so a valid-but-newer key is never dropped without the reader being told the case exists.\n */\nfunction unknownRuleError(ruleName: string): string {\n return (\n `[${ruleName}] Unknown rule — the running @webpieces validator has no schema for it, and no ` +\n `\"rulesDir\" is configured to supply custom rules. A key no validator knows controls NOTHING, so ` +\n `DELETE the \"${ruleName}\" key from webpieces.config.json — run \\`${PRUNE_UNKNOWN_COMMAND}\\` to ` +\n `strip it (and every other unknown key) mechanically. It may be RETIRED: a newer release can move ` +\n `a setting out of this file entirely, in which case deleting the key here is the WHOLE fix. ` +\n `MACHINE-LOCAL settings in particular now live in ~/.webpieces/config.json under \"experimental\" — ` +\n `an optional file tracked by no repo, whose absence is the default behaviour — so if ` +\n `\"${ruleName}\" is one of those, delete it here and set it there. Secondary, and rare: a key is ` +\n `valid-but-unlearned when package.json pins an @webpieces OLDER than this config was written for, ` +\n `and the version-drift guard reports THAT separately with its own cure (bump the pin) before this ` +\n `validator ever runs — so it is not what you are looking at.`\n );\n}\n\n// Fields we DELETED from a rule's schema, keyed by \"<rule>.<field>\". The generic unknown-field error\n// (\"Unknown field ... Valid fields: [...]\") is correct but doesn't say WHY the field vanished, so an AI\n// might re-add it. These hints explain the removal so the only action left is to delete the key.\nconst RETIRED_FIELD_HINTS: Record<string, string> = {\n 'runtime-architecture.servicePaths':\n 'This field was removed — it was never read. The runtime graph is derived automatically from ' +\n 'architecture/dependencies.json (apiRelations + project roles). Delete it.',\n 'runtime-architecture.apiProjectPaths':\n 'This field was removed — it was never read. The runtime graph is derived automatically from ' +\n 'architecture/dependencies.json, so there is NO list of api libs to maintain. Delete it (do not ' +\n 'enumerate api libs and do not replace it with a glob).',\n 'runtime-architecture.allowedCycles':\n 'This field was removed — a runtime cycle is not allowable at all any more. Levelling now FAILS ' +\n 'on any cycle, because CD deploys services in dependency order and a cycle has no such order. ' +\n 'Delete the key. If a cycle genuinely cannot be broken yet, declare it PER EDGE with a ' +\n '`cutLegacyCycle:<targetService>` nx tag on the CALLING project, which admits the debt where ' +\n '`grep -rn cutLegacyCycle` can enumerate it — there is no config key for it.',\n // The two per-guard command strings, deleted as SECOND SPELLINGS of commands.guardHints. They were\n // read at the point of use, so they BEAT the commands section — which made guardHintsWhy's promise\n // (\"rename a gated command here and every guard message follows\") false for any repo that set them.\n // Keyed on the new policy key, since that is the entry a consumer's field now sits inside.\n 'pr-lifecycle-guard.upsertPrCommand':\n 'This field was removed. The command the push/PR-creation block prints lives in ONE place: ' +\n '\"commands\": { \"guardHints\": { \"prCreationOrPush\": <value> } }. Move your value there and delete ' +\n 'this key.',\n 'pr-lifecycle-guard.mergeCompleteCommand':\n 'This field was removed. The command the unfinished-merge block prints lives in ONE place: ' +\n '\"commands\": { \"guardHints\": { \"mergeInProgress\": <value> } }. Move your value there and delete ' +\n 'this key.',\n};\n\n// Universal field renames (apply to EVERY rule/guard AND every match-rule, unlike the per-rule\n// RETIRED_FIELD_HINTS). When an entry still uses the old escape-hatch name, the generic unknown-field\n// error is replaced with a precise \"renamed to X — rename it\" instruction so the fix is mechanical.\nconst RENAMED_FIELD_ALIASES: Record<string, string> = {\n ignoreModifiedUntilEpoch: 'turnOffRuleUntilEpoch',\n ignoreRuleWhileOnBranch: 'turnOffRuleWhileOnBranch',\n};\n\n\n// The renamed-field message shared by keyed rules and match-rules.\n// webpieces-disable no-function-outside-class -- module-level config validator, matches the rest of this file\nfunction renamedFieldError(scope: string, oldKey: string, newKey: string): string {\n return `${scope} Unknown field \"${oldKey}\" — it was renamed to \"${newKey}\". Rename it (the value carries over unchanged; for the branch hatch, use null when there is no branch).`;\n}\n\n/**\n * Field-level errors for ONE configured rule entry: unknown/renamed/retired keys, type and enum\n * mismatches, and the two-week cap on turnOffRuleUntilEpoch.\n *\n * Extracted out of validateWebpiecesConfig purely so that function stays inside max-method-lines; it is\n * the same checks in the same order.\n */\n// webpieces-disable no-any-unknown -- one config entry as opaque JSON; every field is typed-checked below\n// webpieces-disable no-function-outside-class -- module-scope validator helper, matching every other check in this file\nfunction fieldErrors(ruleName: string, entry: Record<string, unknown>, schema: Record<string, FieldDef>): string[] {\n const errors: string[] = [];\n for (const [key, value] of Object.entries(entry)) {\n const fieldDef = schema[key];\n if (!fieldDef) {\n const renamedTo = RENAMED_FIELD_ALIASES[key];\n if (renamedTo) {\n errors.push(renamedFieldError(`[${ruleName}]`, key, renamedTo));\n continue;\n }\n const retiredHint = RETIRED_FIELD_HINTS[`${ruleName}.${key}`];\n const suffix = retiredHint ? ` ${retiredHint}` : '';\n errors.push(`[${ruleName}] Unknown field \"${key}\". Valid fields: [${Object.keys(schema).join(', ')}].${suffix}`);\n continue;\n }\n // A nullable field (e.g. turnOffRuleWhileOnBranch) accepts JSON null in addition to its type.\n if (value === null && fieldDef.nullable) continue;\n if (fieldDef.type === 'string[]') {\n if (!Array.isArray(value) || !value.every(v => typeof v === 'string'))\n errors.push(`[${ruleName}] \"${key}\" must be string[], got ${typeof value}.`);\n } else if (typeof value !== fieldDef.type) {\n errors.push(`[${ruleName}] \"${key}\" must be ${fieldDef.type}, got ${typeof value}.`);\n } else if (fieldDef.enumValues && !fieldDef.enumValues.includes(value as string)) {\n errors.push(`[${ruleName}] \"${key}\" = \"${value}\" is not valid. Must be one of: ${fieldDef.enumValues.join(', ')}.`);\n } else if (key === 'turnOffRuleUntilEpoch') {\n const capError = epochCapError(`[${ruleName}]`, value as number);\n if (capError) errors.push(capError);\n } else if (ruleName === 'branch-state-guard' && key === 'maxCommitsBehind'\n && (!Number.isInteger(value) || (value as number) < 0)) {\n errors.push('[branch-state-guard] \"maxCommitsBehind\" must be a non-negative integer.');\n }\n }\n return errors;\n}\n\n// webpieces-disable no-any-unknown -- rawRules values are opaque JSON; each field is validated individually\nexport function validateWebpiecesConfig(\n rawRules: Record<string, Record<string, unknown>>,\n hasCustomRulesDir: boolean = false,\n): string[] {\n const errors: string[] = [];\n\n // Check field-level correctness for rules that are present\n for (const [ruleName, entry] of Object.entries(rawRules)) {\n const schema = RULE_SCHEMAS[ruleName];\n if (!schema) {\n // A name we KNOW is retired beats the generic unknown-rule message, because only the table\n // knows WHERE the setting went — a rename carries its value over, and a bare \"delete it\"\n // would throw that value away. It fires even when a rulesDir is set, because a custom rule\n // must not reuse a retired name.\n const retired = retiredRuleFor(ruleName);\n if (retired) {\n errors.push(retiredKeyError(retired));\n continue;\n }\n // No built-in schema. With no rulesDir there are no custom rules, so this key is a\n // dead/typo'd entry — tell the AI to remove it (a removed rule like no-shell-substitution\n // lingers here otherwise). With a rulesDir it may be a legitimate custom rule → skip.\n if (!hasCustomRulesDir) errors.push(unknownRuleError(ruleName));\n continue;\n }\n errors.push(...fieldErrors(ruleName, entry, schema));\n // Required fields must actually be present. Until now the loop above only checked\n // fields that WERE present, so an entry like `{}` (or one missing `mode` /\n // `turnOffRuleUntilEpoch`) slipped through. Every non-optional schema field is mandatory.\n for (const [key, fieldDef] of Object.entries(schema)) {\n if (!fieldDef.optional && !(key in entry)) {\n errors.push(`[${ruleName}] Missing required field \"${key}\". Add ${key}: ${valueHint(fieldDef, key)}.`);\n }\n }\n }\n\n // Every built-in rule must be explicitly configured — no silent defaults.\n // When a new rule is added to the framework, this check surfaces it immediately\n // with a ready-to-copy snippet so AI can configure it in one pass.\n for (const [ruleName, schema] of Object.entries(RULE_SCHEMAS)) {\n if (!(ruleName in rawRules)) {\n errors.push(missingRuleSnippet(ruleName, schema));\n }\n }\n\n return errors;\n}\n\nconst PR_GATE_MODES = ['ON', 'OFF'] as const;\n// Optional — omitted means DETECT. Kept inline (like prGateExample) to avoid a load-config ↔\n// pr-gate-config import cycle; the canonical list + semantics live in pr-gate-config.ts.\nconst PR_GATE_MERGE_MODES = ['AUTO', 'NONE'] as const;\n\n// Spelled out because the choice is a POLICY decision with a consequence the chooser cannot see:\n// only the AUTO path can put the compact risk/flags body in main's history, because a UI merge is\n// composed from the repo's squash_merge_commit_title/message settings, which the tooling pins.\nconst MERGE_MODE_HELP = (\n `Must be one of: ${PR_GATE_MERGE_MODES.join(', ')}.\\n` +\n ` \"AUTO\" — wp-finish-upsert-pr lands the PR: it squash-merges when mergeable, else enables\\n` +\n ` GitHub auto-merge, both with an explicit --subject/--body-file so main's history\\n` +\n ` gets the PR title + the compact risk/flags body. Needs allow_auto_merge on the repo\\n` +\n ` (gh api repos/{owner}/{repo} --jq .allow_auto_merge).\\n` +\n ` \"NONE\" — wp-finish-upsert-pr only opens/updates the PR; a human merges it, and that still\\n` +\n ` lands the compact body: the PR DESCRIPTION *is* that body, and stage \\u2462 keeps the repo's\\n` +\n ` squash_merge_commit_title/message pinned to PR_TITLE/PR_BODY so a UI merge copies it\\n` +\n ` verbatim (SquashSettingsEnforcer). Nothing to set by hand.`\n);\n\n// Copy-paste example for the top-level `pr-gate` block (sibling of `rules`). Kept inline rather\n// than imported from pr-gate-config.ts to avoid a load-config ↔ pr-gate-config import cycle.\nfunction prGateExample(): string {\n return (\n ` \"pr-gate\": {\\n` +\n ` \"mode\": \"ON\",\\n` +\n ` \"buildCommand\": \"<command CI runs to validate a PR, e.g. pnpm nx affected --target=ci --base=$(git merge-base origin/main HEAD)>\",\\n` +\n ` \"gates\": [\\n` +\n ` { \"name\": \"API Changed\", \"patterns\": [\"libraries/apis/**\", \"**/*Api.ts\"], \"warningColor\": \"yellow\" }\\n` +\n ` ],\\n` +\n ` \"reviewerAgents\": 1, // OPTIONAL — the most reviewer subagents per round; omit for one per checklist\\n` +\n ` \"checklists\": [ // OPTIONAL — per-area review, each against its own doc\\n` +\n ` { \"id\": \"db-migrations\", \"doc\": \".claude/review/db-migrations.md\", \"patterns\": [\"**/*.sql\"], \"required\": true }\\n` +\n ` ]\\n` +\n ` }`\n );\n}\n\n// The `gates` array: dashboard-only warning flags. Extracted from validatePrGateSection to keep that\n// method inside the length limit.\n// webpieces-disable no-any-unknown -- `value` is the opaque consumer `gates` value until narrowed here\n// webpieces-disable no-function-outside-class -- module-level config validator, matches the rest of this file\nfunction validateGatesSection(value: unknown): string[] {\n if (!Array.isArray(value)) {\n return [`[pr-gate] \"gates\" must be an array of { name, patterns, warningColor, disabled? }.`];\n }\n const errors: string[] = [];\n for (let i = 0; i < value.length; i += 1) {\n errors.push(...validateGate(value[i], i));\n }\n return errors;\n}\n\n// webpieces-disable no-any-unknown -- one gate entry from opaque consumer JSON, validated field-by-field\nfunction validateGate(gate: unknown, index: number): string[] {\n if (typeof gate !== 'object' || gate === null) {\n return [`[pr-gate] gates[${index}] must be an object { name, patterns, warningColor, disabled? }.`];\n }\n // webpieces-disable no-any-unknown -- narrowing one opaque gate object from consumer JSON\n const g = gate as Record<string, unknown>;\n const errors: string[] = [];\n if (typeof g['name'] !== 'string') errors.push(`[pr-gate] gates[${index}].name must be a string.`);\n if (!Array.isArray(g['patterns']) || !g['patterns'].every(p => typeof p === 'string'))\n errors.push(`[pr-gate] gates[${index}].patterns must be string[].`);\n if (g['warningColor'] === undefined)\n errors.push(`[pr-gate] gates[${index}].warningColor is required — set it to \"yellow\" or \"red\" (green is implicit when nothing matches).`);\n else if (g['warningColor'] !== 'yellow' && g['warningColor'] !== 'red')\n errors.push(`[pr-gate] gates[${index}].warningColor must be \"yellow\" or \"red\" (green is implicit when nothing matches).`);\n if (g['disabled'] !== undefined && typeof g['disabled'] !== 'boolean')\n errors.push(`[pr-gate] gates[${index}].disabled must be a boolean (example/inactive gate kept in the file).`);\n return errors;\n}\n\n/**\n * Validate the top-level `pr-gate` section. It is REQUIRED (a client that opts out sets mode \"OFF\").\n * `buildCommand` is required unless mode is \"OFF\". Returns human-readable, copy-paste-friendly errors\n * — never throws. The pr-gate block lives outside the FieldDef-driven `rules` schema because its\n * nested `gates`/`checklists` arrays can't be expressed there, so they get structural validation here.\n * `repoRoot` (when known) lets the `checklists[].docs` existence check run.\n */\n// webpieces-disable no-any-unknown -- `section` is opaque consumer JSON until narrowed below\n// webpieces-disable no-function-outside-class -- module-level config validator, matches the rest of this file\nexport function validatePrGateSection(section: unknown, repoRoot?: string): string[] {\n if (section === undefined || section === null) {\n return [\n `[pr-gate] Not configured in webpieces.config.json. Add this block under the \"commands\" ` +\n `section (set \"mode\": \"OFF\" to opt out):\\n\\n${prGateExample()}`,\n ];\n }\n if (typeof section !== 'object' || Array.isArray(section)) {\n return [`[pr-gate] Must be an object. Example:\\n\\n${prGateExample()}`];\n }\n // webpieces-disable no-any-unknown -- narrowing the opaque pr-gate section from consumer JSON\n const s = section as Record<string, unknown>;\n const errors: string[] = [];\n\n if (!('mode' in s)) {\n errors.push(`[pr-gate] Missing required field \"mode\". Must be one of: ${PR_GATE_MODES.join(', ')}.`);\n } else if (typeof s['mode'] !== 'string' || !PR_GATE_MODES.includes(s['mode'] as typeof PR_GATE_MODES[number])) {\n errors.push(`[pr-gate] \"mode\" = \"${String(s['mode'])}\" is not valid. Must be one of: ${PR_GATE_MODES.join(', ')}.`);\n }\n\n // buildCommand and mergeMode are both required whenever the gate is active (mode !== OFF). There\n // is deliberately NO default for mergeMode: whether the tooling may land your PRs is a policy\n // decision, and either guess is wrong for somebody.\n if (s['mode'] !== 'OFF') {\n const cmd = s['buildCommand'];\n if (typeof cmd !== 'string' || cmd.trim() === '') {\n errors.push(\n `[pr-gate] Missing required field \"buildCommand\" — the command CI runs to validate a PR. ` +\n `Add e.g. \"buildCommand\": \"pnpm nx affected --target=ci --base=$(git merge-base origin/main HEAD)\".`,\n );\n }\n const mm = s['mergeMode'];\n if (!('mergeMode' in s)) {\n errors.push(`[pr-gate] Missing required field \"mergeMode\". ${MERGE_MODE_HELP}`);\n } else if (typeof mm !== 'string' || !PR_GATE_MERGE_MODES.includes(mm as typeof PR_GATE_MERGE_MODES[number])) {\n errors.push(`[pr-gate] \"mergeMode\" = \"${String(mm)}\" is not valid. ${MERGE_MODE_HELP}`);\n }\n errors.push(...validateReviewerAgentKeys(s, repoRoot));\n }\n\n if ('gates' in s) errors.push(...validateGatesSection(s['gates']));\n\n // Optional extension point: company review checklists, as an ARRAY right here in the config. Absent ⇒\n // none. The removed { doc } manifest shape is rejected with the exact migration edit.\n if ('checklists' in s) errors.push(...validateChecklistsSection(s['checklists'], repoRoot));\n\n // Optional server-token salt. Absent ⇒ no token minted, CI enforcement is a no-op. Present ⇒ must be\n // a non-empty string (an empty salt would mint a token anyone can forge from a known-empty secret).\n if ('gateSalt' in s) {\n const salt = s['gateSalt'];\n if (typeof salt !== 'string' || salt.trim() === '') {\n errors.push(`[pr-gate] \"gateSalt\" must be a non-empty string — it is the shared secret the gate token is HMAC'd with. Omit the key entirely to disable server-side token enforcement.`);\n }\n }\n\n // Optional: what happens to the LOCAL branch once its PR lands. Absent ⇒ \"archive-tag\".\n if ('landPr' in s) errors.push(...validateLandPrSection(s['landPr']));\n\n // Optional: where wp-push-dev publishes the disposable copy. Absent ⇒ \"dev-include\" / \"dev\".\n if ('devDeploy' in s) errors.push(...validateDevDeploySection(s['devDeploy']));\n\n errors.push(...validateNoGateSaltRationale(s));\n\n // Optional: publish reviewer output as a PR comment (defaults true). Must be a boolean when present.\n if ('checklistComments' in s && typeof s['checklistComments'] !== 'boolean') {\n errors.push(`[pr-gate] \"checklistComments\" must be a boolean (defaults to true; set false to keep the PR body-only).`);\n }\n\n return errors;\n}\n\nfunction excludePathsExample(): string {\n return '\"excludePaths\": [\"repositories/**\"]';\n}\n\n// A glob list: must be a string[] (may be empty). `key` names it for the error.\n// webpieces-disable no-any-unknown -- `value` is opaque consumer JSON until narrowed here\nfunction validateExcludeList(value: unknown, key: string): string[] {\n if (!(Array.isArray(value) && value.every(p => typeof p === 'string'))) {\n return [`[excludePaths] \"${key}\" must be a string[] of glob paths (use [] for none).`];\n }\n return [];\n}\n\n/**\n * Validate the REQUIRED top-level `excludePaths` block: ONE glob list suppressing hook enforcement per\n * file path, for code-style rules and file-scoped guards alike. Required so every client upgrading is\n * forced to declare it (as [] to keep today's behavior, or with real paths). Returns copy-paste\n * friendly errors and never throws — same contract as validatePrGateSection.\n *\n * The two-list object form `{ \"rules\": [...], \"guards\": [...] }` is RETIRED, not tolerated. It used to be\n * accepted and silently unioned, which is why this repo's own config sat on the dead shape for releases: an\n * accepted shape is never migrated. Rejecting it cannot wedge a consumer — editing webpieces.config.json is\n * always permitted, even while it is invalid. See retired-config-keys.ts.\n */\n// webpieces-disable no-any-unknown -- `section` is opaque consumer JSON until narrowed below\nexport function validateExcludePaths(section: unknown): string[] {\n if (section === undefined || section === null) {\n return [\n `[excludePaths] Not configured in webpieces.config.json. Add this REQUIRED block ` +\n `(use an empty array to keep enforcing everywhere):\\n\\n ${excludePathsExample()}`,\n ];\n }\n if (Array.isArray(section)) return validateExcludeList(section, 'excludePaths');\n if (typeof section !== 'object') {\n return [`[excludePaths] Must be a string[] of glob paths. Example:\\n\\n ${excludePathsExample()}`];\n }\n // webpieces-disable no-any-unknown -- narrowing the opaque excludePaths section from consumer JSON\n const s = section as Record<string, unknown>;\n // The retired two-list object. One table row owns the message for either key present.\n const retired = retiredEntry('rules', '[excludePaths]');\n if (retired && (s['rules'] !== undefined || s['guards'] !== undefined)) {\n return [`${retiredKeyError(retired)}\\n\\n ${excludePathsExample()}`];\n }\n return [`[excludePaths] Must be a string[] of glob paths. Example:\\n\\n ${excludePathsExample()}`];\n}\n\n// ---------------------------------------------------------------------------\n// match-rules — a new top-level ARRAY section (parallel to pr-gate/excludePaths). Each entry is a\n// client-authored content guard (raw-regex patterns + message + scoping). Validated structurally here\n// the same way pr-gate's `gates` are, because an array of objects can't be expressed in FieldDef schema.\n// ---------------------------------------------------------------------------\n\nfunction matchRulesExample(): string {\n return `\"match-rules\": ${JSON.stringify(DEFAULT_MATCH_RULES, null, 4)}`;\n}\n\n// webpieces-disable no-any-unknown -- generic type guard over an opaque JSON value\nfunction isStringArray(value: unknown): value is string[] {\n return Array.isArray(value) && value.every(v => typeof v === 'string');\n}\n\n// Compile a pattern to validate it; returns the error message, or undefined when it compiles.\nfunction regexError(pattern: string): string | undefined {\n // eslint-disable-next-line @webpieces/no-unmanaged-exceptions\n try {\n // Constructed only to validate the syntax; the object is intentionally discarded.\n void new RegExp(pattern);\n return undefined;\n } catch (err: unknown) {\n const error = toError(err);\n return error.message;\n }\n}\n\n// One entry of the match-rules array, validated field-by-field (see validateGate for the pattern).\n// webpieces-disable no-any-unknown -- one match-rule entry from opaque consumer JSON, validated field-by-field\nfunction validateMatchRule(entry: unknown, index: number): string[] {\n if (typeof entry !== 'object' || entry === null || Array.isArray(entry)) {\n return [`[match-rules] entry[${index}] must be an object { name, patterns, mainMessage, mode, turnOffRuleUntilEpoch, turnOffRuleWhileOnBranch, ... }.`];\n }\n // webpieces-disable no-any-unknown -- narrowing one opaque match-rule entry from consumer JSON\n const e = entry as Record<string, unknown>;\n const label = typeof e['name'] === 'string' ? `\"${e['name']}\"` : `entry[${index}]`;\n const errors: string[] = [];\n\n if (typeof e['name'] !== 'string' || e['name'].trim() === '')\n errors.push(`[match-rules] entry[${index}].name must be a non-empty string (it is the disable token and report label).`);\n\n if (!isStringArray(e['patterns']) || e['patterns'].length === 0) {\n errors.push(`[match-rules] ${label}.patterns must be a non-empty string[] of regexes.`);\n } else {\n e['patterns'].forEach((p: string, pi: number) => {\n const rxErr = regexError(p);\n if (rxErr) errors.push(`[match-rules] ${label}.patterns[${pi}] is not a valid regex: ${rxErr}`);\n });\n }\n\n if (typeof e['mainMessage'] !== 'string' || e['mainMessage'].trim() === '')\n errors.push(`[match-rules] ${label}.mainMessage must be a non-empty string.`);\n\n if (typeof e['mode'] !== 'string' || !MODIFIED_CODE_MODES.includes(e['mode'] as typeof MODIFIED_CODE_MODES[number]))\n errors.push(`[match-rules] ${label}.mode must be one of: ${MODIFIED_CODE_MODES.join(', ')}.`);\n\n // Both escape hatches are REQUIRED on every match-rule too (same as keyed rules), so they are always\n // visible. turnOffRuleUntilEpoch: number (0 = active; a future unix-epoch in seconds = temporarily\n // off). turnOffRuleWhileOnBranch: string | null (null = always on; an EXACT branch name — matched\n // with ===, never as a glob — disables the rule while that branch is checked out).\n if (typeof e['turnOffRuleUntilEpoch'] !== 'number') {\n errors.push(`[match-rules] ${label}.turnOffRuleUntilEpoch must be a number (0 = active; future unix-epoch seconds = temporarily off).`);\n } else {\n const capError = epochCapError(`[match-rules] ${label}`, e['turnOffRuleUntilEpoch']);\n if (capError) errors.push(capError);\n }\n if (!(e['turnOffRuleWhileOnBranch'] === null || typeof e['turnOffRuleWhileOnBranch'] === 'string'))\n errors.push(`[match-rules] ${label}.turnOffRuleWhileOnBranch must be a string or null (null = no branch / always on; a string is an EXACT branch name, globs are not supported).`);\n\n // The old escape-hatch names were renamed — flag them precisely.\n for (const oldKey of Object.keys(RENAMED_FIELD_ALIASES)) {\n if (oldKey in e) errors.push(renamedFieldError(`[match-rules] ${label}`, oldKey, RENAMED_FIELD_ALIASES[oldKey]));\n }\n\n if (e['options'] !== undefined && !isStringArray(e['options']))\n errors.push(`[match-rules] ${label}.options must be a string[] (omit if not needed).`);\n if (e['allowedPaths'] !== undefined && !isStringArray(e['allowedPaths']))\n errors.push(`[match-rules] ${label}.allowedPaths must be a string[] of globs (omit if not needed).`);\n if (e['disableAllowed'] !== undefined && typeof e['disableAllowed'] !== 'boolean')\n errors.push(`[match-rules] ${label}.disableAllowed must be a boolean.`);\n\n return errors;\n}\n\n/**\n * Validate the REQUIRED top-level `match-rules` array (client-authored content guards). MISSING →\n * one error printing the ready-to-paste `no-fetch` example (add at least this; more can follow).\n * Present-but-`[]` → allowed (a conscious opt-out, matching pr-gate mode:OFF / excludePaths []).\n * Otherwise every entry is validated field-by-field (each regex compile-checked) plus name\n * uniqueness. Copy-paste-friendly errors; never throws — same contract as validatePrGateSection.\n */\n// webpieces-disable no-any-unknown -- `section` is opaque consumer JSON until narrowed below\nexport function validateMatchRulesSection(section: unknown): string[] {\n if (section === undefined || section === null) {\n return [\n `[match-rules] Not configured in webpieces.config.json. Add this REQUIRED top-level array — ` +\n `seed it with the no-fetch guard below (you can add more entries: no-moment, no-lodash-chain, …):\\n\\n${matchRulesExample()}`,\n ];\n }\n if (!Array.isArray(section)) {\n return [`[match-rules] Must be an array of content-guard objects. Example:\\n\\n${matchRulesExample()}`];\n }\n\n const errors: string[] = [];\n const seen = new Set<string>();\n for (let i = 0; i < section.length; i += 1) {\n errors.push(...validateMatchRule(section[i], i));\n // webpieces-disable no-any-unknown -- reading the name off an opaque entry only to dedupe\n const name = (section[i] as Record<string, unknown> | null)?.['name'];\n if (typeof name === 'string') {\n if (seen.has(name)) errors.push(`[match-rules] duplicate entry name \"${name}\" — each match-rule name must be unique.`);\n seen.add(name);\n }\n }\n return errors;\n}\n\n/**\n * Enforce that each built-in lives in its correct section: code rules under `rules`, bash guards\n * under `hookGuards`. A guard left in `rules` (or a rule placed in `hookGuards`) is reported with a\n * \"move it\" message so the split stays clean. Unknown/custom names are ignored (they may be custom\n * rules from rulesDir). Presence (\"every built-in must be configured\") is checked separately by\n * validateWebpiecesConfig against the merged map.\n */\n// webpieces-disable no-any-unknown -- section maps are opaque consumer JSON\nexport function validateSectionPlacement(\n rulesSection: Record<string, Record<string, unknown>>,\n hookGuardsSection: Record<string, Record<string, unknown>>,\n): string[] {\n const errors: string[] = [];\n for (const name of Object.keys(rulesSection)) {\n if (isHookGuard(name)) {\n errors.push(\n `[${name}] is a hook guard and ${SECTION_PLACEMENT_MARKER} \"hookGuards\" section, not \"rules\". ` +\n `Move it.`,\n );\n }\n }\n for (const name of Object.keys(hookGuardsSection)) {\n // Only flag KNOWN code rules misplaced into hookGuards; unknown names may be custom rules.\n if (!isHookGuard(name) && RULE_SCHEMAS[name]) {\n errors.push(\n `[${name}] is a code rule and ${SECTION_PLACEMENT_MARKER} \"rules\" section, not \"hookGuards\". ` +\n `Move it.`,\n );\n }\n }\n return errors;\n}\n"]}