@webpieces/rules-config 0.4.619 → 0.4.621

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":"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 { validateChecklistsSection, validateDevDeploySection, validateLandPrSection, validateNoGateSaltRationale } from './pr-gate-section-validators';\nimport { retiredEntry, retiredKeyError, retiredRuleFor } from './retired-config-keys';\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\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; a branch name 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// A config key under rules/hookGuards that the RUNNING validator has no schema for (and no rulesDir is\n// set to supply custom rules). Two very different causes, so the message leads with the common one:\n// 1. Version skew (most common — happens right after a dep bump): webpieces.config.json references a\n// rule a NEWER @webpieces release added, but the installed guard is OLDER and doesn't know it yet.\n// Fix = `pnpm install` (NOT deleting the key — the key is valid, the validator is just stale).\n// 2. A genuinely removed/renamed rule left behind, or a typo. Fix = remove the key.\n// Do NOT tell the AI to delete first — that destroys valid config in case 1 (the trap that made the AI\n// gut a working config instead of running `pnpm install`). The banner in load-config.ts spells out the\n// ordered \"run pnpm install, THEN edit only if it persists\" fix.\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. Most often this means your installed guard is a ` +\n `release BEHIND this webpieces.config.json: run \\`pnpm install\\` first (see the fix steps below) so ` +\n `the validator learns \"${ruleName}\". Only if it is STILL unknown after a fresh install is it a ` +\n `removed/renamed rule or a typo — then remove the \"${ruleName}\" key from webpieces.config.json.`\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};\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// 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 unknown-rule message, which leads with \"run `pnpm\n // install`, your validator may be stale\" — precisely the wrong advice for a dead name. It\n // fires even when a rulesDir is set, because a custom rule 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 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 }\n }\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 ` \"checklists\": [ // OPTIONAL — per-area review, one distinct reviewer subagent each\\n` +\n ` { \"subagent\": \"db-migration-reviewer\", \"doc\": \".claude/review/db-migrations.md\", \"patterns\": [\"**/*.sql\"] }\\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 }\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; a branch name disables the rule\n // 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 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).`);\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":";;;AA2IA,0DAqEC;AAmFD,sDAoEC;AA2BD,oDAmBC;AA2FD,8DAuBC;AAUD,4DAuBC;AAriBD,wGAAwG;AACxG,kFAAkF;AAClF,+DAAiE;AACjE,yCAAyD;AACzD,iDAA4D;AAC5D,6CAAqE;AACrE,iDAAqD;AACrD,6EAAuJ;AAK9I,0GALA,sDAAyB,OAKA;AAJlC,+DAAsF;AACtF,2CAAoD;AAIpD,yFAAyF;AACzF,+CAA8C;AAArC,4GAAA,YAAY,OAAA;AACrB,2CAA6F;AAApF,iHAAA,mBAAmB,OAAA;AAAE,oHAAA,sBAAsB,OAAA;AAAE,8GAAA,gBAAgB,OAAA;AACtE,6DAA2D;AAC3D,yCAAqC;AAErC,SAAS,SAAS,CAAC,GAAa,EAAE,GAAY;IAC1C,oGAAoG;IACpG,oGAAoG;IACpG,IAAI,GAAG,KAAK,uBAAuB;QAAE,OAAO,8DAA8D,CAAC;IAC3G,IAAI,GAAG,KAAK,0BAA0B;QAAE,OAAO,4FAA4F,CAAC;IAC5I,OAAO,GAAG,CAAC,UAAU;QACjB,CAAC,CAAC,IAAI,GAAG,CAAC,UAAU,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG;QACnC,CAAC,CAAC,GAAG,CAAC,IAAI,KAAK,UAAU,CAAC,CAAC,CAAC,mBAAmB;YAC/C,CAAC,CAAC,GAAG,CAAC,IAAI,KAAK,QAAQ,CAAG,CAAC,CAAC,UAAU;gBACtC,CAAC,CAAC,GAAG,CAAC,IAAI,KAAK,SAAS,CAAE,CAAC,CAAC,WAAW;oBACvC,CAAC,CAAC,YAAY,CAAC;AACvB,CAAC;AAED,yGAAyG;AACzG,SAAS,UAAU,CAAC,MAAgC;IAChD,MAAM,KAAK,GAAG,MAAM,CAAC,MAAM,CAAC,EAAE,UAAU,IAAI,EAAE,CAAC;IAC/C,iGAAiG;IACjG,8FAA8F;IAC9F,MAAM,WAAW,GAAG,IAAA,mCAAsB,EAAC,KAAK,CAAC,CAAC;IAClD,IAAI,CAAC,IAAA,0BAAa,EAAC,WAAW,CAAC;QAAE,OAAO,EAAE,CAAC;IAC3C,MAAM,MAAM,GAAG,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,yCAAyC,CAAC,CAAC,CAAC,EAAE,CAAC;IACtF,OAAO,CACH,2CAA2C,WAAW,mCAAmC;QACzF,4FAA4F;QAC5F,4CAA4C,MAAM,EAAE,CACvD,CAAC;AACN,CAAC;AAED,SAAS,kBAAkB,CAAC,QAAgB,EAAE,MAAgC;IAC1E,+EAA+E;IAC/E,oGAAoG;IACpG,yGAAyG;IACzG,MAAM,MAAM,GAAG,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IACnC,MAAM,QAAQ,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC;IACzD,MAAM,QAAQ,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC;IAExD,MAAM,aAAa,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,QAAQ,CAAC,MAAM,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC;IAClF,MAAM,OAAO,GAAG,IAAA,yBAAc,EAAC,QAAQ,CAAC,CAAC;IACzC,IAAI,GAAG,GACH,IAAI,QAAQ,qEAAqE,OAAO,aAAa;QACrG,mDAAmD;QACnD,MAAM,QAAQ,SAAS,aAAa,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC;IAE5D,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACtB,MAAM,aAAa,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,QAAQ,CAAC,MAAM,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC;QAClF,GAAG;YACC,sEAAsE;gBACtE,GAAG,aAAa,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;IACvC,CAAC;IACD,GAAG,IAAI,UAAU,CAAC,MAAM,CAAC,CAAC;IAC1B,OAAO,GAAG,CAAC;AACf,CAAC;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,SAAS,gBAAgB,CAAC,QAAgB;IACtC,OAAO,CACH,IAAI,QAAQ,iFAAiF;QAC7F,iGAAiG;QACjG,eAAe,QAAQ,4CAA4C,iCAAqB,QAAQ;QAChG,mGAAmG;QACnG,6FAA6F;QAC7F,mGAAmG;QACnG,sFAAsF;QACtF,IAAI,QAAQ,oFAAoF;QAChG,mGAAmG;QACnG,mGAAmG;QACnG,6DAA6D,CAChE,CAAC;AACN,CAAC;AAED,qGAAqG;AACrG,wGAAwG;AACxG,iGAAiG;AACjG,MAAM,mBAAmB,GAA2B;IAChD,mCAAmC,EAC/B,8FAA8F;QAC9F,2EAA2E;IAC/E,sCAAsC,EAClC,8FAA8F;QAC9F,iGAAiG;QACjG,wDAAwD;CAC/D,CAAC;AAEF,+FAA+F;AAC/F,sGAAsG;AACtG,oGAAoG;AACpG,MAAM,qBAAqB,GAA2B;IAClD,wBAAwB,EAAE,uBAAuB;IACjD,uBAAuB,EAAE,0BAA0B;CACtD,CAAC;AAGF,mEAAmE;AACnE,8GAA8G;AAC9G,SAAS,iBAAiB,CAAC,KAAa,EAAE,MAAc,EAAE,MAAc;IACpE,OAAO,GAAG,KAAK,mBAAmB,MAAM,0BAA0B,MAAM,0GAA0G,CAAC;AACvL,CAAC;AAED,4GAA4G;AAC5G,SAAgB,uBAAuB,CACnC,QAAiD,EACjD,oBAA6B,KAAK;IAElC,MAAM,MAAM,GAAa,EAAE,CAAC;IAE5B,2DAA2D;IAC3D,KAAK,MAAM,CAAC,QAAQ,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAC;QACvD,MAAM,MAAM,GAAG,2BAAY,CAAC,QAAQ,CAAC,CAAC;QACtC,IAAI,CAAC,MAAM,EAAE,CAAC;YACV,2FAA2F;YAC3F,yFAAyF;YACzF,2FAA2F;YAC3F,iCAAiC;YACjC,MAAM,OAAO,GAAG,IAAA,oCAAc,EAAC,QAAQ,CAAC,CAAC;YACzC,IAAI,OAAO,EAAE,CAAC;gBACV,MAAM,CAAC,IAAI,CAAC,IAAA,qCAAe,EAAC,OAAO,CAAC,CAAC,CAAC;gBACtC,SAAS;YACb,CAAC;YACD,mFAAmF;YACnF,0FAA0F;YAC1F,sFAAsF;YACtF,IAAI,CAAC,iBAAiB;gBAAE,MAAM,CAAC,IAAI,CAAC,gBAAgB,CAAC,QAAQ,CAAC,CAAC,CAAC;YAChE,SAAS;QACb,CAAC;QACD,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;YAC/C,MAAM,QAAQ,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC;YAC7B,IAAI,CAAC,QAAQ,EAAE,CAAC;gBACZ,MAAM,SAAS,GAAG,qBAAqB,CAAC,GAAG,CAAC,CAAC;gBAC7C,IAAI,SAAS,EAAE,CAAC;oBACZ,MAAM,CAAC,IAAI,CAAC,iBAAiB,CAAC,IAAI,QAAQ,GAAG,EAAE,GAAG,EAAE,SAAS,CAAC,CAAC,CAAC;oBAChE,SAAS;gBACb,CAAC;gBACD,MAAM,WAAW,GAAG,mBAAmB,CAAC,GAAG,QAAQ,IAAI,GAAG,EAAE,CAAC,CAAC;gBAC9D,MAAM,MAAM,GAAG,WAAW,CAAC,CAAC,CAAC,IAAI,WAAW,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;gBACpD,MAAM,CAAC,IAAI,CAAC,IAAI,QAAQ,oBAAoB,GAAG,qBAAqB,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,MAAM,EAAE,CAAC,CAAC;gBACjH,SAAS;YACb,CAAC;YACD,8FAA8F;YAC9F,IAAI,KAAK,KAAK,IAAI,IAAI,QAAQ,CAAC,QAAQ;gBAAE,SAAS;YAClD,IAAI,QAAQ,CAAC,IAAI,KAAK,UAAU,EAAE,CAAC;gBAC/B,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC,KAAK,QAAQ,CAAC;oBACjE,MAAM,CAAC,IAAI,CAAC,IAAI,QAAQ,MAAM,GAAG,2BAA2B,OAAO,KAAK,GAAG,CAAC,CAAC;YACrF,CAAC;iBAAM,IAAI,OAAO,KAAK,KAAK,QAAQ,CAAC,IAAI,EAAE,CAAC;gBACxC,MAAM,CAAC,IAAI,CAAC,IAAI,QAAQ,MAAM,GAAG,aAAa,QAAQ,CAAC,IAAI,SAAS,OAAO,KAAK,GAAG,CAAC,CAAC;YACzF,CAAC;iBAAM,IAAI,QAAQ,CAAC,UAAU,IAAI,CAAC,QAAQ,CAAC,UAAU,CAAC,QAAQ,CAAC,KAAe,CAAC,EAAE,CAAC;gBAC/E,MAAM,CAAC,IAAI,CAAC,IAAI,QAAQ,MAAM,GAAG,QAAQ,KAAK,mCAAmC,QAAQ,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;YACxH,CAAC;QACL,CAAC;QACD,kFAAkF;QAClF,2EAA2E;QAC3E,0FAA0F;QAC1F,KAAK,MAAM,CAAC,GAAG,EAAE,QAAQ,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;YACnD,IAAI,CAAC,QAAQ,CAAC,QAAQ,IAAI,CAAC,CAAC,GAAG,IAAI,KAAK,CAAC,EAAE,CAAC;gBACxC,MAAM,CAAC,IAAI,CAAC,IAAI,QAAQ,6BAA6B,GAAG,UAAU,GAAG,KAAK,SAAS,CAAC,QAAQ,EAAE,GAAG,CAAC,GAAG,CAAC,CAAC;YAC3G,CAAC;QACL,CAAC;IACL,CAAC;IAED,0EAA0E;IAC1E,gFAAgF;IAChF,mEAAmE;IACnE,KAAK,MAAM,CAAC,QAAQ,EAAE,MAAM,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,2BAAY,CAAC,EAAE,CAAC;QAC5D,IAAI,CAAC,CAAC,QAAQ,IAAI,QAAQ,CAAC,EAAE,CAAC;YAC1B,MAAM,CAAC,IAAI,CAAC,kBAAkB,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC,CAAC;QACtD,CAAC;IACL,CAAC;IAED,OAAO,MAAM,CAAC;AAClB,CAAC;AAED,MAAM,aAAa,GAAG,CAAC,IAAI,EAAE,KAAK,CAAU,CAAC;AAC7C,6FAA6F;AAC7F,yFAAyF;AACzF,MAAM,mBAAmB,GAAG,CAAC,MAAM,EAAE,MAAM,CAAU,CAAC;AAEtD,iGAAiG;AACjG,kGAAkG;AAClG,+FAA+F;AAC/F,MAAM,eAAe,GAAG,CAChB,mBAAmB,mBAAmB,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK;IACtD,8FAA8F;IAC9F,+FAA+F;IAC/F,kGAAkG;IAClG,oEAAoE;IACpE,+FAA+F;IAC/F,2GAA2G;IAC3G,mGAAmG;IACnG,uEAAuE,CAC9E,CAAC;AAEF,gGAAgG;AAChG,6FAA6F;AAC7F,SAAS,aAAa;IAClB,OAAO,CACH,kBAAkB;QAClB,qBAAqB;QACrB,0IAA0I;QAC1I,kBAAkB;QAClB,8GAA8G;QAC9G,UAAU;QACV,4FAA4F;QAC5F,qHAAqH;QACrH,SAAS;QACT,KAAK,CACR,CAAC;AACN,CAAC;AAED,qGAAqG;AACrG,kCAAkC;AAClC,uGAAuG;AACvG,8GAA8G;AAC9G,SAAS,oBAAoB,CAAC,KAAc;IACxC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;QACxB,OAAO,CAAC,oFAAoF,CAAC,CAAC;IAClG,CAAC;IACD,MAAM,MAAM,GAAa,EAAE,CAAC;IAC5B,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC;QACvC,MAAM,CAAC,IAAI,CAAC,GAAG,YAAY,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;IAC9C,CAAC;IACD,OAAO,MAAM,CAAC;AAClB,CAAC;AAED,yGAAyG;AACzG,SAAS,YAAY,CAAC,IAAa,EAAE,KAAa;IAC9C,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,IAAI,KAAK,IAAI,EAAE,CAAC;QAC5C,OAAO,CAAC,mBAAmB,KAAK,kEAAkE,CAAC,CAAC;IACxG,CAAC;IACD,0FAA0F;IAC1F,MAAM,CAAC,GAAG,IAA+B,CAAC;IAC1C,MAAM,MAAM,GAAa,EAAE,CAAC;IAC5B,IAAI,OAAO,CAAC,CAAC,MAAM,CAAC,KAAK,QAAQ;QAAE,MAAM,CAAC,IAAI,CAAC,mBAAmB,KAAK,0BAA0B,CAAC,CAAC;IACnG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC,KAAK,QAAQ,CAAC;QACjF,MAAM,CAAC,IAAI,CAAC,mBAAmB,KAAK,8BAA8B,CAAC,CAAC;IACxE,IAAI,CAAC,CAAC,cAAc,CAAC,KAAK,SAAS;QAC/B,MAAM,CAAC,IAAI,CAAC,mBAAmB,KAAK,oGAAoG,CAAC,CAAC;SACzI,IAAI,CAAC,CAAC,cAAc,CAAC,KAAK,QAAQ,IAAI,CAAC,CAAC,cAAc,CAAC,KAAK,KAAK;QAClE,MAAM,CAAC,IAAI,CAAC,mBAAmB,KAAK,oFAAoF,CAAC,CAAC;IAC9H,IAAI,CAAC,CAAC,UAAU,CAAC,KAAK,SAAS,IAAI,OAAO,CAAC,CAAC,UAAU,CAAC,KAAK,SAAS;QACjE,MAAM,CAAC,IAAI,CAAC,mBAAmB,KAAK,wEAAwE,CAAC,CAAC;IAClH,OAAO,MAAM,CAAC;AAClB,CAAC;AAED;;;;;;GAMG;AACH,6FAA6F;AAC7F,8GAA8G;AAC9G,SAAgB,qBAAqB,CAAC,OAAgB,EAAE,QAAiB;IACrE,IAAI,OAAO,KAAK,SAAS,IAAI,OAAO,KAAK,IAAI,EAAE,CAAC;QAC5C,OAAO;YACH,yFAAyF;gBACzF,8CAA8C,aAAa,EAAE,EAAE;SAClE,CAAC;IACN,CAAC;IACD,IAAI,OAAO,OAAO,KAAK,QAAQ,IAAI,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC;QACxD,OAAO,CAAC,4CAA4C,aAAa,EAAE,EAAE,CAAC,CAAC;IAC3E,CAAC;IACD,8FAA8F;IAC9F,MAAM,CAAC,GAAG,OAAkC,CAAC;IAC7C,MAAM,MAAM,GAAa,EAAE,CAAC;IAE5B,IAAI,CAAC,CAAC,MAAM,IAAI,CAAC,CAAC,EAAE,CAAC;QACjB,MAAM,CAAC,IAAI,CAAC,4DAA4D,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IACzG,CAAC;SAAM,IAAI,OAAO,CAAC,CAAC,MAAM,CAAC,KAAK,QAAQ,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAiC,CAAC,EAAE,CAAC;QAC7G,MAAM,CAAC,IAAI,CAAC,uBAAuB,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,mCAAmC,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IACxH,CAAC;IAED,iGAAiG;IACjG,8FAA8F;IAC9F,oDAAoD;IACpD,IAAI,CAAC,CAAC,MAAM,CAAC,KAAK,KAAK,EAAE,CAAC;QACtB,MAAM,GAAG,GAAG,CAAC,CAAC,cAAc,CAAC,CAAC;QAC9B,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,GAAG,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC;YAC/C,MAAM,CAAC,IAAI,CACP,0FAA0F;gBAC1F,oGAAoG,CACvG,CAAC;QACN,CAAC;QACD,MAAM,EAAE,GAAG,CAAC,CAAC,WAAW,CAAC,CAAC;QAC1B,IAAI,CAAC,CAAC,WAAW,IAAI,CAAC,CAAC,EAAE,CAAC;YACtB,MAAM,CAAC,IAAI,CAAC,iDAAiD,eAAe,EAAE,CAAC,CAAC;QACpF,CAAC;aAAM,IAAI,OAAO,EAAE,KAAK,QAAQ,IAAI,CAAC,mBAAmB,CAAC,QAAQ,CAAC,EAAwC,CAAC,EAAE,CAAC;YAC3G,MAAM,CAAC,IAAI,CAAC,4BAA4B,MAAM,CAAC,EAAE,CAAC,mBAAmB,eAAe,EAAE,CAAC,CAAC;QAC5F,CAAC;IACL,CAAC;IAED,IAAI,OAAO,IAAI,CAAC;QAAE,MAAM,CAAC,IAAI,CAAC,GAAG,oBAAoB,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;IAEnE,sGAAsG;IACtG,sFAAsF;IACtF,IAAI,YAAY,IAAI,CAAC;QAAE,MAAM,CAAC,IAAI,CAAC,GAAG,IAAA,sDAAyB,EAAC,CAAC,CAAC,YAAY,CAAC,EAAE,QAAQ,CAAC,CAAC,CAAC;IAE5F,qGAAqG;IACrG,oGAAoG;IACpG,IAAI,UAAU,IAAI,CAAC,EAAE,CAAC;QAClB,MAAM,IAAI,GAAG,CAAC,CAAC,UAAU,CAAC,CAAC;QAC3B,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,IAAI,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC;YACjD,MAAM,CAAC,IAAI,CAAC,0KAA0K,CAAC,CAAC;QAC5L,CAAC;IACL,CAAC;IAED,wFAAwF;IACxF,IAAI,QAAQ,IAAI,CAAC;QAAE,MAAM,CAAC,IAAI,CAAC,GAAG,IAAA,kDAAqB,EAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;IAEtE,6FAA6F;IAC7F,IAAI,WAAW,IAAI,CAAC;QAAE,MAAM,CAAC,IAAI,CAAC,GAAG,IAAA,qDAAwB,EAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC;IAE/E,MAAM,CAAC,IAAI,CAAC,GAAG,IAAA,wDAA2B,EAAC,CAAC,CAAC,CAAC,CAAC;IAE/C,qGAAqG;IACrG,IAAI,mBAAmB,IAAI,CAAC,IAAI,OAAO,CAAC,CAAC,mBAAmB,CAAC,KAAK,SAAS,EAAE,CAAC;QAC1E,MAAM,CAAC,IAAI,CAAC,yGAAyG,CAAC,CAAC;IAC3H,CAAC;IAED,OAAO,MAAM,CAAC;AAClB,CAAC;AAED,SAAS,mBAAmB;IACxB,OAAO,qCAAqC,CAAC;AACjD,CAAC;AAED,gFAAgF;AAChF,0FAA0F;AAC1F,SAAS,mBAAmB,CAAC,KAAc,EAAE,GAAW;IACpD,IAAI,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC,KAAK,QAAQ,CAAC,CAAC,EAAE,CAAC;QACrE,OAAO,CAAC,mBAAmB,GAAG,uDAAuD,CAAC,CAAC;IAC3F,CAAC;IACD,OAAO,EAAE,CAAC;AACd,CAAC;AAED;;;;;;;;;;GAUG;AACH,6FAA6F;AAC7F,SAAgB,oBAAoB,CAAC,OAAgB;IACjD,IAAI,OAAO,KAAK,SAAS,IAAI,OAAO,KAAK,IAAI,EAAE,CAAC;QAC5C,OAAO;YACH,kFAAkF;gBAClF,2DAA2D,mBAAmB,EAAE,EAAE;SACrF,CAAC;IACN,CAAC;IACD,IAAI,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC;QAAE,OAAO,mBAAmB,CAAC,OAAO,EAAE,cAAc,CAAC,CAAC;IAChF,IAAI,OAAO,OAAO,KAAK,QAAQ,EAAE,CAAC;QAC9B,OAAO,CAAC,kEAAkE,mBAAmB,EAAE,EAAE,CAAC,CAAC;IACvG,CAAC;IACD,mGAAmG;IACnG,MAAM,CAAC,GAAG,OAAkC,CAAC;IAC7C,sFAAsF;IACtF,MAAM,OAAO,GAAG,IAAA,kCAAY,EAAC,OAAO,EAAE,gBAAgB,CAAC,CAAC;IACxD,IAAI,OAAO,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,SAAS,IAAI,CAAC,CAAC,QAAQ,CAAC,KAAK,SAAS,CAAC,EAAE,CAAC;QACrE,OAAO,CAAC,GAAG,IAAA,qCAAe,EAAC,OAAO,CAAC,SAAS,mBAAmB,EAAE,EAAE,CAAC,CAAC;IACzE,CAAC;IACD,OAAO,CAAC,kEAAkE,mBAAmB,EAAE,EAAE,CAAC,CAAC;AACvG,CAAC;AAED,8EAA8E;AAC9E,kGAAkG;AAClG,sGAAsG;AACtG,yGAAyG;AACzG,8EAA8E;AAE9E,SAAS,iBAAiB;IACtB,OAAO,kBAAkB,IAAI,CAAC,SAAS,CAAC,wCAAmB,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC;AAC5E,CAAC;AAED,mFAAmF;AACnF,SAAS,aAAa,CAAC,KAAc;IACjC,OAAO,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC,KAAK,QAAQ,CAAC,CAAC;AAC3E,CAAC;AAED,8FAA8F;AAC9F,SAAS,UAAU,CAAC,OAAe;IAC/B,8DAA8D;IAC9D,IAAI,CAAC;QACD,kFAAkF;QAClF,KAAK,IAAI,MAAM,CAAC,OAAO,CAAC,CAAC;QACzB,OAAO,SAAS,CAAC;IACrB,CAAC;IAAC,OAAO,GAAY,EAAE,CAAC;QACpB,MAAM,KAAK,GAAG,IAAA,kBAAO,EAAC,GAAG,CAAC,CAAC;QAC3B,OAAO,KAAK,CAAC,OAAO,CAAC;IACzB,CAAC;AACL,CAAC;AAED,mGAAmG;AACnG,+GAA+G;AAC/G,SAAS,iBAAiB,CAAC,KAAc,EAAE,KAAa;IACpD,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;QACtE,OAAO,CAAC,uBAAuB,KAAK,kHAAkH,CAAC,CAAC;IAC5J,CAAC;IACD,+FAA+F;IAC/F,MAAM,CAAC,GAAG,KAAgC,CAAC;IAC3C,MAAM,KAAK,GAAG,OAAO,CAAC,CAAC,MAAM,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,SAAS,KAAK,GAAG,CAAC;IACnF,MAAM,MAAM,GAAa,EAAE,CAAC;IAE5B,IAAI,OAAO,CAAC,CAAC,MAAM,CAAC,KAAK,QAAQ,IAAI,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE;QACxD,MAAM,CAAC,IAAI,CAAC,uBAAuB,KAAK,+EAA+E,CAAC,CAAC;IAE7H,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,CAAC,UAAU,CAAC,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC9D,MAAM,CAAC,IAAI,CAAC,iBAAiB,KAAK,oDAAoD,CAAC,CAAC;IAC5F,CAAC;SAAM,CAAC;QACJ,CAAC,CAAC,UAAU,CAAC,CAAC,OAAO,CAAC,CAAC,CAAS,EAAE,EAAU,EAAE,EAAE;YAC5C,MAAM,KAAK,GAAG,UAAU,CAAC,CAAC,CAAC,CAAC;YAC5B,IAAI,KAAK;gBAAE,MAAM,CAAC,IAAI,CAAC,iBAAiB,KAAK,aAAa,EAAE,2BAA2B,KAAK,EAAE,CAAC,CAAC;QACpG,CAAC,CAAC,CAAC;IACP,CAAC;IAED,IAAI,OAAO,CAAC,CAAC,aAAa,CAAC,KAAK,QAAQ,IAAI,CAAC,CAAC,aAAa,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE;QACtE,MAAM,CAAC,IAAI,CAAC,iBAAiB,KAAK,0CAA0C,CAAC,CAAC;IAElF,IAAI,OAAO,CAAC,CAAC,MAAM,CAAC,KAAK,QAAQ,IAAI,CAAC,kCAAmB,CAAC,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAuC,CAAC;QAC/G,MAAM,CAAC,IAAI,CAAC,iBAAiB,KAAK,yBAAyB,kCAAmB,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAElG,qGAAqG;IACrG,mGAAmG;IACnG,mGAAmG;IACnG,qCAAqC;IACrC,IAAI,OAAO,CAAC,CAAC,uBAAuB,CAAC,KAAK,QAAQ;QAC9C,MAAM,CAAC,IAAI,CAAC,iBAAiB,KAAK,oGAAoG,CAAC,CAAC;IAC5I,IAAI,CAAC,CAAC,CAAC,CAAC,0BAA0B,CAAC,KAAK,IAAI,IAAI,OAAO,CAAC,CAAC,0BAA0B,CAAC,KAAK,QAAQ,CAAC;QAC9F,MAAM,CAAC,IAAI,CAAC,iBAAiB,KAAK,oFAAoF,CAAC,CAAC;IAE5H,iEAAiE;IACjE,KAAK,MAAM,MAAM,IAAI,MAAM,CAAC,IAAI,CAAC,qBAAqB,CAAC,EAAE,CAAC;QACtD,IAAI,MAAM,IAAI,CAAC;YAAE,MAAM,CAAC,IAAI,CAAC,iBAAiB,CAAC,iBAAiB,KAAK,EAAE,EAAE,MAAM,EAAE,qBAAqB,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;IACrH,CAAC;IAED,IAAI,CAAC,CAAC,SAAS,CAAC,KAAK,SAAS,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC;QAC1D,MAAM,CAAC,IAAI,CAAC,iBAAiB,KAAK,mDAAmD,CAAC,CAAC;IAC3F,IAAI,CAAC,CAAC,cAAc,CAAC,KAAK,SAAS,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC;QACpE,MAAM,CAAC,IAAI,CAAC,iBAAiB,KAAK,iEAAiE,CAAC,CAAC;IACzG,IAAI,CAAC,CAAC,gBAAgB,CAAC,KAAK,SAAS,IAAI,OAAO,CAAC,CAAC,gBAAgB,CAAC,KAAK,SAAS;QAC7E,MAAM,CAAC,IAAI,CAAC,iBAAiB,KAAK,oCAAoC,CAAC,CAAC;IAE5E,OAAO,MAAM,CAAC;AAClB,CAAC;AAED;;;;;;GAMG;AACH,6FAA6F;AAC7F,SAAgB,yBAAyB,CAAC,OAAgB;IACtD,IAAI,OAAO,KAAK,SAAS,IAAI,OAAO,KAAK,IAAI,EAAE,CAAC;QAC5C,OAAO;YACH,6FAA6F;gBAC7F,uGAAuG,iBAAiB,EAAE,EAAE;SAC/H,CAAC;IACN,CAAC;IACD,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC;QAC1B,OAAO,CAAC,wEAAwE,iBAAiB,EAAE,EAAE,CAAC,CAAC;IAC3G,CAAC;IAED,MAAM,MAAM,GAAa,EAAE,CAAC;IAC5B,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAC;IAC/B,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC;QACzC,MAAM,CAAC,IAAI,CAAC,GAAG,iBAAiB,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;QACjD,0FAA0F;QAC1F,MAAM,IAAI,GAAI,OAAO,CAAC,CAAC,CAAoC,EAAE,CAAC,MAAM,CAAC,CAAC;QACtE,IAAI,OAAO,IAAI,KAAK,QAAQ,EAAE,CAAC;YAC3B,IAAI,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC;gBAAE,MAAM,CAAC,IAAI,CAAC,uCAAuC,IAAI,0CAA0C,CAAC,CAAC;YACvH,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QACnB,CAAC;IACL,CAAC;IACD,OAAO,MAAM,CAAC;AAClB,CAAC;AAED;;;;;;GAMG;AACH,4EAA4E;AAC5E,SAAgB,wBAAwB,CACpC,YAAqD,EACrD,iBAA0D;IAE1D,MAAM,MAAM,GAAa,EAAE,CAAC;IAC5B,KAAK,MAAM,IAAI,IAAI,MAAM,CAAC,IAAI,CAAC,YAAY,CAAC,EAAE,CAAC;QAC3C,IAAI,IAAA,sBAAW,EAAC,IAAI,CAAC,EAAE,CAAC;YACpB,MAAM,CAAC,IAAI,CACP,IAAI,IAAI,yBAAyB,8CAAwB,sCAAsC;gBAC/F,UAAU,CACb,CAAC;QACN,CAAC;IACL,CAAC;IACD,KAAK,MAAM,IAAI,IAAI,MAAM,CAAC,IAAI,CAAC,iBAAiB,CAAC,EAAE,CAAC;QAChD,2FAA2F;QAC3F,IAAI,CAAC,IAAA,sBAAW,EAAC,IAAI,CAAC,IAAI,2BAAY,CAAC,IAAI,CAAC,EAAE,CAAC;YAC3C,MAAM,CAAC,IAAI,CACP,IAAI,IAAI,wBAAwB,8CAAwB,sCAAsC;gBAC9F,UAAU,CACb,CAAC;QACN,CAAC;IACL,CAAC;IACD,OAAO,MAAM,CAAC;AAClB,CAAC","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 { validateChecklistsSection, validateDevDeploySection, validateLandPrSection, validateNoGateSaltRationale } 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\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; a branch name 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};\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// 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 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 }\n }\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 ` \"checklists\": [ // OPTIONAL — per-area review, one distinct reviewer subagent each\\n` +\n ` { \"subagent\": \"db-migration-reviewer\", \"doc\": \".claude/review/db-migrations.md\", \"patterns\": [\"**/*.sql\"] }\\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 }\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; a branch name disables the rule\n // 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 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).`);\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"]}
@@ -35,15 +35,28 @@ A rejected config is always repairable from inside the failure:
35
35
 
