@webpieces/pr-gate 0.4.564 → 0.4.565
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +2 -2
- package/src/dashboard/checklist-comment-row.d.ts +42 -0
- package/src/dashboard/checklist-comment-row.js +59 -0
- package/src/dashboard/checklist-comment-row.js.map +1 -0
- package/src/dashboard/dashboard.d.ts +19 -29
- package/src/dashboard/dashboard.js +57 -53
- package/src/dashboard/dashboard.js.map +1 -1
- package/src/scripts/commands/finish-upsert-pr-command.d.ts +9 -0
- package/src/scripts/commands/finish-upsert-pr-command.js +24 -4
- package/src/scripts/commands/finish-upsert-pr-command.js.map +1 -1
- package/src/scripts/commands/review-upsert-pr-command.d.ts +12 -1
- package/src/scripts/commands/review-upsert-pr-command.js +20 -4
- package/src/scripts/commands/review-upsert-pr-command.js.map +1 -1
- package/src/scripts/pr-gate-app.d.ts +2 -2
- package/src/scripts/pr-gate-app.js +2 -2
- package/src/scripts/pr-gate-app.js.map +1 -1
- package/src/scripts/workflow/checklist-detector.js +1 -1
- package/src/scripts/workflow/checklist-detector.js.map +1 -1
- package/src/scripts/workflow/checklist-scanner.d.ts +21 -1
- package/src/scripts/workflow/checklist-scanner.js +31 -3
- package/src/scripts/workflow/checklist-scanner.js.map +1 -1
- package/src/scripts/workflow/review-report.d.ts +62 -1
- package/src/scripts/workflow/review-report.js +165 -34
- package/src/scripts/workflow/review-report.js.map +1 -1
- package/src/scripts/workflow/reviewer-briefing-builder.js +1 -0
- package/src/scripts/workflow/reviewer-briefing-builder.js.map +1 -1
- package/src/scripts/workflow/reviewer-verdict-gate.d.ts +10 -0
- package/src/scripts/workflow/reviewer-verdict-gate.js +17 -1
- package/src/scripts/workflow/reviewer-verdict-gate.js.map +1 -1
- package/src/scripts/wp-review-upsert-pr.js +9 -2
- package/src/scripts/wp-review-upsert-pr.js.map +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"finish-upsert-pr-command.js","sourceRoot":"","sources":["../../../../../../../packages/tooling/pr-gate/src/scripts/commands/finish-upsert-pr-command.ts"],"names":[],"mappings":"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","sourcesContent":["import { execSync, spawnSync } from 'child_process';\nimport * as fs from 'fs';\nimport * as path from 'path';\nimport {\n loadAndValidate, prDirFor, reviewJsonPath, ReviewJson, RequiredChecklist, ChecklistVerdict,\n writeTemplate, RepoRootFinder, ReviewJsonService,\n GateTokenService, SubagentProvenanceService, PROVENANCE_OK, PROVENANCE_MISSING, PROVENANCE_SKIPPED,\n ProvenanceResult, ReviewerEvidence, EvidenceRequest, PrGateConfig,\n ReviewProvenanceService, ProvenanceWriteRequest, ReviewerTranscript, ReviewerPaths, OfferedContext,\n ReviewerInstructionsService,\n InformAiError, toError,\n} from '@webpieces/rules-config';\nimport { injectable, bindingScopeValues } from 'inversify';\nimport { AiBranchName } from '../workflow/git-readAiBranchName';\nimport { BranchNaming } from '../workflow/branch-naming';\nimport { ChecklistScan, ChecklistScanOptions, ChecklistScanner } from '../workflow/checklist-scanner';\nimport { ReviewerVerdictGate } from '../workflow/reviewer-verdict-gate';\nimport { GitExec } from '../workflow/git-exec';\nimport { BuildAffected, BuildGateOptions } from '../workflow/build-affected';\nimport { MergeState } from '../workflow/merge-state';\nimport { ReviewStageReceiptService } from '../workflow/review-stage-receipt';\nimport { PrMerger, MergeOutcome, MERGE_RESULT_FAILED } from '../workflow/pr-merger';\nimport { FinishBanner, FinishBannerInput } from '../workflow/finish-banner';\nimport { GatedPrPublisher } from '../workflow/gated-pr-publisher';\nimport { TriggeredChecklist } from '../workflow/checklist-detector';\nimport {\n Dashboard, DashboardInput, ChecklistRow, ChecklistCommentRow, CHECKLIST_COMMENT_MARKER,\n} from '../../dashboard/dashboard';\n\nconst SEP = '━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\\n';\n\n/**\n * The provenance outcome: whether each reviewer was VERIFIED to have run (the integrity check, which\n * blocks) plus what each one actually read (the quality signal, which is published). Data-only.\n */\nclass ProvenanceReport {\n verified: boolean;\n evidence: ReviewerEvidence[];\n\n constructor(verified: boolean, evidence: ReviewerEvidence[]) {\n this.verified = verified;\n this.evidence = evidence;\n }\n}\n\n// A resolved PR's number + web URL. Both '' when the PR can't be resolved (e.g. create failed).\nclass PrRef {\n number: string;\n url: string;\n\n constructor(number: string, url: string) {\n this.number = number;\n this.url = url;\n }\n}\n\n// The outcome of the whole upsert: the PR number + web URL ('' each when unresolved) plus what actually\n// happened to the merge, so the final summary reports the REAL result rather than assuming success. The\n// URL is carried so the closing block can hand the AI a clickable link to relay to the user verbatim.\nclass UpsertResult {\n prNumber: string;\n prUrl: string;\n merge: MergeOutcome;\n\n constructor(prNumber: string, prUrl: string, merge: MergeOutcome) {\n this.prNumber = prNumber;\n this.prUrl = prUrl;\n this.merge = merge;\n }\n}\n\n// STAGE ③ — FINISH of the AI-first PR flow, and the ONLY command that posts PRs. Runs after\n// `wp-review-upsert-pr` verified the branch and the AI spawned the reviewers + wrote review.json.\n//\n// In order: (1) REFUSE on an unvalidated 3-point merge and REQUIRE stage ②'s receipt; (2) REQUIRE\n// review.json + every reviewer's verdict + provenance; (3) run the build gate UNLESS the receipt already\n// covers this exact HEAD; (4) render the dashboard; (5) create/update the PR via `gh`.\n//\n// It no longer FINALIZES a merge — stage ② does. Two commands owning conflict-resolution validation is two\n// implementations that drift, and finalizing here came too late to help anyway: the reviewers had already\n// reviewed the pre-merge tree by then.\n@injectable(bindingScopeValues.Singleton)\nexport class FinishUpsertPrCommand {\n constructor(\n private readonly repoRootFinder: RepoRootFinder,\n private readonly aiBranchName: AiBranchName,\n private readonly branchNaming: BranchNaming,\n private readonly gitExec: GitExec,\n private readonly buildAffected: BuildAffected,\n private readonly mergeState: MergeState,\n private readonly prMerger: PrMerger,\n private readonly publisher: GatedPrPublisher,\n private readonly dashboard: Dashboard,\n private readonly checklistScanner: ChecklistScanner,\n private readonly verdictGate: ReviewerVerdictGate,\n private readonly reviewJsonService: ReviewJsonService,\n private readonly gateTokenService: GateTokenService,\n private readonly provenance: SubagentProvenanceService,\n private readonly provenanceRecord: ReviewProvenanceService,\n private readonly reviewerInstructions: ReviewerInstructionsService,\n // NOTE: ChecklistInstructionsService is deliberately NOT injected here any more. Its \"You MUST run\n // these N reviewer subagent(s)\" block is now rendered by ReviewerVerdictGate and ONLY for checklists\n // that genuinely never ran, so no other code path in this command can print it at a refusal.\n private readonly receipts: ReviewStageReceiptService,\n private readonly banner: FinishBanner,\n ) {}\n\n async run(): Promise<void> {\n const repoRoot = this.repoRootFinder.resolveRepoRoot(process.cwd());\n // Refresh the AI-facing workflow doc so it's present + current for any failure message to cite.\n writeTemplate(repoRoot, 'webpieces.git-workflow.md');\n // 1. REQUIRE stage ② — see assertStageTwoRan. Returns true when its receipt covers THIS commit,\n // which is what lets the build gate below be skipped rather than re-run for a foregone answer.\n const buildAlreadyGreen = this.assertStageTwoRan(repoRoot);\n\n // 2. REQUIRE the AI-authored review.json (throws InformAiError with the schema if missing/invalid).\n // Compute the consumer checklists this diff triggered FIRST so an unacknowledged BLOCK throws\n // here — BEFORE any `gh pr create` — matching the guarantee buildCommand already provides.\n // The SAME scan wp-review-upsert-pr runs, with filterAlreadyReviewed:true so `outstanding` is exactly what\n // still owes a verdict (Z of N of X). Sharing the computation is the point: the command that REPORTS\n // and the command that GATES must not be able to disagree about what is owed. review-<id>.json files\n // persist locally, so a re-run re-validates the EXISTING verdicts against the (possibly changed)\n // applicable set for free — an unchanged checklist needs no re-review, a newly-applicable one refuses\n // until its file is written.\n const featureName = this.aiBranchName.getFeatureName();\n const scan = this.checklistScanner.scan(repoRoot, loadAndValidate(repoRoot).prGate.checklists, new ChecklistScanOptions(true, 'stage3-finish'));\n const required = scan.applicable;\n // FAIL FAST on an unclear checklist, BEFORE review.json is parsed and before the build gate runs. A\n // missing reviewer is not a review.json defect (folding it in made the AI fix the wrong thing), and\n // nobody should wait on a build to be told a reviewer never ran. ReviewerVerdictGate owns the\n // distinction between unreadable / REFUSED / never-ran, and retires the red verdicts it acts on.\n this.verdictGate.assertEveryReviewerRan(scan);\n const review = this.reviewJsonService.loadReviewJson(reviewJsonPath(repoRoot, featureName), required);\n\n // 2c. For any BLOCK checklist that names a reviewer `subagent`, VERIFY (from the harness's own\n // artifacts) that such a subagent actually ran on this branch — the coding agent may not\n // self-certify. Absent CLAUDE_CODE_SESSION_ID this skips with a warning (CI / plain terminal).\n const currentBranch = execSync('git branch --show-current', { encoding: 'utf8' }).trim();\n const provenance = this.enforceProvenance(required, currentBranch, repoRoot, loadAndValidate(repoRoot).prGate);\n\n // 2b. The build gate validates the WORKING TREE but we push HEAD — so they MUST be identical.\n this.gitExec.assertCleanTree(repoRoot);\n\n // 3. Build gate, then post the gated body, then push (that ORDER — see GatedPrPublisher).\n this.runOrSkipBuildGate(repoRoot, buildAlreadyGreen);\n const base = this.branchNaming.baseBranchName(execSync('git branch --show-current', { encoding: 'utf8' }).trim());\n\n process.stdout.write('\\n' + SEP + '📋 Dashboard + PR\\n' + SEP + '\\n');\n const title = this.prTitleFrom(review);\n const input = this.computeDashboardInput(repoRoot, true, review, title, required);\n // Append the hidden HMAC gate token bound to the LOCAL HEAD sha — computed BEFORE the push, because\n // GatedPrPublisher writes the body first so CI's `synchronize` read can never see a stale token. A\n // valid token in the PR body is proof this gated flow ran + passed on this exact commit, which CI\n // (`wp-check-pr`) recomputes. We reach here only after the build gate + every BLOCK checklist\n // passed, so minting is legitimate. Nothing about HMAC(salt, HEAD) needs the remote to have it.\n const gateSalt = loadAndValidate(repoRoot).prGate.gateSalt;\n const headSha = this.gitOut(['rev-parse', 'HEAD']);\n const body = this.dashboard.renderDashboard(input) + this.gateTokenBody(gateSalt, headSha);\n const result = this.upsertPr(repoRoot, base, body, title, input);\n // Publish each reviewer's full output as ONE combined PR comment (idempotent, opt-out-aware). Never\n // fatal — the PR is already up by now, so a comment failure only warns.\n this.postChecklistComment(repoRoot, result.prNumber, scan, review, provenance);\n this.archiveConsumedReview(repoRoot, featureName, result);\n\n // The closing recap + the clickable-link directive, BOTH derived from the real merge outcome.\n // Nothing here may hard-code success: a stranded PR under a green checkmark is how PRs got\n // abandoned (see FinishBanner).\n const bannerInput = new FinishBannerInput(result.prNumber, result.prUrl, title, base, result.merge);\n process.stdout.write(this.banner.render(bannerInput));\n process.stdout.write(this.banner.linkDirective(bannerInput));\n }\n\n // Validate + commit + finalize a 3-point merge the AI resolved, if one is in progress. Finalizing here\n // does NOT push (pushRemote=false): this command pushes exactly ONCE, from GatedPrPublisher, and only\n // after review.json + every BLOCK checklist + the build gate pass and the gated PR body is written.\n /**\n * The build gate — SKIPPED when stage ②'s receipt already covers this exact HEAD.\n *\n * The gate is authoritative per-COMMIT, not per-command: re-running it on a tree that has not moved\n * since stage ② verified it buys nothing and costs a full `nx affected`. That skip is what makes the\n * three-stage flow cost ONE build rather than two, and it is why moving the gate earlier was affordable.\n */\n private runOrSkipBuildGate(repoRoot: string, alreadyGreen: boolean): void {\n if (alreadyGreen) {\n process.stdout.write('\\n🛠️ Build gate: already green for this commit (stage ② receipt) — skipping the rebuild.\\n');\n return;\n }\n this.buildAffected.runBuildGate(repoRoot, new BuildGateOptions(\n '🛠️ Build gate (authoritative)', 'pnpm wp-finish-upsert-pr', 'Build failed — no PR created/updated.',\n ));\n }\n\n /**\n * The two stage-② preconditions, together: no unvalidated merge, and a receipt proving stage ② ran.\n * Returns true when that receipt covers the CURRENT HEAD, i.e. the build gate can be skipped.\n */\n private assertStageTwoRan(repoRoot: string): boolean {\n this.assertNoUnvalidatedMerge(repoRoot);\n return this.assertReviewStageRan(\n repoRoot, this.aiBranchName.getFeatureName(), this.gitOut(['rev-parse', 'HEAD']));\n }\n\n /**\n * REFUSE while a 3-point merge is still unvalidated — do not finalize it here.\n *\n * This command used to do the finalizing itself. Finalizing means validating a conflict resolution, and\n * two commands owning that means two implementations that can drift; `PrContextWriter`'s docstring\n * records this codebase already paying for exactly that once. It also came too late to matter: by the\n * time finish ran, the reviewers had already reviewed the pre-merge tree.\n *\n * So stage ② owns it, and finish only checks. Nothing is lost — the recovery is one command away, and\n * running it also builds the merged tree and re-briefs the reviewers against it, which finalizing here\n * never did.\n */\n private assertNoUnvalidatedMerge(repoRoot: string): void {\n const home = this.mergeState.mergeDirFor(repoRoot, this.aiBranchName.getFeatureName());\n const activeDir = this.mergeState.findActiveMergeRunDir(home);\n const marker = activeDir ? this.mergeState.readMergeMarker(activeDir) : null;\n if (!activeDir || !marker || marker.validated) return;\n throw new InformAiError(\n '⛔ NO PR — a 3-point merge on this branch is still unvalidated, so nothing here has been\\n' +\n 'verified: the conflict resolution is unchecked, the merged tree was never built, and any\\n' +\n 'reviewer that ran judged the PRE-merge code.\\n\\n' +\n `Conflicted file(s): ${marker.conflictedFiles.join(', ')}\\n\\n` +\n 'Resolve them (see .webpieces/instruct-ai/webpieces.mergeprocess.md), then run:\\n' +\n ' pnpm wp-review-upsert-pr\\n' +\n 'It validates the resolution, commits it, builds it, and re-briefs the reviewers.',\n );\n }\n\n /**\n * REQUIRE stage ② (`wp-review-upsert-pr`) to have run, and report whether it ran on THIS commit.\n *\n * Returns true when the receipt matches the current HEAD — the caller then skips its own build, because\n * the receipt IS the gate for that sha and rebuilding an unchanged tree is a second full `nx affected`\n * run for a foregone answer.\n *\n * Without this check a repo with NO checklists has nothing forcing stage ②: `assertEveryReviewerRan`\n * is vacuous, and review.json — the only other interlock — is a file the AI writes itself. It could\n * write it and come straight here, skipping the merge validation and the build entirely.\n */\n private assertReviewStageRan(repoRoot: string, featureName: string, headSha: string): boolean {\n const receipt = this.receipts.read(repoRoot, featureName);\n if (receipt === null) {\n throw new InformAiError(\n '⛔ NO PR — stage ② never ran on this branch. That means the 3-point merge is unvalidated,\\n' +\n 'the build gate has not run, no diff was extracted, and no reviewer was briefed.\\n\\n' +\n 'Run: pnpm wp-review-upsert-pr\\n' +\n '(then spawn the reviewers it names, write review.json, and re-run this command)',\n );\n }\n if (receipt.headSha === headSha) return true;\n // Not fatal. Re-reviewing on every follow-up commit would be intolerable, and most drift is a typo\n // fix. But it is never silent: the build re-runs here, and the PR says the reviewers saw an older tree.\n process.stderr.write(\n `\\n⚠️ HEAD moved since stage ② ran (reviewed ${receipt.headSha.slice(0, 8)}, now ${headSha.slice(0, 8)}).\\n` +\n ' The build gate will re-run, and the PR will record that reviewers judged an earlier tree.\\n' +\n ' If the change was substantive, re-run pnpm wp-review-upsert-pr and re-spawn the reviewers.\\n\\n');\n return false;\n }\n\n /**\n * Retire the review this run just used — move review.json to old-review.json beside it, stamped as\n * audit-only (see ReviewJsonService.archiveReviewJson).\n *\n * WHY it moves rather than staying put: review.json left behind is a live-looking file describing a\n * review that has already shipped, and the next `wp-review-upsert-pr` on this branch finds it sitting\n * there. A reviewer subagent that judges the PR's stated INTENT — its title, summary or risk level —\n * then reads the previous round's review and can return GREEN against a title that no longer exists,\n * with nothing in the verdict distinguishing that from a real pass. Moving it makes the only route back\n * to this command a freshly-written review.\n *\n * ONLY on a PR that actually went up. A run that died before publishing must stay re-runnable without\n * making the AI rewrite a review that was never used, and prNumber === '' is exactly that case.\n * Non-fatal: the PR is live by here, so an unwritable archive warns rather than failing the command.\n */\n private archiveConsumedReview(repoRoot: string, featureName: string, result: UpsertResult): void {\n if (result.prNumber === '') return;\n // webpieces-disable no-unmanaged-exceptions -- chokepoint: the PR is already up; a failed archive must not fail the command\n // eslint-disable-next-line @webpieces/no-unmanaged-exceptions\n try {\n const archived = this.reviewJsonService.archiveReviewJson(reviewJsonPath(repoRoot, featureName));\n if (archived !== '') process.stdout.write(` archived this run's review.json → ${archived} (audit only) ✓\\n`);\n // Beside it, so an archived review keeps the transcript links belonging to the round that\n // produced it — a review whose provenance was overwritten by the NEXT round audits nothing.\n this.provenanceRecord.archive(prDirFor(repoRoot, featureName));\n } catch (err: unknown) {\n const error = toError(err);\n process.stderr.write(`⚠️ Could not archive review.json (non-fatal — the PR is already up): ${error.message}\\n`);\n }\n }\n\n private gitOut(args: string[]): string {\n const result = spawnSync('git', args, { encoding: 'utf8' });\n return result.status === 0 ? (result.stdout ?? '').trim() : '';\n }\n\n // The user-facing PR title: the AI-authored review.title, or — if omitted — a readable fallback\n // derived from the stable feature name (NEVER the internal `Squash merge of <branch>` commit subject).\n private prTitleFrom(review: ReviewJson): string {\n if (review.title !== '') return review.title;\n return this.aiBranchName.getFeatureName().replace(/[-/]+/g, ' ').trim();\n }\n\n // eslint-disable-next-line @typescript-eslint/max-params\n private computeDashboardInput(repoRoot: string, buildPassed: boolean, review: ReviewJson, title: string, required: readonly RequiredChecklist[]): DashboardInput {\n const config = loadAndValidate(repoRoot).prGate;\n const forkPoint = this.gitOut(['merge-base', 'origin/main', 'HEAD']);\n const featureHead = this.gitOut(['rev-parse', 'HEAD']);\n const mainHead = this.gitOut(['rev-parse', 'origin/main']);\n const range = `${forkPoint}..${featureHead}`;\n const changedFiles = this.gitOut(['diff', range, '--name-only']).split('\\n').filter((f: string): boolean => f.trim() !== '');\n const patch = this.gitOut(['diff', range]);\n\n const gateResults = this.dashboard.computeGateResults(config.gates, changedFiles);\n const disables = this.dashboard.countAddedDisables(patch);\n const rows = this.checklistRows(required, review);\n return new DashboardInput(title, gateResults, disables, buildPassed, forkPoint, featureHead, mainHead, review, rows);\n }\n\n // Pair each matched checklist with its resolved verdict for the dashboard.\n //\n // A checklist reaching this point is always PASS, WARN or OVERRIDDEN, and the reason is ReviewerVerdictGate\n // — NOT loadReviewJson. The gate runs one line earlier and throws on every other state (FAIL, MISSING,\n // BAD_FORMAT), so loadReviewJson's own checklist validation can no longer be the thing that rejects them;\n // it re-validates the same set and finds it clean. This comment used to credit loadReviewJson, which made\n // the ordering look deliberate while the gate's generic \"no verdict yet\" message masked every refusal.\n // WARN belongs in that list: yellow SHIPS, so it is not outstanding and reaches the dashboard.\n private checklistRows(required: readonly RequiredChecklist[], review: ReviewJson): ChecklistRow[] {\n return required.map((req: RequiredChecklist): ChecklistRow => {\n const verdict = this.reviewJsonService.resolveVerdict(req, review.results);\n return new ChecklistRow(req.id, verdict.status, verdict.detail);\n });\n }\n\n /**\n * One comment row per DEFINED checklist — matched or not — pairing the roster's match evidence with the\n * resolved verdict. Built from `scan.roster` rather than from the applicable set: the skipped ones are\n * absent from `applicable` by construction, and their \"why not\" evidence (the configured globs and the\n * changed-file total) exists nowhere else without recomputing the diff a second way.\n */\n private commentRows(scan: ChecklistScan, review: ReviewJson, provenance: ProvenanceReport): ChecklistCommentRow[] {\n // agentType -> did it open the diff. Absent ⇒ not assessed, which prints nothing (see ChecklistCommentRow.diffRead).\n const readByAgent = new Map<string, boolean>();\n for (const e of provenance.evidence) readByAgent.set(e.agentType, e.readDiff);\n return scan.roster.entries.map((entry: TriggeredChecklist): ChecklistCommentRow => {\n const ran = entry.matchedFiles.length > 0;\n const req = new RequiredChecklist(\n entry.def.id, entry.def.subagent, entry.def.doc, entry.matchedFiles, entry.matchedPatterns);\n // A skipped checklist has no verdict to resolve — asking for one would report it as MISSING,\n // i.e. as an unreviewed obligation, when in fact it never had one.\n const verdict = ran\n ? this.reviewJsonService.resolveVerdict(req, review.results)\n : new ChecklistVerdict(entry.def.id, '', '');\n const row = new ChecklistCommentRow(\n entry.def.subagent, verdict.status, verdict.detail, ran,\n entry.def.patterns, entry.matchedPatterns, entry.matchedFiles, scan.roster.changedFileCount);\n const read = readByAgent.get(entry.def.subagent);\n row.diffRead = read === undefined ? '' : (read ? 'yes' : 'no');\n return row;\n });\n }\n\n // Hidden HMAC gate-token marker (with a leading blank line) to append to the PR body, or '' when the\n // repo sets no gateSalt (byte-identical body to before this feature). Bound to the pushed HEAD sha.\n private gateTokenBody(gateSalt: string, headSha: string): string {\n const marker = this.gateTokenService.gateTokenMarker(gateSalt, headSha);\n return marker === '' ? '' : `\\n\\n${marker}\\n`;\n }\n\n // Enforce that EACH matched checklist was reviewed by its OWN named subagent, as a DISTINCT run —\n // the coding agent may not self-certify, and one reviewer may not stand in for several. A verified set\n // passes silently; no session id warns but passes; any missing reviewer throws so the PR does not open.\n // eslint-disable-next-line @typescript-eslint/max-params\n private enforceProvenance(required: readonly RequiredChecklist[], branch: string, repoRoot: string, config: PrGateConfig): ProvenanceReport {\n const errors: string[] = [];\n const report = new ProvenanceReport(true, []); // no reviewers to verify ⇒ vacuously verified\n const subagents = required.map((r: RequiredChecklist): string => r.subagent.trim()).filter((s: string): boolean => s !== '');\n // verifyDistinct short-circuits to OK on an empty set, so this runs unconditionally: a repo with no\n // checklists still gets a provenance record naming the session and the main agent's own transcript.\n const result = this.provenance.verifyDistinct(subagents, branch);\n report.verified = result.status === PROVENANCE_OK;\n if (result.status === PROVENANCE_MISSING) {\n errors.push(result.detail);\n } else if (result.status === PROVENANCE_SKIPPED) {\n process.stderr.write(`⚠️ ${result.detail}\\n`);\n }\n report.evidence = this.gatherEvidence(repoRoot, required, result, branch);\n errors.push(...this.evidenceErrors(report.evidence, config));\n // BEFORE the throw below, deliberately. A refused round is the one most worth auditing, and a record\n // that only ever appeared on success could not answer what the reviewers did the time it was refused.\n this.writeProvenanceRecord(repoRoot, required, result, report.evidence);\n if (errors.length > 0) {\n throw new InformAiError(\n `${errors.length} checklist(s) require an independent reviewer subagent that did not run — fix, then re-run pnpm wp-finish-upsert-pr:\\n\\n` +\n errors.map((e: string): string => ` • ${e}`).join('\\n') +\n `\\n\\nSpawn the named reviewer subagent to review the checklist on THIS branch, then re-run.`,\n );\n }\n return report;\n }\n\n /**\n * What each credited reviewer actually read. Purely observational here — {@link evidenceErrors} decides\n * whether any of it blocks, and by default none of it does.\n */\n // eslint-disable-next-line @typescript-eslint/max-params\n private gatherEvidence(repoRoot: string, required: readonly RequiredChecklist[], result: ProvenanceResult, branch: string): ReviewerEvidence[] {\n const docPaths: Record<string, string> = {};\n for (const req of required) {\n if (req.subagent.trim() !== '') docPaths[req.subagent] = req.doc.trim() === '' ? '' : path.resolve(repoRoot, req.doc);\n }\n const diffDir = path.join(prDirFor(repoRoot, this.aiBranchName.getFeatureName()), 'diff');\n return this.provenance.evidenceFor(new EvidenceRequest(branch, result.agentIds, diffDir, docPaths));\n }\n\n /**\n * Write this round's audit record: `.webpieces/pr-review/<branch>/provenance.json`, linking each verdict\n * to the transcript of the subagent that produced it.\n *\n * A SEPARATE file rather than a field inside review.json / review-<id>.json, for two reasons. The\n * reviewer cannot supply this itself — a subagent's environment exposes the PARENT session id and no\n * agent id, so a self-reported transcript link would be invented — and keeping the AI-authored files\n * byte-untouched means nothing in the record can be mistaken for something a reviewer claimed about\n * itself. Every path here is derived by the tooling from the harness's own artifacts.\n *\n * Never fatal: an unwritable record is a lost audit trail, not a reason to refuse a PR.\n */\n // eslint-disable-next-line @typescript-eslint/max-params\n private writeProvenanceRecord(repoRoot: string, required: readonly RequiredChecklist[], result: ProvenanceResult, evidence: readonly ReviewerEvidence[]): void {\n const featureName = this.aiBranchName.getFeatureName();\n const prDir = prDirFor(repoRoot, featureName);\n const request = new ProvenanceWriteRequest(prDir, featureName, this.gitOut(['rev-parse', 'HEAD']), result.status);\n request.offered = new OfferedContext(\n path.join(prDir, 'diff'), this.reviewerInstructions.instructionsDirFor(repoRoot, featureName));\n request.reviewers = evidence.map((e: ReviewerEvidence): ReviewerTranscript =>\n new ReviewerTranscript(e, this.reviewerPathsFor(repoRoot, featureName, required, e.agentType)));\n const written = this.provenanceRecord.write(request);\n if (written !== '') process.stdout.write(` transcript provenance → ${written}\\n`);\n }\n\n // Where ONE reviewer's verdict, instructions and checklist doc live. Keyed by agentType, which IS the\n // checklist id: ChecklistDefinition sets `id = subagent`, so the two never diverge.\n // eslint-disable-next-line @typescript-eslint/max-params\n private reviewerPathsFor(repoRoot: string, featureName: string, required: readonly RequiredChecklist[], agentType: string): ReviewerPaths {\n const req = required.find((r: RequiredChecklist): boolean => r.subagent.trim() === agentType);\n const doc = req !== undefined && req.doc.trim() !== '' ? path.resolve(repoRoot, req.doc) : '';\n return new ReviewerPaths(\n this.reviewJsonService.checklistResultPath(reviewJsonPath(repoRoot, featureName), req?.id ?? agentType),\n this.reviewerInstructions.pathFor(repoRoot, featureName, agentType),\n doc,\n );\n }\n\n /**\n * WARN (default) or REFUSE (opt-in) on a reviewer that wrote a verdict without opening the diff.\n *\n * Default-warn because the signal is derived from undocumented Claude Code transcript internals: if the\n * format shifts, a blocking check wedges every PR in every consumer repo with no self-service recovery.\n * `requireDiffEvidence` lets a repo that has watched the warning promote it deliberately.\n */\n private evidenceErrors(evidence: readonly ReviewerEvidence[], config: PrGateConfig): string[] {\n const blind = evidence.filter((e: ReviewerEvidence): boolean => !e.readDiff);\n if (blind.length === 0) return [];\n const names = blind.map((e: ReviewerEvidence): string => e.agentType).join(', ');\n if (!config.requireDiffEvidence) {\n process.stderr.write(\n `\\n⚠️ ${blind.length} reviewer(s) wrote a verdict with no record of opening the extracted diff: ${names}\\n` +\n ' Published on the PR as a note. Not blocking — set pr-gate.requireDiffEvidence:true to make it one.\\n');\n return [];\n }\n return [`these reviewers wrote a verdict without opening the diff (pr-gate.requireDiffEvidence is on): ${names}`];\n }\n\n /**\n * Publish the roster + every reviewer's full `output` as ONE combined PR comment, idempotently (find the\n * marker comment → PATCH it, else POST). Never fatal: by here the PR is already created/updated, so a\n * `gh` failure only warns.\n *\n * Posted on EVERY run of a repo that defines checklists — including one where nothing matched, because\n * \"all five were evaluated and none applied\" is the good news the old comment could not deliver. The\n * guard is `scan.defined.length`, deliberately NOT the number of rows that ran: a repo with no\n * checklists configured must still see no comment at all (see ChecklistNotice / renderDashboard).\n */\n // eslint-disable-next-line @typescript-eslint/max-params\n // eslint-disable-next-line @typescript-eslint/max-params\n private postChecklistComment(repoRoot: string, prNumber: string, scan: ChecklistScan, review: ReviewJson, provenance: ProvenanceReport): void {\n if (prNumber === '' || scan.defined.length === 0) return;\n if (!loadAndValidate(repoRoot).prGate.checklistComments) return;\n const body = this.dashboard.renderChecklistComment(\n this.commentRows(scan, review, provenance), provenance.verified, scan.roster.baseResolved);\n const prDir = prDirFor(repoRoot, this.aiBranchName.getFeatureName());\n fs.mkdirSync(prDir, { recursive: true });\n const payload = path.join(prDir, 'checklist-comment.json');\n fs.writeFileSync(payload, JSON.stringify({ body }));\n const commentId = this.findChecklistCommentId(prNumber);\n const args = commentId !== ''\n ? ['api', '--method', 'PATCH', `repos/{owner}/{repo}/issues/comments/${commentId}`, '--input', payload]\n : ['api', '--method', 'POST', `repos/{owner}/{repo}/issues/${prNumber}/comments`, '--input', payload];\n const res = spawnSync('gh', args, { encoding: 'utf8' });\n if (res.status !== 0) {\n process.stderr.write('⚠️ Could not post the checklist review comment (non-fatal — the PR is already up).\\n');\n } else {\n process.stdout.write(` ${commentId !== '' ? 'updated' : 'posted'} the checklist review comment ✓\\n`);\n }\n }\n\n // The id of THIS tool's existing checklist comment on the PR (by the hidden marker), or '' if none.\n private findChecklistCommentId(prNumber: string): string {\n const res = spawnSync('gh', [\n 'api', '--paginate', `repos/{owner}/{repo}/issues/${prNumber}/comments`,\n '--jq', `.[] | select(.body | contains(\"${CHECKLIST_COMMENT_MARKER}\")) | .id`,\n ], { encoding: 'utf8' });\n if (res.status !== 0) return '';\n return (res.stdout ?? '').trim().split('\\n')[0] ?? '';\n }\n\n // The PR, the remote branch, and the local branch all share the one stable feature name. Look up /\n // create / merge against `baseBranch` (baseBranchName tolerates a leftover `…wpN` mid-transition).\n // GatedPrPublisher owns the edit/push/create half and its ORDERING — the gated body goes up before\n // the push, so CI's `synchronize` read cannot see the previous run's token.\n private upsertPr(repoRoot: string, baseBranch: string, body: string, title: string, input: DashboardInput): UpsertResult {\n const prDir = prDirFor(repoRoot, this.aiBranchName.getFeatureName());\n fs.mkdirSync(prDir, { recursive: true });\n const bodyFile = path.join(prDir, 'pr-body.md');\n fs.writeFileSync(bodyFile, body + '\\n');\n\n const published = this.publisher.publish(baseBranch, title, bodyFile);\n if (published.createFailed) {\n process.stderr.write('⚠️ gh pr create failed — create the PR manually with the body in:\\n ' + bodyFile + '\\n');\n return new UpsertResult('', '', new MergeOutcome(false, false,\n '⚠️ did NOT merge — there is no PR to merge (gh pr create failed above)', MERGE_RESULT_FAILED));\n }\n const num = published.number;\n\n // Set the squash-merge SUBJECT to the PR title (+ the `(#N)` GitHub normally appends, which an\n // explicit --subject would otherwise drop) and the BODY to the compact commit summary, so main's\n // history carries the PR title + risk/flags/link — NOT the internal `Squash merge of <branch>`\n // subject GitHub would inherit from the single squash commit on the branch.\n const ref = this.prRef(baseBranch);\n const subject = ref.number !== '' ? `${title} (#${ref.number})` : title;\n const mergeBodyFile = path.join(prDir, 'merge-commit-body.md');\n fs.writeFileSync(mergeBodyFile, this.dashboard.renderCommitBody(input, ref.url) + '\\n');\n // PrMerger owns the direct-merge / auto-merge-fallback decision AND checks every gh status, so a\n // merge that did not happen is reported as such instead of being swallowed (see pr-merger.ts).\n // REQUIRED config — no default here on purpose. A missing value (an older published\n // rules-config that has no such field) reaches PrMerger as '' and is treated as \"do not merge\".\n const mergeMode = loadAndValidate(repoRoot).prGate.mergeMode ?? '';\n const outcome = this.prMerger.merge(baseBranch, subject, mergeBodyFile, mergeMode);\n return new UpsertResult(ref.number !== '' ? ref.number : num, ref.url, outcome);\n }\n\n // The PR's number + web URL (for the merge subject `(#N)` and the commit-body back-link). Both ''\n // if it can't be resolved. Rendered via jq into one tab-separated line so no JSON parsing is needed.\n private prRef(baseBranch: string): PrRef {\n const result = spawnSync(\n 'gh', ['pr', 'view', baseBranch, '--json', 'number,url', '--jq', '\"\\\\(.number)\\\\t\\\\(.url)\"'],\n { encoding: 'utf8' },\n );\n if (result.status !== 0) {\n return new PrRef('', '');\n }\n const parts = (result.stdout ?? '').trim().split('\\t');\n return new PrRef(parts[0] ?? '', parts[1] ?? '');\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"finish-upsert-pr-command.js","sourceRoot":"","sources":["../../../../../../../packages/tooling/pr-gate/src/scripts/commands/finish-upsert-pr-command.ts"],"names":[],"mappings":"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","sourcesContent":["import { execSync, spawnSync } from 'child_process';\nimport * as fs from 'fs';\nimport * as path from 'path';\nimport {\n loadAndValidate, prDirFor, reviewJsonPath, ReviewJson, RequiredChecklist, ChecklistVerdict,\n writeTemplate, RepoRootFinder, ReviewJsonService,\n GateTokenService, SubagentProvenanceService, PROVENANCE_OK, PROVENANCE_MISSING, PROVENANCE_SKIPPED,\n ProvenanceResult, ReviewerEvidence, EvidenceRequest, PrGateConfig,\n ReviewProvenanceService, ProvenanceWriteRequest, ReviewerTranscript, ReviewerPaths, OfferedContext,\n ReviewerInstructionsService,\n InformAiError, toError,\n} from '@webpieces/rules-config';\nimport { injectable, bindingScopeValues } from 'inversify';\nimport { AiBranchName } from '../workflow/git-readAiBranchName';\nimport { BranchNaming } from '../workflow/branch-naming';\nimport { ChecklistScan, ChecklistScanOptions, ChecklistScanner } from '../workflow/checklist-scanner';\nimport { ReviewerVerdictGate } from '../workflow/reviewer-verdict-gate';\nimport { GitExec } from '../workflow/git-exec';\nimport { BuildAffected, BuildGateOptions } from '../workflow/build-affected';\nimport { MergeState } from '../workflow/merge-state';\nimport { ReviewStageReceiptService } from '../workflow/review-stage-receipt';\nimport { PrMerger, MergeOutcome, MERGE_RESULT_FAILED } from '../workflow/pr-merger';\nimport { FinishBanner, FinishBannerInput } from '../workflow/finish-banner';\nimport { GatedPrPublisher } from '../workflow/gated-pr-publisher';\nimport { TriggeredChecklist } from '../workflow/checklist-detector';\nimport {\n Dashboard, DashboardInput, ChecklistRow, CHECKLIST_COMMENT_MARKER,\n} from '../../dashboard/dashboard';\nimport { ChecklistCommentRow } from '../../dashboard/checklist-comment-row';\n\nconst SEP = '━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\\n';\n\n/**\n * The provenance outcome: whether each reviewer was VERIFIED to have run (the integrity check, which\n * blocks) plus what each one actually read (the quality signal, which is published). Data-only.\n */\nclass ProvenanceReport {\n verified: boolean;\n evidence: ReviewerEvidence[];\n\n constructor(verified: boolean, evidence: ReviewerEvidence[]) {\n this.verified = verified;\n this.evidence = evidence;\n }\n}\n\n// A resolved PR's number + web URL. Both '' when the PR can't be resolved (e.g. create failed).\nclass PrRef {\n number: string;\n url: string;\n\n constructor(number: string, url: string) {\n this.number = number;\n this.url = url;\n }\n}\n\n// The outcome of the whole upsert: the PR number + web URL ('' each when unresolved) plus what actually\n// happened to the merge, so the final summary reports the REAL result rather than assuming success. The\n// URL is carried so the closing block can hand the AI a clickable link to relay to the user verbatim.\nclass UpsertResult {\n prNumber: string;\n prUrl: string;\n merge: MergeOutcome;\n\n constructor(prNumber: string, prUrl: string, merge: MergeOutcome) {\n this.prNumber = prNumber;\n this.prUrl = prUrl;\n this.merge = merge;\n }\n}\n\n// STAGE ③ — FINISH of the AI-first PR flow, and the ONLY command that posts PRs. Runs after\n// `wp-review-upsert-pr` verified the branch and the AI spawned the reviewers + wrote review.json.\n//\n// In order: (1) REFUSE on an unvalidated 3-point merge and REQUIRE stage ②'s receipt; (2) REQUIRE\n// review.json + every reviewer's verdict + provenance; (3) run the build gate UNLESS the receipt already\n// covers this exact HEAD; (4) render the dashboard; (5) create/update the PR via `gh`.\n//\n// It no longer FINALIZES a merge — stage ② does. Two commands owning conflict-resolution validation is two\n// implementations that drift, and finalizing here came too late to help anyway: the reviewers had already\n// reviewed the pre-merge tree by then.\n@injectable(bindingScopeValues.Singleton)\nexport class FinishUpsertPrCommand {\n constructor(\n private readonly repoRootFinder: RepoRootFinder,\n private readonly aiBranchName: AiBranchName,\n private readonly branchNaming: BranchNaming,\n private readonly gitExec: GitExec,\n private readonly buildAffected: BuildAffected,\n private readonly mergeState: MergeState,\n private readonly prMerger: PrMerger,\n private readonly publisher: GatedPrPublisher,\n private readonly dashboard: Dashboard,\n private readonly checklistScanner: ChecklistScanner,\n private readonly verdictGate: ReviewerVerdictGate,\n private readonly reviewJsonService: ReviewJsonService,\n private readonly gateTokenService: GateTokenService,\n private readonly provenance: SubagentProvenanceService,\n private readonly provenanceRecord: ReviewProvenanceService,\n private readonly reviewerInstructions: ReviewerInstructionsService,\n // NOTE: ChecklistInstructionsService is deliberately NOT injected here any more. Its \"You MUST run\n // these N reviewer subagent(s)\" block is now rendered by ReviewerVerdictGate and ONLY for checklists\n // that genuinely never ran, so no other code path in this command can print it at a refusal.\n private readonly receipts: ReviewStageReceiptService,\n private readonly banner: FinishBanner,\n ) {}\n\n async run(): Promise<void> {\n const repoRoot = this.repoRootFinder.resolveRepoRoot(process.cwd());\n // Refresh the AI-facing workflow doc so it's present + current for any failure message to cite.\n writeTemplate(repoRoot, 'webpieces.git-workflow.md');\n // 1. REQUIRE stage ② — see assertStageTwoRan. Returns true when its receipt covers THIS commit,\n // which is what lets the build gate below be skipped rather than re-run for a foregone answer.\n const buildAlreadyGreen = this.assertStageTwoRan(repoRoot);\n\n // 2. REQUIRE the AI-authored review.json (throws InformAiError with the schema if missing/invalid).\n // Compute the consumer checklists this diff triggered FIRST so an unacknowledged BLOCK throws\n // here — BEFORE any `gh pr create` — matching the guarantee buildCommand already provides.\n // The SAME scan wp-review-upsert-pr runs, with filterAlreadyReviewed:true so `outstanding` is exactly what\n // still owes a verdict (Z of N of X). Sharing the computation is the point: the command that REPORTS\n // and the command that GATES must not be able to disagree about what is owed. review-<id>.json files\n // persist locally, so a re-run re-validates the EXISTING verdicts against the (possibly changed)\n // applicable set for free — an unchanged checklist needs no re-review, a newly-applicable one refuses\n // until its file is written.\n const featureName = this.aiBranchName.getFeatureName();\n const scan = this.checklistScanner.scan(repoRoot, loadAndValidate(repoRoot).prGate.checklists, new ChecklistScanOptions(true, 'stage3-finish'));\n const required = scan.applicable;\n // The applicable checklists that are supposed to HAVE a verdict — everything except the optional ones\n // nobody ran. Used for provenance and for the dashboard rows, both of which ask \"who reviewed this?\"\n // and would otherwise demand an answer from a review the human declined: provenance would refuse the\n // PR because a subagent that was never meant to run cannot be proven to have run, and the dashboard\n // would render a MISSING verdict for it.\n const verdicted = this.verdictedOf(scan);\n // FAIL FAST on an unclear checklist, BEFORE review.json is parsed and before the build gate runs. A\n // missing reviewer is not a review.json defect (folding it in made the AI fix the wrong thing), and\n // nobody should wait on a build to be told a reviewer never ran. ReviewerVerdictGate owns the\n // distinction between unreadable / REFUSED / never-ran, and retires the red verdicts it acts on.\n this.verdictGate.assertEveryReviewerRan(scan);\n const review = this.reviewJsonService.loadReviewJson(reviewJsonPath(repoRoot, featureName), required);\n\n // 2c. For any BLOCK checklist that names a reviewer `subagent`, VERIFY (from the harness's own\n // artifacts) that such a subagent actually ran on this branch — the coding agent may not\n // self-certify. Absent CLAUDE_CODE_SESSION_ID this skips with a warning (CI / plain terminal).\n const currentBranch = execSync('git branch --show-current', { encoding: 'utf8' }).trim();\n const provenance = this.enforceProvenance(verdicted, currentBranch, repoRoot, loadAndValidate(repoRoot).prGate);\n\n // 2b. The build gate validates the WORKING TREE but we push HEAD — so they MUST be identical.\n this.gitExec.assertCleanTree(repoRoot);\n\n // 3. Build gate, then post the gated body, then push (that ORDER — see GatedPrPublisher).\n this.runOrSkipBuildGate(repoRoot, buildAlreadyGreen);\n const base = this.branchNaming.baseBranchName(execSync('git branch --show-current', { encoding: 'utf8' }).trim());\n\n process.stdout.write('\\n' + SEP + '📋 Dashboard + PR\\n' + SEP + '\\n');\n const title = this.prTitleFrom(review);\n const input = this.computeDashboardInput(repoRoot, true, review, title, verdicted);\n // Append the hidden HMAC gate token bound to the LOCAL HEAD sha — computed BEFORE the push, because\n // GatedPrPublisher writes the body first so CI's `synchronize` read can never see a stale token. A\n // valid token in the PR body is proof this gated flow ran + passed on this exact commit, which CI\n // (`wp-check-pr`) recomputes. We reach here only after the build gate + every BLOCK checklist\n // passed, so minting is legitimate. Nothing about HMAC(salt, HEAD) needs the remote to have it.\n const gateSalt = loadAndValidate(repoRoot).prGate.gateSalt;\n const headSha = this.gitOut(['rev-parse', 'HEAD']);\n const body = this.dashboard.renderDashboard(input) + this.gateTokenBody(gateSalt, headSha);\n const result = this.upsertPr(repoRoot, base, body, title, input);\n // Publish each reviewer's full output as ONE combined PR comment (idempotent, opt-out-aware). Never\n // fatal — the PR is already up by now, so a comment failure only warns.\n this.postChecklistComment(repoRoot, result.prNumber, scan, review, provenance);\n this.archiveConsumedReview(repoRoot, featureName, result);\n\n // The closing recap + the clickable-link directive, BOTH derived from the real merge outcome.\n // Nothing here may hard-code success: a stranded PR under a green checkmark is how PRs got\n // abandoned (see FinishBanner).\n const bannerInput = new FinishBannerInput(result.prNumber, result.prUrl, title, base, result.merge);\n process.stdout.write(this.banner.render(bannerInput));\n process.stdout.write(this.banner.linkDirective(bannerInput));\n }\n\n // Validate + commit + finalize a 3-point merge the AI resolved, if one is in progress. Finalizing here\n // does NOT push (pushRemote=false): this command pushes exactly ONCE, from GatedPrPublisher, and only\n // after review.json + every BLOCK checklist + the build gate pass and the gated PR body is written.\n /**\n * The build gate — SKIPPED when stage ②'s receipt already covers this exact HEAD.\n *\n * The gate is authoritative per-COMMIT, not per-command: re-running it on a tree that has not moved\n * since stage ② verified it buys nothing and costs a full `nx affected`. That skip is what makes the\n * three-stage flow cost ONE build rather than two, and it is why moving the gate earlier was affordable.\n */\n private runOrSkipBuildGate(repoRoot: string, alreadyGreen: boolean): void {\n if (alreadyGreen) {\n process.stdout.write('\\n🛠️ Build gate: already green for this commit (stage ② receipt) — skipping the rebuild.\\n');\n return;\n }\n this.buildAffected.runBuildGate(repoRoot, new BuildGateOptions(\n '🛠️ Build gate (authoritative)', 'pnpm wp-finish-upsert-pr', 'Build failed — no PR created/updated.',\n ));\n }\n\n /**\n * The two stage-② preconditions, together: no unvalidated merge, and a receipt proving stage ② ran.\n * Returns true when that receipt covers the CURRENT HEAD, i.e. the build gate can be skipped.\n */\n private assertStageTwoRan(repoRoot: string): boolean {\n this.assertNoUnvalidatedMerge(repoRoot);\n return this.assertReviewStageRan(\n repoRoot, this.aiBranchName.getFeatureName(), this.gitOut(['rev-parse', 'HEAD']));\n }\n\n /**\n * REFUSE while a 3-point merge is still unvalidated — do not finalize it here.\n *\n * This command used to do the finalizing itself. Finalizing means validating a conflict resolution, and\n * two commands owning that means two implementations that can drift; `PrContextWriter`'s docstring\n * records this codebase already paying for exactly that once. It also came too late to matter: by the\n * time finish ran, the reviewers had already reviewed the pre-merge tree.\n *\n * So stage ② owns it, and finish only checks. Nothing is lost — the recovery is one command away, and\n * running it also builds the merged tree and re-briefs the reviewers against it, which finalizing here\n * never did.\n */\n private assertNoUnvalidatedMerge(repoRoot: string): void {\n const home = this.mergeState.mergeDirFor(repoRoot, this.aiBranchName.getFeatureName());\n const activeDir = this.mergeState.findActiveMergeRunDir(home);\n const marker = activeDir ? this.mergeState.readMergeMarker(activeDir) : null;\n if (!activeDir || !marker || marker.validated) return;\n throw new InformAiError(\n '⛔ NO PR — a 3-point merge on this branch is still unvalidated, so nothing here has been\\n' +\n 'verified: the conflict resolution is unchecked, the merged tree was never built, and any\\n' +\n 'reviewer that ran judged the PRE-merge code.\\n\\n' +\n `Conflicted file(s): ${marker.conflictedFiles.join(', ')}\\n\\n` +\n 'Resolve them (see .webpieces/instruct-ai/webpieces.mergeprocess.md), then run:\\n' +\n ' pnpm wp-review-upsert-pr\\n' +\n 'It validates the resolution, commits it, builds it, and re-briefs the reviewers.',\n );\n }\n\n /**\n * REQUIRE stage ② (`wp-review-upsert-pr`) to have run, and report whether it ran on THIS commit.\n *\n * Returns true when the receipt matches the current HEAD — the caller then skips its own build, because\n * the receipt IS the gate for that sha and rebuilding an unchanged tree is a second full `nx affected`\n * run for a foregone answer.\n *\n * Without this check a repo with NO checklists has nothing forcing stage ②: `assertEveryReviewerRan`\n * is vacuous, and review.json — the only other interlock — is a file the AI writes itself. It could\n * write it and come straight here, skipping the merge validation and the build entirely.\n */\n private assertReviewStageRan(repoRoot: string, featureName: string, headSha: string): boolean {\n const receipt = this.receipts.read(repoRoot, featureName);\n if (receipt === null) {\n throw new InformAiError(\n '⛔ NO PR — stage ② never ran on this branch. That means the 3-point merge is unvalidated,\\n' +\n 'the build gate has not run, no diff was extracted, and no reviewer was briefed.\\n\\n' +\n 'Run: pnpm wp-review-upsert-pr\\n' +\n '(then spawn the reviewers it names, write review.json, and re-run this command)',\n );\n }\n if (receipt.headSha === headSha) return true;\n // Not fatal. Re-reviewing on every follow-up commit would be intolerable, and most drift is a typo\n // fix. But it is never silent: the build re-runs here, and the PR says the reviewers saw an older tree.\n process.stderr.write(\n `\\n⚠️ HEAD moved since stage ② ran (reviewed ${receipt.headSha.slice(0, 8)}, now ${headSha.slice(0, 8)}).\\n` +\n ' The build gate will re-run, and the PR will record that reviewers judged an earlier tree.\\n' +\n ' If the change was substantive, re-run pnpm wp-review-upsert-pr and re-spawn the reviewers.\\n\\n');\n return false;\n }\n\n /**\n * Retire the review this run just used — move review.json to old-review.json beside it, stamped as\n * audit-only (see ReviewJsonService.archiveReviewJson).\n *\n * WHY it moves rather than staying put: review.json left behind is a live-looking file describing a\n * review that has already shipped, and the next `wp-review-upsert-pr` on this branch finds it sitting\n * there. A reviewer subagent that judges the PR's stated INTENT — its title, summary or risk level —\n * then reads the previous round's review and can return GREEN against a title that no longer exists,\n * with nothing in the verdict distinguishing that from a real pass. Moving it makes the only route back\n * to this command a freshly-written review.\n *\n * ONLY on a PR that actually went up. A run that died before publishing must stay re-runnable without\n * making the AI rewrite a review that was never used, and prNumber === '' is exactly that case.\n * Non-fatal: the PR is live by here, so an unwritable archive warns rather than failing the command.\n */\n private archiveConsumedReview(repoRoot: string, featureName: string, result: UpsertResult): void {\n if (result.prNumber === '') return;\n // webpieces-disable no-unmanaged-exceptions -- chokepoint: the PR is already up; a failed archive must not fail the command\n // eslint-disable-next-line @webpieces/no-unmanaged-exceptions\n try {\n const archived = this.reviewJsonService.archiveReviewJson(reviewJsonPath(repoRoot, featureName));\n if (archived !== '') process.stdout.write(` archived this run's review.json → ${archived} (audit only) ✓\\n`);\n // Beside it, so an archived review keeps the transcript links belonging to the round that\n // produced it — a review whose provenance was overwritten by the NEXT round audits nothing.\n this.provenanceRecord.archive(prDirFor(repoRoot, featureName));\n } catch (err: unknown) {\n const error = toError(err);\n process.stderr.write(`⚠️ Could not archive review.json (non-fatal — the PR is already up): ${error.message}\\n`);\n }\n }\n\n private gitOut(args: string[]): string {\n const result = spawnSync('git', args, { encoding: 'utf8' });\n return result.status === 0 ? (result.stdout ?? '').trim() : '';\n }\n\n // The user-facing PR title: the AI-authored review.title, or — if omitted — a readable fallback\n // derived from the stable feature name (NEVER the internal `Squash merge of <branch>` commit subject).\n private prTitleFrom(review: ReviewJson): string {\n if (review.title !== '') return review.title;\n return this.aiBranchName.getFeatureName().replace(/[-/]+/g, ' ').trim();\n }\n\n // eslint-disable-next-line @typescript-eslint/max-params\n private computeDashboardInput(repoRoot: string, buildPassed: boolean, review: ReviewJson, title: string, required: readonly RequiredChecklist[]): DashboardInput {\n const config = loadAndValidate(repoRoot).prGate;\n const forkPoint = this.gitOut(['merge-base', 'origin/main', 'HEAD']);\n const featureHead = this.gitOut(['rev-parse', 'HEAD']);\n const mainHead = this.gitOut(['rev-parse', 'origin/main']);\n const range = `${forkPoint}..${featureHead}`;\n const changedFiles = this.gitOut(['diff', range, '--name-only']).split('\\n').filter((f: string): boolean => f.trim() !== '');\n const patch = this.gitOut(['diff', range]);\n\n const gateResults = this.dashboard.computeGateResults(config.gates, changedFiles);\n const disables = this.dashboard.countAddedDisables(patch);\n const rows = this.checklistRows(required, review);\n return new DashboardInput(title, gateResults, disables, buildPassed, forkPoint, featureHead, mainHead, review, rows);\n }\n\n /**\n * The applicable checklists MINUS the optional ones nobody ran.\n *\n * Not folded into `ChecklistScan` as yet another field: `applicable` (what matched) and `optionalNotRun`\n * (what was declined) are both facts about the scan, whereas this is one command's view of them, and the\n * roster comment deliberately wants the OTHER view — it lists the declined ones precisely so the PR does\n * not imply they passed.\n */\n private verdictedOf(scan: ChecklistScan): RequiredChecklist[] {\n const skipped = new Set(scan.optionalNotRun.map((r: RequiredChecklist): string => r.id));\n return scan.applicable.filter((r: RequiredChecklist): boolean => !skipped.has(r.id));\n }\n\n // Pair each matched checklist with its resolved verdict for the dashboard.\n //\n // A checklist reaching this point is always PASS, WARN or OVERRIDDEN, and the reason is ReviewerVerdictGate\n // — NOT loadReviewJson. The gate runs one line earlier and throws on every other state (FAIL, MISSING,\n // BAD_FORMAT), so loadReviewJson's own checklist validation can no longer be the thing that rejects them;\n // it re-validates the same set and finds it clean. This comment used to credit loadReviewJson, which made\n // the ordering look deliberate while the gate's generic \"no verdict yet\" message masked every refusal.\n // WARN belongs in that list: yellow SHIPS, so it is not outstanding and reaches the dashboard.\n private checklistRows(required: readonly RequiredChecklist[], review: ReviewJson): ChecklistRow[] {\n return required.map((req: RequiredChecklist): ChecklistRow => {\n const verdict = this.reviewJsonService.resolveVerdict(req, review.results);\n return new ChecklistRow(req.id, verdict.status, verdict.detail);\n });\n }\n\n /**\n * One comment row per DEFINED checklist — matched or not — pairing the roster's match evidence with the\n * resolved verdict. Built from `scan.roster` rather than from the applicable set: the skipped ones are\n * absent from `applicable` by construction, and their \"why not\" evidence (the configured globs and the\n * changed-file total) exists nowhere else without recomputing the diff a second way.\n */\n private commentRows(scan: ChecklistScan, review: ReviewJson, provenance: ProvenanceReport): ChecklistCommentRow[] {\n // agentType -> did it open the diff. Absent ⇒ not assessed, which prints nothing (see ChecklistCommentRow.diffRead).\n const readByAgent = new Map<string, boolean>();\n for (const e of provenance.evidence) readByAgent.set(e.agentType, e.readDiff);\n return scan.roster.entries.map((entry: TriggeredChecklist): ChecklistCommentRow => {\n const ran = entry.matchedFiles.length > 0;\n const req = new RequiredChecklist(\n entry.def.id, entry.def.subagent, entry.def.doc, entry.matchedFiles, entry.matchedPatterns,\n entry.def.required);\n // A skipped checklist has no verdict to resolve — asking for one would report it as MISSING,\n // i.e. as an unreviewed obligation, when in fact it never had one.\n const verdict = ran\n ? this.reviewJsonService.resolveVerdict(req, review.results)\n : new ChecklistVerdict(entry.def.id, '', '');\n const row = new ChecklistCommentRow(\n entry.def.subagent, verdict.status, verdict.detail, ran,\n entry.def.patterns, entry.matchedPatterns, entry.matchedFiles, scan.roster.changedFileCount);\n row.required = entry.def.required;\n const read = readByAgent.get(entry.def.subagent);\n row.diffRead = read === undefined ? '' : (read ? 'yes' : 'no');\n return row;\n });\n }\n\n // Hidden HMAC gate-token marker (with a leading blank line) to append to the PR body, or '' when the\n // repo sets no gateSalt (byte-identical body to before this feature). Bound to the pushed HEAD sha.\n private gateTokenBody(gateSalt: string, headSha: string): string {\n const marker = this.gateTokenService.gateTokenMarker(gateSalt, headSha);\n return marker === '' ? '' : `\\n\\n${marker}\\n`;\n }\n\n // Enforce that EACH matched checklist was reviewed by its OWN named subagent, as a DISTINCT run —\n // the coding agent may not self-certify, and one reviewer may not stand in for several. A verified set\n // passes silently; no session id warns but passes; any missing reviewer throws so the PR does not open.\n // eslint-disable-next-line @typescript-eslint/max-params\n private enforceProvenance(required: readonly RequiredChecklist[], branch: string, repoRoot: string, config: PrGateConfig): ProvenanceReport {\n const errors: string[] = [];\n const report = new ProvenanceReport(true, []); // no reviewers to verify ⇒ vacuously verified\n const subagents = required.map((r: RequiredChecklist): string => r.subagent.trim()).filter((s: string): boolean => s !== '');\n // verifyDistinct short-circuits to OK on an empty set, so this runs unconditionally: a repo with no\n // checklists still gets a provenance record naming the session and the main agent's own transcript.\n const result = this.provenance.verifyDistinct(subagents, branch);\n report.verified = result.status === PROVENANCE_OK;\n if (result.status === PROVENANCE_MISSING) {\n errors.push(result.detail);\n } else if (result.status === PROVENANCE_SKIPPED) {\n process.stderr.write(`⚠️ ${result.detail}\\n`);\n }\n report.evidence = this.gatherEvidence(repoRoot, required, result, branch);\n errors.push(...this.evidenceErrors(report.evidence, config));\n // BEFORE the throw below, deliberately. A refused round is the one most worth auditing, and a record\n // that only ever appeared on success could not answer what the reviewers did the time it was refused.\n this.writeProvenanceRecord(repoRoot, required, result, report.evidence);\n if (errors.length > 0) {\n throw new InformAiError(\n `${errors.length} checklist(s) require an independent reviewer subagent that did not run — fix, then re-run pnpm wp-finish-upsert-pr:\\n\\n` +\n errors.map((e: string): string => ` • ${e}`).join('\\n') +\n `\\n\\nSpawn the named reviewer subagent to review the checklist on THIS branch, then re-run.`,\n );\n }\n return report;\n }\n\n /**\n * What each credited reviewer actually read. Purely observational here — {@link evidenceErrors} decides\n * whether any of it blocks, and by default none of it does.\n */\n // eslint-disable-next-line @typescript-eslint/max-params\n private gatherEvidence(repoRoot: string, required: readonly RequiredChecklist[], result: ProvenanceResult, branch: string): ReviewerEvidence[] {\n const docPaths: Record<string, string> = {};\n for (const req of required) {\n if (req.subagent.trim() !== '') docPaths[req.subagent] = req.doc.trim() === '' ? '' : path.resolve(repoRoot, req.doc);\n }\n const diffDir = path.join(prDirFor(repoRoot, this.aiBranchName.getFeatureName()), 'diff');\n return this.provenance.evidenceFor(new EvidenceRequest(branch, result.agentIds, diffDir, docPaths));\n }\n\n /**\n * Write this round's audit record: `.webpieces/pr-review/<branch>/provenance.json`, linking each verdict\n * to the transcript of the subagent that produced it.\n *\n * A SEPARATE file rather than a field inside review.json / review-<id>.json, for two reasons. The\n * reviewer cannot supply this itself — a subagent's environment exposes the PARENT session id and no\n * agent id, so a self-reported transcript link would be invented — and keeping the AI-authored files\n * byte-untouched means nothing in the record can be mistaken for something a reviewer claimed about\n * itself. Every path here is derived by the tooling from the harness's own artifacts.\n *\n * Never fatal: an unwritable record is a lost audit trail, not a reason to refuse a PR.\n */\n // eslint-disable-next-line @typescript-eslint/max-params\n private writeProvenanceRecord(repoRoot: string, required: readonly RequiredChecklist[], result: ProvenanceResult, evidence: readonly ReviewerEvidence[]): void {\n const featureName = this.aiBranchName.getFeatureName();\n const prDir = prDirFor(repoRoot, featureName);\n const request = new ProvenanceWriteRequest(prDir, featureName, this.gitOut(['rev-parse', 'HEAD']), result.status);\n request.offered = new OfferedContext(\n path.join(prDir, 'diff'), this.reviewerInstructions.instructionsDirFor(repoRoot, featureName));\n request.reviewers = evidence.map((e: ReviewerEvidence): ReviewerTranscript =>\n new ReviewerTranscript(e, this.reviewerPathsFor(repoRoot, featureName, required, e.agentType)));\n const written = this.provenanceRecord.write(request);\n if (written !== '') process.stdout.write(` transcript provenance → ${written}\\n`);\n }\n\n // Where ONE reviewer's verdict, instructions and checklist doc live. Keyed by agentType, which IS the\n // checklist id: ChecklistDefinition sets `id = subagent`, so the two never diverge.\n // eslint-disable-next-line @typescript-eslint/max-params\n private reviewerPathsFor(repoRoot: string, featureName: string, required: readonly RequiredChecklist[], agentType: string): ReviewerPaths {\n const req = required.find((r: RequiredChecklist): boolean => r.subagent.trim() === agentType);\n const doc = req !== undefined && req.doc.trim() !== '' ? path.resolve(repoRoot, req.doc) : '';\n return new ReviewerPaths(\n this.reviewJsonService.checklistResultPath(reviewJsonPath(repoRoot, featureName), req?.id ?? agentType),\n this.reviewerInstructions.pathFor(repoRoot, featureName, agentType),\n doc,\n );\n }\n\n /**\n * WARN (default) or REFUSE (opt-in) on a reviewer that wrote a verdict without opening the diff.\n *\n * Default-warn because the signal is derived from undocumented Claude Code transcript internals: if the\n * format shifts, a blocking check wedges every PR in every consumer repo with no self-service recovery.\n * `requireDiffEvidence` lets a repo that has watched the warning promote it deliberately.\n */\n private evidenceErrors(evidence: readonly ReviewerEvidence[], config: PrGateConfig): string[] {\n const blind = evidence.filter((e: ReviewerEvidence): boolean => !e.readDiff);\n if (blind.length === 0) return [];\n const names = blind.map((e: ReviewerEvidence): string => e.agentType).join(', ');\n if (!config.requireDiffEvidence) {\n process.stderr.write(\n `\\n⚠️ ${blind.length} reviewer(s) wrote a verdict with no record of opening the extracted diff: ${names}\\n` +\n ' Published on the PR as a note. Not blocking — set pr-gate.requireDiffEvidence:true to make it one.\\n');\n return [];\n }\n return [`these reviewers wrote a verdict without opening the diff (pr-gate.requireDiffEvidence is on): ${names}`];\n }\n\n /**\n * Publish the roster + every reviewer's full `output` as ONE combined PR comment, idempotently (find the\n * marker comment → PATCH it, else POST). Never fatal: by here the PR is already created/updated, so a\n * `gh` failure only warns.\n *\n * Posted on EVERY run of a repo that defines checklists — including one where nothing matched, because\n * \"all five were evaluated and none applied\" is the good news the old comment could not deliver. The\n * guard is `scan.defined.length`, deliberately NOT the number of rows that ran: a repo with no\n * checklists configured must still see no comment at all (see ChecklistNotice / renderDashboard).\n */\n // eslint-disable-next-line @typescript-eslint/max-params\n // eslint-disable-next-line @typescript-eslint/max-params\n private postChecklistComment(repoRoot: string, prNumber: string, scan: ChecklistScan, review: ReviewJson, provenance: ProvenanceReport): void {\n if (prNumber === '' || scan.defined.length === 0) return;\n if (!loadAndValidate(repoRoot).prGate.checklistComments) return;\n const body = this.dashboard.renderChecklistComment(\n this.commentRows(scan, review, provenance), provenance.verified, scan.roster.baseResolved);\n const prDir = prDirFor(repoRoot, this.aiBranchName.getFeatureName());\n fs.mkdirSync(prDir, { recursive: true });\n const payload = path.join(prDir, 'checklist-comment.json');\n fs.writeFileSync(payload, JSON.stringify({ body }));\n const commentId = this.findChecklistCommentId(prNumber);\n const args = commentId !== ''\n ? ['api', '--method', 'PATCH', `repos/{owner}/{repo}/issues/comments/${commentId}`, '--input', payload]\n : ['api', '--method', 'POST', `repos/{owner}/{repo}/issues/${prNumber}/comments`, '--input', payload];\n const res = spawnSync('gh', args, { encoding: 'utf8' });\n if (res.status !== 0) {\n process.stderr.write('⚠️ Could not post the checklist review comment (non-fatal — the PR is already up).\\n');\n } else {\n process.stdout.write(` ${commentId !== '' ? 'updated' : 'posted'} the checklist review comment ✓\\n`);\n }\n }\n\n // The id of THIS tool's existing checklist comment on the PR (by the hidden marker), or '' if none.\n private findChecklistCommentId(prNumber: string): string {\n const res = spawnSync('gh', [\n 'api', '--paginate', `repos/{owner}/{repo}/issues/${prNumber}/comments`,\n '--jq', `.[] | select(.body | contains(\"${CHECKLIST_COMMENT_MARKER}\")) | .id`,\n ], { encoding: 'utf8' });\n if (res.status !== 0) return '';\n return (res.stdout ?? '').trim().split('\\n')[0] ?? '';\n }\n\n // The PR, the remote branch, and the local branch all share the one stable feature name. Look up /\n // create / merge against `baseBranch` (baseBranchName tolerates a leftover `…wpN` mid-transition).\n // GatedPrPublisher owns the edit/push/create half and its ORDERING — the gated body goes up before\n // the push, so CI's `synchronize` read cannot see the previous run's token.\n private upsertPr(repoRoot: string, baseBranch: string, body: string, title: string, input: DashboardInput): UpsertResult {\n const prDir = prDirFor(repoRoot, this.aiBranchName.getFeatureName());\n fs.mkdirSync(prDir, { recursive: true });\n const bodyFile = path.join(prDir, 'pr-body.md');\n fs.writeFileSync(bodyFile, body + '\\n');\n\n const published = this.publisher.publish(baseBranch, title, bodyFile);\n if (published.createFailed) {\n process.stderr.write('⚠️ gh pr create failed — create the PR manually with the body in:\\n ' + bodyFile + '\\n');\n return new UpsertResult('', '', new MergeOutcome(false, false,\n '⚠️ did NOT merge — there is no PR to merge (gh pr create failed above)', MERGE_RESULT_FAILED));\n }\n const num = published.number;\n\n // Set the squash-merge SUBJECT to the PR title (+ the `(#N)` GitHub normally appends, which an\n // explicit --subject would otherwise drop) and the BODY to the compact commit summary, so main's\n // history carries the PR title + risk/flags/link — NOT the internal `Squash merge of <branch>`\n // subject GitHub would inherit from the single squash commit on the branch.\n const ref = this.prRef(baseBranch);\n const subject = ref.number !== '' ? `${title} (#${ref.number})` : title;\n const mergeBodyFile = path.join(prDir, 'merge-commit-body.md');\n fs.writeFileSync(mergeBodyFile, this.dashboard.renderCommitBody(input, ref.url) + '\\n');\n // PrMerger owns the direct-merge / auto-merge-fallback decision AND checks every gh status, so a\n // merge that did not happen is reported as such instead of being swallowed (see pr-merger.ts).\n // REQUIRED config — no default here on purpose. A missing value (an older published\n // rules-config that has no such field) reaches PrMerger as '' and is treated as \"do not merge\".\n const mergeMode = loadAndValidate(repoRoot).prGate.mergeMode ?? '';\n const outcome = this.prMerger.merge(baseBranch, subject, mergeBodyFile, mergeMode);\n return new UpsertResult(ref.number !== '' ? ref.number : num, ref.url, outcome);\n }\n\n // The PR's number + web URL (for the merge subject `(#N)` and the commit-body back-link). Both ''\n // if it can't be resolved. Rendered via jq into one tab-separated line so no JSON parsing is needed.\n private prRef(baseBranch: string): PrRef {\n const result = spawnSync(\n 'gh', ['pr', 'view', baseBranch, '--json', 'number,url', '--jq', '\"\\\\(.number)\\\\t\\\\(.url)\"'],\n { encoding: 'utf8' },\n );\n if (result.status !== 0) {\n return new PrRef('', '');\n }\n const parts = (result.stdout ?? '').trim().split('\\t');\n return new PrRef(parts[0] ?? '', parts[1] ?? '');\n }\n}\n"]}
|
|
@@ -11,6 +11,17 @@ import { PrContextWriter } from '../workflow/pr-context-writer';
|
|
|
11
11
|
import { ReviewerBriefingBuilder } from '../workflow/reviewer-briefing-builder';
|
|
12
12
|
import { ReviewReport } from '../workflow/review-report';
|
|
13
13
|
import { ReviewStageReceiptService } from '../workflow/review-stage-receipt';
|
|
14
|
+
/** The `--no-optional` decision, as data (per CLAUDE.md) rather than a bare boolean parameter. */
|
|
15
|
+
export declare class ReviewUpsertPrOptions {
|
|
16
|
+
/**
|
|
17
|
+
* true ⇒ the human ALREADY said to submit without the optional reviews, so stage ② must not print the
|
|
18
|
+
* block telling the AI to offer them. It changes nothing about what BLOCKS: required checklists are
|
|
19
|
+
* unaffected, and an optional checklist that already has a red verdict on this branch still refuses the
|
|
20
|
+
* PR at finish. This only suppresses the offer.
|
|
21
|
+
*/
|
|
22
|
+
skipOptional: boolean;
|
|
23
|
+
constructor(skipOptional?: boolean);
|
|
24
|
+
}
|
|
14
25
|
/**
|
|
15
26
|
* `wp-review-upsert-pr` — STAGE ② of the three-stage PR flow, between `wp-start-upsert-pr` (sync from main)
|
|
16
27
|
* and `wp-finish-upsert-pr` (post the PR).
|
|
@@ -51,7 +62,7 @@ export declare class ReviewUpsertPrCommand {
|
|
|
51
62
|
private readonly receipts;
|
|
52
63
|
private readonly reviewJsonService;
|
|
53
64
|
constructor(repoRootFinder: RepoRootFinder, aiBranchName: AiBranchName, gitExec: GitExec, buildAffected: BuildAffected, buildArtifactGate: BuildArtifactGate, mergeState: MergeState, mergeEnd: MergeEnd, checklistScanner: ChecklistScanner, reviewReport: ReviewReport, materializer: DiffMaterializer, prContextWriter: PrContextWriter, briefingBuilder: ReviewerBriefingBuilder, reviewerInstructions: ReviewerInstructionsService, receipts: ReviewStageReceiptService, reviewJsonService: ReviewJsonService);
|
|
54
|
-
run(): Promise<void>;
|
|
65
|
+
run(opts?: ReviewUpsertPrOptions): Promise<void>;
|
|
55
66
|
/**
|
|
56
67
|
* Validate + commit + finalize a conflict resolution, if one is in flight. MOVED here from
|
|
57
68
|
* `wp-finish-upsert-pr` so that exactly one command owns merge finalization — two owners is the drift
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.ReviewUpsertPrCommand = void 0;
|
|
3
|
+
exports.ReviewUpsertPrCommand = exports.ReviewUpsertPrOptions = void 0;
|
|
4
4
|
const tslib_1 = require("tslib");
|
|
5
5
|
const fs = tslib_1.__importStar(require("fs"));
|
|
6
6
|
const rules_config_1 = require("@webpieces/rules-config");
|
|
@@ -19,6 +19,20 @@ const reviewer_briefing_builder_1 = require("../workflow/reviewer-briefing-build
|
|
|
19
19
|
const review_report_1 = require("../workflow/review-report");
|
|
20
20
|
const review_stage_receipt_1 = require("../workflow/review-stage-receipt");
|
|
21
21
|
const SEP = '━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n';
|
|
22
|
+
/** The `--no-optional` decision, as data (per CLAUDE.md) rather than a bare boolean parameter. */
|
|
23
|
+
class ReviewUpsertPrOptions {
|
|
24
|
+
/**
|
|
25
|
+
* true ⇒ the human ALREADY said to submit without the optional reviews, so stage ② must not print the
|
|
26
|
+
* block telling the AI to offer them. It changes nothing about what BLOCKS: required checklists are
|
|
27
|
+
* unaffected, and an optional checklist that already has a red verdict on this branch still refuses the
|
|
28
|
+
* PR at finish. This only suppresses the offer.
|
|
29
|
+
*/
|
|
30
|
+
skipOptional;
|
|
31
|
+
constructor(skipOptional = false) {
|
|
32
|
+
this.skipOptional = skipOptional;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
exports.ReviewUpsertPrOptions = ReviewUpsertPrOptions;
|
|
22
36
|
/**
|
|
23
37
|
* `wp-review-upsert-pr` — STAGE ② of the three-stage PR flow, between `wp-start-upsert-pr` (sync from main)
|
|
24
38
|
* and `wp-finish-upsert-pr` (post the PR).
|
|
@@ -78,7 +92,7 @@ let ReviewUpsertPrCommand = class ReviewUpsertPrCommand {
|
|
|
78
92
|
this.receipts = receipts;
|
|
79
93
|
this.reviewJsonService = reviewJsonService;
|
|
80
94
|
}
|
|
81
|
-
async run() {
|
|
95
|
+
async run(opts = new ReviewUpsertPrOptions()) {
|
|
82
96
|
const repoRoot = this.repoRootFinder.resolveRepoRoot(process.cwd());
|
|
83
97
|
(0, rules_config_1.writeTemplate)(repoRoot, 'webpieces.git-workflow.md');
|
|
84
98
|
(0, rules_config_1.writeTemplate)(repoRoot, 'webpieces.review-checklists.md');
|
|
@@ -90,7 +104,7 @@ let ReviewUpsertPrCommand = class ReviewUpsertPrCommand {
|
|
|
90
104
|
const scan = this.checklistScanner.scan(repoRoot, config.checklists, new checklist_scanner_1.ChecklistScanOptions(false, '')); // '' — THIS command writes the context itself, after materializing
|
|
91
105
|
const briefings = this.briefReviewers(repoRoot, featureName, scan, config);
|
|
92
106
|
this.receipts.write(repoRoot, featureName, new review_stage_receipt_1.ReviewStageReceipt(scan.basis.headSha, mergeValidated, this.buildAffected.resolveBuildCommand(repoRoot), buildPassedAt, briefings.map((b) => b.subagent)));
|
|
93
|
-
this.report(repoRoot, featureName, scan, briefings);
|
|
107
|
+
this.report(repoRoot, featureName, scan, briefings, opts);
|
|
94
108
|
}
|
|
95
109
|
/**
|
|
96
110
|
* Validate + commit + finalize a conflict resolution, if one is in flight. MOVED here from
|
|
@@ -162,7 +176,8 @@ let ReviewUpsertPrCommand = class ReviewUpsertPrCommand {
|
|
|
162
176
|
* while the block right beneath it said to write review.json first. An agent that reads top to bottom
|
|
163
177
|
* obeyed the first line and posted a PR with no review at all.
|
|
164
178
|
*/
|
|
165
|
-
|
|
179
|
+
// eslint-disable-next-line @typescript-eslint/max-params
|
|
180
|
+
report(repoRoot, featureName, scan, briefings, opts) {
|
|
166
181
|
const input = new review_report_1.ReviewReportInput(repoRoot, featureName, scan.reviewPath);
|
|
167
182
|
input.definedCount = scan.defined.length;
|
|
168
183
|
input.applicableCount = scan.applicable.length;
|
|
@@ -170,6 +185,7 @@ let ReviewUpsertPrCommand = class ReviewUpsertPrCommand {
|
|
|
170
185
|
input.formatErrors = scan.formatErrors.slice();
|
|
171
186
|
input.briefings = briefings.slice();
|
|
172
187
|
input.refused = this.refusals(scan);
|
|
188
|
+
input.skipOptional = opts.skipOptional;
|
|
173
189
|
process.stdout.write(this.reviewReport.render(input));
|
|
174
190
|
}
|
|
175
191
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"review-upsert-pr-command.js","sourceRoot":"","sources":["../../../../../../../packages/tooling/pr-gate/src/scripts/commands/review-upsert-pr-command.ts"],"names":[],"mappings":"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","sourcesContent":["import * as fs from 'fs';\nimport {\n loadAndValidate, writeTemplate, PrGateConfig, RepoRootFinder, RequiredChecklist,\n ReviewerBriefing, ReviewerInstructionsService, ReviewJsonService,\n} from '@webpieces/rules-config';\nimport { injectable, bindingScopeValues } from 'inversify';\nimport { AiBranchName } from '../workflow/git-readAiBranchName';\nimport { BuildAffected, BuildGateOptions } from '../workflow/build-affected';\nimport { BuildArtifactGate } from '../workflow/build-artifact-gate';\nimport { ChecklistScan, ChecklistScanOptions, ChecklistScanner } from '../workflow/checklist-scanner';\nimport { DiffMaterializer } from '../workflow/diff-materializer';\nimport { GitExec } from '../workflow/git-exec';\nimport { MergeContext } from '../workflow/merge-start';\nimport { MergeEnd, MergeEndOptions } from '../workflow/merge-end';\nimport { MergeState } from '../workflow/merge-state';\nimport { PrContextWriter } from '../workflow/pr-context-writer';\nimport { ReviewerBriefingBuilder } from '../workflow/reviewer-briefing-builder';\nimport { RefusedReviewer, ReviewReport, ReviewReportInput } from '../workflow/review-report';\nimport { ReviewStageReceipt, ReviewStageReceiptService } from '../workflow/review-stage-receipt';\n\nconst SEP = '━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\\n';\n\n/**\n * `wp-review-upsert-pr` — STAGE ② of the three-stage PR flow, between `wp-start-upsert-pr` (sync from main)\n * and `wp-finish-upsert-pr` (post the PR).\n *\n * It exists because reviewing came before verifying. Under the old two-command flow the 3-point merge was\n * finalized and the build gate ran inside `wp-finish-upsert-pr` — i.e. AFTER the reviewers had already run.\n * A reviewer could therefore spend a full review on an unresolved merge, or on code that does not compile,\n * and only afterwards would the branch be checked. This command puts the verification first:\n *\n * 1. finalize + VALIDATE any in-progress 3-point merge (moved here from finish)\n * 2. assert a clean tree (meaningful now — step 1 committed the resolution)\n * 3. run the build gate (on the merged, committed tree)\n * 4. scan the checklists, EXTRACT the diff, BRIEF the reviewers\n * 5. write the stage receipt, then print what to spawn + the review.json schema\n *\n * Unlike the report-only command it replaces — which always exited 0, because reporting is not gating — this\n * command CAN FAIL, at steps 1, 2 and 3. That is the point: it fails BEFORE any reviewer is spawned, so a\n * branch with an unresolved merge or a broken build costs zero reviewer tokens.\n *\n * The ordering of 1 → 2 → 3 is load-bearing. MergeEnd stages and commits the conflict resolution, so the\n * tree is clean by the time the build runs; building first would either build a dirty tree (proving nothing\n * about what ships) or refuse a tree that is legitimately mid-resolution.\n */\n@injectable(bindingScopeValues.Singleton)\nexport class ReviewUpsertPrCommand {\n // eslint-disable-next-line @typescript-eslint/max-params\n constructor(\n private readonly repoRootFinder: RepoRootFinder,\n private readonly aiBranchName: AiBranchName,\n private readonly gitExec: GitExec,\n private readonly buildAffected: BuildAffected,\n private readonly buildArtifactGate: BuildArtifactGate,\n private readonly mergeState: MergeState,\n private readonly mergeEnd: MergeEnd,\n private readonly checklistScanner: ChecklistScanner,\n private readonly reviewReport: ReviewReport,\n private readonly materializer: DiffMaterializer,\n private readonly prContextWriter: PrContextWriter,\n private readonly briefingBuilder: ReviewerBriefingBuilder,\n private readonly reviewerInstructions: ReviewerInstructionsService,\n private readonly receipts: ReviewStageReceiptService,\n // Injected only to RESOLVE + RENDER refusals (see refusals()). This stage never archives a verdict.\n private readonly reviewJsonService: ReviewJsonService,\n ) {}\n\n async run(): Promise<void> {\n const repoRoot = this.repoRootFinder.resolveRepoRoot(process.cwd());\n writeTemplate(repoRoot, 'webpieces.git-workflow.md');\n writeTemplate(repoRoot, 'webpieces.review-checklists.md');\n const featureName = this.aiBranchName.getFeatureName();\n const config = loadAndValidate(repoRoot).prGate;\n\n const mergeValidated = await this.finalizeAnyInProgressMerge(repoRoot);\n this.gitExec.assertCleanTree(repoRoot);\n const buildPassedAt = this.runBuildGate(repoRoot);\n\n const scan = this.checklistScanner.scan(repoRoot, config.checklists, new ChecklistScanOptions(false, '')); // '' — THIS command writes the context itself, after materializing\n const briefings = this.briefReviewers(repoRoot, featureName, scan, config);\n this.receipts.write(repoRoot, featureName, new ReviewStageReceipt(\n scan.basis.headSha, mergeValidated, this.buildAffected.resolveBuildCommand(repoRoot), buildPassedAt,\n briefings.map((b: ReviewerBriefing): string => b.subagent),\n ));\n this.report(repoRoot, featureName, scan, briefings);\n }\n\n /**\n * Validate + commit + finalize a conflict resolution, if one is in flight. MOVED here from\n * `wp-finish-upsert-pr` so that exactly one command owns merge finalization — two owners is the drift\n * failure `PrContextWriter`'s own docstring records having already happened once in this codebase.\n *\n * MergeEnd's three checks are what \"did the AI do the 3-point merge right?\" means concretely: no\n * conflict markers left in the scoped files, `git diff --diff-filter=U` empty, and a non-empty\n * merge-explanation.md beside every conflicted file.\n *\n * Returns true when a merge was finalized OR there was none to finalize; it throws rather than returning\n * false when validation fails, so the receipt can never record an unvalidated merge as validated.\n */\n private async finalizeAnyInProgressMerge(repoRoot: string): Promise<boolean> {\n const home = this.mergeState.mergeDirFor(repoRoot, this.aiBranchName.getFeatureName());\n const activeDir = this.mergeState.findActiveMergeRunDir(home);\n const marker = activeDir ? this.mergeState.readMergeMarker(activeDir) : null;\n if (!activeDir || !marker || marker.validated) return true;\n process.stdout.write('\\n' + SEP + '① Validating your 3-point merge\\n' + SEP + '\\n');\n // pushRemote:false — finish still owns the single push.\n await this.mergeEnd.mergeEnd(\n repoRoot, 'wp-review-upsert-pr', activeDir,\n new MergeContext(marker.currentBranch, marker.squashBranch, marker.backupBranch, marker.prNumber),\n new MergeEndOptions(marker.conflictedFiles, false),\n );\n return true;\n }\n\n /**\n * The build gate, run BEFORE any reviewer is briefed. Returns the ISO time it passed, for the receipt —\n * which is what lets `wp-finish-upsert-pr` skip its own gate when HEAD has not moved, so moving the gate\n * earlier did not turn one build into two.\n */\n private runBuildGate(repoRoot: string): string {\n this.buildAffected.runBuildGate(repoRoot, new BuildGateOptions(\n '🛠️ Build gate',\n 'pnpm wp-review-upsert-pr',\n 'Build failed — NO reviewer was briefed and no diff was extracted. Fix it, then re-run.',\n ));\n // Repo-wide: the build must not have left anything uncommitted AND unstaged. Runs HERE, not in\n // finish, because this is the stage that ran buildCommand and is therefore holding the dirty\n // tree at the exact moment the question is answerable. Replaces the per-project\n // validate-di-graph-unchanged nx target — see BuildArtifactGate for why that one had to go.\n this.buildArtifactGate.assertBuildLeftNothingUncommitted(repoRoot);\n return new Date().toISOString();\n }\n\n /**\n * Extract the diff once, then write one instructions file per reviewer.\n *\n * The changed-file set and the basis both come off the SCAN rather than being recomputed, so the diff a\n * reviewer reads covers exactly the files its checklist matched against.\n */\n private briefReviewers(repoRoot: string, featureName: string, scan: ChecklistScan, config: PrGateConfig): ReviewerBriefing[] {\n if (scan.basis.unresolved) return [];\n const manifest = this.materializer.materialize(\n repoRoot, featureName, scan.basis, scan.changedFiles, config.reviewDiffExclude);\n const diffDir = this.materializer.diffDirFor(repoRoot, featureName);\n // Write pr-context.json ONCE, here — after materializing, so `diffDir` is populated on the first\n // write. The scan deliberately did not write it (ChecklistScanOptions.contextStage === ''); it used\n // to, which meant this command wrote the same file twice, the first time with an empty diffDir.\n // `scan.changedFiles` is passed through so the context is not recomputed from a second git call.\n scan.context = this.prContextWriter.ensure(\n repoRoot, featureName, scan.basis, 'stage2-review', scan.changedFiles, diffDir);\n const briefings = this.briefingBuilder.build(repoRoot, scan, manifest, diffDir, config);\n const dir = this.reviewerInstructions.instructionsDirFor(repoRoot, featureName);\n fs.rmSync(dir, { recursive: true, force: true }); // stale instructions read as current are worse than none\n fs.mkdirSync(dir, { recursive: true });\n for (const b of briefings) {\n fs.writeFileSync(this.reviewerInstructions.pathFor(repoRoot, featureName, b.subagent),\n this.reviewerInstructions.render(b));\n }\n return briefings;\n }\n\n /**\n * What the AI must do next — rendered by `ReviewReport`, which owns the ordering.\n *\n * The rendering moved OUT of this command so the ordering could be asserted on as a string. It had a\n * real bug: the zero-checklist notice signed off with \"Carry on and run: pnpm wp-finish-upsert-pr\"\n * while the block right beneath it said to write review.json first. An agent that reads top to bottom\n * obeyed the first line and posted a PR with no review at all.\n */\n private report(repoRoot: string, featureName: string, scan: ChecklistScan, briefings: readonly ReviewerBriefing[]): void {\n const input = new ReviewReportInput(repoRoot, featureName, scan.reviewPath);\n input.definedCount = scan.defined.length;\n input.applicableCount = scan.applicable.length;\n input.reviewed = scan.reviewed.slice();\n input.formatErrors = scan.formatErrors.slice();\n input.briefings = briefings.slice();\n input.refused = this.refusals(scan);\n process.stdout.write(this.reviewReport.render(input));\n }\n\n /**\n * The applicable checklists that ALREADY ANSWERED and refused, each with its refusal rendered by the ONE\n * renderer `wp-finish-upsert-pr` also uses.\n *\n * Stage ② had the identical defect finish did: a refused checklist has no passing verdict, so it is not\n * in `scan.reviewed`, so it was printed as an ordinary owed reviewer and re-instructed word for word —\n * and an agent that obeys spawns it against unchanged code, gets the same refusal, and loops one stage\n * earlier than the loop that was reported.\n *\n * NO archive path is passed, deliberately, and this stage moves nothing. Retiring a verdict is finish's\n * act on the refusal it is actually enforcing; doing it here would delete the live verdict of a branch\n * that has not even been asked to finish yet, and `refusalError`'s un-archived wording — \"set an override\n * in review-<id>.json\" — is only correct while that file is still there, which here it is.\n */\n private refusals(scan: ChecklistScan): RefusedReviewer[] {\n const refused = this.reviewJsonService.refusedChecklists(scan.applicable, scan.results);\n return refused.map((req: RequiredChecklist): RefusedReviewer => new RefusedReviewer(\n req.id, this.reviewJsonService.refusalError(req, this.reviewJsonService.resolveVerdict(req, scan.results))));\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"review-upsert-pr-command.js","sourceRoot":"","sources":["../../../../../../../packages/tooling/pr-gate/src/scripts/commands/review-upsert-pr-command.ts"],"names":[],"mappings":"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","sourcesContent":["import * as fs from 'fs';\nimport {\n loadAndValidate, writeTemplate, PrGateConfig, RepoRootFinder, RequiredChecklist,\n ReviewerBriefing, ReviewerInstructionsService, ReviewJsonService,\n} from '@webpieces/rules-config';\nimport { injectable, bindingScopeValues } from 'inversify';\nimport { AiBranchName } from '../workflow/git-readAiBranchName';\nimport { BuildAffected, BuildGateOptions } from '../workflow/build-affected';\nimport { BuildArtifactGate } from '../workflow/build-artifact-gate';\nimport { ChecklistScan, ChecklistScanOptions, ChecklistScanner } from '../workflow/checklist-scanner';\nimport { DiffMaterializer } from '../workflow/diff-materializer';\nimport { GitExec } from '../workflow/git-exec';\nimport { MergeContext } from '../workflow/merge-start';\nimport { MergeEnd, MergeEndOptions } from '../workflow/merge-end';\nimport { MergeState } from '../workflow/merge-state';\nimport { PrContextWriter } from '../workflow/pr-context-writer';\nimport { ReviewerBriefingBuilder } from '../workflow/reviewer-briefing-builder';\nimport { RefusedReviewer, ReviewReport, ReviewReportInput } from '../workflow/review-report';\nimport { ReviewStageReceipt, ReviewStageReceiptService } from '../workflow/review-stage-receipt';\n\nconst SEP = '━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\\n';\n\n/** The `--no-optional` decision, as data (per CLAUDE.md) rather than a bare boolean parameter. */\nexport class ReviewUpsertPrOptions {\n /**\n * true ⇒ the human ALREADY said to submit without the optional reviews, so stage ② must not print the\n * block telling the AI to offer them. It changes nothing about what BLOCKS: required checklists are\n * unaffected, and an optional checklist that already has a red verdict on this branch still refuses the\n * PR at finish. This only suppresses the offer.\n */\n skipOptional: boolean;\n\n constructor(skipOptional = false) {\n this.skipOptional = skipOptional;\n }\n}\n\n/**\n * `wp-review-upsert-pr` — STAGE ② of the three-stage PR flow, between `wp-start-upsert-pr` (sync from main)\n * and `wp-finish-upsert-pr` (post the PR).\n *\n * It exists because reviewing came before verifying. Under the old two-command flow the 3-point merge was\n * finalized and the build gate ran inside `wp-finish-upsert-pr` — i.e. AFTER the reviewers had already run.\n * A reviewer could therefore spend a full review on an unresolved merge, or on code that does not compile,\n * and only afterwards would the branch be checked. This command puts the verification first:\n *\n * 1. finalize + VALIDATE any in-progress 3-point merge (moved here from finish)\n * 2. assert a clean tree (meaningful now — step 1 committed the resolution)\n * 3. run the build gate (on the merged, committed tree)\n * 4. scan the checklists, EXTRACT the diff, BRIEF the reviewers\n * 5. write the stage receipt, then print what to spawn + the review.json schema\n *\n * Unlike the report-only command it replaces — which always exited 0, because reporting is not gating — this\n * command CAN FAIL, at steps 1, 2 and 3. That is the point: it fails BEFORE any reviewer is spawned, so a\n * branch with an unresolved merge or a broken build costs zero reviewer tokens.\n *\n * The ordering of 1 → 2 → 3 is load-bearing. MergeEnd stages and commits the conflict resolution, so the\n * tree is clean by the time the build runs; building first would either build a dirty tree (proving nothing\n * about what ships) or refuse a tree that is legitimately mid-resolution.\n */\n@injectable(bindingScopeValues.Singleton)\nexport class ReviewUpsertPrCommand {\n // eslint-disable-next-line @typescript-eslint/max-params\n constructor(\n private readonly repoRootFinder: RepoRootFinder,\n private readonly aiBranchName: AiBranchName,\n private readonly gitExec: GitExec,\n private readonly buildAffected: BuildAffected,\n private readonly buildArtifactGate: BuildArtifactGate,\n private readonly mergeState: MergeState,\n private readonly mergeEnd: MergeEnd,\n private readonly checklistScanner: ChecklistScanner,\n private readonly reviewReport: ReviewReport,\n private readonly materializer: DiffMaterializer,\n private readonly prContextWriter: PrContextWriter,\n private readonly briefingBuilder: ReviewerBriefingBuilder,\n private readonly reviewerInstructions: ReviewerInstructionsService,\n private readonly receipts: ReviewStageReceiptService,\n // Injected only to RESOLVE + RENDER refusals (see refusals()). This stage never archives a verdict.\n private readonly reviewJsonService: ReviewJsonService,\n ) {}\n\n async run(opts: ReviewUpsertPrOptions = new ReviewUpsertPrOptions()): Promise<void> {\n const repoRoot = this.repoRootFinder.resolveRepoRoot(process.cwd());\n writeTemplate(repoRoot, 'webpieces.git-workflow.md');\n writeTemplate(repoRoot, 'webpieces.review-checklists.md');\n const featureName = this.aiBranchName.getFeatureName();\n const config = loadAndValidate(repoRoot).prGate;\n\n const mergeValidated = await this.finalizeAnyInProgressMerge(repoRoot);\n this.gitExec.assertCleanTree(repoRoot);\n const buildPassedAt = this.runBuildGate(repoRoot);\n\n const scan = this.checklistScanner.scan(repoRoot, config.checklists, new ChecklistScanOptions(false, '')); // '' — THIS command writes the context itself, after materializing\n const briefings = this.briefReviewers(repoRoot, featureName, scan, config);\n this.receipts.write(repoRoot, featureName, new ReviewStageReceipt(\n scan.basis.headSha, mergeValidated, this.buildAffected.resolveBuildCommand(repoRoot), buildPassedAt,\n briefings.map((b: ReviewerBriefing): string => b.subagent),\n ));\n this.report(repoRoot, featureName, scan, briefings, opts);\n }\n\n /**\n * Validate + commit + finalize a conflict resolution, if one is in flight. MOVED here from\n * `wp-finish-upsert-pr` so that exactly one command owns merge finalization — two owners is the drift\n * failure `PrContextWriter`'s own docstring records having already happened once in this codebase.\n *\n * MergeEnd's three checks are what \"did the AI do the 3-point merge right?\" means concretely: no\n * conflict markers left in the scoped files, `git diff --diff-filter=U` empty, and a non-empty\n * merge-explanation.md beside every conflicted file.\n *\n * Returns true when a merge was finalized OR there was none to finalize; it throws rather than returning\n * false when validation fails, so the receipt can never record an unvalidated merge as validated.\n */\n private async finalizeAnyInProgressMerge(repoRoot: string): Promise<boolean> {\n const home = this.mergeState.mergeDirFor(repoRoot, this.aiBranchName.getFeatureName());\n const activeDir = this.mergeState.findActiveMergeRunDir(home);\n const marker = activeDir ? this.mergeState.readMergeMarker(activeDir) : null;\n if (!activeDir || !marker || marker.validated) return true;\n process.stdout.write('\\n' + SEP + '① Validating your 3-point merge\\n' + SEP + '\\n');\n // pushRemote:false — finish still owns the single push.\n await this.mergeEnd.mergeEnd(\n repoRoot, 'wp-review-upsert-pr', activeDir,\n new MergeContext(marker.currentBranch, marker.squashBranch, marker.backupBranch, marker.prNumber),\n new MergeEndOptions(marker.conflictedFiles, false),\n );\n return true;\n }\n\n /**\n * The build gate, run BEFORE any reviewer is briefed. Returns the ISO time it passed, for the receipt —\n * which is what lets `wp-finish-upsert-pr` skip its own gate when HEAD has not moved, so moving the gate\n * earlier did not turn one build into two.\n */\n private runBuildGate(repoRoot: string): string {\n this.buildAffected.runBuildGate(repoRoot, new BuildGateOptions(\n '🛠️ Build gate',\n 'pnpm wp-review-upsert-pr',\n 'Build failed — NO reviewer was briefed and no diff was extracted. Fix it, then re-run.',\n ));\n // Repo-wide: the build must not have left anything uncommitted AND unstaged. Runs HERE, not in\n // finish, because this is the stage that ran buildCommand and is therefore holding the dirty\n // tree at the exact moment the question is answerable. Replaces the per-project\n // validate-di-graph-unchanged nx target — see BuildArtifactGate for why that one had to go.\n this.buildArtifactGate.assertBuildLeftNothingUncommitted(repoRoot);\n return new Date().toISOString();\n }\n\n /**\n * Extract the diff once, then write one instructions file per reviewer.\n *\n * The changed-file set and the basis both come off the SCAN rather than being recomputed, so the diff a\n * reviewer reads covers exactly the files its checklist matched against.\n */\n private briefReviewers(repoRoot: string, featureName: string, scan: ChecklistScan, config: PrGateConfig): ReviewerBriefing[] {\n if (scan.basis.unresolved) return [];\n const manifest = this.materializer.materialize(\n repoRoot, featureName, scan.basis, scan.changedFiles, config.reviewDiffExclude);\n const diffDir = this.materializer.diffDirFor(repoRoot, featureName);\n // Write pr-context.json ONCE, here — after materializing, so `diffDir` is populated on the first\n // write. The scan deliberately did not write it (ChecklistScanOptions.contextStage === ''); it used\n // to, which meant this command wrote the same file twice, the first time with an empty diffDir.\n // `scan.changedFiles` is passed through so the context is not recomputed from a second git call.\n scan.context = this.prContextWriter.ensure(\n repoRoot, featureName, scan.basis, 'stage2-review', scan.changedFiles, diffDir);\n const briefings = this.briefingBuilder.build(repoRoot, scan, manifest, diffDir, config);\n const dir = this.reviewerInstructions.instructionsDirFor(repoRoot, featureName);\n fs.rmSync(dir, { recursive: true, force: true }); // stale instructions read as current are worse than none\n fs.mkdirSync(dir, { recursive: true });\n for (const b of briefings) {\n fs.writeFileSync(this.reviewerInstructions.pathFor(repoRoot, featureName, b.subagent),\n this.reviewerInstructions.render(b));\n }\n return briefings;\n }\n\n /**\n * What the AI must do next — rendered by `ReviewReport`, which owns the ordering.\n *\n * The rendering moved OUT of this command so the ordering could be asserted on as a string. It had a\n * real bug: the zero-checklist notice signed off with \"Carry on and run: pnpm wp-finish-upsert-pr\"\n * while the block right beneath it said to write review.json first. An agent that reads top to bottom\n * obeyed the first line and posted a PR with no review at all.\n */\n // eslint-disable-next-line @typescript-eslint/max-params\n private report(\n repoRoot: string, featureName: string, scan: ChecklistScan, briefings: readonly ReviewerBriefing[],\n opts: ReviewUpsertPrOptions,\n ): void {\n const input = new ReviewReportInput(repoRoot, featureName, scan.reviewPath);\n input.definedCount = scan.defined.length;\n input.applicableCount = scan.applicable.length;\n input.reviewed = scan.reviewed.slice();\n input.formatErrors = scan.formatErrors.slice();\n input.briefings = briefings.slice();\n input.refused = this.refusals(scan);\n input.skipOptional = opts.skipOptional;\n process.stdout.write(this.reviewReport.render(input));\n }\n\n /**\n * The applicable checklists that ALREADY ANSWERED and refused, each with its refusal rendered by the ONE\n * renderer `wp-finish-upsert-pr` also uses.\n *\n * Stage ② had the identical defect finish did: a refused checklist has no passing verdict, so it is not\n * in `scan.reviewed`, so it was printed as an ordinary owed reviewer and re-instructed word for word —\n * and an agent that obeys spawns it against unchanged code, gets the same refusal, and loops one stage\n * earlier than the loop that was reported.\n *\n * NO archive path is passed, deliberately, and this stage moves nothing. Retiring a verdict is finish's\n * act on the refusal it is actually enforcing; doing it here would delete the live verdict of a branch\n * that has not even been asked to finish yet, and `refusalError`'s un-archived wording — \"set an override\n * in review-<id>.json\" — is only correct while that file is still there, which here it is.\n */\n private refusals(scan: ChecklistScan): RefusedReviewer[] {\n const refused = this.reviewJsonService.refusedChecklists(scan.applicable, scan.results);\n return refused.map((req: RequiredChecklist): RefusedReviewer => new RefusedReviewer(\n req.id, this.reviewJsonService.refusalError(req, this.reviewJsonService.resolveVerdict(req, scan.results))));\n }\n}\n"]}
|
|
@@ -5,7 +5,7 @@ import { FinishUpsertPrCommand } from './commands/finish-upsert-pr-command';
|
|
|
5
5
|
import { CleanupCommand } from './commands/cleanup-command';
|
|
6
6
|
import { LandPrCommand } from './commands/land-pr-command';
|
|
7
7
|
import { CheckPrCommand } from './commands/check-pr-command';
|
|
8
|
-
import { ReviewUpsertPrCommand } from './commands/review-upsert-pr-command';
|
|
8
|
+
import { ReviewUpsertPrCommand, ReviewUpsertPrOptions } from './commands/review-upsert-pr-command';
|
|
9
9
|
import { ReapWorktreeCommand } from './commands/reap-worktree-command';
|
|
10
10
|
/**
|
|
11
11
|
* The pr-gate application root. `container.get(PrGateApp)` resolves the entire workflow DAG (the command
|
|
@@ -47,7 +47,7 @@ export declare class PrGateApp {
|
|
|
47
47
|
* branch's diff, and brief the reviewer subagents. Unlike the report-only command it replaces, this CAN
|
|
48
48
|
* fail — before any reviewer is spawned, so a broken branch costs no reviewer tokens.
|
|
49
49
|
*/
|
|
50
|
-
reviewUpsertPr(): Promise<void>;
|
|
50
|
+
reviewUpsertPr(opts?: ReviewUpsertPrOptions): Promise<void>;
|
|
51
51
|
/** `wp-check-pr`: READ-ONLY CI check — verify the PR body carries a valid HMAC gate token for its head sha. */
|
|
52
52
|
checkPr(): Promise<void>;
|
|
53
53
|
}
|
|
@@ -77,8 +77,8 @@ let PrGateApp = class PrGateApp {
|
|
|
77
77
|
* branch's diff, and brief the reviewer subagents. Unlike the report-only command it replaces, this CAN
|
|
78
78
|
* fail — before any reviewer is spawned, so a broken branch costs no reviewer tokens.
|
|
79
79
|
*/
|
|
80
|
-
reviewUpsertPr() {
|
|
81
|
-
return this.reviewUpsertPrCommand.run();
|
|
80
|
+
reviewUpsertPr(opts = new review_upsert_pr_command_1.ReviewUpsertPrOptions()) {
|
|
81
|
+
return this.reviewUpsertPrCommand.run(opts);
|
|
82
82
|
}
|
|
83
83
|
/** `wp-check-pr`: READ-ONLY CI check — verify the PR body carries a valid HMAC gate token for its head sha. */
|
|
84
84
|
checkPr() {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pr-gate-app.js","sourceRoot":"","sources":["../../../../../../packages/tooling/pr-gate/src/scripts/pr-gate-app.ts"],"names":[],"mappings":";;;;AAAA,0DAAyD;AACzD,yCAA2D;AAC3D,0EAAqE;AACrE,4EAAuE;AACvE,gFAA0E;AAC1E,kFAA4E;AAC5E,gEAA4D;AAC5D,gEAA2D;AAC3D,kEAA6D;AAC7D,
|
|
1
|
+
{"version":3,"file":"pr-gate-app.js","sourceRoot":"","sources":["../../../../../../packages/tooling/pr-gate/src/scripts/pr-gate-app.ts"],"names":[],"mappings":";;;;AAAA,0DAAyD;AACzD,yCAA2D;AAC3D,0EAAqE;AACrE,4EAAuE;AACvE,gFAA0E;AAC1E,kFAA4E;AAC5E,gEAA4D;AAC5D,gEAA2D;AAC3D,kEAA6D;AAC7D,kFAAmG;AACnG,4EAAuE;AAEvE;;;;;GAKG;AAGI,IAAM,SAAS,GAAf,MAAM,SAAS;IAEG;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IATrB,YACqB,kBAAsC,EACtC,mBAAwC,EACxC,oBAA0C,EAC1C,qBAA4C,EAC5C,cAA8B,EAC9B,aAA4B,EAC5B,cAA8B,EAC9B,qBAA4C,EAC5C,mBAAwC;QARxC,uBAAkB,GAAlB,kBAAkB,CAAoB;QACtC,wBAAmB,GAAnB,mBAAmB,CAAqB;QACxC,yBAAoB,GAApB,oBAAoB,CAAsB;QAC1C,0BAAqB,GAArB,qBAAqB,CAAuB;QAC5C,mBAAc,GAAd,cAAc,CAAgB;QAC9B,kBAAa,GAAb,aAAa,CAAe;QAC5B,mBAAc,GAAd,cAAc,CAAgB;QAC9B,0BAAqB,GAArB,qBAAqB,CAAuB;QAC5C,wBAAmB,GAAnB,mBAAmB,CAAqB;IAC1D,CAAC;IAEJ;;;;OAIG;IACH,YAAY,CAAC,IAAc;QACvB,OAAO,IAAI,CAAC,mBAAmB,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IAC9C,CAAC;IAED,kEAAkE;IAClE,WAAW;QACP,OAAO,IAAI,CAAC,kBAAkB,CAAC,GAAG,EAAE,CAAC;IACzC,CAAC;IAED,gFAAgF;IAChF,YAAY;QACR,OAAO,IAAI,CAAC,mBAAmB,CAAC,GAAG,EAAE,CAAC;IAC1C,CAAC;IAED,4GAA4G;IAC5G,aAAa;QACT,OAAO,IAAI,CAAC,oBAAoB,CAAC,GAAG,EAAE,CAAC;IAC3C,CAAC;IAED,oGAAoG;IACpG,cAAc;QACV,OAAO,IAAI,CAAC,qBAAqB,CAAC,GAAG,EAAE,CAAC;IAC5C,CAAC;IAED,mGAAmG;IACnG,OAAO;QACH,OAAO,IAAI,CAAC,cAAc,CAAC,GAAG,EAAE,CAAC;IACrC,CAAC;IAED,0FAA0F;IAC1F,MAAM;QACF,OAAO,IAAI,CAAC,aAAa,CAAC,GAAG,EAAE,CAAC;IACpC,CAAC;IAED;;;;OAIG;IACH,cAAc,CAAC,OAA8B,IAAI,gDAAqB,EAAE;QACpE,OAAO,IAAI,CAAC,qBAAqB,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IAChD,CAAC;IAED,+GAA+G;IAC/G,OAAO;QACH,OAAO,IAAI,CAAC,cAAc,CAAC,GAAG,EAAE,CAAC;IACrC,CAAC;CACJ,CAAA;AAjEY,8BAAS;oBAAT,SAAS;IAFrB,IAAA,6BAAc,GAAE;IAChB,IAAA,sBAAU,EAAC,8BAAkB,CAAC,SAAS,CAAC;6CAGI,yCAAkB;QACjB,2CAAmB;QAClB,8CAAoB;QACnB,gDAAqB;QAC5B,gCAAc;QACf,+BAAa;QACZ,iCAAc;QACP,gDAAqB;QACvB,2CAAmB;GAVpD,SAAS,CAiErB","sourcesContent":["import { DocumentDesign } from '@webpieces/rules-config';\nimport { injectable, bindingScopeValues } from 'inversify';\nimport { StartUpdateCommand } from './commands/start-update-command';\nimport { FinishUpdateCommand } from './commands/finish-update-command';\nimport { StartUpsertPrCommand } from './commands/start-upsert-pr-command';\nimport { FinishUpsertPrCommand } from './commands/finish-upsert-pr-command';\nimport { CleanupCommand } from './commands/cleanup-command';\nimport { LandPrCommand } from './commands/land-pr-command';\nimport { CheckPrCommand } from './commands/check-pr-command';\nimport { ReviewUpsertPrCommand, ReviewUpsertPrOptions } from './commands/review-upsert-pr-command';\nimport { ReapWorktreeCommand } from './commands/reap-worktree-command';\n\n/**\n * The pr-gate application root. `container.get(PrGateApp)` resolves the entire workflow DAG (the command\n * classes → the injected git/merge/dashboard services). `@DocumentDesign` marks it the\n * top-of-DAG the DI-design analyzer roots on, so `role:app` pr-gate draws its design. Each `bin/*`\n * entry resolves THIS and calls the matching command method.\n */\n@DocumentDesign()\n@injectable(bindingScopeValues.Singleton)\nexport class PrGateApp {\n constructor(\n private readonly startUpdateCommand: StartUpdateCommand,\n private readonly finishUpdateCommand: FinishUpdateCommand,\n private readonly startUpsertPrCommand: StartUpsertPrCommand,\n private readonly finishUpsertPrCommand: FinishUpsertPrCommand,\n private readonly cleanupCommand: CleanupCommand,\n private readonly landPrCommand: LandPrCommand,\n private readonly checkPrCommand: CheckPrCommand,\n private readonly reviewUpsertPrCommand: ReviewUpsertPrCommand,\n private readonly reapWorktreeCommand: ReapWorktreeCommand,\n ) {}\n\n /**\n * INTERNAL (`wp-reap-worktree.js`, no `bin` entry): remove ONE named worktree and its branch.\n * `wp-land-pr` spawns it with cwd = the primary clone so the tree it just landed from can be\n * reaped by a process that is not standing in it.\n */\n reapWorktree(args: string[]): Promise<void> {\n return this.reapWorktreeCommand.run(args);\n }\n\n /** `wp-start-update`: 3-point squash-update from main (no PR). */\n startUpdate(): Promise<void> {\n return this.startUpdateCommand.run();\n }\n\n /** `wp-finish-update`: validate + finalize a resolved 3-point merge (no PR). */\n finishUpdate(): Promise<void> {\n return this.finishUpdateCommand.run();\n }\n\n /** `wp-start-upsert-pr`: update from main (3-point merge), hand off review.json. No build gate, no push. */\n startUpsertPr(): Promise<void> {\n return this.startUpsertPrCommand.run();\n }\n\n /** `wp-finish-upsert-pr`: finalize merge, authoritative build gate, dashboard, create/update PR. */\n finishUpsertPr(): Promise<void> {\n return this.finishUpsertPrCommand.run();\n }\n\n /** `wp-cleanup`: reap what is provably merged, and ASK about everything that merely looks dead. */\n cleanup(): Promise<void> {\n return this.cleanupCommand.run();\n }\n\n /** `wp-land-pr`: squash-merge this branch's PR into main with the compact commit body. */\n landPr(): Promise<void> {\n return this.landPrCommand.run();\n }\n\n /**\n * `wp-review-upsert-pr`: STAGE ② — validate the 3-point merge, run the build gate, extract this\n * branch's diff, and brief the reviewer subagents. Unlike the report-only command it replaces, this CAN\n * fail — before any reviewer is spawned, so a broken branch costs no reviewer tokens.\n */\n reviewUpsertPr(opts: ReviewUpsertPrOptions = new ReviewUpsertPrOptions()): Promise<void> {\n return this.reviewUpsertPrCommand.run(opts);\n }\n\n /** `wp-check-pr`: READ-ONLY CI check — verify the PR body carries a valid HMAC gate token for its head sha. */\n checkPr(): Promise<void> {\n return this.checkPrCommand.run();\n }\n}\n"]}
|
|
@@ -105,7 +105,7 @@ let ChecklistDetector = class ChecklistDetector {
|
|
|
105
105
|
// Flatten matched checklists into the RequiredChecklist shape that review.json enforcement + the hint
|
|
106
106
|
// consume.
|
|
107
107
|
toRequired(triggered) {
|
|
108
|
-
return triggered.map((t) => new rules_config_1.RequiredChecklist(t.def.id, t.def.subagent, t.def.doc, t.matchedFiles, t.matchedPatterns));
|
|
108
|
+
return triggered.map((t) => new rules_config_1.RequiredChecklist(t.def.id, t.def.subagent, t.def.doc, t.matchedFiles, t.matchedPatterns, t.def.required));
|
|
109
109
|
}
|
|
110
110
|
};
|
|
111
111
|
exports.ChecklistDetector = ChecklistDetector;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"checklist-detector.js","sourceRoot":"","sources":["../../../../../../../packages/tooling/pr-gate/src/scripts/workflow/checklist-detector.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"checklist-detector.js","sourceRoot":"","sources":["../../../../../../../packages/tooling/pr-gate/src/scripts/workflow/checklist-detector.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n ChecklistDefinition, RequiredChecklist, DiffScope, ChangedFilesOptions, isPathExcluded,\n} from '@webpieces/rules-config';\nimport { injectable, bindingScopeValues } from 'inversify';\n\n// A checklist whose `patterns` matched the diff (so its reviewer subagent must run), plus the matched\n// files (for the dashboard + hint). Data-only (per CLAUDE.md, classes for data).\nexport class TriggeredChecklist {\n def: ChecklistDefinition;\n matchedFiles: string[];\n // Which of `def.patterns` actually hit a changed file. Carried so the printed instruction can say WHAT\n // matched, not just which files: a reviewer judges a `db/migrations/**` hit differently from a `**` one.\n matchedPatterns: string[];\n\n constructor(def: ChecklistDefinition, matchedFiles: string[], matchedPatterns: string[] = []) {\n this.def = def;\n this.matchedFiles = matchedFiles;\n this.matchedPatterns = matchedPatterns;\n }\n}\n\n/**\n * Every DEFINED checklist paired with what it matched, plus the two facts a reader needs to judge a skip:\n * how many files were even considered, and whether a diff was computable at all. Data-only (per CLAUDE.md).\n */\nexport class ChecklistRoster {\n entries: TriggeredChecklist[]; // one per defined checklist, in config order; matchedFiles may be []\n changedFileCount: number; // N — \"matched 0 of N changed files\" is only meaningful with N\n /**\n * false when no fork point resolved. Load-bearing: with no base the changed-file set is EMPTY, so\n * nothing matches — including patternless ALWAYS-RUNS checklists. Rendering that as \"all skipped ✅\"\n * would post a green all-clear to GitHub for a PR where no checklist was actually evaluated.\n */\n baseResolved: boolean;\n\n constructor(entries: TriggeredChecklist[], changedFileCount: number, baseResolved: boolean) {\n this.entries = entries;\n this.changedFileCount = changedFileCount;\n this.baseResolved = baseResolved;\n }\n}\n\n/**\n * Decides which company review checklists a branch matched, from what the diff CHANGED. Path matching\n * uses `isPathExcluded` — the SAME minimatch-based matcher rules-config already shares across\n * exclude-paths and the rule validators. A checklist with empty `patterns` matches every PR (always runs).\n *\n * `@injectable(bindingScopeValues.Singleton)` + injects {@link DiffScope} so it appears in the DI design\n * and reuses the ONE git-diff service instead of adding new git plumbing.\n */\n@injectable(bindingScopeValues.Singleton)\nexport class ChecklistDetector {\n constructor(private readonly diffScope: DiffScope) {}\n\n /**\n * Pure matching over EVERY defined checklist, matched or not — one entry per def, in config order, with\n * `matchedFiles: []` for the ones nothing hit. This is what lets the PR comment publish the full roster:\n * a skipped checklist is the normal, healthy outcome, and a comment that lists only the ones that fired\n * cannot distinguish \"evaluated and irrelevant\" from \"never configured\".\n *\n * A skipped entry has `matchedPatterns: []` — and so does a PATTERNLESS one. They mean opposite things,\n * so a renderer must decide \"always runs\" from `def.patterns.length === 0`, NEVER from\n * `matchedPatterns.length`, or every skipped checklist claims the whole diff was in its scope.\n */\n roster(defs: readonly ChecklistDefinition[], changedFiles: readonly string[]): TriggeredChecklist[] {\n return defs.map((def: ChecklistDefinition): TriggeredChecklist => {\n const matched = def.patterns.length === 0\n ? [...changedFiles]\n : changedFiles.filter((f: string): boolean => isPathExcluded(f, def.patterns));\n return new TriggeredChecklist(def, matched, this.firedPatterns(def, changedFiles));\n });\n }\n\n // Pure matching — unit-testable without git. Return every checklist whose patterns hit a changed file\n // (empty patterns ⇒ always matches). Defined as the roster minus the empty entries so the set that GATES\n // and the set the comment REPORTS can never be computed two different ways.\n detect(defs: readonly ChecklistDefinition[], changedFiles: readonly string[]): TriggeredChecklist[] {\n return this.roster(defs, changedFiles)\n .filter((t: TriggeredChecklist): boolean => t.matchedFiles.length > 0);\n }\n\n // Which of a checklist's globs hit at least one changed file. [] for a patternless checklist (it matches\n // every PR, and saying \"matched by nothing\" would read as a bug).\n private firedPatterns(def: ChecklistDefinition, changedFiles: readonly string[]): string[] {\n return def.patterns.filter((p: string): boolean => changedFiles.some((f: string): boolean => isPathExcluded(f, [p])));\n }\n\n // Resolve the diff base for the local branch, then detect. Returns [] when there is no base to diff.\n detectForRepo(repoRoot: string, defs: readonly ChecklistDefinition[]): TriggeredChecklist[] {\n if (defs.length === 0) return [];\n const range = this.diffScope.resolveBase(repoRoot);\n if (!range.base) return [];\n return this.detectForRange(repoRoot, defs, range.base, range.head);\n }\n\n // Same detection against an EXPLICIT (base, head) — used by CI, where the useful range is the PR's\n // merge base .. head. tsOnly=false is load-bearing: the default drops every *.sql / Dockerfile / .env*\n // / metadata file a checklist most wants to key on, silently producing \"no checklists matched\".\n detectForRange(repoRoot: string, defs: readonly ChecklistDefinition[], base: string, head?: string): TriggeredChecklist[] {\n if (defs.length === 0 || !base) return [];\n const opts = new ChangedFilesOptions();\n opts.tsOnly = false;\n const changedFiles = this.diffScope.getChangedFiles(repoRoot, base, head, opts);\n return this.detect(defs, changedFiles);\n }\n\n // Flatten matched checklists into the RequiredChecklist shape that review.json enforcement + the hint\n // consume.\n toRequired(triggered: readonly TriggeredChecklist[]): RequiredChecklist[] {\n return triggered.map((t: TriggeredChecklist): RequiredChecklist =>\n new RequiredChecklist(\n t.def.id, t.def.subagent, t.def.doc, t.matchedFiles, t.matchedPatterns, t.def.required));\n }\n}\n"]}
|