@webpieces/rules-config 0.4.471 → 0.4.473

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.ReviewJsonService = exports.ChecklistVerdict = exports.CK_ACKED = exports.CK_MISSING = exports.CK_FAIL = exports.CK_OVERRIDDEN = exports.CK_PASS = exports.ReviewJson = exports.RequiredChecklist = exports.ChecklistResult = exports.ChecklistAck = void 0;
3
+ exports.ReviewJsonService = exports.ChecklistVerdict = exports.CK_MISSING = exports.CK_FAIL = exports.CK_OVERRIDDEN = exports.CK_PASS = exports.ReviewJson = exports.RequiredChecklist = exports.ChecklistResult = void 0;
4
4
  exports.prDirFor = prDirFor;
5
5
  exports.reviewJsonPath = reviewJsonPath;
6
6
  exports.reviewJsonSchemaHint = reviewJsonSchemaHint;
@@ -10,34 +10,20 @@ const fs = tslib_1.__importStar(require("fs"));
10
10
  const path = tslib_1.__importStar(require("path"));
11
11
  const inversify_1 = require("inversify");
12
12
  const constants_1 = require("./constants");
13
- const checklist_config_1 = require("./checklist-config");
14
13
  const inform_ai_error_1 = require("./inform-ai-error");
15
14
  const to_error_1 = require("./to-error");
16
- // One entry the AI writes into review.json's `checklists[]`: "I read the doc for <id> and walked it".
17
- // acknowledged: true is the AI attesting it did the walk a SURFACING/AUDIT signal, not authorization.
18
- class ChecklistAck {
19
- id;
20
- acknowledged;
21
- notes; // per-item findings the AI chose to record (optional; [] when none)
22
- constructor(id, acknowledged, notes) {
23
- this.id = id;
24
- this.acknowledged = acknowledged;
25
- this.notes = notes;
26
- }
27
- }
28
- exports.ChecklistAck = ChecklistAck;
29
- // The verdict a reviewer wrote into a PER-CHECKLIST file `.webpieces/pr-review/<branch>/review-<id>.json`,
30
- // one per triggered checklist. Replaces the single shared `checklists[]` array so concurrent reviewer
31
- // subagents never clobber one file. Unlike ChecklistAck's bare boolean, this records the OUTCOME:
15
+ // The verdict a reviewer SUBAGENT writes into `.webpieces/pr-review/<branch>/review-<id>.json`, one per
16
+ // matched checklist. One file per checklist so N concurrent reviewer subagents never clobber a shared
17
+ // file. It records the OUTCOME:
32
18
  // success:true → PASS
33
19
  // success:false + override non-empty → OVERRIDDEN (pass; the free-text justification reaches the PR)
34
20
  // success:false + no override → FAIL (refuse; `output` is printed verbatim)