36
36
  ## What to do when the config fails to load
37
37
 
38
- Do these in order. **Do not start by deleting keys** — that usually deletes valid config.
39
-
40
- 1. **`pnpm install`.** This is the most common cause by far: your installed `@webpieces` validator is a
41
- release BEHIND this config (a dep bump updated the config and lockfile, but `node_modules` was never
42
- re-installed), so the running validator does not recognise a legitimately newer key. Installing syncs
43
- them.
44
- 2. **Re-run your command.** If the errors are gone you are done — do not touch the config file.
45
- 3. **Only if an error survives a fresh install** is it a genuine retired / renamed / typo'd key. Now edit
46
- `webpieces.config.json`, applying each error's instruction literally.
38
+ **Edit `webpieces.config.json` and apply every error literally. That is the whole procedure.** Each error
39
+ names the exact change to make, and editing this file is always allowed — including right now, while it is
40
+ invalid.
41
+
42
+ - **An UNKNOWN key: delete it.** A key the running validator has no schema for controls nothing — every
43
+ code path that would read it is keyed off that schema — so leaving it is dead config that reads as live
44
+ config to the next reader. When the key is RETIRED, deleting it is the *whole* fix.
45
+ `pnpm wp-prune-unknown-config` strips every unknown key for you, and it is on the guard's cure allowlist,
46
+ so it runs even while the invalid config is blocking everything else.
47
+ - **A RETIRED key with a destination: apply the move.** A rename carries its value over, so delete-and-move
48
+ on is wrong there — the error tells you which case you are in.
49
+ - **A MACHINE-LOCAL setting does not belong in this file.** Those live in `~/.webpieces/config.json` under
50
+ `experimental` — an optional file tracked by no repo, whose absence is the default behaviour.
51
+
52
+ **Do NOT run `pnpm install` for a validation error.** It cannot help: the guards only run once package.json
53
+ and node_modules already agree, so there is nothing out of date to install.
54
+
55
+ The one case that *is* a stale install — your pinned `@webpieces` being a release BEHIND this config, so the
56
+ running validator does not recognise a legitimately newer key — never reaches this banner. The
57
+ version-drift guard compares the pin against the installed version *before* the validator runs, and denies
58
+ every tool call with its own message and its own cure. So if you are reading a validation error, no drift
59
+ was detected.
47
60
 