35
- // `override` is deliberately free text, not a boolean — it forces the bypass to be stated in words and
36
- // surfaces it on the dashboard, where a human sees it. Data-only (per CLAUDE.md).
21
+ // `override` is deliberately free text, not a boolean — it forces the ship-anyway decision to be stated
22
+ // in words and surfaces it on the dashboard, where a human sees it. Data-only (per CLAUDE.md).
37
23
  class ChecklistResult {
38
24
  id;
39
25
  success;
40
- output; // what the reviewer found; printed verbatim when a BLOCK checklist fails
26
+ output; // what the reviewer found; printed verbatim when the checklist fails
41
27
  override; // '' = no override; non-empty = ship-anyway justification (renders 🟡 overridden)
42
28
  constructor(id, success, output, override) {
43
29
  this.id = id;
@@ -47,31 +33,25 @@ class ChecklistResult {
47
33
  }
48
34
  }
49
35
  exports.ChecklistResult = ChecklistResult;
50
- // What the CALLER (the pr-gate command) computed from the diff: the checklists this branch triggered.
51
- // Drives BOTH review.json validation (BLOCK must be acknowledged) AND the printed schema hint (so the
52
- // AI is told, at the moment it writes review.json, exactly which docs to read). Data-only.
36
+ // What the pr-gate command computed from the diff: a checklist this branch MATCHED (its patterns hit the
37
+ // diff, so its reviewer subagent must run). Drives review-<id>.json enforcement, provenance, the schema
38
+ // hint, and the dashboard. Data-only.
53
39
  class RequiredChecklist {
54
- id;
55
- title;
56
- severity; // 'BLOCK' | 'WARN'
57
- docs;
58
- blockMessage;
59
- matchedFiles; // the changed files that triggered it (for the dashboard + hint)
60
- subagent; // expected reviewer agentType ('' = no provenance requirement); enforced by finish
61
- // eslint-disable-next-line @typescript-eslint/max-params
62
- constructor(id, title, severity, docs, blockMessage, matchedFiles, subagent = '') {
40
+ id; // = subagent name; keys review-<id>.json
41
+ subagent; // reviewer agent that must run (agentType the harness stamps)
42
+ doc; // guidance doc the reviewer reads ('' it reads the manifest doc)
43
+ matchedFiles; // the changed files that matched it (for the dashboard + hint)
44
+ constructor(id, subagent, doc, matchedFiles) {
63
45
  this.id = id;
64
- this.title = title;
65
- this.severity = severity;
66
- this.docs = docs;
67
- this.blockMessage = blockMessage;
68
- this.matchedFiles = matchedFiles;
69
46
  this.subagent = subagent;
47
+ this.doc = doc;
48
+ this.matchedFiles = matchedFiles;
70
49
  }
71
50
  }
72
51
  exports.RequiredChecklist = RequiredChecklist;
73
- // The AI-authored review for a PR. The AI writes this file itself between `wp-start-upsert-pr` (which
74
- // prints the schema) and `wp-finish-upsert-pr` (which reads it). Data-only (per CLAUDE.md).
52
+ // The AI-authored review for a PR. The AI writes review.json itself between `wp-start-upsert-pr` (which
53
+ // prints the schema) and `wp-finish-upsert-pr` (which reads it); reviewer subagents write the per-checklist
54
+ // review-<id>.json files. Data-only (per CLAUDE.md).
75
55
  class ReviewJson {
76
56
  title; // human PR title describing the change; used as the `gh pr` title (empty → caller falls back)
77
57
  riskScore; // 0–100, drives the risk bar
@@ -81,10 +61,9 @@ class ReviewJson {
81
61
  violations; // pattern/architecture violations; length = the Pattern Violations count
82
62
  risks;
83
63
  filesToReview;
84
- checklists; // legacy inline acknowledgments (back-compat); [] when none written
85
64
  results; // resolved per-checklist verdicts (from review-<id>.json); [] when none
86
65
  // eslint-disable-next-line @typescript-eslint/max-params
87
- constructor(title, riskScore, riskLevel, riskEmoji, summary, violations, risks, filesToReview, checklists = [], results = []) {
66
+ constructor(title, riskScore, riskLevel, riskEmoji, summary, violations, risks, filesToReview, results = []) {
88
67
  this.title = title;
89
68
  this.riskScore = riskScore;
90
69
  this.riskLevel = riskLevel;
@@ -93,7 +72,6 @@ class ReviewJson {
93
72
  this.violations = violations;
94
73
  this.risks = risks;
95
74
  this.filesToReview = filesToReview;
96
- this.checklists = checklists;
97
75
  this.results = results;
98
76
  }
99
77
  }
@@ -102,12 +80,11 @@ exports.ReviewJson = ReviewJson;
102
80
  exports.CK_PASS = 'pass'; // review-<id>.json success:true
103
81
  exports.CK_OVERRIDDEN = 'overridden'; // review-<id>.json success:false + non-empty override → 🟡
104
82
  exports.CK_FAIL = 'fail'; // review-<id>.json success:false + no override → refuse
105
- exports.CK_MISSING = 'missing'; // no verdict file and no inline ack → refuse (BLOCK)
106
- exports.CK_ACKED = 'acknowledged'; // legacy inline checklists[] ack satisfied (back-compat)
83
+ exports.CK_MISSING = 'missing'; // no review-<id>.json written → refuse
107
84
  class ChecklistVerdict {
108
85
  id;
109
- status; // one of CK_PASS | CK_OVERRIDDEN | CK_FAIL | CK_MISSING | CK_ACKED
110
- detail; // reviewer output / override justification / ack notes (for the dashboard + errors)
86
+ status; // one of CK_PASS | CK_OVERRIDDEN | CK_FAIL | CK_MISSING
87
+ detail; // reviewer output / override justification (for the dashboard + errors)
111
88
  constructor(id, status, detail) {
112
89
  this.id = id;
113
90
  this.status = status;
@@ -127,11 +104,9 @@ let ReviewJsonService = class ReviewJsonService {
127
104
  reviewJsonPath(repoRoot, featureName) {
128
105
  return path.join(this.prDirFor(repoRoot, featureName), 'review.json');
129
106
  }
130
- // Copy-paste schema both commands print (write it / fix it). `required` is the set of consumer
131
- // checklists the diff triggered; when it is empty the output is byte-identical to before this
132
- // feature existed (non-adopting repos see no change). When non-empty it grows a `checklists` line
133
- // in the JSON shape PLUS an instruction block naming the docs to read — diff-derived instructions
134
- // injected at exactly the moment the AI writes review.json.
107
+ // Copy-paste schema both commands print. `required` is the set of checklists the diff MATCHED; empty
108
+ // output identical to a repo with no checklists. Non-empty appends per-checklist instructions
109
+ // naming the reviewer subagent + doc + the review-<id>.json to write.
135
110
  reviewJsonSchemaHint(filePath, required = []) {
136
111
  return (`Write your PR review to:\n ${filePath}\n\n` +
137
112
  `with this exact JSON shape (riskEmoji optional — derived from riskLevel):\n\n` +
@@ -150,44 +125,33 @@ let ReviewJsonService = class ReviewJsonService {
150
125
  checklistResultPath(reviewJsonFilePath, checklistId) {
151
126
  return path.join(path.dirname(reviewJsonFilePath), `review-${checklistId}.json`);
152
127
  }
153
- // The diff-triggered instruction block, appended ONLY when the branch triggered a checklist. This is
154
- // the consumer's review process, re-injected: read doc Y because the diff touched X, then write ONE
155
- // file per checklist — `review-<id>.json` — so concurrent reviewer subagents never clobber a shared
156
- // file. A BLOCK checklist with success:false and no override refuses to open the PR.
128
+ // The matched-checklist instruction block, appended ONLY when the diff matched a checklist. Each matched
129
+ // checklist must be reviewed by its OWN subagent (a distinct one), which writes review-<id>.json.
157
130
  requiredChecklistHint(reviewJsonFilePath, required) {
158
131
  if (required.length === 0)
159
132
  return '';
160
- const lines = ['', '', 'This branch triggered company review checklist(s). For EACH one below: READ its docs, walk'];
161
- lines.push('the items against your diff, then write a SEPARATE file `review-<id>.json` beside review.json');
162
- lines.push('with this shape (override optional a free-text ship-anyway justification):');
133
+ const lines = ['', '', 'This diff MATCHED company review checklist(s). Spawn EACH named subagent as a SEPARATE'];
134
+ lines.push('subagent (a different one per checklist the coding agent may NOT self-certify). Each reads its');
135
+ lines.push('doc + the diff and writes its own review-<id>.json with this shape:');
163
136
  lines.push('');
164
- lines.push(' { "success": true, "output": "what you checked / what you found", "override": "" }');
137
+ lines.push(' { "id": "<id>", "success": true, "output": "what you checked / found", "override": "" }');
138
+ lines.push(' (success:false with no non-empty "override" refuses the PR; a non-empty override ships it 🟡.)');
165
139
  lines.push('');
166
140
  for (const req of required) {
167
- const gate = req.severity === checklist_config_1.CHECKLIST_BLOCK
168
- ? 'BLOCK — success:false with no "override" will NOT open the PR'
169
- : 'WARN — recorded on the dashboard; never blocks';
170
- lines.push(` • [${req.id}] ${req.title} (${gate})`);
141
+ lines.push(` • [${req.id}] reviewer subagent: ${req.subagent}`);
171
142
  lines.push(` write: ${this.checklistResultPath(reviewJsonFilePath, req.id)}`);
172
- lines.push(` docs to read: ${req.docs.join(', ')}`);
173
- if (req.subagent.trim() !== '')
174
- lines.push(` must be reviewed by the "${req.subagent.trim()}" subagent (its independent run is verified from the harness).`);
175
- if (req.blockMessage.trim() !== '')
176
- lines.push(` ${req.blockMessage.trim()}`);
143
+ if (req.doc.trim() !== '')
144
+ lines.push(` doc to read: ${req.doc}`);
177
145
  if (req.matchedFiles.length > 0)
178
- lines.push(` triggered by: ${req.matchedFiles.slice(0, 5).join(', ')}`);
146
+ lines.push(` matched: ${req.matchedFiles.slice(0, 5).join(', ')}`);
179
147
  }
180
148
  return lines.join('\n');
181
149
  }
182
150
  /**
183
151
  * Load + validate the AI-authored review.json. Throws InformAiError (with the schema) when missing,
184
- * unparseable, or structurally wrong. Returns a fully-populated ReviewJson on success.
185
- *
186
- * `required` is the set of consumer checklists the diff triggered (empty for non-adopting repos, in
187
- * which case this behaves byte-identically to before the feature). Every BLOCK entry must appear in
188
- * review.json's `checklists[]` with `acknowledged: true`, or a validation error is raised alongside
189
- * the usual ones so the AI gets ONE message. WARN entries are never validated; unknown ids in
190
- * `checklists[]` are ignored (forward-compat).
152
+ * unparseable, or structurally wrong. `required` is the set of checklists the diff matched: every one
153
+ * must have a well-formed, passing (or overridden) review-<id>.json or a validation error is raised
154
+ * alongside the usual ones so the AI gets ONE message.
191
155
  */
192
156
  // webpieces-disable max-lines-new-methods -- one cohesive load+validate pass over the review fields
193
157
  loadReviewJson(filePath, required = []) {
@@ -212,9 +176,8 @@ let ReviewJsonService = class ReviewJsonService {
212
176
  if (title === '') {
213
177
  errors.push('"title" must be a non-empty, imperative PR title describing the change (no branch names).');
214
178
  }
215
- const acks = this.parseChecklistAcks(raw['checklists']);
216
179
  const results = this.loadChecklistResults(filePath, required);
217
- for (const err of this.requiredChecklistErrors(required, acks, results))
180
+ for (const err of this.requiredChecklistErrors(required, results))
218
181
  errors.push(err);
219
182
  if (errors.length > 0) {
220
183
  throw new inform_ai_error_1.InformAiError(`review.json has ${errors.length} error(s) — fix ALL, then re-run pnpm wp-finish-upsert-pr:\n\n` +
@@ -226,32 +189,11 @@ let ReviewJsonService = class ReviewJsonService {
226
189
  ? raw['riskEmoji']
227
190
  : (EMOJI_FOR_LEVEL[level] ?? '🟡');
228
191
  const summary = typeof raw['summary'] === 'string' ? raw['summary'] : '';
229
- return new ReviewJson(title, riskScore, level, emoji, summary, this.asStringArray(raw['violations']), this.asStringArray(raw['risks']), this.asStringArray(raw['filesToReview']), acks, results);
192
+ return new ReviewJson(title, riskScore, level, emoji, summary, this.asStringArray(raw['violations']), this.asStringArray(raw['risks']), this.asStringArray(raw['filesToReview']), results);
230
193
  }
231
- // Parse the AI-authored `checklists[]` into typed ChecklistAck[]. Tolerant of a missing/garbage
232
- // field (→ []) and of non-object entries (skipped) malformed acks simply fail to satisfy a BLOCK
233
- // requirement rather than crashing the load.
234
- // webpieces-disable no-any-unknown -- opaque parsed JSON value, narrowed here
235
- parseChecklistAcks(value) {
236
- if (!Array.isArray(value))
237
- return [];
238
- const acks = [];
239
- for (const entry of value) {
240
- if (typeof entry !== 'object' || entry === null || Array.isArray(entry))
241
- continue;
242
- // webpieces-disable no-any-unknown -- one opaque ack entry, narrowed field-by-field
243
- const e = entry;
244
- const id = typeof e['id'] === 'string' ? e['id'] : '';
245
- if (id === '')
246
- continue;
247
- acks.push(new ChecklistAck(id, e['acknowledged'] === true, this.asStringArray(e['notes'])));
248
- }
249
- return acks;
250
- }
251
- // Read the per-checklist verdict files `review-<id>.json` that sit beside review.json — one per
252
- // triggered checklist. Tolerant like parseChecklistAcks: a missing file is simply absent from the
253
- // result (→ falls back to the inline ack / counts as unmet for a BLOCK), and a malformed one is
254
- // skipped (an unknown/stale review-<id>.json never wedges the branch).
194
+ // Read the per-checklist verdict files `review-<id>.json` beside review.json one per matched checklist.
195
+ // A missing file is simply absent from the result ( counts as MISSING for that checklist); a malformed
196
+ // one is skipped (a stale review-<id>.json never wedges the branch).
255
197
  loadChecklistResults(reviewJsonFilePath, required) {
256
198
  const results = [];
257
199
  for (const req of required) {
@@ -264,42 +206,33 @@ let ReviewJsonService = class ReviewJsonService {
264
206
  }
265
207
  return results;
266
208
  }
267
- // Resolve ONE checklist's verdict from its per-file result (preferred) or its legacy inline ack.
268
- // Central so review.json enforcement AND the finish-command dashboard agree on the outcome.
269
- resolveVerdict(req, acks, results) {
209
+ // Resolve ONE checklist's verdict from its review-<id>.json. Central so review.json enforcement AND the
210
+ // finish-command dashboard agree on the outcome.
211
+ resolveVerdict(req, results) {
270
212
  const result = results.find((r) => r.id === req.id);
271
- if (result) {
272
- if (result.success)
273
- return new ChecklistVerdict(req.id, exports.CK_PASS, result.output);
274
- if (result.override.trim() !== '')
275
- return new ChecklistVerdict(req.id, exports.CK_OVERRIDDEN, result.override.trim());
276
- return new ChecklistVerdict(req.id, exports.CK_FAIL, result.output);
277
- }
278
- const ack = acks.find((a) => a.id === req.id);
279
- if (ack && ack.acknowledged)
280
- return new ChecklistVerdict(req.id, exports.CK_ACKED, ack.notes.join('; '));
281
- return new ChecklistVerdict(req.id, exports.CK_MISSING, '');
213
+ if (!result)
214
+ return new ChecklistVerdict(req.id, exports.CK_MISSING, '');
215
+ if (result.success)
216
+ return new ChecklistVerdict(req.id, exports.CK_PASS, result.output);
217
+ if (result.override.trim() !== '')
218
+ return new ChecklistVerdict(req.id, exports.CK_OVERRIDDEN, result.override.trim());
219
+ return new ChecklistVerdict(req.id, exports.CK_FAIL, result.output);
282
220
  }
283
- // BLOCK requirements whose verdict is FAIL (reviewed, found a problem, no override) or MISSING (no
284
- // verdict written at all) → one error each. WARN never blocks. Uses the consumer's blockMessage /
285
- // the reviewer's `output` verbatim so the consumer owns the wording and webpieces owns the mechanism.
286
- requiredChecklistErrors(required, acks, results) {
221
+ // Every matched checklist whose verdict is FAIL (reviewed, found a problem, no override) or MISSING (no
222
+ // review-<id>.json written) → one error each, printing the reviewer's `output` verbatim.
223
+ requiredChecklistErrors(required, results) {
287
224
  const errors = [];
288
225
  for (const req of required) {
289
- if (req.severity !== checklist_config_1.CHECKLIST_BLOCK)
290
- continue;
291
- const verdict = this.resolveVerdict(req, acks, results);
226
+ const verdict = this.resolveVerdict(req, results);
292
227
  if (verdict.status === exports.CK_FAIL) {
293
- const msg = req.blockMessage.trim() !== '' ? `${req.blockMessage.trim()} ` : '';
294
- errors.push(`Checklist "${req.id}" (${req.title}) FAILED review. ${msg}` +
295
- `The reviewer wrote:\n ${verdict.detail.split('\n').join('\n ')}\n` +
228
+ errors.push(`Checklist "${req.id}" FAILED review. The reviewer (${req.subagent}) wrote:\n ` +
229
+ `${verdict.detail.split('\n').join('\n ')}\n` +
296
230
  ` Fix it, then re-run; or set a non-empty "override" in ${this.checklistFileName(req.id)} to ship anyway with a stated justification.`);
297
231
  }
298
232
  else if (verdict.status === exports.CK_MISSING) {
299
- const docs = req.docs.length > 0 ? ` Read: ${req.docs.join(', ')}.` : '';
300
- const msg = req.blockMessage.trim() !== '' ? `${req.blockMessage.trim()} ` : '';
301
- errors.push(`Checklist "${req.id}" (${req.title}) is REQUIRED for this diff but has no verdict. ${msg}` +
302
- `Write ${this.checklistFileName(req.id)} with {"success":true,"output":"…"} once you have walked it.${docs}`);
233
+ const doc = req.doc.trim() !== '' ? ` Read: ${req.doc}.` : '';
234
+ errors.push(`Checklist "${req.id}" MATCHED this diff but has no verdict. Spawn the "${req.subagent}" subagent to review it, ` +
235
+ `then write ${this.checklistFileName(req.id)} with {"id":"${req.id}","success":true,"output":"…"}.${doc}`);
303
236
  }
304
237
  }
305
238
  return errors;
@@ -337,8 +270,7 @@ let ReviewJsonService = class ReviewJsonService {
337
270
  return value.filter((v) => typeof v === 'string');
338
271
  }
339
272
  // Parse opaque AI-authored JSON, converting a SyntaxError into a readable InformAiError. `required`
340
- // is threaded through so a JSON syntax error still prints the checklist instructions the AI needs
341
- // exactly when it most needs them — rather than the bare schema.
273
+ // is threaded through so a JSON syntax error still prints the checklist instructions the AI needs.
342
274
  // webpieces-disable no-any-unknown -- returns the opaque parsed object; loadReviewJson narrows each field
343
275
  parseReviewJson(raw, filePath, required) {
344
276
  // webpieces-disable no-unmanaged-exceptions -- chokepoint: convert JSON.parse SyntaxError to an InformAiError for the AI
@@ -1 +1 @@
1
- {"version":3,"file":"review-json.js","sourceRoot":"","sources":["../../../../../packages/tooling/rules-config/src/review-json.ts"],"names":[],"mappings":"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","sourcesContent":["import * as fs from 'fs';\nimport * as path from 'path';\nimport { injectable, bindingScopeValues } from 'inversify';\nimport { WEBPIECES_TMP_DIR, PR_REVIEW_DIR } from './constants';\nimport { CHECKLIST_BLOCK } from './checklist-config';\nimport { InformAiError } from './inform-ai-error';\nimport { toError } from './to-error';\n\n// One entry the AI writes into review.json's `checklists[]`: \"I read the doc for <id> and walked it\".\n// acknowledged: true is the AI attesting it did the walk — a SURFACING/AUDIT signal, not authorization.\nexport class ChecklistAck {\n id: string;\n acknowledged: boolean;\n notes: string[]; // per-item findings the AI chose to record (optional; [] when none)\n\n constructor(id: string, acknowledged: boolean, notes: string[]) {\n this.id = id;\n this.acknowledged = acknowledged;\n this.notes = notes;\n }\n}\n\n// The verdict a reviewer wrote into a PER-CHECKLIST file `.webpieces/pr-review/<branch>/review-<id>.json`,\n// one per triggered checklist. Replaces the single shared `checklists[]` array so concurrent reviewer\n// subagents never clobber one file. Unlike ChecklistAck's bare boolean, this records the OUTCOME:\n// success:true → PASS\n// success:false + override non-empty → OVERRIDDEN (pass; the free-text justification reaches the PR)\n// success:false + no override → FAIL (refuse; `output` is printed verbatim)\n// `override` is deliberately free text, not a boolean — it forces the bypass to be stated in words and\n// surfaces it on the dashboard, where a human sees it. Data-only (per CLAUDE.md).\nexport class ChecklistResult {\n id: string;\n success: boolean;\n output: string; // what the reviewer found; printed verbatim when a BLOCK checklist fails\n override: string; // '' = no override; non-empty = ship-anyway justification (renders 🟡 overridden)\n\n constructor(id: string, success: boolean, output: string, override: string) {\n this.id = id;\n this.success = success;\n this.output = output;\n this.override = override;\n }\n}\n\n// What the CALLER (the pr-gate command) computed from the diff: the checklists this branch triggered.\n// Drives BOTH review.json validation (BLOCK must be acknowledged) AND the printed schema hint (so the\n// AI is told, at the moment it writes review.json, exactly which docs to read). Data-only.\nexport class RequiredChecklist {\n id: string;\n title: string;\n severity: string; // 'BLOCK' | 'WARN'\n docs: string[];\n blockMessage: string;\n matchedFiles: string[]; // the changed files that triggered it (for the dashboard + hint)\n subagent: string; // expected reviewer agentType ('' = no provenance requirement); enforced by finish\n\n // eslint-disable-next-line @typescript-eslint/max-params\n constructor(id: string, title: string, severity: string, docs: string[], blockMessage: string, matchedFiles: string[], subagent = '') {\n this.id = id;\n this.title = title;\n this.severity = severity;\n this.docs = docs;\n this.blockMessage = blockMessage;\n this.matchedFiles = matchedFiles;\n this.subagent = subagent;\n }\n}\n\n// The AI-authored review for a PR. The AI writes this file itself between `wp-start-upsert-pr` (which\n// prints the schema) and `wp-finish-upsert-pr` (which reads it). Data-only (per CLAUDE.md).\nexport class ReviewJson {\n title: string; // human PR title describing the change; used as the `gh pr` title (empty → caller falls back)\n riskScore: number; // 0–100, drives the risk bar\n riskLevel: string; // 'green' | 'yellow' | 'red'\n riskEmoji: string; // '🟢' | '🟡' | '🔴' — derived from riskLevel when omitted\n summary: string; // rendered in the dashboard Summary section\n violations: string[]; // pattern/architecture violations; length = the Pattern Violations count\n risks: string[];\n filesToReview: string[];\n checklists: ChecklistAck[]; // legacy inline acknowledgments (back-compat); [] when none written\n results: ChecklistResult[]; // resolved per-checklist verdicts (from review-<id>.json); [] when none\n\n // eslint-disable-next-line @typescript-eslint/max-params\n constructor(\n title: string,\n riskScore: number,\n riskLevel: string,\n riskEmoji: string,\n summary: string,\n violations: string[],\n risks: string[],\n filesToReview: string[],\n checklists: ChecklistAck[] = [],\n results: ChecklistResult[] = [],\n ) {\n this.title = title;\n this.riskScore = riskScore;\n this.riskLevel = riskLevel;\n this.riskEmoji = riskEmoji;\n this.summary = summary;\n this.violations = violations;\n this.risks = risks;\n this.filesToReview = filesToReview;\n this.checklists = checklists;\n this.results = results;\n }\n}\n\n// A checklist's resolved outcome, shared by review.json enforcement and the dashboard so both agree.\nexport const CK_PASS = 'pass'; // review-<id>.json success:true\nexport const CK_OVERRIDDEN = 'overridden'; // review-<id>.json success:false + non-empty override → 🟡\nexport const CK_FAIL = 'fail'; // review-<id>.json success:false + no override → refuse\nexport const CK_MISSING = 'missing'; // no verdict file and no inline ack → refuse (BLOCK)\nexport const CK_ACKED = 'acknowledged'; // legacy inline checklists[] ack satisfied (back-compat)\n\nexport class ChecklistVerdict {\n id: string;\n status: string; // one of CK_PASS | CK_OVERRIDDEN | CK_FAIL | CK_MISSING | CK_ACKED\n detail: string; // reviewer output / override justification / ack notes (for the dashboard + errors)\n\n constructor(id: string, status: string, detail: string) {\n this.id = id;\n this.status = status;\n this.detail = detail;\n }\n}\n\nconst RISK_LEVELS = ['green', 'yellow', 'red'] as const;\nconst EMOJI_FOR_LEVEL: Record<string, string> = { green: '🟢', yellow: '🟡', red: '🔴' };\n\n/** Locates + loads/validates the AI-authored review.json. `@injectable(bindingScopeValues.Singleton)` so it's drawn in the design. */\n@injectable(bindingScopeValues.Singleton)\nexport class ReviewJsonService {\n // The per-feature PR working dir: `.webpieces/pr-review/<feature>`.\n prDirFor(repoRoot: string, featureName: string): string {\n return path.join(repoRoot, WEBPIECES_TMP_DIR, PR_REVIEW_DIR, featureName);\n }\n\n // Absolute path of the review.json for a feature — beside pr-body.md, keyed by branch name.\n reviewJsonPath(repoRoot: string, featureName: string): string {\n return path.join(this.prDirFor(repoRoot, featureName), 'review.json');\n }\n\n // Copy-paste schema both commands print (write it / fix it). `required` is the set of consumer\n // checklists the diff triggered; when it is empty the output is byte-identical to before this\n // feature existed (non-adopting repos see no change). When non-empty it grows a `checklists` line\n // in the JSON shape PLUS an instruction block naming the docs to read — diff-derived instructions\n // injected at exactly the moment the AI writes review.json.\n reviewJsonSchemaHint(filePath: string, required: readonly RequiredChecklist[] = []): string {\n return (\n `Write your PR review to:\\n ${filePath}\\n\\n` +\n `with this exact JSON shape (riskEmoji optional — derived from riskLevel):\\n\\n` +\n `{\\n` +\n ` \"title\": \"concise PR title describing the change (imperative, no branch names)\",\\n` +\n ` \"riskScore\": 0, // integer 0–100 (higher = riskier)\\n` +\n ` \"riskLevel\": \"green | yellow | red\",\\n` +\n ` \"summary\": \"5–10 sentence review summary\",\\n` +\n ` \"violations\": [\"pattern/architecture violations you found (empty array if none)\"],\\n` +\n ` \"risks\": [\"notable risks (empty array if none)\"],\\n` +\n ` \"filesToReview\": [\"paths a human should look at (empty array if none)\"]\\n` +\n `}` +\n this.requiredChecklistHint(filePath, required)\n );\n }\n\n // The per-checklist review file path that sits beside review.json: review-<id>.json.\n checklistResultPath(reviewJsonFilePath: string, checklistId: string): string {\n return path.join(path.dirname(reviewJsonFilePath), `review-${checklistId}.json`);\n }\n\n // The diff-triggered instruction block, appended ONLY when the branch triggered a checklist. This is\n // the consumer's review process, re-injected: read doc Y because the diff touched X, then write ONE\n // file per checklist — `review-<id>.json` — so concurrent reviewer subagents never clobber a shared\n // file. A BLOCK checklist with success:false and no override refuses to open the PR.\n private requiredChecklistHint(reviewJsonFilePath: string, required: readonly RequiredChecklist[]): string {\n if (required.length === 0) return '';\n const lines: string[] = ['', '', 'This branch triggered company review checklist(s). For EACH one below: READ its docs, walk'];\n lines.push('the items against your diff, then write a SEPARATE file `review-<id>.json` beside review.json');\n lines.push('with this shape (override optional — a free-text ship-anyway justification):');\n lines.push('');\n lines.push(' { \"success\": true, \"output\": \"what you checked / what you found\", \"override\": \"\" }');\n lines.push('');\n for (const req of required) {\n const gate = req.severity === CHECKLIST_BLOCK\n ? 'BLOCK — success:false with no \"override\" will NOT open the PR'\n : 'WARN — recorded on the dashboard; never blocks';\n lines.push(` • [${req.id}] ${req.title} (${gate})`);\n lines.push(` write: ${this.checklistResultPath(reviewJsonFilePath, req.id)}`);\n lines.push(` docs to read: ${req.docs.join(', ')}`);\n if (req.subagent.trim() !== '') lines.push(` must be reviewed by the \"${req.subagent.trim()}\" subagent (its independent run is verified from the harness).`);\n if (req.blockMessage.trim() !== '') lines.push(` ${req.blockMessage.trim()}`);\n if (req.matchedFiles.length > 0) lines.push(` triggered by: ${req.matchedFiles.slice(0, 5).join(', ')}`);\n }\n return lines.join('\\n');\n }\n\n /**\n * Load + validate the AI-authored review.json. Throws InformAiError (with the schema) when missing,\n * unparseable, or structurally wrong. Returns a fully-populated ReviewJson on success.\n *\n * `required` is the set of consumer checklists the diff triggered (empty for non-adopting repos, in\n * which case this behaves byte-identically to before the feature). Every BLOCK entry must appear in\n * review.json's `checklists[]` with `acknowledged: true`, or a validation error is raised alongside\n * the usual ones so the AI gets ONE message. WARN entries are never validated; unknown ids in\n * `checklists[]` are ignored (forward-compat).\n */\n // webpieces-disable max-lines-new-methods -- one cohesive load+validate pass over the review fields\n loadReviewJson(filePath: string, required: readonly RequiredChecklist[] = []): ReviewJson {\n if (!fs.existsSync(filePath)) {\n throw new InformAiError(\n `Required review.json not found.\\n\\n${this.reviewJsonSchemaHint(filePath, required)}\\n\\n` +\n `Then re-run: pnpm wp-finish-upsert-pr`,\n );\n }\n\n const raw = this.parseReviewJson(fs.readFileSync(filePath, 'utf8'), filePath, required);\n if (typeof raw !== 'object' || raw === null || Array.isArray(raw)) {\n throw new InformAiError(`review.json must be a JSON object.\\n\\n${this.reviewJsonSchemaHint(filePath, required)}`);\n }\n\n const errors: string[] = [];\n\n const riskScore = raw['riskScore'];\n if (typeof riskScore !== 'number' || !Number.isFinite(riskScore) || riskScore < 0 || riskScore > 100) {\n errors.push(`\"riskScore\" must be a number 0–100, got ${JSON.stringify(riskScore)}.`);\n }\n\n const riskLevel = raw['riskLevel'];\n if (typeof riskLevel !== 'string' || !RISK_LEVELS.includes(riskLevel as typeof RISK_LEVELS[number])) {\n errors.push(`\"riskLevel\" must be one of: ${RISK_LEVELS.join(', ')}.`);\n }\n\n const title = typeof raw['title'] === 'string' ? (raw['title'] as string).trim() : '';\n if (title === '') {\n errors.push('\"title\" must be a non-empty, imperative PR title describing the change (no branch names).');\n }\n\n const acks = this.parseChecklistAcks(raw['checklists']);\n const results = this.loadChecklistResults(filePath, required);\n for (const err of this.requiredChecklistErrors(required, acks, results)) errors.push(err);\n\n if (errors.length > 0) {\n throw new InformAiError(\n `review.json has ${errors.length} error(s) — fix ALL, then re-run pnpm wp-finish-upsert-pr:\\n\\n` +\n errors.map((e: string): string => ` • ${e}`).join('\\n') +\n `\\n\\n${this.reviewJsonSchemaHint(filePath, required)}`,\n );\n }\n\n const level = riskLevel as string;\n const emoji = typeof raw['riskEmoji'] === 'string' && raw['riskEmoji'] !== ''\n ? (raw['riskEmoji'] as string)\n : (EMOJI_FOR_LEVEL[level] ?? '🟡');\n const summary = typeof raw['summary'] === 'string' ? (raw['summary'] as string) : '';\n\n return new ReviewJson(\n title,\n riskScore as number,\n level,\n emoji,\n summary,\n this.asStringArray(raw['violations']),\n this.asStringArray(raw['risks']),\n this.asStringArray(raw['filesToReview']),\n acks,\n results,\n );\n }\n\n // Parse the AI-authored `checklists[]` into typed ChecklistAck[]. Tolerant of a missing/garbage\n // field (→ []) and of non-object entries (skipped) — malformed acks simply fail to satisfy a BLOCK\n // requirement rather than crashing the load.\n // webpieces-disable no-any-unknown -- opaque parsed JSON value, narrowed here\n private parseChecklistAcks(value: unknown): ChecklistAck[] {\n if (!Array.isArray(value)) return [];\n const acks: ChecklistAck[] = [];\n for (const entry of value) {\n if (typeof entry !== 'object' || entry === null || Array.isArray(entry)) continue;\n // webpieces-disable no-any-unknown -- one opaque ack entry, narrowed field-by-field\n const e = entry as Record<string, unknown>;\n const id = typeof e['id'] === 'string' ? (e['id'] as string) : '';\n if (id === '') continue;\n acks.push(new ChecklistAck(id, e['acknowledged'] === true, this.asStringArray(e['notes'])));\n }\n return acks;\n }\n\n // Read the per-checklist verdict files `review-<id>.json` that sit beside review.json — one per\n // triggered checklist. Tolerant like parseChecklistAcks: a missing file is simply absent from the\n // result (→ falls back to the inline ack / counts as unmet for a BLOCK), and a malformed one is\n // skipped (an unknown/stale review-<id>.json never wedges the branch).\n loadChecklistResults(reviewJsonFilePath: string, required: readonly RequiredChecklist[]): ChecklistResult[] {\n const results: ChecklistResult[] = [];\n for (const req of required) {\n const p = this.checklistResultPath(reviewJsonFilePath, req.id);\n if (!fs.existsSync(p)) continue;\n const parsed = this.parseChecklistResult(p, req.id);\n if (parsed) results.push(parsed);\n }\n return results;\n }\n\n // Resolve ONE checklist's verdict from its per-file result (preferred) or its legacy inline ack.\n // Central so review.json enforcement AND the finish-command dashboard agree on the outcome.\n resolveVerdict(req: RequiredChecklist, acks: readonly ChecklistAck[], results: readonly ChecklistResult[]): ChecklistVerdict {\n const result = results.find((r: ChecklistResult): boolean => r.id === req.id);\n if (result) {\n if (result.success) return new ChecklistVerdict(req.id, CK_PASS, result.output);\n if (result.override.trim() !== '') return new ChecklistVerdict(req.id, CK_OVERRIDDEN, result.override.trim());\n return new ChecklistVerdict(req.id, CK_FAIL, result.output);\n }\n const ack = acks.find((a: ChecklistAck): boolean => a.id === req.id);\n if (ack && ack.acknowledged) return new ChecklistVerdict(req.id, CK_ACKED, ack.notes.join('; '));\n return new ChecklistVerdict(req.id, CK_MISSING, '');\n }\n\n // BLOCK requirements whose verdict is FAIL (reviewed, found a problem, no override) or MISSING (no\n // verdict written at all) → one error each. WARN never blocks. Uses the consumer's blockMessage /\n // the reviewer's `output` verbatim so the consumer owns the wording and webpieces owns the mechanism.\n private requiredChecklistErrors(required: readonly RequiredChecklist[], acks: readonly ChecklistAck[], results: readonly ChecklistResult[]): string[] {\n const errors: string[] = [];\n for (const req of required) {\n if (req.severity !== CHECKLIST_BLOCK) continue;\n const verdict = this.resolveVerdict(req, acks, results);\n if (verdict.status === CK_FAIL) {\n const msg = req.blockMessage.trim() !== '' ? `${req.blockMessage.trim()} ` : '';\n errors.push(\n `Checklist \"${req.id}\" (${req.title}) FAILED review. ${msg}` +\n `The reviewer wrote:\\n ${verdict.detail.split('\\n').join('\\n ')}\\n` +\n ` Fix it, then re-run; or set a non-empty \"override\" in ${this.checklistFileName(req.id)} to ship anyway with a stated justification.`,\n );\n } else if (verdict.status === CK_MISSING) {\n const docs = req.docs.length > 0 ? ` Read: ${req.docs.join(', ')}.` : '';\n const msg = req.blockMessage.trim() !== '' ? `${req.blockMessage.trim()} ` : '';\n errors.push(\n `Checklist \"${req.id}\" (${req.title}) is REQUIRED for this diff but has no verdict. ${msg}` +\n `Write ${this.checklistFileName(req.id)} with {\"success\":true,\"output\":\"…\"} once you have walked it.${docs}`,\n );\n }\n }\n return errors;\n }\n\n private checklistFileName(checklistId: string): string {\n return `review-${checklistId}.json`;\n }\n\n // Parse one review-<id>.json into a ChecklistResult, or null when malformed. Tolerant: missing\n // `success` counts as false (fail-closed), `output`/`override` default to ''.\n // webpieces-disable no-any-unknown -- opaque parsed JSON, narrowed field-by-field\n private parseChecklistResult(filePath: string, id: string): ChecklistResult | null {\n // webpieces-disable no-unmanaged-exceptions -- chokepoint: a malformed per-checklist file is skipped, not fatal\n // eslint-disable-next-line @webpieces/no-unmanaged-exceptions\n try {\n // webpieces-disable no-any-unknown -- parsed JSON is opaque until narrowed below\n const raw = JSON.parse(fs.readFileSync(filePath, 'utf8')) as Record<string, unknown>;\n if (typeof raw !== 'object' || raw === null || Array.isArray(raw)) return null;\n const success = raw['success'] === true;\n const output = typeof raw['output'] === 'string' ? (raw['output'] as string) : '';\n const override = typeof raw['override'] === 'string' ? (raw['override'] as string) : '';\n return new ChecklistResult(id, success, output, override);\n } catch (err: unknown) {\n const error = toError(err);\n void error;\n return null;\n }\n }\n\n // webpieces-disable no-any-unknown -- opaque parsed JSON value, narrowed to string[] here\n private asStringArray(value: unknown): string[] {\n if (!Array.isArray(value)) return [];\n // webpieces-disable no-any-unknown -- element of an opaque JSON array, narrowed by the type guard\n return value.filter((v: unknown): v is string => typeof v === 'string');\n }\n\n // Parse opaque AI-authored JSON, converting a SyntaxError into a readable InformAiError. `required`\n // is threaded through so a JSON syntax error still prints the checklist instructions the AI needs —\n // exactly when it most needs them — rather than the bare schema.\n // webpieces-disable no-any-unknown -- returns the opaque parsed object; loadReviewJson narrows each field\n private parseReviewJson(raw: string, filePath: string, required: readonly RequiredChecklist[]): Record<string, unknown> {\n // webpieces-disable no-unmanaged-exceptions -- chokepoint: convert JSON.parse SyntaxError to an InformAiError for the AI\n // eslint-disable-next-line @webpieces/no-unmanaged-exceptions\n try {\n // webpieces-disable no-any-unknown -- parsed JSON is opaque until narrowed by the caller\n return JSON.parse(raw) as Record<string, unknown>;\n } catch (err: unknown) {\n const error = toError(err);\n throw new InformAiError(\n `review.json is not valid JSON (${error.message}).\\n\\n${this.reviewJsonSchemaHint(filePath, required)}\\n\\n` +\n `Then re-run: pnpm wp-finish-upsert-pr`,\n );\n }\n }\n}\n\n// Temporary migration delegators to ReviewJsonService — removed once consumers inject it.\nconst reviewJsonSvc = new ReviewJsonService();\n\n// webpieces-disable no-function-outside-class -- temporary back-compat delegator to ReviewJsonService; removed once consumers inject it\nexport function prDirFor(repoRoot: string, featureName: string): string {\n return reviewJsonSvc.prDirFor(repoRoot, featureName);\n}\n\n// webpieces-disable no-function-outside-class -- temporary back-compat delegator to ReviewJsonService; removed once consumers inject it\nexport function reviewJsonPath(repoRoot: string, featureName: string): string {\n return reviewJsonSvc.reviewJsonPath(repoRoot, featureName);\n}\n\n// webpieces-disable no-function-outside-class -- temporary back-compat delegator to ReviewJsonService; removed once consumers inject it\nexport function reviewJsonSchemaHint(filePath: string, required: readonly RequiredChecklist[] = []): string {\n return reviewJsonSvc.reviewJsonSchemaHint(filePath, required);\n}\n\n// webpieces-disable no-function-outside-class -- temporary back-compat delegator to ReviewJsonService; removed once consumers inject it\nexport function loadReviewJson(filePath: string, required: readonly RequiredChecklist[] = []): ReviewJson {\n return reviewJsonSvc.loadReviewJson(filePath, required);\n}\n"]}
1
+ {"version":3,"file":"review-json.js","sourceRoot":"","sources":["../../../../../packages/tooling/rules-config/src/review-json.ts"],"names":[],"mappings":";;;AA4UA,4BAEC;AAGD,wCAEC;AAGD,oDAEC;AAGD,wCAEC;;AA7VD,+CAAyB;AACzB,mDAA6B;AAC7B,yCAA2D;AAC3D,2CAA+D;AAC/D,uDAAkD;AAClD,yCAAqC;AAErC,wGAAwG;AACxG,sGAAsG;AACtG,gCAAgC;AAChC,8CAA8C;AAC9C,uGAAuG;AACvG,qFAAqF;AACrF,wGAAwG;AACxG,+FAA+F;AAC/F,MAAa,eAAe;IACxB,EAAE,CAAS;IACX,OAAO,CAAU;IACjB,MAAM,CAAS,CAAG,qEAAqE;IACvF,QAAQ,CAAS,CAAE,kFAAkF;IAErG,YAAY,EAAU,EAAE,OAAgB,EAAE,MAAc,EAAE,QAAgB;QACtE,IAAI,CAAC,EAAE,GAAG,EAAE,CAAC;QACb,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;QACvB,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QACrB,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC;IAC7B,CAAC;CACJ;AAZD,0CAYC;AAED,yGAAyG;AACzG,wGAAwG;AACxG,sCAAsC;AACtC,MAAa,iBAAiB;IAC1B,EAAE,CAAS,CAAa,yCAAyC;IACjE,QAAQ,CAAS,CAAO,8DAA8D;IACtF,GAAG,CAAS,CAAY,mEAAmE;IAC3F,YAAY,CAAW,CAAC,+DAA+D;IAEvF,YAAY,EAAU,EAAE,QAAgB,EAAE,GAAW,EAAE,YAAsB;QACzE,IAAI,CAAC,EAAE,GAAG,EAAE,CAAC;QACb,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC;QACzB,IAAI,CAAC,GAAG,GAAG,GAAG,CAAC;QACf,IAAI,CAAC,YAAY,GAAG,YAAY,CAAC;IACrC,CAAC;CACJ;AAZD,8CAYC;AAED,wGAAwG;AACxG,4GAA4G;AAC5G,qDAAqD;AACrD,MAAa,UAAU;IACnB,KAAK,CAAS,CAAC,8FAA8F;IAC7G,SAAS,CAAS,CAAC,6BAA6B;IAChD,SAAS,CAAS,CAAC,6BAA6B;IAChD,SAAS,CAAS,CAAC,2DAA2D;IAC9E,OAAO,CAAS,CAAC,4CAA4C;IAC7D,UAAU,CAAW,CAAC,yEAAyE;IAC/F,KAAK,CAAW;IAChB,aAAa,CAAW;IACxB,OAAO,CAAoB,CAAC,wEAAwE;IAEpG,yDAAyD;IACzD,YACI,KAAa,EACb,SAAiB,EACjB,SAAiB,EACjB,SAAiB,EACjB,OAAe,EACf,UAAoB,EACpB,KAAe,EACf,aAAuB,EACvB,UAA6B,EAAE;QAE/B,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;QACnB,IAAI,CAAC,SAAS,GAAG,SAAS,CAAC;QAC3B,IAAI,CAAC,SAAS,GAAG,SAAS,CAAC;QAC3B,IAAI,CAAC,SAAS,GAAG,SAAS,CAAC;QAC3B,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;QACvB,IAAI,CAAC,UAAU,GAAG,UAAU,CAAC;QAC7B,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;QACnB,IAAI,CAAC,aAAa,GAAG,aAAa,CAAC;QACnC,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;IAC3B,CAAC;CACJ;AAjCD,gCAiCC;AAED,qGAAqG;AACxF,QAAA,OAAO,GAAG,MAAM,CAAC,CAAe,gCAAgC;AAChE,QAAA,aAAa,GAAG,YAAY,CAAC,CAAG,2DAA2D;AAC3F,QAAA,OAAO,GAAG,MAAM,CAAC,CAAe,wDAAwD;AACxF,QAAA,UAAU,GAAG,SAAS,CAAC,CAAS,uCAAuC;AAEpF,MAAa,gBAAgB;IACzB,EAAE,CAAS;IACX,MAAM,CAAS,CAAC,wDAAwD;IACxE,MAAM,CAAS,CAAC,wEAAwE;IAExF,YAAY,EAAU,EAAE,MAAc,EAAE,MAAc;QAClD,IAAI,CAAC,EAAE,GAAG,EAAE,CAAC;QACb,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QACrB,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;IACzB,CAAC;CACJ;AAVD,4CAUC;AAED,MAAM,WAAW,GAAG,CAAC,OAAO,EAAE,QAAQ,EAAE,KAAK,CAAU,CAAC;AACxD,MAAM,eAAe,GAA2B,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,EAAE,IAAI,EAAE,CAAC;AAEzF,sIAAsI;AAE/H,IAAM,iBAAiB,GAAvB,MAAM,iBAAiB;IAC1B,oEAAoE;IACpE,QAAQ,CAAC,QAAgB,EAAE,WAAmB;QAC1C,OAAO,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,6BAAiB,EAAE,yBAAa,EAAE,WAAW,CAAC,CAAC;IAC9E,CAAC;IAED,4FAA4F;IAC5F,cAAc,CAAC,QAAgB,EAAE,WAAmB;QAChD,OAAO,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,QAAQ,EAAE,WAAW,CAAC,EAAE,aAAa,CAAC,CAAC;IAC1E,CAAC;IAED,qGAAqG;IACrG,kGAAkG;IAClG,sEAAsE;IACtE,oBAAoB,CAAC,QAAgB,EAAE,WAAyC,EAAE;QAC9E,OAAO,CACH,+BAA+B,QAAQ,MAAM;YAC7C,+EAA+E;YAC/E,KAAK;YACL,sFAAsF;YACtF,+EAA+E;YAC/E,0CAA0C;YAC1C,gDAAgD;YAChD,wFAAwF;YACxF,uDAAuD;YACvD,6EAA6E;YAC7E,GAAG;YACH,IAAI,CAAC,qBAAqB,CAAC,QAAQ,EAAE,QAAQ,CAAC,CACjD,CAAC;IACN,CAAC;IAED,qFAAqF;IACrF,mBAAmB,CAAC,kBAA0B,EAAE,WAAmB;QAC/D,OAAO,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,kBAAkB,CAAC,EAAE,UAAU,WAAW,OAAO,CAAC,CAAC;IACrF,CAAC;IAED,yGAAyG;IACzG,kGAAkG;IAC1F,qBAAqB,CAAC,kBAA0B,EAAE,QAAsC;QAC5F,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO,EAAE,CAAC;QACrC,MAAM,KAAK,GAAa,CAAC,EAAE,EAAE,EAAE,EAAE,wFAAwF,CAAC,CAAC;QAC3H,KAAK,CAAC,IAAI,CAAC,kGAAkG,CAAC,CAAC;QAC/G,KAAK,CAAC,IAAI,CAAC,qEAAqE,CAAC,CAAC;QAClF,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACf,KAAK,CAAC,IAAI,CAAC,2FAA2F,CAAC,CAAC;QACxG,KAAK,CAAC,IAAI,CAAC,kGAAkG,CAAC,CAAC;QAC/G,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACf,KAAK,MAAM,GAAG,IAAI,QAAQ,EAAE,CAAC;YACzB,KAAK,CAAC,IAAI,CAAC,QAAQ,GAAG,CAAC,EAAE,wBAAwB,GAAG,CAAC,QAAQ,EAAE,CAAC,CAAC;YACjE,KAAK,CAAC,IAAI,CAAC,gBAAgB,IAAI,CAAC,mBAAmB,CAAC,kBAAkB,EAAE,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;YACnF,IAAI,GAAG,CAAC,GAAG,CAAC,IAAI,EAAE,KAAK,EAAE;gBAAE,KAAK,CAAC,IAAI,CAAC,sBAAsB,GAAG,CAAC,GAAG,EAAE,CAAC,CAAC;YACvE,IAAI,GAAG,CAAC,YAAY,CAAC,MAAM,GAAG,CAAC;gBAAE,KAAK,CAAC,IAAI,CAAC,kBAAkB,GAAG,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QAC7G,CAAC;QACD,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC5B,CAAC;IAED;;;;;OAKG;IACH,oGAAoG;IACpG,cAAc,CAAC,QAAgB,EAAE,WAAyC,EAAE;QACxE,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;YAC3B,MAAM,IAAI,+BAAa,CACnB,sCAAsC,IAAI,CAAC,oBAAoB,CAAC,QAAQ,EAAE,QAAQ,CAAC,MAAM;gBACzF,uCAAuC,CAC1C,CAAC;QACN,CAAC;QAED,MAAM,GAAG,GAAG,IAAI,CAAC,eAAe,CAAC,EAAE,CAAC,YAAY,CAAC,QAAQ,EAAE,MAAM,CAAC,EAAE,QAAQ,EAAE,QAAQ,CAAC,CAAC;QACxF,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,GAAG,KAAK,IAAI,IAAI,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC;YAChE,MAAM,IAAI,+BAAa,CAAC,yCAAyC,IAAI,CAAC,oBAAoB,CAAC,QAAQ,EAAE,QAAQ,CAAC,EAAE,CAAC,CAAC;QACtH,CAAC;QAED,MAAM,MAAM,GAAa,EAAE,CAAC;QAE5B,MAAM,SAAS,GAAG,GAAG,CAAC,WAAW,CAAC,CAAC;QACnC,IAAI,OAAO,SAAS,KAAK,QAAQ,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,SAAS,CAAC,IAAI,SAAS,GAAG,CAAC,IAAI,SAAS,GAAG,GAAG,EAAE,CAAC;YACnG,MAAM,CAAC,IAAI,CAAC,2CAA2C,IAAI,CAAC,SAAS,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;QACzF,CAAC;QAED,MAAM,SAAS,GAAG,GAAG,CAAC,WAAW,CAAC,CAAC;QACnC,IAAI,OAAO,SAAS,KAAK,QAAQ,IAAI,CAAC,WAAW,CAAC,QAAQ,CAAC,SAAuC,CAAC,EAAE,CAAC;YAClG,MAAM,CAAC,IAAI,CAAC,+BAA+B,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QAC1E,CAAC;QAED,MAAM,KAAK,GAAG,OAAO,GAAG,CAAC,OAAO,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAE,GAAG,CAAC,OAAO,CAAY,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACtF,IAAI,KAAK,KAAK,EAAE,EAAE,CAAC;YACf,MAAM,CAAC,IAAI,CAAC,2FAA2F,CAAC,CAAC;QAC7G,CAAC;QAED,MAAM,OAAO,GAAG,IAAI,CAAC,oBAAoB,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;QAC9D,KAAK,MAAM,GAAG,IAAI,IAAI,CAAC,uBAAuB,CAAC,QAAQ,EAAE,OAAO,CAAC;YAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QAEpF,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACpB,MAAM,IAAI,+BAAa,CACnB,mBAAmB,MAAM,CAAC,MAAM,gEAAgE;gBAChG,MAAM,CAAC,GAAG,CAAC,CAAC,CAAS,EAAU,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC;gBACxD,OAAO,IAAI,CAAC,oBAAoB,CAAC,QAAQ,EAAE,QAAQ,CAAC,EAAE,CACzD,CAAC;QACN,CAAC;QAED,MAAM,KAAK,GAAG,SAAmB,CAAC;QAClC,MAAM,KAAK,GAAG,OAAO,GAAG,CAAC,WAAW,CAAC,KAAK,QAAQ,IAAI,GAAG,CAAC,WAAW,CAAC,KAAK,EAAE;YACzE,CAAC,CAAE,GAAG,CAAC,WAAW,CAAY;YAC9B,CAAC,CAAC,CAAC,eAAe,CAAC,KAAK,CAAC,IAAI,IAAI,CAAC,CAAC;QACvC,MAAM,OAAO,GAAG,OAAO,GAAG,CAAC,SAAS,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAE,GAAG,CAAC,SAAS,CAAY,CAAC,CAAC,CAAC,EAAE,CAAC;QAErF,OAAO,IAAI,UAAU,CACjB,KAAK,EACL,SAAmB,EACnB,KAAK,EACL,KAAK,EACL,OAAO,EACP,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC,EACrC,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,EAChC,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,eAAe,CAAC,CAAC,EACxC,OAAO,CACV,CAAC;IACN,CAAC;IAED,0GAA0G;IAC1G,wGAAwG;IACxG,qEAAqE;IACrE,oBAAoB,CAAC,kBAA0B,EAAE,QAAsC;QACnF,MAAM,OAAO,GAAsB,EAAE,CAAC;QACtC,KAAK,MAAM,GAAG,IAAI,QAAQ,EAAE,CAAC;YACzB,MAAM,CAAC,GAAG,IAAI,CAAC,mBAAmB,CAAC,kBAAkB,EAAE,GAAG,CAAC,EAAE,CAAC,CAAC;YAC/D,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,CAAC,CAAC;gBAAE,SAAS;YAChC,MAAM,MAAM,GAAG,IAAI,CAAC,oBAAoB,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,CAAC,CAAC;YACpD,IAAI,MAAM;gBAAE,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QACrC,CAAC;QACD,OAAO,OAAO,CAAC;IACnB,CAAC;IAED,wGAAwG;IACxG,iDAAiD;IACjD,cAAc,CAAC,GAAsB,EAAE,OAAmC;QACtE,MAAM,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAkB,EAAW,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,GAAG,CAAC,EAAE,CAAC,CAAC;QAC9E,IAAI,CAAC,MAAM;YAAE,OAAO,IAAI,gBAAgB,CAAC,GAAG,CAAC,EAAE,EAAE,kBAAU,EAAE,EAAE,CAAC,CAAC;QACjE,IAAI,MAAM,CAAC,OAAO;YAAE,OAAO,IAAI,gBAAgB,CAAC,GAAG,CAAC,EAAE,EAAE,eAAO,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC;QAChF,IAAI,MAAM,CAAC,QAAQ,CAAC,IAAI,EAAE,KAAK,EAAE;YAAE,OAAO,IAAI,gBAAgB,CAAC,GAAG,CAAC,EAAE,EAAE,qBAAa,EAAE,MAAM,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAC;QAC9G,OAAO,IAAI,gBAAgB,CAAC,GAAG,CAAC,EAAE,EAAE,eAAO,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC;IAChE,CAAC;IAED,wGAAwG;IACxG,yFAAyF;IACjF,uBAAuB,CAAC,QAAsC,EAAE,OAAmC;QACvG,MAAM,MAAM,GAAa,EAAE,CAAC;QAC5B,KAAK,MAAM,GAAG,IAAI,QAAQ,EAAE,CAAC;YACzB,MAAM,OAAO,GAAG,IAAI,CAAC,cAAc,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;YAClD,IAAI,OAAO,CAAC,MAAM,KAAK,eAAO,EAAE,CAAC;gBAC7B,MAAM,CAAC,IAAI,CACP,cAAc,GAAG,CAAC,EAAE,kCAAkC,GAAG,CAAC,QAAQ,kBAAkB;oBACpF,GAAG,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI;oBAClD,+DAA+D,IAAI,CAAC,iBAAiB,CAAC,GAAG,CAAC,EAAE,CAAC,8CAA8C,CAC9I,CAAC;YACN,CAAC;iBAAM,IAAI,OAAO,CAAC,MAAM,KAAK,kBAAU,EAAE,CAAC;gBACvC,MAAM,GAAG,GAAG,GAAG,CAAC,GAAG,CAAC,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,UAAU,GAAG,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;gBAC9D,MAAM,CAAC,IAAI,CACP,cAAc,GAAG,CAAC,EAAE,sDAAsD,GAAG,CAAC,QAAQ,2BAA2B;oBACjH,cAAc,IAAI,CAAC,iBAAiB,CAAC,GAAG,CAAC,EAAE,CAAC,gBAAgB,GAAG,CAAC,EAAE,kCAAkC,GAAG,EAAE,CAC5G,CAAC;YACN,CAAC;QACL,CAAC;QACD,OAAO,MAAM,CAAC;IAClB,CAAC;IAEO,iBAAiB,CAAC,WAAmB;QACzC,OAAO,UAAU,WAAW,OAAO,CAAC;IACxC,CAAC;IAED,+FAA+F;IAC/F,8EAA8E;IAC9E,kFAAkF;IAC1E,oBAAoB,CAAC,QAAgB,EAAE,EAAU;QACrD,gHAAgH;QAChH,8DAA8D;QAC9D,IAAI,CAAC;YACD,iFAAiF;YACjF,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,YAAY,CAAC,QAAQ,EAAE,MAAM,CAAC,CAA4B,CAAC;YACrF,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,GAAG,KAAK,IAAI,IAAI,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC;gBAAE,OAAO,IAAI,CAAC;YAC/E,MAAM,OAAO,GAAG,GAAG,CAAC,SAAS,CAAC,KAAK,IAAI,CAAC;YACxC,MAAM,MAAM,GAAG,OAAO,GAAG,CAAC,QAAQ,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAE,GAAG,CAAC,QAAQ,CAAY,CAAC,CAAC,CAAC,EAAE,CAAC;YAClF,MAAM,QAAQ,GAAG,OAAO,GAAG,CAAC,UAAU,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAE,GAAG,CAAC,UAAU,CAAY,CAAC,CAAC,CAAC,EAAE,CAAC;YACxF,OAAO,IAAI,eAAe,CAAC,EAAE,EAAE,OAAO,EAAE,MAAM,EAAE,QAAQ,CAAC,CAAC;QAC9D,CAAC;QAAC,OAAO,GAAY,EAAE,CAAC;YACpB,MAAM,KAAK,GAAG,IAAA,kBAAO,EAAC,GAAG,CAAC,CAAC;YAC3B,KAAK,KAAK,CAAC;YACX,OAAO,IAAI,CAAC;QAChB,CAAC;IACL,CAAC;IAED,0FAA0F;IAClF,aAAa,CAAC,KAAc;QAChC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;YAAE,OAAO,EAAE,CAAC;QACrC,kGAAkG;QAClG,OAAO,KAAK,CAAC,MAAM,CAAC,CAAC,CAAU,EAAe,EAAE,CAAC,OAAO,CAAC,KAAK,QAAQ,CAAC,CAAC;IAC5E,CAAC;IAED,oGAAoG;IACpG,mGAAmG;IACnG,0GAA0G;IAClG,eAAe,CAAC,GAAW,EAAE,QAAgB,EAAE,QAAsC;QACzF,yHAAyH;QACzH,8DAA8D;QAC9D,IAAI,CAAC;YACD,yFAAyF;YACzF,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAA4B,CAAC;QACtD,CAAC;QAAC,OAAO,GAAY,EAAE,CAAC;YACpB,MAAM,KAAK,GAAG,IAAA,kBAAO,EAAC,GAAG,CAAC,CAAC;YAC3B,MAAM,IAAI,+BAAa,CACnB,kCAAkC,KAAK,CAAC,OAAO,SAAS,IAAI,CAAC,oBAAoB,CAAC,QAAQ,EAAE,QAAQ,CAAC,MAAM;gBAC3G,uCAAuC,CAC1C,CAAC;QACN,CAAC;IACL,CAAC;CACJ,CAAA;AA3NY,8CAAiB;4BAAjB,iBAAiB;IAD7B,IAAA,sBAAU,EAAC,8BAAkB,CAAC,SAAS,CAAC;GAC5B,iBAAiB,CA2N7B;AAED,0FAA0F;AAC1F,MAAM,aAAa,GAAG,IAAI,iBAAiB,EAAE,CAAC;AAE9C,wIAAwI;AACxI,SAAgB,QAAQ,CAAC,QAAgB,EAAE,WAAmB;IAC1D,OAAO,aAAa,CAAC,QAAQ,CAAC,QAAQ,EAAE,WAAW,CAAC,CAAC;AACzD,CAAC;AAED,wIAAwI;AACxI,SAAgB,cAAc,CAAC,QAAgB,EAAE,WAAmB;IAChE,OAAO,aAAa,CAAC,cAAc,CAAC,QAAQ,EAAE,WAAW,CAAC,CAAC;AAC/D,CAAC;AAED,wIAAwI;AACxI,SAAgB,oBAAoB,CAAC,QAAgB,EAAE,WAAyC,EAAE;IAC9F,OAAO,aAAa,CAAC,oBAAoB,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;AAClE,CAAC;AAED,wIAAwI;AACxI,SAAgB,cAAc,CAAC,QAAgB,EAAE,WAAyC,EAAE;IACxF,OAAO,aAAa,CAAC,cAAc,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;AAC5D,CAAC","sourcesContent":["import * as fs from 'fs';\nimport * as path from 'path';\nimport { injectable, bindingScopeValues } from 'inversify';\nimport { WEBPIECES_TMP_DIR, PR_REVIEW_DIR } from './constants';\nimport { InformAiError } from './inform-ai-error';\nimport { toError } from './to-error';\n\n// The verdict a reviewer SUBAGENT writes into `.webpieces/pr-review/<branch>/review-<id>.json`, one per\n// matched checklist. One file per checklist so N concurrent reviewer subagents never clobber a shared\n// file. It records the OUTCOME:\n// success:true → PASS\n// success:false + override non-empty → OVERRIDDEN (pass; the free-text justification reaches the PR)\n// success:false + no override → FAIL (refuse; `output` is printed verbatim)\n// `override` is deliberately free text, not a boolean — it forces the ship-anyway decision to be stated\n// in words and surfaces it on the dashboard, where a human sees it. Data-only (per CLAUDE.md).\nexport class ChecklistResult {\n id: string;\n success: boolean;\n output: string; // what the reviewer found; printed verbatim when the checklist fails\n override: string; // '' = no override; non-empty = ship-anyway justification (renders 🟡 overridden)\n\n constructor(id: string, success: boolean, output: string, override: string) {\n this.id = id;\n this.success = success;\n this.output = output;\n this.override = override;\n }\n}\n\n// What the pr-gate command computed from the diff: a checklist this branch MATCHED (its patterns hit the\n// diff, so its reviewer subagent must run). Drives review-<id>.json enforcement, provenance, the schema\n// hint, and the dashboard. Data-only.\nexport class RequiredChecklist {\n id: string; // = subagent name; keys review-<id>.json\n subagent: string; // reviewer agent that must run (agentType the harness stamps)\n doc: string; // guidance doc the reviewer reads ('' → it reads the manifest doc)\n matchedFiles: string[]; // the changed files that matched it (for the dashboard + hint)\n\n constructor(id: string, subagent: string, doc: string, matchedFiles: string[]) {\n this.id = id;\n this.subagent = subagent;\n this.doc = doc;\n this.matchedFiles = matchedFiles;\n }\n}\n\n// The AI-authored review for a PR. The AI writes review.json itself between `wp-start-upsert-pr` (which\n// prints the schema) and `wp-finish-upsert-pr` (which reads it); reviewer subagents write the per-checklist\n// review-<id>.json files. Data-only (per CLAUDE.md).\nexport class ReviewJson {\n title: string; // human PR title describing the change; used as the `gh pr` title (empty → caller falls back)\n riskScore: number; // 0–100, drives the risk bar\n riskLevel: string; // 'green' | 'yellow' | 'red'\n riskEmoji: string; // '🟢' | '🟡' | '🔴' — derived from riskLevel when omitted\n summary: string; // rendered in the dashboard Summary section\n violations: string[]; // pattern/architecture violations; length = the Pattern Violations count\n risks: string[];\n filesToReview: string[];\n results: ChecklistResult[]; // resolved per-checklist verdicts (from review-<id>.json); [] when none\n\n // eslint-disable-next-line @typescript-eslint/max-params\n constructor(\n title: string,\n riskScore: number,\n riskLevel: string,\n riskEmoji: string,\n summary: string,\n violations: string[],\n risks: string[],\n filesToReview: string[],\n results: ChecklistResult[] = [],\n ) {\n this.title = title;\n this.riskScore = riskScore;\n this.riskLevel = riskLevel;\n this.riskEmoji = riskEmoji;\n this.summary = summary;\n this.violations = violations;\n this.risks = risks;\n this.filesToReview = filesToReview;\n this.results = results;\n }\n}\n\n// A checklist's resolved outcome, shared by review.json enforcement and the dashboard so both agree.\nexport const CK_PASS = 'pass'; // review-<id>.json success:true\nexport const CK_OVERRIDDEN = 'overridden'; // review-<id>.json success:false + non-empty override → 🟡\nexport const CK_FAIL = 'fail'; // review-<id>.json success:false + no override → refuse\nexport const CK_MISSING = 'missing'; // no review-<id>.json written → refuse\n\nexport class ChecklistVerdict {\n id: string;\n status: string; // one of CK_PASS | CK_OVERRIDDEN | CK_FAIL | CK_MISSING\n detail: string; // reviewer output / override justification (for the dashboard + errors)\n\n constructor(id: string, status: string, detail: string) {\n this.id = id;\n this.status = status;\n this.detail = detail;\n }\n}\n\nconst RISK_LEVELS = ['green', 'yellow', 'red'] as const;\nconst EMOJI_FOR_LEVEL: Record<string, string> = { green: '🟢', yellow: '🟡', red: '🔴' };\n\n/** Locates + loads/validates the AI-authored review.json. `@injectable(bindingScopeValues.Singleton)` so it's drawn in the design. */\n@injectable(bindingScopeValues.Singleton)\nexport class ReviewJsonService {\n // The per-feature PR working dir: `.webpieces/pr-review/<feature>`.\n prDirFor(repoRoot: string, featureName: string): string {\n return path.join(repoRoot, WEBPIECES_TMP_DIR, PR_REVIEW_DIR, featureName);\n }\n\n // Absolute path of the review.json for a feature — beside pr-body.md, keyed by branch name.\n reviewJsonPath(repoRoot: string, featureName: string): string {\n return path.join(this.prDirFor(repoRoot, featureName), 'review.json');\n }\n\n // Copy-paste schema both commands print. `required` is the set of checklists the diff MATCHED; empty\n // ⇒ output identical to a repo with no checklists. Non-empty ⇒ appends per-checklist instructions\n // naming the reviewer subagent + doc + the review-<id>.json to write.\n reviewJsonSchemaHint(filePath: string, required: readonly RequiredChecklist[] = []): string {\n return (\n `Write your PR review to:\\n ${filePath}\\n\\n` +\n `with this exact JSON shape (riskEmoji optional — derived from riskLevel):\\n\\n` +\n `{\\n` +\n ` \"title\": \"concise PR title describing the change (imperative, no branch names)\",\\n` +\n ` \"riskScore\": 0, // integer 0–100 (higher = riskier)\\n` +\n ` \"riskLevel\": \"green | yellow | red\",\\n` +\n ` \"summary\": \"5–10 sentence review summary\",\\n` +\n ` \"violations\": [\"pattern/architecture violations you found (empty array if none)\"],\\n` +\n ` \"risks\": [\"notable risks (empty array if none)\"],\\n` +\n ` \"filesToReview\": [\"paths a human should look at (empty array if none)\"]\\n` +\n `}` +\n this.requiredChecklistHint(filePath, required)\n );\n }\n\n // The per-checklist review file path that sits beside review.json: review-<id>.json.\n checklistResultPath(reviewJsonFilePath: string, checklistId: string): string {\n return path.join(path.dirname(reviewJsonFilePath), `review-${checklistId}.json`);\n }\n\n // The matched-checklist instruction block, appended ONLY when the diff matched a checklist. Each matched\n // checklist must be reviewed by its OWN subagent (a distinct one), which writes review-<id>.json.\n private requiredChecklistHint(reviewJsonFilePath: string, required: readonly RequiredChecklist[]): string {\n if (required.length === 0) return '';\n const lines: string[] = ['', '', 'This diff MATCHED company review checklist(s). Spawn EACH named subagent as a SEPARATE'];\n lines.push('subagent (a different one per checklist — the coding agent may NOT self-certify). Each reads its');\n lines.push('doc + the diff and writes its own review-<id>.json with this shape:');\n lines.push('');\n lines.push(' { \"id\": \"<id>\", \"success\": true, \"output\": \"what you checked / found\", \"override\": \"\" }');\n lines.push(' (success:false with no non-empty \"override\" refuses the PR; a non-empty override ships it 🟡.)');\n lines.push('');\n for (const req of required) {\n lines.push(` • [${req.id}] reviewer subagent: ${req.subagent}`);\n lines.push(` write: ${this.checklistResultPath(reviewJsonFilePath, req.id)}`);\n if (req.doc.trim() !== '') lines.push(` doc to read: ${req.doc}`);\n if (req.matchedFiles.length > 0) lines.push(` matched: ${req.matchedFiles.slice(0, 5).join(', ')}`);\n }\n return lines.join('\\n');\n }\n\n /**\n * Load + validate the AI-authored review.json. Throws InformAiError (with the schema) when missing,\n * unparseable, or structurally wrong. `required` is the set of checklists the diff matched: every one\n * must have a well-formed, passing (or overridden) review-<id>.json or a validation error is raised\n * alongside the usual ones so the AI gets ONE message.\n */\n // webpieces-disable max-lines-new-methods -- one cohesive load+validate pass over the review fields\n loadReviewJson(filePath: string, required: readonly RequiredChecklist[] = []): ReviewJson {\n if (!fs.existsSync(filePath)) {\n throw new InformAiError(\n `Required review.json not found.\\n\\n${this.reviewJsonSchemaHint(filePath, required)}\\n\\n` +\n `Then re-run: pnpm wp-finish-upsert-pr`,\n );\n }\n\n const raw = this.parseReviewJson(fs.readFileSync(filePath, 'utf8'), filePath, required);\n if (typeof raw !== 'object' || raw === null || Array.isArray(raw)) {\n throw new InformAiError(`review.json must be a JSON object.\\n\\n${this.reviewJsonSchemaHint(filePath, required)}`);\n }\n\n const errors: string[] = [];\n\n const riskScore = raw['riskScore'];\n if (typeof riskScore !== 'number' || !Number.isFinite(riskScore) || riskScore < 0 || riskScore > 100) {\n errors.push(`\"riskScore\" must be a number 0–100, got ${JSON.stringify(riskScore)}.`);\n }\n\n const riskLevel = raw['riskLevel'];\n if (typeof riskLevel !== 'string' || !RISK_LEVELS.includes(riskLevel as typeof RISK_LEVELS[number])) {\n errors.push(`\"riskLevel\" must be one of: ${RISK_LEVELS.join(', ')}.`);\n }\n\n const title = typeof raw['title'] === 'string' ? (raw['title'] as string).trim() : '';\n if (title === '') {\n errors.push('\"title\" must be a non-empty, imperative PR title describing the change (no branch names).');\n }\n\n const results = this.loadChecklistResults(filePath, required);\n for (const err of this.requiredChecklistErrors(required, results)) errors.push(err);\n\n if (errors.length > 0) {\n throw new InformAiError(\n `review.json has ${errors.length} error(s) — fix ALL, then re-run pnpm wp-finish-upsert-pr:\\n\\n` +\n errors.map((e: string): string => ` • ${e}`).join('\\n') +\n `\\n\\n${this.reviewJsonSchemaHint(filePath, required)}`,\n );\n }\n\n const level = riskLevel as string;\n const emoji = typeof raw['riskEmoji'] === 'string' && raw['riskEmoji'] !== ''\n ? (raw['riskEmoji'] as string)\n : (EMOJI_FOR_LEVEL[level] ?? '🟡');\n const summary = typeof raw['summary'] === 'string' ? (raw['summary'] as string) : '';\n\n return new ReviewJson(\n title,\n riskScore as number,\n level,\n emoji,\n summary,\n this.asStringArray(raw['violations']),\n this.asStringArray(raw['risks']),\n this.asStringArray(raw['filesToReview']),\n results,\n );\n }\n\n // Read the per-checklist verdict files `review-<id>.json` beside review.json — one per matched checklist.\n // A missing file is simply absent from the result (→ counts as MISSING for that checklist); a malformed\n // one is skipped (a stale review-<id>.json never wedges the branch).\n loadChecklistResults(reviewJsonFilePath: string, required: readonly RequiredChecklist[]): ChecklistResult[] {\n const results: ChecklistResult[] = [];\n for (const req of required) {\n const p = this.checklistResultPath(reviewJsonFilePath, req.id);\n if (!fs.existsSync(p)) continue;\n const parsed = this.parseChecklistResult(p, req.id);\n if (parsed) results.push(parsed);\n }\n return results;\n }\n\n // Resolve ONE checklist's verdict from its review-<id>.json. Central so review.json enforcement AND the\n // finish-command dashboard agree on the outcome.\n resolveVerdict(req: RequiredChecklist, results: readonly ChecklistResult[]): ChecklistVerdict {\n const result = results.find((r: ChecklistResult): boolean => r.id === req.id);\n if (!result) return new ChecklistVerdict(req.id, CK_MISSING, '');\n if (result.success) return new ChecklistVerdict(req.id, CK_PASS, result.output);\n if (result.override.trim() !== '') return new ChecklistVerdict(req.id, CK_OVERRIDDEN, result.override.trim());\n return new ChecklistVerdict(req.id, CK_FAIL, result.output);\n }\n\n // Every matched checklist whose verdict is FAIL (reviewed, found a problem, no override) or MISSING (no\n // review-<id>.json written) → one error each, printing the reviewer's `output` verbatim.\n private requiredChecklistErrors(required: readonly RequiredChecklist[], results: readonly ChecklistResult[]): string[] {\n const errors: string[] = [];\n for (const req of required) {\n const verdict = this.resolveVerdict(req, results);\n if (verdict.status === CK_FAIL) {\n errors.push(\n `Checklist \"${req.id}\" FAILED review. The reviewer (${req.subagent}) wrote:\\n ` +\n `${verdict.detail.split('\\n').join('\\n ')}\\n` +\n ` Fix it, then re-run; or set a non-empty \"override\" in ${this.checklistFileName(req.id)} to ship anyway with a stated justification.`,\n );\n } else if (verdict.status === CK_MISSING) {\n const doc = req.doc.trim() !== '' ? ` Read: ${req.doc}.` : '';\n errors.push(\n `Checklist \"${req.id}\" MATCHED this diff but has no verdict. Spawn the \"${req.subagent}\" subagent to review it, ` +\n `then write ${this.checklistFileName(req.id)} with {\"id\":\"${req.id}\",\"success\":true,\"output\":\"…\"}.${doc}`,\n );\n }\n }\n return errors;\n }\n\n private checklistFileName(checklistId: string): string {\n return `review-${checklistId}.json`;\n }\n\n // Parse one review-<id>.json into a ChecklistResult, or null when malformed. Tolerant: missing\n // `success` counts as false (fail-closed), `output`/`override` default to ''.\n // webpieces-disable no-any-unknown -- opaque parsed JSON, narrowed field-by-field\n private parseChecklistResult(filePath: string, id: string): ChecklistResult | null {\n // webpieces-disable no-unmanaged-exceptions -- chokepoint: a malformed per-checklist file is skipped, not fatal\n // eslint-disable-next-line @webpieces/no-unmanaged-exceptions\n try {\n // webpieces-disable no-any-unknown -- parsed JSON is opaque until narrowed below\n const raw = JSON.parse(fs.readFileSync(filePath, 'utf8')) as Record<string, unknown>;\n if (typeof raw !== 'object' || raw === null || Array.isArray(raw)) return null;\n const success = raw['success'] === true;\n const output = typeof raw['output'] === 'string' ? (raw['output'] as string) : '';\n const override = typeof raw['override'] === 'string' ? (raw['override'] as string) : '';\n return new ChecklistResult(id, success, output, override);\n } catch (err: unknown) {\n const error = toError(err);\n void error;\n return null;\n }\n }\n\n // webpieces-disable no-any-unknown -- opaque parsed JSON value, narrowed to string[] here\n private asStringArray(value: unknown): string[] {\n if (!Array.isArray(value)) return [];\n // webpieces-disable no-any-unknown -- element of an opaque JSON array, narrowed by the type guard\n return value.filter((v: unknown): v is string => typeof v === 'string');\n }\n\n // Parse opaque AI-authored JSON, converting a SyntaxError into a readable InformAiError. `required`\n // is threaded through so a JSON syntax error still prints the checklist instructions the AI needs.\n // webpieces-disable no-any-unknown -- returns the opaque parsed object; loadReviewJson narrows each field\n private parseReviewJson(raw: string, filePath: string, required: readonly RequiredChecklist[]): Record<string, unknown> {\n // webpieces-disable no-unmanaged-exceptions -- chokepoint: convert JSON.parse SyntaxError to an InformAiError for the AI\n // eslint-disable-next-line @webpieces/no-unmanaged-exceptions\n try {\n // webpieces-disable no-any-unknown -- parsed JSON is opaque until narrowed by the caller\n return JSON.parse(raw) as Record<string, unknown>;\n } catch (err: unknown) {\n const error = toError(err);\n throw new InformAiError(\n `review.json is not valid JSON (${error.message}).\\n\\n${this.reviewJsonSchemaHint(filePath, required)}\\n\\n` +\n `Then re-run: pnpm wp-finish-upsert-pr`,\n );\n }\n }\n}\n\n// Temporary migration delegators to ReviewJsonService — removed once consumers inject it.\nconst reviewJsonSvc = new ReviewJsonService();\n\n// webpieces-disable no-function-outside-class -- temporary back-compat delegator to ReviewJsonService; removed once consumers inject it\nexport function prDirFor(repoRoot: string, featureName: string): string {\n return reviewJsonSvc.prDirFor(repoRoot, featureName);\n}\n\n// webpieces-disable no-function-outside-class -- temporary back-compat delegator to ReviewJsonService; removed once consumers inject it\nexport function reviewJsonPath(repoRoot: string, featureName: string): string {\n return reviewJsonSvc.reviewJsonPath(repoRoot, featureName);\n}\n\n// webpieces-disable no-function-outside-class -- temporary back-compat delegator to ReviewJsonService; removed once consumers inject it\nexport function reviewJsonSchemaHint(filePath: string, required: readonly RequiredChecklist[] = []): string {\n return reviewJsonSvc.reviewJsonSchemaHint(filePath, required);\n}\n\n// webpieces-disable no-function-outside-class -- temporary back-compat delegator to ReviewJsonService; removed once consumers inject it\nexport function loadReviewJson(filePath: string, required: readonly RequiredChecklist[] = []): ReviewJson {\n return reviewJsonSvc.loadReviewJson(filePath, required);\n}\n"]}
@@ -27,6 +27,8 @@ export declare class ProvenanceResult {
27
27
  */
28
28
  export declare class SubagentProvenanceService {
29
29
  verify(expectedAgentType: string, branch: string): ProvenanceResult;
30
+ verifyDistinct(expectedAgentTypes: readonly string[], branch: string): ProvenanceResult;
31
+ private findMatchingAgentId;
30
32
  private findSubagentsDir;
31
33
  private metaFiles;
32
34
  private agentIdOf;
@@ -51,21 +51,54 @@ let SubagentProvenanceService = class SubagentProvenanceService {
51
51
  if (dir === '') {
52
52
  return new ProvenanceResult(exports.PROVENANCE_MISSING, `No subagents recorded for this session — the "${expectedAgentType}" reviewer subagent must run on this branch before the PR can open.`);
53
53
  }
54
+ const agentId = this.findMatchingAgentId(dir, expectedAgentType, branch);
55
+ return agentId !== ''
56
+ ? new ProvenanceResult(exports.PROVENANCE_OK, `verified "${expectedAgentType}" reviewer subagent ran (agent ${agentId}).`)
57
+ : new ProvenanceResult(exports.PROVENANCE_MISSING, `No "${expectedAgentType}" reviewer subagent ran on this branch — a separate reviewer of that type must review this checklist.`);
58
+ }
59
+ // Verify EVERY expected reviewer subagent ran on `branch` as a DISTINCT run — the coding agent may not
60
+ // self-certify, and one reviewer may not stand in for several. SKIPPED (pass) without a session id.
61
+ verifyDistinct(expectedAgentTypes, branch) {
62
+ if (expectedAgentTypes.length === 0)
63
+ return new ProvenanceResult(exports.PROVENANCE_OK, 'no reviewer subagents required');
64
+ const sessionId = process.env['CLAUDE_CODE_SESSION_ID'] ?? '';
65
+ if (sessionId.trim() === '') {
66
+ return new ProvenanceResult(exports.PROVENANCE_SKIPPED, `CLAUDE_CODE_SESSION_ID not set — cannot verify reviewer subagents ran (plain terminal / CI). Skipping the provenance check.`);
67
+ }
68
+ const dir = this.findSubagentsDir(sessionId);
69
+ if (dir === '') {
70
+ return new ProvenanceResult(exports.PROVENANCE_MISSING, `No subagents recorded for this session — each checklist must be reviewed by its own subagent: ${expectedAgentTypes.join(', ')}.`);
71
+ }
72
+ const missing = [];
73
+ const usedAgentIds = new Set();
74
+ for (const type of expectedAgentTypes) {
75
+ const agentId = this.findMatchingAgentId(dir, type, branch, usedAgentIds);
76
+ if (agentId === '')
77
+ missing.push(type);
78
+ else
79
+ usedAgentIds.add(agentId);
80
+ }
81
+ return missing.length === 0
82
+ ? new ProvenanceResult(exports.PROVENANCE_OK, `verified ${expectedAgentTypes.length} distinct reviewer subagent(s) ran`)
83
+ : new ProvenanceResult(exports.PROVENANCE_MISSING, `these reviewer subagents did not run on this branch (spawn each as its OWN subagent — do not self-certify): ${missing.join(', ')}`);
84
+ }
85
+ // The agentId of a matching subagent run for `agentType` on `branch`, or '' if none. `exclude` skips
86
+ // agentIds already credited to another checklist so one run can't satisfy two.
87
+ findMatchingAgentId(dir, agentType, branch, exclude = new Set()) {
54
88
  for (const metaFile of this.metaFiles(dir)) {
55
- const meta = this.readJson(path.join(dir, metaFile));
56
- if (!meta)
89
+ const agentId = this.agentIdOf(metaFile);
90
+ if (exclude.has(agentId))
57
91
  continue;
58
- if (meta['agentType'] !== expectedAgentType)
92
+ const meta = this.readJson(path.join(dir, metaFile));
93
+ if (!meta || meta['agentType'] !== agentType)
59
94
  continue;
60
95
  const spawnDepth = meta['spawnDepth'];
61
96
  if (typeof spawnDepth !== 'number' || spawnDepth < 1)
62
97
  continue;
63
- const agentId = this.agentIdOf(metaFile);
64
- if (this.sidechainOnBranch(dir, agentId, branch)) {
65
- return new ProvenanceResult(exports.PROVENANCE_OK, `verified "${expectedAgentType}" reviewer subagent ran (agent ${agentId}).`);
66
- }
98
+ if (this.sidechainOnBranch(dir, agentId, branch))
99
+ return agentId;
67
100
  }
68
- return new ProvenanceResult(exports.PROVENANCE_MISSING, `No "${expectedAgentType}" reviewer subagent ran on this branch — a separate reviewer of that type must review this checklist.`);
101
+ return '';
69
102
  }
70
103
  // Find the subagents dir for `sessionId` by its UNIQUE id, so the cwd-slug never has to be guessed.
71
104
  findSubagentsDir(sessionId) {