48
61
  ## Documenting your own config: the `*Why` convention
49
62
 
@@ -88,9 +88,10 @@ that denied `rm -rf node_modules && pnpm install` while allowing a bare `pnpm in
88
88
  | 5 | git pull / git fetch - merge is NOT on the list | ALLOW |
89
89
  | 6 | pnpm exec wp-upgrade-shim | ALLOW |
90
90
  | 7 | cp node_modules/@webpieces/ai-hook-rules/templates/ai-hook.sh .claude/webpieces/ai-hook.sh | ALLOW |
91
- | 8 | pnpm exec wp-install-ai-hooks (flags allowed, e.g. --target=project) | ALLOW |
92
- | 9 | pnpm add -D @webpieces/ai-hook-rules (an @version and extra flags allowed) | ALLOW |
93
- | 10 | read-only orientation: pwd, git status/log/diff/show/branch/rev-parse, git worktree list | ALLOW |
91
+ | 8 | pnpm wp-prune-unknown-config | ALLOW |
92
+ | 9 | pnpm exec wp-install-ai-hooks (flags allowed, e.g. --target=project) | ALLOW |
93
+ | 10 | pnpm add -D @webpieces/ai-hook-rules (an @version and extra flags allowed) | ALLOW |
94
+ | 11 | read-only orientation: pwd, git status/log/diff/show/branch/rev-parse, git worktree list | ALLOW |
94
95
 
95
96
  - **PASS** — L0 has no objection; the call falls THROUGH so the downstream guards still judge it.
96
97
  - **ALLOW** — terminal; bypasses everything, because a cure must stay reachable even when a