@webpieces/pr-gate 0.4.531 → 0.4.533

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@webpieces/pr-gate",
3
- "version": "0.4.531",
3
+ "version": "0.4.533",
4
4
  "description": "Gated PR system: 3-point squash-merge, merge validation gate, and red/yellow/green PR dashboard. Standalone scripts, no Nx dependency required.",
5
5
  "type": "commonjs",
6
6
  "main": "./src/index.js",
@@ -26,7 +26,7 @@
26
26
  "directory": "packages/tooling/pr-gate"
27
27
  },
28
28
  "dependencies": {
29
- "@webpieces/rules-config": "0.4.531",
29
+ "@webpieces/rules-config": "0.4.533",
30
30
  "@inversifyjs/binding-decorators": "1.1.5",
31
31
  "inversify": "7.10.4",
32
32
  "reflect-metadata": "0.2.2"
@@ -239,8 +239,8 @@ let Dashboard = class Dashboard {
239
239
  lines.push(this.rosterBullet(row));
240
240
  const header = lines.join('\n');
241
241
  if (ran.length === 0) {
242
- return `${header}\n\n_No reviewer had to run on this diff — every configured checklist was ` +
243
- `evaluated and none of them applied._`;
242
+ return (`${header}\n\n_No reviewer had to run on this diff — every configured checklist was ` +
243
+ `evaluated and none of them applied._`);
244
244
  }
245
245
  return this.fitComment(`${header}\n\n### Reviews that ran`, ran.map((r) => this.commentSection(r)));
246
246
  }
@@ -249,9 +249,9 @@ let Dashboard = class Dashboard {
249
249
  // "all skipped ✅" would post a green all-clear for a PR where nothing was actually evaluated.
250
250
  rollupHeader(rows, baseResolved) {
251
251
  if (!baseResolved) {
252
- return `## 🔍 Company review checklists — ⚠️ NOT EVALUATED (${rows.length} defined)\n` +
252
+ return (`## 🔍 Company review checklists — ⚠️ NOT EVALUATED (${rows.length} defined)\n` +
253
253
  `_No diff base (fork point of main) could be resolved, so no checklist was matched against ` +
254
- `anything. This is **not** an all-clear._`;
254
+ `anything. This is **not** an all-clear._`);
255
255
  }
256
256
  const ran = rows.filter((r) => r.ran);
257
257
  const skipped = rows.length - ran.length;
@@ -278,8 +278,8 @@ let Dashboard = class Dashboard {
278
278
  // checklist was evaluated and did not apply, which the words state as the good news it is.
279
279
  rosterBullet(row) {
280
280
  const box = row.ran ? '- [x]' : '- [ ]';
281
- return `${box} ${this.verdictEmoji(row)} **${row.subagent}** — ${this.verdictWords(row)}${this.evidenceSuffix(row)}\n` +
282
- ` - ${this.whyLine(row)}`;
281
+ return (`${box} ${this.verdictEmoji(row)} **${row.subagent}** — ${this.verdictWords(row)}${this.evidenceSuffix(row)}\n` +
282
+ ` - ${this.whyLine(row)}`);
283
283
  }
284
284
  /**
285
285
  * Whether the reviewer demonstrably opened the diff, read from its own transcript. A QUALITY signal and
@@ -330,19 +330,19 @@ let Dashboard = class Dashboard {
330
330
  whyLine(row) {
331
331
  const total = row.changedFileCount;
332
332
  if (row.configuredPatterns.length === 0) {
333
- // Say what "no patterns" COSTS, not just what it means. Six patternless checklists all firing on
334
- // a one-file docs PR is what a missing `patterns` looks like from the outside, and a reader who
335
- // is told only "ALWAYS RUNS" has no reason to suspect the config rather than the diff.
336
- return `ALWAYS RUNS no \`patterns\` configured, so this fires on EVERY PR including docs-only ` +
337
- `ones; add \`patterns\` if that is not intended. Whole diff in scope, ${total} changed file(s): ` +
338
- `${(0, rules_config_1.formatFileList)(row.matchedFiles)}`;
333
+ // State the fact, not a suspicion. Patternless is a deliberate configuration an always-runs
334
+ // gate (every PR names a ticket, every PR has an owner) is exactly what it is FOR so telling
335
+ // every such row to "add `patterns` if that is not intended" nags the repos that meant it, on
336
+ // every PR, forever. A reader who wants to know whether it was intended can read the config.
337
+ return (`ALWAYS RUNS (no patterns) whole diff in scope, ${total} changed file(s): ` +
338
+ `${(0, rules_config_1.formatFileList)(row.matchedFiles)}`);
339
339
  }
340
340
  const configured = this.asCode(row.configuredPatterns);
341
341
  if (row.firedPatterns.length === 0) {
342
342
  return `${configured} matched 0 of ${total} changed file(s)`;
343
343
  }
344
- return `matched ${this.asCode(row.firedPatterns)} → ${row.matchedFiles.length} of ${total} ` +
345
- `changed file(s): ${(0, rules_config_1.formatFileList)(row.matchedFiles)}`;
344
+ return (`matched ${this.asCode(row.firedPatterns)} → ${row.matchedFiles.length} of ${total} ` +
345
+ `changed file(s): ${(0, rules_config_1.formatFileList)(row.matchedFiles)}`);
346
346
  }
347
347
  asCode(patterns) {
348
348
  return patterns.map((p) => `\`${p}\``).join(', ');
@@ -436,7 +436,9 @@ let Dashboard = class Dashboard {
436
436
  flags.push(`${result.name}: ${emoji} ${result.matchedFiles.length} file(s)`);
437
437
  }
438
438
  if (input.disables.webpiecesCount > 0) {
439
- const which = input.disables.webpiecesRules.length > 0 ? ` — ${input.disables.webpiecesRules.join(', ')}` : '';
439
+ const which = input.disables.webpiecesRules.length > 0
440
+ ? ` — ${input.disables.webpiecesRules.join(', ')}`
441
+ : '';
440
442
  flags.push(`Webpieces Disables Added: 🟡 ${input.disables.webpiecesCount} line(s)${which}`);
441
443
  }
442
444
  if (input.disables.eslintCount > 0)
@@ -553,7 +555,9 @@ let Dashboard = class Dashboard {
553
555
  return '**Checklists:** ⚪ 0 ran — no review checklist matched this PR · see the checklist comment';
554
556
  }
555
557
  const allPassed = filled.length === 1 && !filled[0].named;
556
- const detail = allPassed ? 'all passed' : filled.map((b) => this.bucketPhrase(b)).join(', ');
558
+ const detail = allPassed
559
+ ? 'all passed'
560
+ : filled.map((b) => this.bucketPhrase(b)).join(', ');
557
561
  return `**Checklists:** ${filled[0].emoji} ${rows.length} ran — ${detail} · per-checklist detail in the checklist comment`;
558
562
  }
559
563
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"dashboard.js","sourceRoot":"","sources":["../../../../../../packages/tooling/pr-gate/src/dashboard/dashboard.ts"],"names":[],"mappings":";;;;AAAA,0DAGiC;AACjC,yCAA2D;AAE3D,wGAAwG;AACxG,yGAAyG;AACzG,uFAAuF;AAC1E,QAAA,wBAAwB,GAAG,kCAAkC,CAAC;AAC3E,MAAM,aAAa,GAAG,KAAK,CAAC,CAAC,yEAAyE;AAEtG,mGAAmG;AACnG,kFAAkF;AAClF,MAAM,cAAc;IAChB,OAAO,CAAS;IAChB,IAAI,CAAS;IAEb,YAAY,OAAe,EAAE,IAAY;QACrC,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;QACvB,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;IACrB,CAAC;CACJ;AAED,MAAa,UAAU;IACnB,IAAI,CAAS;IACb,YAAY,CAAS,CAAC,4EAA4E;IAClG,YAAY,CAAW;IAEvB,YAAY,IAAY,EAAE,YAAoB,EAAE,YAAsB;QAClE,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QACjB,IAAI,CAAC,YAAY,GAAG,YAAY,CAAC;QACjC,IAAI,CAAC,YAAY,GAAG,YAAY,CAAC;IACrC,CAAC;CACJ;AAVD,gCAUC;AAED,yGAAyG;AACzG,sGAAsG;AACtG,2GAA2G;AAC3G,uGAAuG;AACvG,sGAAsG;AACtG,4DAA4D;AAC5D,MAAa,YAAY;IACrB,KAAK,CAAS,CAAE,8CAA8C;IAC9D,MAAM,CAAS,CAAC,eAAe;IAC/B,MAAM,CAAS,CAAC,qEAAqE;IAErF,YAAY,KAAa,EAAE,MAAc,EAAE,MAAM,GAAG,EAAE;QAClD,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;QACnB,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QACrB,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;IACzB,CAAC;CACJ;AAVD,oCAUC;AAED;;;;;;;;GAQG;AACH,MAAa,mBAAmB;IAC5B,QAAQ,CAAS,CAAc,8BAA8B;IAC7D,MAAM,CAAS,CAAgB,uCAAuC;IACtE,MAAM,CAAS,CAAgB,2BAA2B;IAC1D,GAAG,CAAU,CAAkB,sDAAsD;IACrF,wGAAwG;IACxG,mFAAmF;IACnF,kBAAkB,CAAW;IAC7B,aAAa,CAAW,CAAO,qDAAqD;IACpF,YAAY,CAAW;IACvB,gBAAgB,CAAS,CAAM,+DAA+D;IAC9F;;;;;;;OAOG;IACH,QAAQ,GAAW,EAAE,CAAC;IAEtB,yDAAyD;IACzD,YACI,QAAgB,EAAE,MAAc,EAAE,MAAc,EAAE,GAAY,EAC9D,kBAA4B,EAAE,aAAuB,EAAE,YAAsB,EAAE,gBAAwB;QAEvG,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC;QACzB,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QACrB,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QACrB,IAAI,CAAC,GAAG,GAAG,GAAG,CAAC;QACf,IAAI,CAAC,kBAAkB,GAAG,kBAAkB,CAAC;QAC7C,IAAI,CAAC,aAAa,GAAG,aAAa,CAAC;QACnC,IAAI,CAAC,YAAY,GAAG,YAAY,CAAC;QACjC,IAAI,CAAC,gBAAgB,GAAG,gBAAgB,CAAC;IAC7C,CAAC;CACJ;AAnCD,kDAmCC;AAED;;;;;;GAMG;AACH,MAAM,YAAY;IACd,KAAK,CAAS,CAAI,yDAAyD;IAC3E,KAAK,CAAS;IACd,KAAK,CAAU,CAAG,4DAA4D;IAC9E,MAAM,CAAW;IAEjB,YAAY,KAAa,EAAE,KAAa,EAAE,KAAc;QACpD,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;QACnB,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;QACnB,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;QACnB,IAAI,CAAC,MAAM,GAAG,EAAE,CAAC;IACrB,CAAC;CACJ;AAED,MAAa,aAAa;IACtB,cAAc,CAAS;IACvB,WAAW,CAAS;IACpB,cAAc,CAAW;IAEzB,YAAY,cAAsB,EAAE,WAAmB,EAAE,cAAwB;QAC7E,IAAI,CAAC,cAAc,GAAG,cAAc,CAAC;QACrC,IAAI,CAAC,WAAW,GAAG,WAAW,CAAC;QAC/B,IAAI,CAAC,cAAc,GAAG,cAAc,CAAC;IACzC,CAAC;CACJ;AAVD,sCAUC;AAED,MAAa,cAAc;IACvB,KAAK,CAAS;IACd,WAAW,CAAe;IAC1B,QAAQ,CAAgB;IACxB,WAAW,CAAU;IACrB,SAAS,CAAS;IAClB,WAAW,CAAS;IACpB,QAAQ,CAAS;IACjB,MAAM,CAAa,CAAC,yDAAyD;IAC7E,UAAU,CAAiB,CAAC,uEAAuE;IAEnG,yDAAyD;IACzD,YACI,KAAa,EAAE,WAAyB,EAAE,QAAuB,EACjE,WAAoB,EAAE,SAAiB,EAAE,WAAmB,EAAE,QAAgB,EAAE,MAAkB,EAClG,aAA6B,EAAE;QAE/B,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;QACnB,IAAI,CAAC,WAAW,GAAG,WAAW,CAAC;QAC/B,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC;QACzB,IAAI,CAAC,WAAW,GAAG,WAAW,CAAC;QAC/B,IAAI,CAAC,SAAS,GAAG,SAAS,CAAC;QAC3B,IAAI,CAAC,WAAW,GAAG,WAAW,CAAC;QAC/B,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC;QACzB,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QACrB,IAAI,CAAC,UAAU,GAAG,UAAU,CAAC;IACjC,CAAC;CACJ;AA3BD,wCA2BC;AAED,sGAAsG;AAE/F,IAAM,SAAS,GAAf,MAAM,SAAS;IAClB,mFAAmF;IACnF,kBAAkB,CAAC,KAAuB,EAAE,YAAsB;QAC9D,OAAO,KAAK;aACP,MAAM,CAAC,CAAC,IAAoB,EAAW,EAAE,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC;aACzD,GAAG,CAAC,CAAC,IAAoB,EAAc,EAAE;YACtC,MAAM,OAAO,GAAG,YAAY,CAAC,MAAM,CAAC,CAAC,IAAY,EAAW,EAAE,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC,CAAC;YACrG,OAAO,IAAI,UAAU,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,YAAY,EAAE,OAAO,CAAC,CAAC;QACjE,CAAC,CAAC,CAAC;IACX,CAAC;IAED,+FAA+F;IAC/F,0FAA0F;IAC1F,kBAAkB,CAAC,KAAa;QAC5B,IAAI,cAAc,GAAG,CAAC,CAAC;QACvB,IAAI,WAAW,GAAG,CAAC,CAAC;QACpB,MAAM,KAAK,GAAG,IAAI,GAAG,EAAU,CAAC;QAChC,MAAM,aAAa,GAAG,MAAM,CAAC,IAAI,CAAC,yBAAU,CAAC,CAAC,GAAG,CAAC,CAAC,GAAW,EAAU,EAAE,CAAE,yBAAqC,CAAC,GAAG,CAAC,CAAC,CAAC;QAExH,KAAK,MAAM,IAAI,IAAI,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;YACnC,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC;gBAAE,SAAS;YAC9D,IAAI,IAAI,CAAC,QAAQ,CAAC,gCAAiB,CAAC,EAAE,CAAC;gBACnC,cAAc,IAAI,CAAC,CAAC;gBACpB,KAAK,MAAM,KAAK,IAAI,aAAa,EAAE,CAAC;oBAChC,IAAI,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC;wBAAE,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;gBAC/C,CAAC;YACL,CAAC;YACD,IAAI,IAAI,CAAC,QAAQ,CAAC,gBAAgB,CAAC;gBAAE,WAAW,IAAI,CAAC,CAAC;QAC1D,CAAC;QACD,OAAO,IAAI,aAAa,CAAC,cAAc,EAAE,WAAW,EAAE,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;IACpF,CAAC;IAED,eAAe,CAAC,KAAqB;QACjC,MAAM,KAAK,GAAa,EAAE,CAAC;QAC3B,KAAK,CAAC,IAAI,CAAC,yBAAyB,CAAC,CAAC;QACtC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACf,KAAK,MAAM,IAAI,IAAI,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,MAAM,CAAC;YAAE,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAClE,KAAK,CAAC,IAAI,CAAC,4BAA4B,KAAK,CAAC,WAAW,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC;QACxF,KAAK,MAAM,MAAM,IAAI,KAAK,CAAC,WAAW;YAAE,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC;QAC1E,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC;QAC7C,MAAM,WAAW,GAAG,KAAK,CAAC,QAAQ,CAAC,WAAW,KAAK,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,KAAK,CAAC,QAAQ,CAAC,WAAW,UAAU,CAAC;QAC5G,KAAK,CAAC,IAAI,CAAC,8BAA8B,WAAW,EAAE,CAAC,CAAC;QACxD,mGAAmG;QACnG,kGAAkG;QAClG,8FAA8F;QAC9F,iGAAiG;QACjG,kGAAkG;QAClG,kGAAkG;QAClG,uCAAuC;QACvC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,mBAAmB,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,CAAC;QACvD,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACf,IAAI,KAAK,CAAC,MAAM,CAAC,OAAO,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC;YACrC,KAAK,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;YAC1B,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC;YACxC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACnB,CAAC;QACD,KAAK,CAAC,IAAI,CAAC,4BAA4B,CAAC,CAAC;QACzC,KAAK,CAAC,IAAI,CAAC,uBAAuB,KAAK,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,CAAC;QACpE,KAAK,CAAC,IAAI,CAAC,yBAAyB,KAAK,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,CAAC;QACxE,KAAK,CAAC,IAAI,CAAC,sBAAsB,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,CAAC;QAClE,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACf,KAAK,CAAC,IAAI,CAAC,wGAAwG,CAAC,CAAC;QACrH,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC5B,CAAC;IAED;;;;;;;;;;;;OAYG;IACH,sBAAsB,CAAC,IAAoC,EAAE,kBAA2B,EAAE,YAAqB;QAC3G,MAAM,GAAG,GAAG,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC;QAClC,MAAM,IAAI,GAAG,kBAAkB;YAC3B,CAAC,CAAC,6FAA6F;YAC/F,CAAC,CAAC,iGAAiG,CAAC;QACxG,mGAAmG;QACnG,8EAA8E;QAC9E,MAAM,KAAK,GAAa,CAAC,gCAAwB,EAAE,IAAI,CAAC,YAAY,CAAC,IAAI,EAAE,YAAY,CAAC,CAAC,CAAC;QAC1F,kGAAkG;QAClG,IAAI,GAAG,CAAC,MAAM,GAAG,CAAC;YAAE,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACrC,KAAK,CAAC,IAAI,CAAC,EAAE,EAAE,uBAAuB,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC;QACtD,KAAK,MAAM,GAAG,IAAI,IAAI;YAAE,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC,CAAC;QAC3D,MAAM,MAAM,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAChC,IAAI,GAAG,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACnB,OAAO,GAAG,MAAM,4EAA4E;gBACxF,sCAAsC,CAAC;QAC/C,CAAC;QACD,OAAO,IAAI,CAAC,UAAU,CAAC,GAAG,MAAM,0BAA0B,EAAE,GAAG,CAAC,GAAG,CAAC,CAAC,CAAsB,EAAkB,EAAE,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAC7I,CAAC;IAED,0GAA0G;IAC1G,mGAAmG;IACnG,8FAA8F;IACtF,YAAY,CAAC,IAAoC,EAAE,YAAqB;QAC5E,IAAI,CAAC,YAAY,EAAE,CAAC;YAChB,OAAO,uDAAuD,IAAI,CAAC,MAAM,aAAa;gBAClF,4FAA4F;gBAC5F,0CAA0C,CAAC;QACnD,CAAC;QACD,MAAM,GAAG,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC,CAAsB,EAAW,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;QACpE,MAAM,OAAO,GAAG,IAAI,CAAC,MAAM,GAAG,GAAG,CAAC,MAAM,CAAC;QACzC,MAAM,KAAK,GAAa,EAAE,CAAC;QAC3B,KAAK,MAAM,IAAI,IAAI,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC;YAAE,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC5D,MAAM,SAAS,GAAG,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;QACpE,MAAM,IAAI,GAAG,OAAO,GAAG,CAAC,CAAC,CAAC,CAAC,MAAM,OAAO,YAAY,CAAC,CAAC,CAAC,EAAE,CAAC;QAC1D,OAAO,qCAAqC,IAAI,CAAC,MAAM,cAAc,GAAG,CAAC,MAAM,OAAO,SAAS,GAAG,IAAI,EAAE,CAAC;IAC7G,CAAC;IAED,kGAAkG;IAC1F,YAAY,CAAC,GAAmC;QACpD,MAAM,MAAM,GAAa,EAAE,CAAC;QAC5B,MAAM,QAAQ,GAAa,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC;QAC9C,MAAM,SAAS,GAAa,CAAC,sBAAO,EAAE,sBAAO,EAAE,4BAAa,CAAC,CAAC;QAC9D,SAAS,CAAC,OAAO,CAAC,CAAC,MAAc,EAAE,CAAS,EAAQ,EAAE;YAClD,MAAM,CAAC,GAAG,GAAG,CAAC,MAAM,CAAC,CAAC,CAAsB,EAAW,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,MAAM,CAAC,CAAC,MAAM,CAAC;YACtF,IAAI,CAAC,GAAG,CAAC;gBAAE,MAAM,CAAC,IAAI,CAAC,GAAG,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QAClD,CAAC,CAAC,CAAC;QACH,OAAO,MAAM,CAAC;IAClB,CAAC;IAED,uGAAuG;IACvG,2FAA2F;IACnF,YAAY,CAAC,GAAwB;QACzC,MAAM,GAAG,GAAG,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC;QACxC,OAAO,GAAG,GAAG,IAAI,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,MAAM,GAAG,CAAC,QAAQ,QAAQ,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,IAAI;YAClH,OAAO,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC;IACnC,CAAC;IAED;;;;OAIG;IACK,cAAc,CAAC,GAAwB;QAC3C,IAAI,CAAC,GAAG,CAAC,GAAG,IAAI,GAAG,CAAC,QAAQ,KAAK,EAAE;YAAE,OAAO,EAAE,CAAC;QAC/C,OAAO,GAAG,CAAC,QAAQ,KAAK,KAAK,CAAC,CAAC,CAAC,kBAAkB,CAAC,CAAC,CAAC,+BAA+B,CAAC;IACzF,CAAC;IAEO,YAAY,CAAC,GAAwB;QACzC,IAAI,CAAC,GAAG,CAAC,GAAG;YAAE,OAAO,GAAG,CAAC;QACzB,IAAI,GAAG,CAAC,MAAM,KAAK,sBAAO;YAAE,OAAO,IAAI,CAAC;QACxC,IAAI,GAAG,CAAC,MAAM,KAAK,sBAAO;YAAE,OAAO,IAAI,CAAC;QACxC,IAAI,GAAG,CAAC,MAAM,KAAK,4BAAa;YAAE,OAAO,IAAI,CAAC;QAC9C,IAAI,GAAG,CAAC,MAAM,KAAK,sBAAO;YAAE,OAAO,IAAI,CAAC;QACxC,OAAO,GAAG,CAAC;IACf,CAAC;IAED,uGAAuG;IACvG,yFAAyF;IACjF,YAAY,CAAC,GAAwB;QACzC,IAAI,CAAC,GAAG,CAAC,GAAG;YAAE,OAAO,mDAAmD,CAAC;QACzE,IAAI,GAAG,CAAC,MAAM,KAAK,sBAAO;YAAE,OAAO,QAAQ,CAAC;QAC5C,IAAI,GAAG,CAAC,MAAM,KAAK,sBAAO;YAAE,OAAO,sBAAsB,CAAC;QAC1D,IAAI,GAAG,CAAC,MAAM,KAAK,4BAAa;YAAE,OAAO,kDAAkD,CAAC;QAC5F,IAAI,GAAG,CAAC,MAAM,KAAK,sBAAO;YAAE,OAAO,eAAe,CAAC;QACnD,IAAI,GAAG,CAAC,MAAM,KAAK,yBAAU;YAAE,OAAO,oBAAoB,CAAC;QAC3D,OAAO,oBAAoB,GAAG,CAAC,MAAM,GAAG,CAAC;IAC7C,CAAC;IAED;;;;;OAKG;IACK,OAAO,CAAC,GAAwB;QACpC,MAAM,KAAK,GAAG,GAAG,CAAC,gBAAgB,CAAC;QACnC,IAAI,GAAG,CAAC,kBAAkB,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACtC,iGAAiG;YACjG,gGAAgG;YAChG,uFAAuF;YACvF,OAAO,0FAA0F;gBAC7F,wEAAwE,KAAK,oBAAoB;gBACjG,GAAG,IAAA,6BAAc,EAAC,GAAG,CAAC,YAAY,CAAC,EAAE,CAAC;QAC9C,CAAC;QACD,MAAM,UAAU,GAAG,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,kBAAkB,CAAC,CAAC;QACvD,IAAI,GAAG,CAAC,aAAa,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACjC,OAAO,GAAG,UAAU,iBAAiB,KAAK,kBAAkB,CAAC;QACjE,CAAC;QACD,OAAO,WAAW,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,aAAa,CAAC,MAAM,GAAG,CAAC,YAAY,CAAC,MAAM,OAAO,KAAK,GAAG;YACxF,oBAAoB,IAAA,6BAAc,EAAC,GAAG,CAAC,YAAY,CAAC,EAAE,CAAC;IAC/D,CAAC;IAEO,MAAM,CAAC,QAA2B;QACtC,OAAO,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAS,EAAU,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACtE,CAAC;IAED,mGAAmG;IACnG,oCAAoC;IAC5B,UAAU,CAAC,IAAoC;QACnD,MAAM,IAAI,GAAa,CAAC,4BAAa,EAAE,sBAAO,EAAE,sBAAO,CAAC,CAAC;QACzD,OAAO,IAAI;aACN,MAAM,CAAC,CAAC,CAAsB,EAAW,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC;aAClD,KAAK,EAAE;aACP,IAAI,CAAC,CAAC,CAAsB,EAAE,CAAsB,EAAU,EAAE,CAC7D,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,GAAG,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC;IACvE,CAAC;IAEO,MAAM,CAAC,IAAuB,EAAE,MAAc;QAClD,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;QACjC,OAAO,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC;IACvC,CAAC;IAEO,cAAc,CAAC,GAAwB;QAC3C,MAAM,OAAO,GAAG,QAAQ,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,IAAI,GAAG,CAAC,QAAQ,MAAM,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,EAAE,CAAC;QAC7F,MAAM,IAAI,GAAG,GAAG,CAAC,MAAM,CAAC,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,iCAAiC,CAAC;QAC9F,OAAO,IAAI,cAAc,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;IAC7C,CAAC;IAED,mGAAmG;IACnG,uGAAuG;IAC/F,UAAU,CAAC,MAAc,EAAE,QAA0B;QACzD,MAAM,QAAQ,GAAG,GAAW,EAAE,CAAC,GAAG,MAAM,OAAO,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAiB,EAAU,EAAE,CAAC,GAAG,CAAC,CAAC,OAAO,OAAO,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC;QACvI,MAAM,KAAK,GAAG,yDAAyD,CAAC;QACxE,IAAI,GAAG,GAAG,QAAQ,EAAE,CAAC;QACrB,OAAO,GAAG,CAAC,MAAM,GAAG,aAAa,EAAE,CAAC;YAChC,MAAM,GAAG,GAAG,IAAI,CAAC,gBAAgB,CAAC,QAAQ,CAAC,CAAC;YAC5C,IAAI,GAAG,GAAG,CAAC,IAAI,QAAQ,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,MAAM,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC;gBAAE,MAAM;YACpE,MAAM,IAAI,GAAG,GAAG,CAAC,MAAM,GAAG,aAAa,CAAC;YACxC,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,QAAQ,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,MAAM,GAAG,IAAI,GAAG,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;YAC9E,QAAQ,CAAC,GAAG,CAAC,CAAC,IAAI,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC,OAAO,EAAE,GAAG,KAAK,CAAC;YACzE,GAAG,GAAG,QAAQ,EAAE,CAAC;QACrB,CAAC;QACD,OAAO,GAAG,CAAC;IACf,CAAC;IAEO,gBAAgB,CAAC,QAAmC;QACxD,IAAI,GAAG,GAAG,CAAC,CAAC,CAAC;QACb,IAAI,GAAG,GAAG,CAAC,CAAC,CAAC;QACb,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAiB,EAAE,CAAS,EAAQ,EAAE;YACpD,IAAI,CAAC,CAAC,IAAI,CAAC,MAAM,GAAG,GAAG,EAAE,CAAC;gBAAC,GAAG,GAAG,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC;gBAAC,GAAG,GAAG,CAAC,CAAC;YAAC,CAAC;QAC9D,CAAC,CAAC,CAAC;QACH,OAAO,GAAG,CAAC;IACf,CAAC;IAED,gGAAgG;IAChG,qGAAqG;IACrG,oGAAoG;IACpG,mGAAmG;IACnG,gBAAgB,CAAC,KAAqB,EAAE,KAAa;QACjD,MAAM,KAAK,GAAa,EAAE,CAAC;QAC3B,KAAK,CAAC,IAAI,CAAC,SAAS,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,SAAS,CAAC,IAAI,KAAK,CAAC,MAAM,CAAC,SAAS,QAAQ,KAAK,CAAC,MAAM,CAAC,SAAS,KAAK,KAAK,CAAC,MAAM,CAAC,SAAS,GAAG,CAAC,CAAC;QAChJ,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACf,MAAM,KAAK,GAAG,IAAI,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC;QACxC,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACrB,KAAK,CAAC,IAAI,CAAC,qBAAqB,CAAC,CAAC;QACtC,CAAC;aAAM,CAAC;YACJ,KAAK,CAAC,IAAI,CAAC,oBAAoB,CAAC,CAAC;YACjC,KAAK,MAAM,IAAI,IAAI,KAAK;gBAAE,KAAK,CAAC,IAAI,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC;QACtD,CAAC;QACD,MAAM,OAAO,GAAG,IAAI,CAAC,cAAc,CAAC,KAAK,CAAC,MAAM,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,CAAC;QACpE,IAAI,OAAO,KAAK,EAAE,EAAE,CAAC;YACjB,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;YACf,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QACxB,CAAC;QACD,IAAI,KAAK,KAAK,EAAE,EAAE,CAAC;YACf,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;YACf,KAAK,CAAC,IAAI,CAAC,OAAO,KAAK,EAAE,CAAC,CAAC;QAC/B,CAAC;QACD,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC5B,CAAC;IAED,+FAA+F;IAC/F,0FAA0F;IAClF,aAAa,CAAC,KAAqB;QACvC,MAAM,KAAK,GAAa,EAAE,CAAC;QAC3B,IAAI,CAAC,KAAK,CAAC,WAAW;YAAE,KAAK,CAAC,IAAI,CAAC,gCAAgC,CAAC,CAAC;QACrE,IAAI,KAAK,CAAC,MAAM,CAAC,UAAU,CAAC,MAAM,GAAG,CAAC;YAAE,KAAK,CAAC,IAAI,CAAC,0BAA0B,KAAK,CAAC,MAAM,CAAC,UAAU,CAAC,MAAM,eAAe,CAAC,CAAC;QAC5H,KAAK,MAAM,MAAM,IAAI,KAAK,CAAC,WAAW,EAAE,CAAC;YACrC,IAAI,MAAM,CAAC,YAAY,CAAC,MAAM,KAAK,CAAC;gBAAE,SAAS;YAC/C,MAAM,KAAK,GAAG,MAAM,CAAC,YAAY,KAAK,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC;YAC1D,KAAK,CAAC,IAAI,CAAC,GAAG,MAAM,CAAC,IAAI,KAAK,KAAK,IAAI,MAAM,CAAC,YAAY,CAAC,MAAM,UAAU,CAAC,CAAC;QACjF,CAAC;QACD,IAAI,KAAK,CAAC,QAAQ,CAAC,cAAc,GAAG,CAAC,EAAE,CAAC;YACpC,MAAM,KAAK,GAAG,KAAK,CAAC,QAAQ,CAAC,cAAc,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,MAAM,KAAK,CAAC,QAAQ,CAAC,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YAC/G,KAAK,CAAC,IAAI,CAAC,gCAAgC,KAAK,CAAC,QAAQ,CAAC,cAAc,WAAW,KAAK,EAAE,CAAC,CAAC;QAChG,CAAC;QACD,IAAI,KAAK,CAAC,QAAQ,CAAC,WAAW,GAAG,CAAC;YAAE,KAAK,CAAC,IAAI,CAAC,6BAA6B,KAAK,CAAC,QAAQ,CAAC,WAAW,UAAU,CAAC,CAAC;QAClH,2FAA2F;QAC3F,KAAK,MAAM,GAAG,IAAI,KAAK,CAAC,UAAU,EAAE,CAAC;YACjC,KAAK,CAAC,IAAI,CAAC,eAAe,GAAG,CAAC,KAAK,KAAK,IAAI,CAAC,mBAAmB,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAC7E,CAAC;QACD,OAAO,KAAK,CAAC;IACjB,CAAC;IAED,+FAA+F;IAC/F,mGAAmG;IACnG,sGAAsG;IACtG,gGAAgG;IACxF,mBAAmB,CAAC,GAAiB;QACzC,IAAI,GAAG,CAAC,MAAM,KAAK,4BAAa,EAAE,CAAC;YAC/B,MAAM,GAAG,GAAG,GAAG,CAAC,MAAM,CAAC,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,gBAAgB,GAAG,CAAC,MAAM,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YAChF,OAAO,gBAAgB,GAAG,EAAE,CAAC;QACjC,CAAC;QACD,IAAI,GAAG,CAAC,MAAM,KAAK,sBAAO;YAAE,OAAO,yBAAyB,CAAC;QAC7D,IAAI,GAAG,CAAC,MAAM,KAAK,sBAAO;YAAE,OAAO,kBAAkB,CAAC;QACtD,IAAI,GAAG,CAAC,MAAM,KAAK,yBAAU;YAAE,OAAO,gBAAgB,CAAC;QACvD,IAAI,GAAG,CAAC,MAAM,KAAK,sBAAO;YAAE,OAAO,WAAW,CAAC;QAC/C,OAAO,sBAAsB,GAAG,CAAC,MAAM,GAAG,CAAC;IAC/C,CAAC;IAED,kGAAkG;IAClG,oGAAoG;IACpG,oGAAoG;IACpG,mGAAmG;IACnG,oFAAoF;IAC5E,cAAc,CAAC,IAAY,EAAE,GAAW;QAC5C,IAAI,IAAI,KAAK,EAAE;YAAE,OAAO,EAAE,CAAC;QAC3B,MAAM,SAAS,GAAa,EAAE,CAAC;QAC/B,IAAI,KAAK,GAAG,CAAC,CAAC;QACd,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,MAAM,IAAI,SAAS,CAAC,MAAM,GAAG,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC;YAC7D,MAAM,EAAE,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;YACnB,MAAM,YAAY,GAAG,EAAE,KAAK,GAAG,IAAI,EAAE,KAAK,GAAG,IAAI,EAAE,KAAK,GAAG,CAAC;YAC5D,MAAM,IAAI,GAAG,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;YACzB,IAAI,YAAY,IAAI,CAAC,IAAI,KAAK,SAAS,IAAI,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC;gBAC1D,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;gBAChD,KAAK,GAAG,CAAC,GAAG,CAAC,CAAC;YAClB,CAAC;QACL,CAAC;QACD,+EAA+E;QAC/E,IAAI,SAAS,CAAC,MAAM,GAAG,GAAG,IAAI,KAAK,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC;YAChD,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,IAAI,EAAE,CAAC;YACtC,IAAI,IAAI,KAAK,EAAE;gBAAE,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC1C,CAAC;QACD,OAAO,SAAS,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC;IACtC,CAAC;IAED,yFAAyF;IACjF,WAAW,CAAC,OAAe;QAC/B,IAAI,EAAE,GAAG,EAAE,CAAC;QACZ,IAAI,CAAC,GAAG,CAAC,CAAC;QACV,OAAO,CAAC,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;YACxB,MAAM,EAAE,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;YACtB,IAAI,EAAE,KAAK,GAAG,IAAI,OAAO,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,GAAG,EAAE,CAAC;gBACvC,EAAE,IAAI,IAAI,CAAC;gBACX,CAAC,IAAI,CAAC,CAAC;gBACP,IAAI,OAAO,CAAC,CAAC,CAAC,KAAK,GAAG;oBAAE,CAAC,IAAI,CAAC,CAAC;gBAC/B,SAAS;YACb,CAAC;YACD,IAAI,EAAE,KAAK,GAAG,EAAE,CAAC;gBAAC,EAAE,IAAI,OAAO,CAAC;gBAAC,CAAC,IAAI,CAAC,CAAC;gBAAC,SAAS;YAAC,CAAC;YACpD,IAAI,EAAE,KAAK,GAAG,EAAE,CAAC;gBAAC,EAAE,IAAI,MAAM,CAAC;gBAAC,CAAC,IAAI,CAAC,CAAC;gBAAC,SAAS;YAAC,CAAC;YACnD,IAAI,eAAe,CAAC,QAAQ,CAAC,EAAE,CAAC,EAAE,CAAC;gBAAC,EAAE,IAAI,IAAI,GAAG,EAAE,CAAC;gBAAC,CAAC,IAAI,CAAC,CAAC;gBAAC,SAAS;YAAC,CAAC;YACxE,EAAE,IAAI,EAAE,CAAC;YACT,CAAC,IAAI,CAAC,CAAC;QACX,CAAC;QACD,OAAO,IAAI,MAAM,CAAC,GAAG,GAAG,EAAE,GAAG,GAAG,CAAC,CAAC;IACtC,CAAC;IAEO,UAAU,CAAC,QAAkB,EAAE,IAAY;QAC/C,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;YAC7B,IAAI,IAAI,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC;gBAAE,OAAO,IAAI,CAAC;QAC1D,CAAC;QACD,OAAO,KAAK,CAAC;IACjB,CAAC;IAEO,QAAQ,CAAC,MAAkB;QAC/B,IAAI,MAAM,CAAC,YAAY,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO,KAAK,MAAM,CAAC,IAAI,WAAW,CAAC;QACzE,MAAM,KAAK,GAAG,MAAM,CAAC,YAAY,KAAK,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC;QAC1D,OAAO,KAAK,MAAM,CAAC,IAAI,OAAO,KAAK,SAAS,MAAM,CAAC,YAAY,CAAC,MAAM,WAAW,CAAC;IACtF,CAAC;IAED;;;;OAIG;IACK,mBAAmB,CAAC,IAA6B;QACrD,MAAM,OAAO,GAAG,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC;QACzC,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,CAAe,EAAW,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;QACjF,oGAAoG;QACpG,gGAAgG;QAChG,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACtB,OAAO,2FAA2F,CAAC;QACvG,CAAC;QACD,MAAM,SAAS,GAAG,MAAM,CAAC,MAAM,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC;QAC1D,MAAM,MAAM,GAAG,SAAS,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAe,EAAU,EAAE,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACnH,OAAO,mBAAmB,MAAM,CAAC,CAAC,CAAC,CAAC,KAAK,IAAI,IAAI,CAAC,MAAM,UAAU,MAAM,kDAAkD,CAAC;IAC/H,CAAC;IAED;;;;;;;;;OASG;IACK,aAAa,CAAC,IAA6B;QAC/C,MAAM,QAAQ,GAAG,IAAI,YAAY,CAAC,UAAU,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC;QAC1D,MAAM,UAAU,GAAG,IAAI,YAAY,CAAC,YAAY,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC;QAC9D,MAAM,MAAM,GAAG,IAAI,YAAY,CAAC,eAAe,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC;QAC7D,MAAM,MAAM,GAAG,IAAI,YAAY,CAAC,QAAQ,EAAE,IAAI,EAAE,KAAK,CAAC,CAAC;QACvD,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;YACrB,IAAI,GAAG,CAAC,MAAM,KAAK,sBAAO;gBAAE,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;iBACrD,IAAI,GAAG,CAAC,MAAM,KAAK,sBAAO;gBAAE,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;iBAC1D,IAAI,GAAG,CAAC,MAAM,KAAK,4BAAa;gBAAE,UAAU,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;;gBACpE,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;QACzC,CAAC;QACD,OAAO,CAAC,QAAQ,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;IAClD,CAAC;IAED,wGAAwG;IACxG,mFAAmF;IAC3E,YAAY,CAAC,MAAoB;QACrC,IAAI,CAAC,MAAM,CAAC,KAAK;YAAE,OAAO,GAAG,MAAM,CAAC,MAAM,CAAC,MAAM,IAAI,MAAM,CAAC,KAAK,EAAE,CAAC;QACpE,OAAO,GAAG,MAAM,CAAC,MAAM,CAAC,MAAM,IAAI,MAAM,CAAC,KAAK,KAAK,IAAI,CAAC,YAAY,CAAC,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC;IAC3F,CAAC;IAEO,YAAY,CAAC,MAAyB;QAC1C,MAAM,GAAG,GAAG,CAAC,CAAC;QACd,IAAI,MAAM,CAAC,MAAM,IAAI,GAAG;YAAE,OAAO,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACnD,OAAO,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,MAAM,CAAC,MAAM,GAAG,GAAG,OAAO,CAAC;IAC7E,CAAC;IAED,+FAA+F;IACvF,OAAO,CAAC,KAAa;QACzB,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC,CAAC;QAClD,MAAM,IAAI,GAAG,OAAO,IAAI,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,OAAO,IAAI,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,OAAO,IAAI,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC;QACvF,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,IAAI,CAAC,KAAK,CAAC,OAAO,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC;QACnE,OAAO,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,GAAG,GAAG,CAAC,MAAM,CAAC,EAAE,GAAG,MAAM,CAAC,CAAC;IACzD,CAAC;IAED,8EAA8E;IACtE,SAAS,CAAC,MAAkB;QAChC,MAAM,UAAU,GAAG,MAAM,CAAC,UAAU,CAAC,MAAM,CAAC;QAC5C,MAAM,aAAa,GAAG,UAAU,KAAK,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,WAAW,UAAU,gBAAgB,CAAC;QACzF,OAAO;YACH,mBAAmB,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,SAAS,CAAC,MAAM,MAAM,CAAC,SAAS,UAAU,MAAM,CAAC,SAAS,EAAE;YACnG,mBAAmB,MAAM,CAAC,SAAS,MAAM,MAAM,CAAC,SAAS,IAAI;YAC7D,2BAA2B,aAAa,EAAE;SAC7C,CAAC;IACN,CAAC;IAEO,WAAW,CAAC,QAAuB;QACvC,IAAI,QAAQ,CAAC,cAAc,KAAK,CAAC;YAAE,OAAO,qCAAqC,CAAC;QAChF,MAAM,KAAK,GAAG,QAAQ,CAAC,cAAc,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,MAAM,QAAQ,CAAC,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACnG,OAAO,oCAAoC,QAAQ,CAAC,cAAc,WAAW,KAAK,EAAE,CAAC;IACzF,CAAC;CACJ,CAAA;AAhcY,8BAAS;oBAAT,SAAS;IADrB,IAAA,sBAAU,EAAC,8BAAkB,CAAC,SAAS,CAAC;GAC5B,SAAS,CAgcrB","sourcesContent":["import {\n GateDefinition, WEBPIECES_DISABLE, RULE_NAMES, ReviewJson, formatFileList,\n CK_PASS, CK_WARN, CK_OVERRIDDEN, CK_FAIL, CK_MISSING,\n} from '@webpieces/rules-config';\nimport { injectable, bindingScopeValues } from 'inversify';\n\n// Hidden marker on the checklist review COMMENT, so wp-finish can find + PATCH its own comment on every\n// push instead of appending a new one. Versioned so the format can evolve without matching an old shape.\n// v2 = the full roster (every DEFINED checklist, matched or not) + tri-state verdicts.\nexport const CHECKLIST_COMMENT_MARKER = '<!-- webpieces-checklists v2 -->';\nconst COMMENT_LIMIT = 65000; // under GitHub's 65536-char cap, with headroom for the marker + roll-up.\n\n// One checklist section for the combined comment (heading + verbatim reviewer output), so oversize\n// truncation can shrink the longest BODY without ever dropping a verdict heading.\nclass CommentSection {\n heading: string;\n body: string;\n\n constructor(heading: string, body: string) {\n this.heading = heading;\n this.body = body;\n }\n}\n\nexport class GateResult {\n name: string;\n warningColor: string; // 'yellow' | 'red' — the color shown WHEN files matched (green is implicit)\n matchedFiles: string[];\n\n constructor(name: string, warningColor: string, matchedFiles: string[]) {\n this.name = name;\n this.warningColor = warningColor;\n this.matchedFiles = matchedFiles;\n }\n}\n\n// One row for a consumer review checklist the branch triggered. `status` is the resolved verdict (one of\n// CK_PASS | CK_WARN | CK_OVERRIDDEN | CK_FAIL | CK_MISSING | CK_BAD_FORMAT); `detail` is the reviewer\n// output / override justification. A row is always PASS/WARN/OVERRIDDEN by the time it renders — a failed,\n// missing or unreadable verdict throws before the dashboard is built. Rendered into the PR body so the\n// verdict reaches the server — the PR body is the artifact of the local flow that leaves the checkout\n// (alongside the HMAC gate token that proves the flow ran).\nexport class ChecklistRow {\n title: string; // the checklist id (= reviewer subagent name)\n status: string; // CK_* verdict\n detail: string; // reviewer output / override justification (surfaced for OVERRIDDEN)\n\n constructor(title: string, status: string, detail = '') {\n this.title = title;\n this.status = status;\n this.detail = detail;\n }\n}\n\n/**\n * One roster line of the checklist COMMENT: a defined checklist, whether its reviewer ran, and the evidence\n * for WHY. Deliberately separate from {@link ChecklistRow} rather than five more fields on it — ChecklistRow\n * also feeds the PR body and the squash-commit body, and roster evidence has no business travelling into\n * main's git history or through every DashboardInput construction site.\n *\n * Kept in pr-gate, not rules-config: the shape of a GitHub comment is this package's concern, and\n * rules-config is the dependency, not the dependent.\n */\nexport class ChecklistCommentRow {\n subagent: string; // the reviewer / checklist id\n status: string; // CK_* verdict; '' when it did not run\n detail: string; // verbatim reviewer output\n ran: boolean; // false = skipped, which is a NORMAL, healthy outcome\n // The checklist's CONFIGURED globs. The only safe signal for \"always runs\": a patternless checklist and\n // a skipped one both have an empty `firedPatterns`, and they mean opposite things.\n configuredPatterns: string[];\n firedPatterns: string[]; // which configured globs actually hit a changed file\n matchedFiles: string[];\n changedFileCount: number; // how many files were considered at all — \"0 of N\" needs the N\n /**\n * Whether this reviewer's own transcript shows it OPENING the extracted diff.\n *\n * '' = not assessed (no Claude Code session, or nothing was materialized) and prints nothing — \"no\n * evidence recorded\" and \"evidence says it never looked\" are different claims, and conflating them\n * would accuse a reviewer that ran perfectly well in CI. 'yes' | 'no' otherwise. Defaulted, so every\n * existing construction site is unchanged.\n */\n diffRead: string = '';\n\n // eslint-disable-next-line @typescript-eslint/max-params\n constructor(\n subagent: string, status: string, detail: string, ran: boolean,\n configuredPatterns: string[], firedPatterns: string[], matchedFiles: string[], changedFileCount: number,\n ) {\n this.subagent = subagent;\n this.status = status;\n this.detail = detail;\n this.ran = ran;\n this.configuredPatterns = configuredPatterns;\n this.firedPatterns = firedPatterns;\n this.matchedFiles = matchedFiles;\n this.changedFileCount = changedFileCount;\n }\n}\n\n/**\n * One severity bucket of the rolled-up **Checklists** dashboard row: its emoji, the words that describe it,\n * and which checklists landed in it. Data-only.\n *\n * A bucket knows whether it should NAME its members: the non-green ones do (a reader has to know WHICH\n * reviewer to go read), the passed bucket does not (a list of what went fine is noise on a one-line row).\n */\nclass RollupBucket {\n label: string; // 'blocking' | 'overridden' | 'with concerns' | 'passed'\n emoji: string;\n named: boolean; // list the checklist ids on the row, or report a bare count\n titles: string[];\n\n constructor(label: string, emoji: string, named: boolean) {\n this.label = label;\n this.emoji = emoji;\n this.named = named;\n this.titles = [];\n }\n}\n\nexport class DisableCounts {\n webpiecesCount: number;\n eslintCount: number;\n webpiecesRules: string[];\n\n constructor(webpiecesCount: number, eslintCount: number, webpiecesRules: string[]) {\n this.webpiecesCount = webpiecesCount;\n this.eslintCount = eslintCount;\n this.webpiecesRules = webpiecesRules;\n }\n}\n\nexport class DashboardInput {\n title: string;\n gateResults: GateResult[];\n disables: DisableCounts;\n buildPassed: boolean;\n forkPoint: string;\n featureHead: string;\n mainHead: string;\n review: ReviewJson; // AI-authored risk/violations/summary (from review.json)\n checklists: ChecklistRow[]; // consumer checklists this branch triggered; [] for non-adopting repos\n\n // eslint-disable-next-line @typescript-eslint/max-params\n constructor(\n title: string, gateResults: GateResult[], disables: DisableCounts,\n buildPassed: boolean, forkPoint: string, featureHead: string, mainHead: string, review: ReviewJson,\n checklists: ChecklistRow[] = [],\n ) {\n this.title = title;\n this.gateResults = gateResults;\n this.disables = disables;\n this.buildPassed = buildPassed;\n this.forkPoint = forkPoint;\n this.featureHead = featureHead;\n this.mainHead = mainHead;\n this.review = review;\n this.checklists = checklists;\n }\n}\n\n/** Renders the PR-gate dashboard markdown (gates × changed files, disables, risk, 3-point hashes). */\n@injectable(bindingScopeValues.Singleton)\nexport class Dashboard {\n // Disabled gates are in-file examples (JSON has no comments) — skip them entirely.\n computeGateResults(gates: GateDefinition[], changedFiles: string[]): GateResult[] {\n return gates\n .filter((gate: GateDefinition): boolean => !gate.disabled)\n .map((gate: GateDefinition): GateResult => {\n const matched = changedFiles.filter((file: string): boolean => this.matchesAny(gate.patterns, file));\n return new GateResult(gate.name, gate.warningColor, matched);\n });\n }\n\n // Count disables ADDED in this PR by scanning added (`+`) lines of the diff patch. Rule-aware:\n // reports which webpieces rules were disabled, using the canonical RULE_NAMES vocabulary.\n countAddedDisables(patch: string): DisableCounts {\n let webpiecesCount = 0;\n let eslintCount = 0;\n const rules = new Set<string>();\n const allRuleTokens = Object.keys(RULE_NAMES).map((key: string): string => (RULE_NAMES as Record<string, string>)[key]);\n\n for (const line of patch.split('\\n')) {\n if (!line.startsWith('+') || line.startsWith('+++')) continue;\n if (line.includes(WEBPIECES_DISABLE)) {\n webpiecesCount += 1;\n for (const token of allRuleTokens) {\n if (line.includes(token)) rules.add(token);\n }\n }\n if (line.includes('eslint-disable')) eslintCount += 1;\n }\n return new DisableCounts(webpiecesCount, eslintCount, Array.from(rules).sort());\n }\n\n renderDashboard(input: DashboardInput): string {\n const lines: string[] = [];\n lines.push('## 🚦 PR Gate Dashboard');\n lines.push('');\n for (const line of this.riskLines(input.review)) lines.push(line);\n lines.push(`**Build (nx affected):** ${input.buildPassed ? '🟢 Passed' : '🔴 Failed'}`);\n for (const result of input.gateResults) lines.push(this.gateLine(result));\n lines.push(this.disableLine(input.disables));\n const eslintEmoji = input.disables.eslintCount === 0 ? '🟢 No' : `🟡 ${input.disables.eslintCount} line(s)`;\n lines.push(`**ESLint Disables Added:** ${eslintEmoji}`);\n // ONE rolled-up row for ALL triggered consumer checklists — a worst-of colour and a count, sitting\n // with the other status rows. It used to be one row PER checklist, each inlining that checklist's\n // whole verdict/override paragraph: on a six-checklist PR that was the same ~90-word override\n // repeated six times, burying the signal rows above it — and every word of it was already in the\n // checklist COMMENT, per reviewer, in full. ALWAYS emitted, including the zero case: \"no reviewer\n // looked at this PR\" is a fact a reader must be told, and an absent row silently reads as a green\n // all-clear (see checklistRollupLine).\n lines.push(this.checklistRollupLine(input.checklists));\n lines.push('');\n if (input.review.summary.trim() !== '') {\n lines.push('### Summary');\n lines.push(input.review.summary.trim());\n lines.push('');\n }\n lines.push('### 🔍 3-Point Hash Points');\n lines.push(`- Fork point (A): \\`${input.forkPoint.slice(0, 12)}\\``);\n lines.push(`- Feature HEAD (B): \\`${input.featureHead.slice(0, 12)}\\``);\n lines.push(`- Main HEAD (C): \\`${input.mainHead.slice(0, 12)}\\``);\n lines.push('');\n lines.push('<sub>🤖 Generated by `pnpm wp-finish-upsert-pr` (build ran via nx affected — not self-attested).</sub>');\n return lines.join('\\n');\n }\n\n /**\n * The ONE combined PR comment. Two halves, in this order:\n *\n * 1. A roll-up plus the FULL ROSTER — every DEFINED checklist as a checkbox, each with a sub-bullet\n * stating exactly which globs fired against which files, or which did not and out of how many.\n * Skipped checklists are listed on purpose: skipping is the normal, healthy outcome, and a comment\n * that names only the reviewers that fired cannot distinguish \"evaluated and irrelevant\" from\n * \"never wired up\" — nor answer \"why did the DB reviewer run on my frontend PR?\".\n * 2. One section per reviewer that RAN, carrying its full `output` — the depth a verdict line throws\n * away. Overridden first, then warned, then passed: a reader should meet the exceptions first.\n *\n * Idempotent: keyed by the hidden marker so wp-finish PATCHes this same comment on every push.\n */\n renderChecklistComment(rows: readonly ChecklistCommentRow[], provenanceVerified: boolean, baseResolved: boolean): string {\n const ran = this.ranOrdered(rows);\n const prov = provenanceVerified\n ? '_Each reviewer ran as its own independent subagent, verified from the Claude Code harness._'\n : '_⚠️ Reviewer provenance was NOT verified (no Claude Code session) — treat these as unverified._';\n // The roster lives in the HEADER, never in a section: fitComment only ever shrinks section bodies,\n // so a roster line can never be the thing an oversize comment silently drops.\n const lines: string[] = [CHECKLIST_COMMENT_MARKER, this.rollupHeader(rows, baseResolved)];\n // No reviewer ran ⇒ no provenance claim to make. Printing one either way would attest to nothing.\n if (ran.length > 0) lines.push(prov);\n lines.push('', `### Checklists (all ${rows.length})`);\n for (const row of rows) lines.push(this.rosterBullet(row));\n const header = lines.join('\\n');\n if (ran.length === 0) {\n return `${header}\\n\\n_No reviewer had to run on this diff — every configured checklist was ` +\n `evaluated and none of them applied._`;\n }\n return this.fitComment(`${header}\\n\\n### Reviews that ran`, ran.map((r: ChecklistCommentRow): CommentSection => this.commentSection(r)));\n }\n\n // The roll-up line. `baseResolved:false` replaces it entirely: with no fork point the changed-file set is\n // EMPTY, so nothing matched — including patternless ALWAYS-RUNS checklists — and reporting that as\n // \"all skipped ✅\" would post a green all-clear for a PR where nothing was actually evaluated.\n private rollupHeader(rows: readonly ChecklistCommentRow[], baseResolved: boolean): string {\n if (!baseResolved) {\n return `## 🔍 Company review checklists — ⚠️ NOT EVALUATED (${rows.length} defined)\\n` +\n `_No diff base (fork point of main) could be resolved, so no checklist was matched against ` +\n `anything. This is **not** an all-clear._`;\n }\n const ran = rows.filter((r: ChecklistCommentRow): boolean => r.ran);\n const skipped = rows.length - ran.length;\n const parts: string[] = [];\n for (const pair of this.rollupCounts(ran)) parts.push(pair);\n const breakdown = parts.length > 0 ? ` (${parts.join(' · ')})` : '';\n const skip = skipped > 0 ? ` · ${skipped} skipped ✅` : '';\n return `## 🔍 Company review checklists — ${rows.length} defined · ${ran.length} ran${breakdown}${skip}`;\n }\n\n // `🟢 2 · 🟡 1` — only the non-zero buckets, so a clean run reads as one number rather than four.\n private rollupCounts(ran: readonly ChecklistCommentRow[]): string[] {\n const counts: string[] = [];\n const emojiFor: string[] = ['🟢', '🟡', '🟠'];\n const statusFor: string[] = [CK_PASS, CK_WARN, CK_OVERRIDDEN];\n statusFor.forEach((status: string, i: number): void => {\n const n = ran.filter((r: ChecklistCommentRow): boolean => r.status === status).length;\n if (n > 0) counts.push(`${emojiFor[i]} ${n}`);\n });\n return counts;\n }\n\n // One roster line + its why sub-bullet. A checked box means a reviewer ran; an unchecked one means the\n // checklist was evaluated and did not apply, which the words state as the good news it is.\n private rosterBullet(row: ChecklistCommentRow): string {\n const box = row.ran ? '- [x]' : '- [ ]';\n return `${box} ${this.verdictEmoji(row)} **${row.subagent}** — ${this.verdictWords(row)}${this.evidenceSuffix(row)}\\n` +\n ` - ${this.whyLine(row)}`;\n }\n\n /**\n * Whether the reviewer demonstrably opened the diff, read from its own transcript. A QUALITY signal and\n * never a blocker (see SubagentProvenanceService.evidenceFor) — but published, because \"wrote a verdict\n * without reading the change\" is exactly what a reader of this comment would want to weigh.\n */\n private evidenceSuffix(row: ChecklistCommentRow): string {\n if (!row.ran || row.diffRead === '') return '';\n return row.diffRead === 'yes' ? ' _(diff read ✓)_' : ' _(⚠️ no diff read recorded)_';\n }\n\n private verdictEmoji(row: ChecklistCommentRow): string {\n if (!row.ran) return '⚪';\n if (row.status === CK_PASS) return '🟢';\n if (row.status === CK_WARN) return '🟡';\n if (row.status === CK_OVERRIDDEN) return '🟠';\n if (row.status === CK_FAIL) return '🔴';\n return '⚪';\n }\n\n // SHORT words for a roster line / section heading. Short on purpose: the reviewer's own output and any\n // override justification get their own section below, and a roster exists to be scanned.\n private verdictWords(row: ChecklistCommentRow): string {\n if (!row.ran) return 'skipped, not applicable to this diff (expected ✅)';\n if (row.status === CK_PASS) return 'passed';\n if (row.status === CK_WARN) return 'passed with concerns';\n if (row.status === CK_OVERRIDDEN) return 'OVERRIDDEN — shipped with a stated justification';\n if (row.status === CK_FAIL) return 'FAILED review';\n if (row.status === CK_MISSING) return 'no verdict written';\n return `unknown verdict (${row.status})`;\n }\n\n /**\n * WHY this checklist ran or did not — the line that answers \"why was this reviewer involved?\". Branches\n * on `configuredPatterns`, NEVER on `firedPatterns.length`: a patternless checklist and a skipped one\n * both fired zero globs and they mean opposite things, so keying off the fired list would tell every\n * skipped checklist's reader that the whole diff had been in its scope.\n */\n private whyLine(row: ChecklistCommentRow): string {\n const total = row.changedFileCount;\n if (row.configuredPatterns.length === 0) {\n // Say what \"no patterns\" COSTS, not just what it means. Six patternless checklists all firing on\n // a one-file docs PR is what a missing `patterns` looks like from the outside, and a reader who\n // is told only \"ALWAYS RUNS\" has no reason to suspect the config rather than the diff.\n return `ALWAYS RUNS — no \\`patterns\\` configured, so this fires on EVERY PR including docs-only ` +\n `ones; add \\`patterns\\` if that is not intended. Whole diff in scope, ${total} changed file(s): ` +\n `${formatFileList(row.matchedFiles)}`;\n }\n const configured = this.asCode(row.configuredPatterns);\n if (row.firedPatterns.length === 0) {\n return `${configured} matched 0 of ${total} changed file(s)`;\n }\n return `matched ${this.asCode(row.firedPatterns)} → ${row.matchedFiles.length} of ${total} ` +\n `changed file(s): ${formatFileList(row.matchedFiles)}`;\n }\n\n private asCode(patterns: readonly string[]): string {\n return patterns.map((p: string): string => `\\`${p}\\``).join(', ');\n }\n\n // Reviewers that ran, exceptions first (overridden → warned → passed) so a reader meets what needs\n // attention before a wall of green.\n private ranOrdered(rows: readonly ChecklistCommentRow[]): ChecklistCommentRow[] {\n const rank: string[] = [CK_OVERRIDDEN, CK_WARN, CK_PASS];\n return rows\n .filter((r: ChecklistCommentRow): boolean => r.ran)\n .slice()\n .sort((a: ChecklistCommentRow, b: ChecklistCommentRow): number =>\n this.rankOf(rank, a.status) - this.rankOf(rank, b.status));\n }\n\n private rankOf(rank: readonly string[], status: string): number {\n const idx = rank.indexOf(status);\n return idx < 0 ? rank.length : idx;\n }\n\n private commentSection(row: ChecklistCommentRow): CommentSection {\n const heading = `#### ${this.verdictEmoji(row)} ${row.subagent} — ${this.verdictWords(row)}`;\n const body = row.detail.trim() !== '' ? row.detail.trim() : '_(reviewer recorded no output)_';\n return new CommentSection(heading, body);\n }\n\n // Keep the comment under GitHub's size cap by shrinking the LONGEST section body first (so a short\n // overridden note is never cut to make room for a long passing one), never dropping a verdict heading.\n private fitComment(header: string, sections: CommentSection[]): string {\n const assemble = (): string => `${header}\\n\\n${sections.map((s: CommentSection): string => `${s.heading}\\n\\n${s.body}`).join('\\n\\n')}`;\n const trunc = '\\n\\n…_[truncated to fit the GitHub comment size limit]_';\n let out = assemble();\n while (out.length > COMMENT_LIMIT) {\n const idx = this.longestBodyIndex(sections);\n if (idx < 0 || sections[idx].body.length <= trunc.length + 1) break;\n const over = out.length - COMMENT_LIMIT;\n const keep = Math.max(0, sections[idx].body.length - over - trunc.length - 8);\n sections[idx].body = sections[idx].body.slice(0, keep).trimEnd() + trunc;\n out = assemble();\n }\n return out;\n }\n\n private longestBodyIndex(sections: readonly CommentSection[]): number {\n let idx = -1;\n let max = -1;\n sections.forEach((s: CommentSection, i: number): void => {\n if (s.body.length > max) { max = s.body.length; idx = i; }\n });\n return idx;\n }\n\n // The squash-merge COMMIT body that lands in main's history (subject is the PR title, passed to\n // `gh pr merge --subject`). Deliberately compact — unlike the full PR-body dashboard: the risk score\n // (always), every NON-green flag (green rows omitted — a commit log should surface only what stands\n // out), the summary capped at 4 sentences, and a quick link back to the PR for the full dashboard.\n renderCommitBody(input: DashboardInput, prUrl: string): string {\n const lines: string[] = [];\n lines.push(`Risk: ${this.riskBar(input.review.riskScore)} ${input.review.riskScore}/100 ${input.review.riskEmoji} (${input.review.riskLevel})`);\n lines.push('');\n const flags = this.nonGreenFlags(input);\n if (flags.length === 0) {\n lines.push('Flags: 🟢 all green');\n } else {\n lines.push('Flags (non-green):');\n for (const flag of flags) lines.push(`- ${flag}`);\n }\n const summary = this.firstSentences(input.review.summary.trim(), 4);\n if (summary !== '') {\n lines.push('');\n lines.push(summary);\n }\n if (prUrl !== '') {\n lines.push('');\n lines.push(`PR: ${prUrl}`);\n }\n return lines.join('\\n');\n }\n\n // Every dashboard row that is NOT green, as a flat bullet list for the commit body. Green rows\n // (build passed, gate did not match, zero disables/violations) are intentionally omitted.\n private nonGreenFlags(input: DashboardInput): string[] {\n const flags: string[] = [];\n if (!input.buildPassed) flags.push('Build (nx affected): 🔴 Failed');\n if (input.review.violations.length > 0) flags.push(`Pattern Violations: 🟡 ${input.review.violations.length} violation(s)`);\n for (const result of input.gateResults) {\n if (result.matchedFiles.length === 0) continue;\n const emoji = result.warningColor === 'red' ? '🔴' : '🟡';\n flags.push(`${result.name}: ${emoji} ${result.matchedFiles.length} file(s)`);\n }\n if (input.disables.webpiecesCount > 0) {\n const which = input.disables.webpiecesRules.length > 0 ? ` — ${input.disables.webpiecesRules.join(', ')}` : '';\n flags.push(`Webpieces Disables Added: 🟡 ${input.disables.webpiecesCount} line(s)${which}`);\n }\n if (input.disables.eslintCount > 0) flags.push(`ESLint Disables Added: 🟡 ${input.disables.eslintCount} line(s)`);\n // A triggered checklist is noteworthy in main's history — carry each into the commit body.\n for (const row of input.checklists) {\n flags.push(`Checklist — ${row.title}: ${this.checklistStatusText(row)}`);\n }\n return flags;\n }\n\n // Emoji + words for a checklist verdict, shared by the dashboard row and the commit-body flag.\n // Every state is matched EXPLICITLY and the fallthrough names the status it did not recognize. The\n // previous `return '🟢 passed'` fallthrough meant any newly-added verdict rendered as a clean pass on\n // both the PR body and main's commit history until someone noticed — exactly the wrong default.\n private checklistStatusText(row: ChecklistRow): string {\n if (row.status === CK_OVERRIDDEN) {\n const why = row.detail.trim() !== '' ? ` — override: ${row.detail.trim()}` : '';\n return `🟠 OVERRIDDEN${why}`;\n }\n if (row.status === CK_WARN) return '🟡 passed with concerns';\n if (row.status === CK_FAIL) return '🔴 FAILED review';\n if (row.status === CK_MISSING) return '⚪ not reviewed';\n if (row.status === CK_PASS) return '🟢 passed';\n return `⚪ unknown verdict (${row.status})`;\n }\n\n // First `max` sentences of `text`. A sentence ends at `. ! ?` ONLY when followed by whitespace or\n // end-of-string, so interior dots in filenames/paths/versions (dependencies.json, runtime-graph.ts,\n // 0.4.447) do NOT split — and, unlike a greedy `[^.!?]+` regex, no text is ever dropped when such a\n // dot appears (that footgun silently deleted the run of prose up to the next real boundary). Keeps\n // the commit body scannable; the full summary still lives in the PR-body dashboard.\n private firstSentences(text: string, max: number): string {\n if (text === '') return '';\n const sentences: string[] = [];\n let start = 0;\n for (let i = 0; i < text.length && sentences.length < max; i++) {\n const ch = text[i];\n const isTerminator = ch === '.' || ch === '!' || ch === '?';\n const next = text[i + 1];\n if (isTerminator && (next === undefined || /\\s/.test(next))) {\n sentences.push(text.slice(start, i + 1).trim());\n start = i + 1;\n }\n }\n // Trailing text with no terminator still counts as a sentence (up to the cap).\n if (sentences.length < max && start < text.length) {\n const tail = text.slice(start).trim();\n if (tail !== '') sentences.push(tail);\n }\n return sentences.join(' ').trim();\n }\n\n // Self-contained glob matcher (** , * , ?) so pr-gate needs no extra runtime dependency.\n private globToRegex(pattern: string): RegExp {\n let re = '';\n let i = 0;\n while (i < pattern.length) {\n const ch = pattern[i];\n if (ch === '*' && pattern[i + 1] === '*') {\n re += '.*';\n i += 2;\n if (pattern[i] === '/') i += 1;\n continue;\n }\n if (ch === '*') { re += '[^/]*'; i += 1; continue; }\n if (ch === '?') { re += '[^/]'; i += 1; continue; }\n if ('.+^$(){}|[]\\\\'.includes(ch)) { re += '\\\\' + ch; i += 1; continue; }\n re += ch;\n i += 1;\n }\n return new RegExp('^' + re + '$');\n }\n\n private matchesAny(patterns: string[], file: string): boolean {\n for (const pattern of patterns) {\n if (this.globToRegex(pattern).test(file)) return true;\n }\n return false;\n }\n\n private gateLine(result: GateResult): string {\n if (result.matchedFiles.length === 0) return `**${result.name}:** 🟢 No`;\n const emoji = result.warningColor === 'red' ? '🔴' : '🟡';\n return `**${result.name}:** ${emoji} Yes (${result.matchedFiles.length} file(s))`;\n }\n\n /**\n * The ONE rolled-up **Checklists:** row, coloured worst-of across every checklist that ran, in the same\n * shape as its neighbours (`**Build (nx affected):** 🟢 Passed`). Counts and names only — never a line\n * of reviewer output or override justification, which is the whole reason this row exists.\n */\n private checklistRollupLine(rows: readonly ChecklistRow[]): string {\n const buckets = this.rollupBuckets(rows);\n const filled = buckets.filter((b: RollupBucket): boolean => b.titles.length > 0);\n // NO reviewer ran ⇒ the SKIPPED icon, never green. Green claims something was checked and came back\n // clean; ⚪ says nobody looked, which is what a reader has to be able to tell apart at a glance.\n if (filled.length === 0) {\n return '**Checklists:** ⚪ 0 ran — no review checklist matched this PR · see the checklist comment';\n }\n const allPassed = filled.length === 1 && !filled[0].named;\n const detail = allPassed ? 'all passed' : filled.map((b: RollupBucket): string => this.bucketPhrase(b)).join(', ');\n return `**Checklists:** ${filled[0].emoji} ${rows.length} ran — ${detail} · per-checklist detail in the checklist comment`;\n }\n\n /**\n * The four severity buckets, WORST FIRST, so `filled[0]` is the roll-up colour: red beats orange beats\n * yellow beats green. The colours are the same vocabulary the comment already uses (see verdictEmoji).\n *\n * OVERRIDDEN is deliberately NOT folded into passed: an override is a human knowingly accepting a red\n * verdict, and a dashboard that painted that green would hide the single most review-worthy thing on\n * the PR. The blocking bucket is the FALLTHROUGH — CK_FAIL, CK_MISSING, CK_BAD_FORMAT and any verdict\n * added later all land there, matching review.json's own \"not pass|warn|overridden ⇒ refuse\" rule\n * rather than a second list that could silently drift green.\n */\n private rollupBuckets(rows: readonly ChecklistRow[]): RollupBucket[] {\n const blocking = new RollupBucket('blocking', '🔴', true);\n const overridden = new RollupBucket('overridden', '🟠', true);\n const warned = new RollupBucket('with concerns', '🟡', true);\n const passed = new RollupBucket('passed', '🟢', false);\n for (const row of rows) {\n if (row.status === CK_PASS) passed.titles.push(row.title);\n else if (row.status === CK_WARN) warned.titles.push(row.title);\n else if (row.status === CK_OVERRIDDEN) overridden.titles.push(row.title);\n else blocking.titles.push(row.title);\n }\n return [blocking, overridden, warned, passed];\n }\n\n // `2 overridden (a, b)` for the buckets a reviewer must act on; a bare `3 passed` for the one they need\n // no list of. Names are capped so a many-checklist repo still gets a ONE-LINE row.\n private bucketPhrase(bucket: RollupBucket): string {\n if (!bucket.named) return `${bucket.titles.length} ${bucket.label}`;\n return `${bucket.titles.length} ${bucket.label} (${this.compactNames(bucket.titles)})`;\n }\n\n private compactNames(titles: readonly string[]): string {\n const max = 4;\n if (titles.length <= max) return titles.join(', ');\n return `${titles.slice(0, max).join(', ')} +${titles.length - max} more`;\n }\n\n // 10-cell risk bar colored by band (🟩 ≤25, 🟨 ≤50, 🟧 ≤75, 🟥 >75), at least one filled cell.\n private riskBar(score: number): string {\n const clamped = Math.max(0, Math.min(100, score));\n const cell = clamped <= 25 ? '🟩' : clamped <= 50 ? '🟨' : clamped <= 75 ? '🟧' : '🟥';\n const filled = Math.max(1, Math.min(10, Math.round(clamped / 10)));\n return cell.repeat(filled) + '⬜'.repeat(10 - filled);\n }\n\n // RISK section (the AI half): Risk Score bar, Risk Level, Pattern Violations.\n private riskLines(review: ReviewJson): string[] {\n const violations = review.violations.length;\n const violationLine = violations === 0 ? '🟢 No' : `🟡 Yes (${violations} violation(s))`;\n return [\n `**Risk Score:** ${this.riskBar(review.riskScore)} **${review.riskScore}/100** ${review.riskEmoji}`,\n `**Risk Level:** ${review.riskEmoji} **${review.riskLevel}**`,\n `**Pattern Violations:** ${violationLine}`,\n ];\n }\n\n private disableLine(disables: DisableCounts): string {\n if (disables.webpiecesCount === 0) return '**Webpieces Disables Added:** 🟢 No';\n const which = disables.webpiecesRules.length > 0 ? ` — ${disables.webpiecesRules.join(', ')}` : '';\n return `**Webpieces Disables Added:** 🟡 ${disables.webpiecesCount} line(s)${which}`;\n }\n}\n"]}
1
+ {"version":3,"file":"dashboard.js","sourceRoot":"","sources":["../../../../../../packages/tooling/pr-gate/src/dashboard/dashboard.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n GateDefinition,\n WEBPIECES_DISABLE,\n RULE_NAMES,\n ReviewJson,\n formatFileList,\n CK_PASS,\n CK_WARN,\n CK_OVERRIDDEN,\n CK_FAIL,\n CK_MISSING,\n} from '@webpieces/rules-config';\nimport { injectable, bindingScopeValues } from 'inversify';\n\n// Hidden marker on the checklist review COMMENT, so wp-finish can find + PATCH its own comment on every\n// push instead of appending a new one. Versioned so the format can evolve without matching an old shape.\n// v2 = the full roster (every DEFINED checklist, matched or not) + tri-state verdicts.\nexport const CHECKLIST_COMMENT_MARKER = '<!-- webpieces-checklists v2 -->';\nconst COMMENT_LIMIT = 65000; // under GitHub's 65536-char cap, with headroom for the marker + roll-up.\n\n// One checklist section for the combined comment (heading + verbatim reviewer output), so oversize\n// truncation can shrink the longest BODY without ever dropping a verdict heading.\nclass CommentSection {\n heading: string;\n body: string;\n\n constructor(heading: string, body: string) {\n this.heading = heading;\n this.body = body;\n }\n}\n\nexport class GateResult {\n name: string;\n warningColor: string; // 'yellow' | 'red' — the color shown WHEN files matched (green is implicit)\n matchedFiles: string[];\n\n constructor(name: string, warningColor: string, matchedFiles: string[]) {\n this.name = name;\n this.warningColor = warningColor;\n this.matchedFiles = matchedFiles;\n }\n}\n\n// One row for a consumer review checklist the branch triggered. `status` is the resolved verdict (one of\n// CK_PASS | CK_WARN | CK_OVERRIDDEN | CK_FAIL | CK_MISSING | CK_BAD_FORMAT); `detail` is the reviewer\n// output / override justification. A row is always PASS/WARN/OVERRIDDEN by the time it renders — a failed,\n// missing or unreadable verdict throws before the dashboard is built. Rendered into the PR body so the\n// verdict reaches the server — the PR body is the artifact of the local flow that leaves the checkout\n// (alongside the HMAC gate token that proves the flow ran).\nexport class ChecklistRow {\n title: string; // the checklist id (= reviewer subagent name)\n status: string; // CK_* verdict\n detail: string; // reviewer output / override justification (surfaced for OVERRIDDEN)\n\n constructor(title: string, status: string, detail = '') {\n this.title = title;\n this.status = status;\n this.detail = detail;\n }\n}\n\n/**\n * One roster line of the checklist COMMENT: a defined checklist, whether its reviewer ran, and the evidence\n * for WHY. Deliberately separate from {@link ChecklistRow} rather than five more fields on it — ChecklistRow\n * also feeds the PR body and the squash-commit body, and roster evidence has no business travelling into\n * main's git history or through every DashboardInput construction site.\n *\n * Kept in pr-gate, not rules-config: the shape of a GitHub comment is this package's concern, and\n * rules-config is the dependency, not the dependent.\n */\nexport class ChecklistCommentRow {\n subagent: string; // the reviewer / checklist id\n status: string; // CK_* verdict; '' when it did not run\n detail: string; // verbatim reviewer output\n ran: boolean; // false = skipped, which is a NORMAL, healthy outcome\n // The checklist's CONFIGURED globs. The only safe signal for \"always runs\": a patternless checklist and\n // a skipped one both have an empty `firedPatterns`, and they mean opposite things.\n configuredPatterns: string[];\n firedPatterns: string[]; // which configured globs actually hit a changed file\n matchedFiles: string[];\n changedFileCount: number; // how many files were considered at all — \"0 of N\" needs the N\n /**\n * Whether this reviewer's own transcript shows it OPENING the extracted diff.\n *\n * '' = not assessed (no Claude Code session, or nothing was materialized) and prints nothing — \"no\n * evidence recorded\" and \"evidence says it never looked\" are different claims, and conflating them\n * would accuse a reviewer that ran perfectly well in CI. 'yes' | 'no' otherwise. Defaulted, so every\n * existing construction site is unchanged.\n */\n diffRead: string = '';\n\n // eslint-disable-next-line @typescript-eslint/max-params\n constructor(\n subagent: string,\n status: string,\n detail: string,\n ran: boolean,\n configuredPatterns: string[],\n firedPatterns: string[],\n matchedFiles: string[],\n changedFileCount: number,\n ) {\n this.subagent = subagent;\n this.status = status;\n this.detail = detail;\n this.ran = ran;\n this.configuredPatterns = configuredPatterns;\n this.firedPatterns = firedPatterns;\n this.matchedFiles = matchedFiles;\n this.changedFileCount = changedFileCount;\n }\n}\n\n/**\n * One severity bucket of the rolled-up **Checklists** dashboard row: its emoji, the words that describe it,\n * and which checklists landed in it. Data-only.\n *\n * A bucket knows whether it should NAME its members: the non-green ones do (a reader has to know WHICH\n * reviewer to go read), the passed bucket does not (a list of what went fine is noise on a one-line row).\n */\nclass RollupBucket {\n label: string; // 'blocking' | 'overridden' | 'with concerns' | 'passed'\n emoji: string;\n named: boolean; // list the checklist ids on the row, or report a bare count\n titles: string[];\n\n constructor(label: string, emoji: string, named: boolean) {\n this.label = label;\n this.emoji = emoji;\n this.named = named;\n this.titles = [];\n }\n}\n\nexport class DisableCounts {\n webpiecesCount: number;\n eslintCount: number;\n webpiecesRules: string[];\n\n constructor(webpiecesCount: number, eslintCount: number, webpiecesRules: string[]) {\n this.webpiecesCount = webpiecesCount;\n this.eslintCount = eslintCount;\n this.webpiecesRules = webpiecesRules;\n }\n}\n\nexport class DashboardInput {\n title: string;\n gateResults: GateResult[];\n disables: DisableCounts;\n buildPassed: boolean;\n forkPoint: string;\n featureHead: string;\n mainHead: string;\n review: ReviewJson; // AI-authored risk/violations/summary (from review.json)\n checklists: ChecklistRow[]; // consumer checklists this branch triggered; [] for non-adopting repos\n\n // eslint-disable-next-line @typescript-eslint/max-params\n constructor(\n title: string,\n gateResults: GateResult[],\n disables: DisableCounts,\n buildPassed: boolean,\n forkPoint: string,\n featureHead: string,\n mainHead: string,\n review: ReviewJson,\n checklists: ChecklistRow[] = [],\n ) {\n this.title = title;\n this.gateResults = gateResults;\n this.disables = disables;\n this.buildPassed = buildPassed;\n this.forkPoint = forkPoint;\n this.featureHead = featureHead;\n this.mainHead = mainHead;\n this.review = review;\n this.checklists = checklists;\n }\n}\n\n/** Renders the PR-gate dashboard markdown (gates × changed files, disables, risk, 3-point hashes). */\n@injectable(bindingScopeValues.Singleton)\nexport class Dashboard {\n // Disabled gates are in-file examples (JSON has no comments) — skip them entirely.\n computeGateResults(gates: GateDefinition[], changedFiles: string[]): GateResult[] {\n return gates\n .filter((gate: GateDefinition): boolean => !gate.disabled)\n .map((gate: GateDefinition): GateResult => {\n const matched = changedFiles.filter((file: string): boolean =>\n this.matchesAny(gate.patterns, file),\n );\n return new GateResult(gate.name, gate.warningColor, matched);\n });\n }\n\n // Count disables ADDED in this PR by scanning added (`+`) lines of the diff patch. Rule-aware:\n // reports which webpieces rules were disabled, using the canonical RULE_NAMES vocabulary.\n countAddedDisables(patch: string): DisableCounts {\n let webpiecesCount = 0;\n let eslintCount = 0;\n const rules = new Set<string>();\n const allRuleTokens = Object.keys(RULE_NAMES).map(\n (key: string): string => (RULE_NAMES as Record<string, string>)[key],\n );\n\n for (const line of patch.split('\\n')) {\n if (!line.startsWith('+') || line.startsWith('+++')) continue;\n if (line.includes(WEBPIECES_DISABLE)) {\n webpiecesCount += 1;\n for (const token of allRuleTokens) {\n if (line.includes(token)) rules.add(token);\n }\n }\n if (line.includes('eslint-disable')) eslintCount += 1;\n }\n return new DisableCounts(webpiecesCount, eslintCount, Array.from(rules).sort());\n }\n\n renderDashboard(input: DashboardInput): string {\n const lines: string[] = [];\n lines.push('## 🚦 PR Gate Dashboard');\n lines.push('');\n for (const line of this.riskLines(input.review)) lines.push(line);\n lines.push(`**Build (nx affected):** ${input.buildPassed ? '🟢 Passed' : '🔴 Failed'}`);\n for (const result of input.gateResults) lines.push(this.gateLine(result));\n lines.push(this.disableLine(input.disables));\n const eslintEmoji =\n input.disables.eslintCount === 0 ? '🟢 No' : `🟡 ${input.disables.eslintCount} line(s)`;\n lines.push(`**ESLint Disables Added:** ${eslintEmoji}`);\n // ONE rolled-up row for ALL triggered consumer checklists — a worst-of colour and a count, sitting\n // with the other status rows. It used to be one row PER checklist, each inlining that checklist's\n // whole verdict/override paragraph: on a six-checklist PR that was the same ~90-word override\n // repeated six times, burying the signal rows above it — and every word of it was already in the\n // checklist COMMENT, per reviewer, in full. ALWAYS emitted, including the zero case: \"no reviewer\n // looked at this PR\" is a fact a reader must be told, and an absent row silently reads as a green\n // all-clear (see checklistRollupLine).\n lines.push(this.checklistRollupLine(input.checklists));\n lines.push('');\n if (input.review.summary.trim() !== '') {\n lines.push('### Summary');\n lines.push(input.review.summary.trim());\n lines.push('');\n }\n lines.push('### 🔍 3-Point Hash Points');\n lines.push(`- Fork point (A): \\`${input.forkPoint.slice(0, 12)}\\``);\n lines.push(`- Feature HEAD (B): \\`${input.featureHead.slice(0, 12)}\\``);\n lines.push(`- Main HEAD (C): \\`${input.mainHead.slice(0, 12)}\\``);\n lines.push('');\n lines.push(\n '<sub>🤖 Generated by `pnpm wp-finish-upsert-pr` (build ran via nx affected — not self-attested).</sub>',\n );\n return lines.join('\\n');\n }\n\n /**\n * The ONE combined PR comment. Two halves, in this order:\n *\n * 1. A roll-up plus the FULL ROSTER — every DEFINED checklist as a checkbox, each with a sub-bullet\n * stating exactly which globs fired against which files, or which did not and out of how many.\n * Skipped checklists are listed on purpose: skipping is the normal, healthy outcome, and a comment\n * that names only the reviewers that fired cannot distinguish \"evaluated and irrelevant\" from\n * \"never wired up\" — nor answer \"why did the DB reviewer run on my frontend PR?\".\n * 2. One section per reviewer that RAN, carrying its full `output` — the depth a verdict line throws\n * away. Overridden first, then warned, then passed: a reader should meet the exceptions first.\n *\n * Idempotent: keyed by the hidden marker so wp-finish PATCHes this same comment on every push.\n */\n renderChecklistComment(\n rows: readonly ChecklistCommentRow[],\n provenanceVerified: boolean,\n baseResolved: boolean,\n ): string {\n const ran = this.ranOrdered(rows);\n const prov = provenanceVerified\n ? '_Each reviewer ran as its own independent subagent, verified from the Claude Code harness._'\n : '_⚠️ Reviewer provenance was NOT verified (no Claude Code session) — treat these as unverified._';\n // The roster lives in the HEADER, never in a section: fitComment only ever shrinks section bodies,\n // so a roster line can never be the thing an oversize comment silently drops.\n const lines: string[] = [CHECKLIST_COMMENT_MARKER, this.rollupHeader(rows, baseResolved)];\n // No reviewer ran ⇒ no provenance claim to make. Printing one either way would attest to nothing.\n if (ran.length > 0) lines.push(prov);\n lines.push('', `### Checklists (all ${rows.length})`);\n for (const row of rows) lines.push(this.rosterBullet(row));\n const header = lines.join('\\n');\n if (ran.length === 0) {\n return (\n `${header}\\n\\n_No reviewer had to run on this diff — every configured checklist was ` +\n `evaluated and none of them applied._`\n );\n }\n return this.fitComment(\n `${header}\\n\\n### Reviews that ran`,\n ran.map((r: ChecklistCommentRow): CommentSection => this.commentSection(r)),\n );\n }\n\n // The roll-up line. `baseResolved:false` replaces it entirely: with no fork point the changed-file set is\n // EMPTY, so nothing matched — including patternless ALWAYS-RUNS checklists — and reporting that as\n // \"all skipped ✅\" would post a green all-clear for a PR where nothing was actually evaluated.\n private rollupHeader(rows: readonly ChecklistCommentRow[], baseResolved: boolean): string {\n if (!baseResolved) {\n return (\n `## 🔍 Company review checklists — ⚠️ NOT EVALUATED (${rows.length} defined)\\n` +\n `_No diff base (fork point of main) could be resolved, so no checklist was matched against ` +\n `anything. This is **not** an all-clear._`\n );\n }\n const ran = rows.filter((r: ChecklistCommentRow): boolean => r.ran);\n const skipped = rows.length - ran.length;\n const parts: string[] = [];\n for (const pair of this.rollupCounts(ran)) parts.push(pair);\n const breakdown = parts.length > 0 ? ` (${parts.join(' · ')})` : '';\n const skip = skipped > 0 ? ` · ${skipped} skipped ✅` : '';\n return `## 🔍 Company review checklists — ${rows.length} defined · ${ran.length} ran${breakdown}${skip}`;\n }\n\n // `🟢 2 · 🟡 1` — only the non-zero buckets, so a clean run reads as one number rather than four.\n private rollupCounts(ran: readonly ChecklistCommentRow[]): string[] {\n const counts: string[] = [];\n const emojiFor: string[] = ['🟢', '🟡', '🟠'];\n const statusFor: string[] = [CK_PASS, CK_WARN, CK_OVERRIDDEN];\n statusFor.forEach((status: string, i: number): void => {\n const n = ran.filter((r: ChecklistCommentRow): boolean => r.status === status).length;\n if (n > 0) counts.push(`${emojiFor[i]} ${n}`);\n });\n return counts;\n }\n\n // One roster line + its why sub-bullet. A checked box means a reviewer ran; an unchecked one means the\n // checklist was evaluated and did not apply, which the words state as the good news it is.\n private rosterBullet(row: ChecklistCommentRow): string {\n const box = row.ran ? '- [x]' : '- [ ]';\n return (\n `${box} ${this.verdictEmoji(row)} **${row.subagent}** — ${this.verdictWords(row)}${this.evidenceSuffix(row)}\\n` +\n ` - ${this.whyLine(row)}`\n );\n }\n\n /**\n * Whether the reviewer demonstrably opened the diff, read from its own transcript. A QUALITY signal and\n * never a blocker (see SubagentProvenanceService.evidenceFor) — but published, because \"wrote a verdict\n * without reading the change\" is exactly what a reader of this comment would want to weigh.\n */\n private evidenceSuffix(row: ChecklistCommentRow): string {\n if (!row.ran || row.diffRead === '') return '';\n return row.diffRead === 'yes' ? ' _(diff read ✓)_' : ' _(⚠️ no diff read recorded)_';\n }\n\n private verdictEmoji(row: ChecklistCommentRow): string {\n if (!row.ran) return '⚪';\n if (row.status === CK_PASS) return '🟢';\n if (row.status === CK_WARN) return '🟡';\n if (row.status === CK_OVERRIDDEN) return '🟠';\n if (row.status === CK_FAIL) return '🔴';\n return '⚪';\n }\n\n // SHORT words for a roster line / section heading. Short on purpose: the reviewer's own output and any\n // override justification get their own section below, and a roster exists to be scanned.\n private verdictWords(row: ChecklistCommentRow): string {\n if (!row.ran) return 'skipped, not applicable to this diff (expected ✅)';\n if (row.status === CK_PASS) return 'passed';\n if (row.status === CK_WARN) return 'passed with concerns';\n if (row.status === CK_OVERRIDDEN) return 'OVERRIDDEN — shipped with a stated justification';\n if (row.status === CK_FAIL) return 'FAILED review';\n if (row.status === CK_MISSING) return 'no verdict written';\n return `unknown verdict (${row.status})`;\n }\n\n /**\n * WHY this checklist ran or did not — the line that answers \"why was this reviewer involved?\". Branches\n * on `configuredPatterns`, NEVER on `firedPatterns.length`: a patternless checklist and a skipped one\n * both fired zero globs and they mean opposite things, so keying off the fired list would tell every\n * skipped checklist's reader that the whole diff had been in its scope.\n */\n private whyLine(row: ChecklistCommentRow): string {\n const total = row.changedFileCount;\n if (row.configuredPatterns.length === 0) {\n // State the fact, not a suspicion. Patternless is a deliberate configuration — an always-runs\n // gate (every PR names a ticket, every PR has an owner) is exactly what it is FOR — so telling\n // every such row to \"add `patterns` if that is not intended\" nags the repos that meant it, on\n // every PR, forever. A reader who wants to know whether it was intended can read the config.\n return (\n `ALWAYS RUNS (no patterns) — whole diff in scope, ${total} changed file(s): ` +\n `${formatFileList(row.matchedFiles)}`\n );\n }\n const configured = this.asCode(row.configuredPatterns);\n if (row.firedPatterns.length === 0) {\n return `${configured} matched 0 of ${total} changed file(s)`;\n }\n return (\n `matched ${this.asCode(row.firedPatterns)} → ${row.matchedFiles.length} of ${total} ` +\n `changed file(s): ${formatFileList(row.matchedFiles)}`\n );\n }\n\n private asCode(patterns: readonly string[]): string {\n return patterns.map((p: string): string => `\\`${p}\\``).join(', ');\n }\n\n // Reviewers that ran, exceptions first (overridden → warned → passed) so a reader meets what needs\n // attention before a wall of green.\n private ranOrdered(rows: readonly ChecklistCommentRow[]): ChecklistCommentRow[] {\n const rank: string[] = [CK_OVERRIDDEN, CK_WARN, CK_PASS];\n return rows\n .filter((r: ChecklistCommentRow): boolean => r.ran)\n .slice()\n .sort(\n (a: ChecklistCommentRow, b: ChecklistCommentRow): number =>\n this.rankOf(rank, a.status) - this.rankOf(rank, b.status),\n );\n }\n\n private rankOf(rank: readonly string[], status: string): number {\n const idx = rank.indexOf(status);\n return idx < 0 ? rank.length : idx;\n }\n\n private commentSection(row: ChecklistCommentRow): CommentSection {\n const heading = `#### ${this.verdictEmoji(row)} ${row.subagent} — ${this.verdictWords(row)}`;\n const body =\n row.detail.trim() !== '' ? row.detail.trim() : '_(reviewer recorded no output)_';\n return new CommentSection(heading, body);\n }\n\n // Keep the comment under GitHub's size cap by shrinking the LONGEST section body first (so a short\n // overridden note is never cut to make room for a long passing one), never dropping a verdict heading.\n private fitComment(header: string, sections: CommentSection[]): string {\n const assemble = (): string =>\n `${header}\\n\\n${sections.map((s: CommentSection): string => `${s.heading}\\n\\n${s.body}`).join('\\n\\n')}`;\n const trunc = '\\n\\n…_[truncated to fit the GitHub comment size limit]_';\n let out = assemble();\n while (out.length > COMMENT_LIMIT) {\n const idx = this.longestBodyIndex(sections);\n if (idx < 0 || sections[idx].body.length <= trunc.length + 1) break;\n const over = out.length - COMMENT_LIMIT;\n const keep = Math.max(0, sections[idx].body.length - over - trunc.length - 8);\n sections[idx].body = sections[idx].body.slice(0, keep).trimEnd() + trunc;\n out = assemble();\n }\n return out;\n }\n\n private longestBodyIndex(sections: readonly CommentSection[]): number {\n let idx = -1;\n let max = -1;\n sections.forEach((s: CommentSection, i: number): void => {\n if (s.body.length > max) {\n max = s.body.length;\n idx = i;\n }\n });\n return idx;\n }\n\n // The squash-merge COMMIT body that lands in main's history (subject is the PR title, passed to\n // `gh pr merge --subject`). Deliberately compact — unlike the full PR-body dashboard: the risk score\n // (always), every NON-green flag (green rows omitted — a commit log should surface only what stands\n // out), the summary capped at 4 sentences, and a quick link back to the PR for the full dashboard.\n renderCommitBody(input: DashboardInput, prUrl: string): string {\n const lines: string[] = [];\n lines.push(\n `Risk: ${this.riskBar(input.review.riskScore)} ${input.review.riskScore}/100 ${input.review.riskEmoji} (${input.review.riskLevel})`,\n );\n lines.push('');\n const flags = this.nonGreenFlags(input);\n if (flags.length === 0) {\n lines.push('Flags: 🟢 all green');\n } else {\n lines.push('Flags (non-green):');\n for (const flag of flags) lines.push(`- ${flag}`);\n }\n const summary = this.firstSentences(input.review.summary.trim(), 4);\n if (summary !== '') {\n lines.push('');\n lines.push(summary);\n }\n if (prUrl !== '') {\n lines.push('');\n lines.push(`PR: ${prUrl}`);\n }\n return lines.join('\\n');\n }\n\n // Every dashboard row that is NOT green, as a flat bullet list for the commit body. Green rows\n // (build passed, gate did not match, zero disables/violations) are intentionally omitted.\n private nonGreenFlags(input: DashboardInput): string[] {\n const flags: string[] = [];\n if (!input.buildPassed) flags.push('Build (nx affected): 🔴 Failed');\n if (input.review.violations.length > 0)\n flags.push(`Pattern Violations: 🟡 ${input.review.violations.length} violation(s)`);\n for (const result of input.gateResults) {\n if (result.matchedFiles.length === 0) continue;\n const emoji = result.warningColor === 'red' ? '🔴' : '🟡';\n flags.push(`${result.name}: ${emoji} ${result.matchedFiles.length} file(s)`);\n }\n if (input.disables.webpiecesCount > 0) {\n const which =\n input.disables.webpiecesRules.length > 0\n ? ` — ${input.disables.webpiecesRules.join(', ')}`\n : '';\n flags.push(\n `Webpieces Disables Added: 🟡 ${input.disables.webpiecesCount} line(s)${which}`,\n );\n }\n if (input.disables.eslintCount > 0)\n flags.push(`ESLint Disables Added: 🟡 ${input.disables.eslintCount} line(s)`);\n // A triggered checklist is noteworthy in main's history — carry each into the commit body.\n for (const row of input.checklists) {\n flags.push(`Checklist — ${row.title}: ${this.checklistStatusText(row)}`);\n }\n return flags;\n }\n\n // Emoji + words for a checklist verdict, shared by the dashboard row and the commit-body flag.\n // Every state is matched EXPLICITLY and the fallthrough names the status it did not recognize. The\n // previous `return '🟢 passed'` fallthrough meant any newly-added verdict rendered as a clean pass on\n // both the PR body and main's commit history until someone noticed — exactly the wrong default.\n private checklistStatusText(row: ChecklistRow): string {\n if (row.status === CK_OVERRIDDEN) {\n const why = row.detail.trim() !== '' ? ` — override: ${row.detail.trim()}` : '';\n return `🟠 OVERRIDDEN${why}`;\n }\n if (row.status === CK_WARN) return '🟡 passed with concerns';\n if (row.status === CK_FAIL) return '🔴 FAILED review';\n if (row.status === CK_MISSING) return '⚪ not reviewed';\n if (row.status === CK_PASS) return '🟢 passed';\n return `⚪ unknown verdict (${row.status})`;\n }\n\n // First `max` sentences of `text`. A sentence ends at `. ! ?` ONLY when followed by whitespace or\n // end-of-string, so interior dots in filenames/paths/versions (dependencies.json, runtime-graph.ts,\n // 0.4.447) do NOT split — and, unlike a greedy `[^.!?]+` regex, no text is ever dropped when such a\n // dot appears (that footgun silently deleted the run of prose up to the next real boundary). Keeps\n // the commit body scannable; the full summary still lives in the PR-body dashboard.\n private firstSentences(text: string, max: number): string {\n if (text === '') return '';\n const sentences: string[] = [];\n let start = 0;\n for (let i = 0; i < text.length && sentences.length < max; i++) {\n const ch = text[i];\n const isTerminator = ch === '.' || ch === '!' || ch === '?';\n const next = text[i + 1];\n if (isTerminator && (next === undefined || /\\s/.test(next))) {\n sentences.push(text.slice(start, i + 1).trim());\n start = i + 1;\n }\n }\n // Trailing text with no terminator still counts as a sentence (up to the cap).\n if (sentences.length < max && start < text.length) {\n const tail = text.slice(start).trim();\n if (tail !== '') sentences.push(tail);\n }\n return sentences.join(' ').trim();\n }\n\n // Self-contained glob matcher (** , * , ?) so pr-gate needs no extra runtime dependency.\n private globToRegex(pattern: string): RegExp {\n let re = '';\n let i = 0;\n while (i < pattern.length) {\n const ch = pattern[i];\n if (ch === '*' && pattern[i + 1] === '*') {\n re += '.*';\n i += 2;\n if (pattern[i] === '/') i += 1;\n continue;\n }\n if (ch === '*') {\n re += '[^/]*';\n i += 1;\n continue;\n }\n if (ch === '?') {\n re += '[^/]';\n i += 1;\n continue;\n }\n if ('.+^$(){}|[]\\\\'.includes(ch)) {\n re += '\\\\' + ch;\n i += 1;\n continue;\n }\n re += ch;\n i += 1;\n }\n return new RegExp('^' + re + '$');\n }\n\n private matchesAny(patterns: string[], file: string): boolean {\n for (const pattern of patterns) {\n if (this.globToRegex(pattern).test(file)) return true;\n }\n return false;\n }\n\n private gateLine(result: GateResult): string {\n if (result.matchedFiles.length === 0) return `**${result.name}:** 🟢 No`;\n const emoji = result.warningColor === 'red' ? '🔴' : '🟡';\n return `**${result.name}:** ${emoji} Yes (${result.matchedFiles.length} file(s))`;\n }\n\n /**\n * The ONE rolled-up **Checklists:** row, coloured worst-of across every checklist that ran, in the same\n * shape as its neighbours (`**Build (nx affected):** 🟢 Passed`). Counts and names only — never a line\n * of reviewer output or override justification, which is the whole reason this row exists.\n */\n private checklistRollupLine(rows: readonly ChecklistRow[]): string {\n const buckets = this.rollupBuckets(rows);\n const filled = buckets.filter((b: RollupBucket): boolean => b.titles.length > 0);\n // NO reviewer ran ⇒ the SKIPPED icon, never green. Green claims something was checked and came back\n // clean; ⚪ says nobody looked, which is what a reader has to be able to tell apart at a glance.\n if (filled.length === 0) {\n return '**Checklists:** ⚪ 0 ran — no review checklist matched this PR · see the checklist comment';\n }\n const allPassed = filled.length === 1 && !filled[0].named;\n const detail = allPassed\n ? 'all passed'\n : filled.map((b: RollupBucket): string => this.bucketPhrase(b)).join(', ');\n return `**Checklists:** ${filled[0].emoji} ${rows.length} ran — ${detail} · per-checklist detail in the checklist comment`;\n }\n\n /**\n * The four severity buckets, WORST FIRST, so `filled[0]` is the roll-up colour: red beats orange beats\n * yellow beats green. The colours are the same vocabulary the comment already uses (see verdictEmoji).\n *\n * OVERRIDDEN is deliberately NOT folded into passed: an override is a human knowingly accepting a red\n * verdict, and a dashboard that painted that green would hide the single most review-worthy thing on\n * the PR. The blocking bucket is the FALLTHROUGH — CK_FAIL, CK_MISSING, CK_BAD_FORMAT and any verdict\n * added later all land there, matching review.json's own \"not pass|warn|overridden ⇒ refuse\" rule\n * rather than a second list that could silently drift green.\n */\n private rollupBuckets(rows: readonly ChecklistRow[]): RollupBucket[] {\n const blocking = new RollupBucket('blocking', '🔴', true);\n const overridden = new RollupBucket('overridden', '🟠', true);\n const warned = new RollupBucket('with concerns', '🟡', true);\n const passed = new RollupBucket('passed', '🟢', false);\n for (const row of rows) {\n if (row.status === CK_PASS) passed.titles.push(row.title);\n else if (row.status === CK_WARN) warned.titles.push(row.title);\n else if (row.status === CK_OVERRIDDEN) overridden.titles.push(row.title);\n else blocking.titles.push(row.title);\n }\n return [blocking, overridden, warned, passed];\n }\n\n // `2 overridden (a, b)` for the buckets a reviewer must act on; a bare `3 passed` for the one they need\n // no list of. Names are capped so a many-checklist repo still gets a ONE-LINE row.\n private bucketPhrase(bucket: RollupBucket): string {\n if (!bucket.named) return `${bucket.titles.length} ${bucket.label}`;\n return `${bucket.titles.length} ${bucket.label} (${this.compactNames(bucket.titles)})`;\n }\n\n private compactNames(titles: readonly string[]): string {\n const max = 4;\n if (titles.length <= max) return titles.join(', ');\n return `${titles.slice(0, max).join(', ')} +${titles.length - max} more`;\n }\n\n // 10-cell risk bar colored by band (🟩 ≤25, 🟨 ≤50, 🟧 ≤75, 🟥 >75), at least one filled cell.\n private riskBar(score: number): string {\n const clamped = Math.max(0, Math.min(100, score));\n const cell = clamped <= 25 ? '🟩' : clamped <= 50 ? '🟨' : clamped <= 75 ? '🟧' : '🟥';\n const filled = Math.max(1, Math.min(10, Math.round(clamped / 10)));\n return cell.repeat(filled) + '⬜'.repeat(10 - filled);\n }\n\n // RISK section (the AI half): Risk Score bar, Risk Level, Pattern Violations.\n private riskLines(review: ReviewJson): string[] {\n const violations = review.violations.length;\n const violationLine = violations === 0 ? '🟢 No' : `🟡 Yes (${violations} violation(s))`;\n return [\n `**Risk Score:** ${this.riskBar(review.riskScore)} **${review.riskScore}/100** ${review.riskEmoji}`,\n `**Risk Level:** ${review.riskEmoji} **${review.riskLevel}**`,\n `**Pattern Violations:** ${violationLine}`,\n ];\n }\n\n private disableLine(disables: DisableCounts): string {\n if (disables.webpiecesCount === 0) return '**Webpieces Disables Added:** 🟢 No';\n const which =\n disables.webpiecesRules.length > 0 ? ` — ${disables.webpiecesRules.join(', ')}` : '';\n return `**Webpieces Disables Added:** 🟡 ${disables.webpiecesCount} line(s)${which}`;\n }\n}\n"]}
@@ -75,6 +75,22 @@ export declare class FinishUpsertPrCommand {
75
75
  * No-op for a repo with no applicable checklists.
76
76
  */
77
77
  private assertEveryReviewerRan;
78
+ /**
79
+ * Retire the review this run just used — move review.json to old-review.json beside it, stamped as
80
+ * audit-only (see ReviewJsonService.archiveReviewJson).
81
+ *
82
+ * WHY it moves rather than staying put: review.json left behind is a live-looking file describing a
83
+ * review that has already shipped, and the next `wp-review-upsert-pr` on this branch finds it sitting
84
+ * there. A reviewer subagent that judges the PR's stated INTENT — its title, summary or risk level —
85
+ * then reads the previous round's review and can return GREEN against a title that no longer exists,
86
+ * with nothing in the verdict distinguishing that from a real pass. Moving it makes the only route back
87
+ * to this command a freshly-written review.
88
+ *
89
+ * ONLY on a PR that actually went up. A run that died before publishing must stay re-runnable without
90
+ * making the AI rewrite a review that was never used, and prNumber === '' is exactly that case.
91
+ * Non-fatal: the PR is live by here, so an unwritable archive warns rather than failing the command.
92
+ */
93
+ private archiveConsumedReview;
78
94
  private gitOut;
79
95
  private prTitleFrom;
80
96
  private computeDashboardInput;
@@ -147,6 +147,7 @@ let FinishUpsertPrCommand = class FinishUpsertPrCommand {
147
147
  // Publish each reviewer's full output as ONE combined PR comment (idempotent, opt-out-aware). Never
148
148
  // fatal — the PR is already up by now, so a comment failure only warns.
149
149
  this.postChecklistComment(repoRoot, result.prNumber, scan, review, provenance);
150
+ this.archiveConsumedReview(repoRoot, featureName, result);
150
151
  // The closing recap + the clickable-link directive, BOTH derived from the real merge outcome.
151
152
  // Nothing here may hard-code success: a stranded PR under a green checkmark is how PRs got
152
153
  // abandoned (see FinishBanner).
@@ -258,6 +259,36 @@ let FinishUpsertPrCommand = class FinishUpsertPrCommand {
258
259
  `(Each reviewer's generated instructions file is already written — re-running pnpm wp-review-upsert-pr\n` +
259
260
  ` is only needed if the code changed since it ran.)`);
260
261
  }
262
+ /**
263
+ * Retire the review this run just used — move review.json to old-review.json beside it, stamped as
264
+ * audit-only (see ReviewJsonService.archiveReviewJson).
265
+ *
266
+ * WHY it moves rather than staying put: review.json left behind is a live-looking file describing a
267
+ * review that has already shipped, and the next `wp-review-upsert-pr` on this branch finds it sitting
268
+ * there. A reviewer subagent that judges the PR's stated INTENT — its title, summary or risk level —
269
+ * then reads the previous round's review and can return GREEN against a title that no longer exists,
270
+ * with nothing in the verdict distinguishing that from a real pass. Moving it makes the only route back
271
+ * to this command a freshly-written review.
272
+ *
273
+ * ONLY on a PR that actually went up. A run that died before publishing must stay re-runnable without
274
+ * making the AI rewrite a review that was never used, and prNumber === '' is exactly that case.
275
+ * Non-fatal: the PR is live by here, so an unwritable archive warns rather than failing the command.
276
+ */
277
+ archiveConsumedReview(repoRoot, featureName, result) {
278
+ if (result.prNumber === '')
279
+ return;
280
+ // webpieces-disable no-unmanaged-exceptions -- chokepoint: the PR is already up; a failed archive must not fail the command
281
+ // eslint-disable-next-line @webpieces/no-unmanaged-exceptions
282
+ try {
283
+ const archived = this.reviewJsonService.archiveReviewJson((0, rules_config_1.reviewJsonPath)(repoRoot, featureName));
284
+ if (archived !== '')
285
+ process.stdout.write(` archived this run's review.json → ${archived} (audit only) ✓\n`);
286
+ }
287
+ catch (err) {
288
+ const error = (0, rules_config_1.toError)(err);
289
+ process.stderr.write(`⚠️ Could not archive review.json (non-fatal — the PR is already up): ${error.message}\n`);
290
+ }
291
+ }
261
292
  gitOut(args) {
262
293
  const result = (0, child_process_1.spawnSync)('git', args, { encoding: 'utf8' });
263
294
  return result.status === 0 ? (result.stdout ?? '').trim() : '';
@@ -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 ChecklistInstructionsService, InformAiError,\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 { 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 reviewJsonService: ReviewJsonService,\n private readonly gateTokenService: GateTokenService,\n private readonly provenance: SubagentProvenanceService,\n private readonly instructions: ChecklistInstructionsService,\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 missing reviewers, 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.\n this.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\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 * Refuse the PR while ANY applicable checklist still owes a verdict, naming exactly those reviewers and\n * exactly what to tell them — via the same renderer `wp-review-upsert-pr` uses, so the AI sees the identical\n * block it would have seen there. Lists ONLY the outstanding ones: re-instructing an already-reviewed\n * checklist invites a redundant second run and reads as though the earlier verdict did not count.\n * No-op for a repo with no applicable checklists.\n */\n private assertEveryReviewerRan(scan: ChecklistScan): void {\n if (scan.outstanding.length === 0) return;\n // Unreadable verdict files come FIRST. A reviewer that wrote its verdict in the removed `success`\n // format is otherwise indistinguishable from one that never ran, and the AI would go re-run a\n // subagent instead of correcting four characters of JSON.\n const format = scan.formatErrors.length === 0\n ? ''\n : `${scan.formatErrors.length} verdict file(s) are in an UNREADABLE format:\\n\\n` +\n scan.formatErrors.map((e: string): string => ` • ${e}`).join('\\n') + '\\n\\n';\n throw new InformAiError(\n `⛔ NO PR — ${scan.outstanding.length} of ${scan.applicable.length} review checklist(s) that apply to this ` +\n `branch have no passing verdict yet: ${this.instructions.names(scan.outstanding)}\\n\\n` +\n format +\n `${this.instructions.render(scan.outstanding, scan.reviewPath, scan.context)}\\n\\n` +\n `Then re-run: pnpm wp-finish-upsert-pr\\n` +\n `(Each reviewer's generated instructions file is already written — re-running pnpm wp-review-upsert-pr\\n` +\n ` is only needed if the code changed since it ran.)`,\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. (A checklist reaching this\n // point is always PASS/OVERRIDDEN — loadReviewJson already threw on FAIL/MISSING.)\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 if (subagents.length > 0) {\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 }\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 * 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 ChecklistInstructionsService, 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 { 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 reviewJsonService: ReviewJsonService,\n private readonly gateTokenService: GateTokenService,\n private readonly provenance: SubagentProvenanceService,\n private readonly instructions: ChecklistInstructionsService,\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 missing reviewers, 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.\n this.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 * Refuse the PR while ANY applicable checklist still owes a verdict, naming exactly those reviewers and\n * exactly what to tell them — via the same renderer `wp-review-upsert-pr` uses, so the AI sees the identical\n * block it would have seen there. Lists ONLY the outstanding ones: re-instructing an already-reviewed\n * checklist invites a redundant second run and reads as though the earlier verdict did not count.\n * No-op for a repo with no applicable checklists.\n */\n private assertEveryReviewerRan(scan: ChecklistScan): void {\n if (scan.outstanding.length === 0) return;\n // Unreadable verdict files come FIRST. A reviewer that wrote its verdict in the removed `success`\n // format is otherwise indistinguishable from one that never ran, and the AI would go re-run a\n // subagent instead of correcting four characters of JSON.\n const format = scan.formatErrors.length === 0\n ? ''\n : `${scan.formatErrors.length} verdict file(s) are in an UNREADABLE format:\\n\\n` +\n scan.formatErrors.map((e: string): string => ` • ${e}`).join('\\n') + '\\n\\n';\n throw new InformAiError(\n `⛔ NO PR — ${scan.outstanding.length} of ${scan.applicable.length} review checklist(s) that apply to this ` +\n `branch have no passing verdict yet: ${this.instructions.names(scan.outstanding)}\\n\\n` +\n format +\n `${this.instructions.render(scan.outstanding, scan.reviewPath, scan.context)}\\n\\n` +\n `Then re-run: pnpm wp-finish-upsert-pr\\n` +\n `(Each reviewer's generated instructions file is already written — re-running pnpm wp-review-upsert-pr\\n` +\n ` is only needed if the code changed since it ran.)`,\n );\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 } 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. (A checklist reaching this\n // point is always PASS/OVERRIDDEN — loadReviewJson already threw on FAIL/MISSING.)\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 if (subagents.length > 0) {\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 }\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 * 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"]}
@@ -29,7 +29,7 @@ export declare class ReviewReportInput {
29
29
  *
30
30
  * The invariants, enforced by review-report.spec.ts:
31
31
  * 1. `wp-finish-upsert-pr` is named as a thing to run EXACTLY ONCE in the whole block.
32
- * 2. The review.json instruction comes BEFORE it.
32
+ * 2. The review.json instruction comes BEFORE it — and BEFORE the spawn blocks (see nextSteps).
33
33
  * 3. With zero checklists the all-clear precedes any configuration guidance.
34
34
  *
35
35
  * Pure string building, no I/O. `@injectable(bindingScopeValues.Singleton)` so it is injected by type.
@@ -40,22 +40,43 @@ export declare class ReviewReport {
40
40
  constructor(checklistNotice: ChecklistNotice, reviewerInstructions: ReviewerInstructionsService);
41
41
  render(input: ReviewReportInput): string;
42
42
  private header;
43
- private checklistSection;
43
+ /**
44
+ * What the SCAN found: either "nothing applies here" or the already-reviewed / unreadable-verdict lines.
45
+ * Verdicts, not instructions — every instruction lives in nextSteps() below, so no line up here can be
46
+ * mistaken for the next action.
47
+ */
48
+ private scanVerdict;
44
49
  /**
45
50
  * The ONE instruction block, and the last thing the stage prints. Numbered rather than prose-linked
46
51
  * ("Then… Finally…") so that skipping step 1 is visibly skipping a step, and worded so no earlier line
47
52
  * can be mistaken for the real next action.
48
53
  *
54
+ * review.json is STEP 1 and the spawn blocks are STEP 2 — that ORDER is the contract, not a preference.
55
+ * This block used to print the spawn blocks first and then say to write review.json "WHILE any reviewer
56
+ * subagents above are still running", which does not merely permit spawning first, it instructs it.
57
+ * Harmless for a reviewer that only reads the diff; wrong for one that judges the PR's stated INTENT —
58
+ * its title, summary or risk level — because review.json is the only place that intent lives. Such a
59
+ * reviewer either finds no file (a false RED and a wasted reviewer run) or, on a second run of this
60
+ * stage on the same branch, finds the PREVIOUS run's file and validates a title that no longer exists —
61
+ * a false GREEN, with nothing in the output saying which of the two happened. A consuming repo had to
62
+ * write itself a rule telling its agents to DISOBEY this block to work around it.
63
+ *
64
+ * What the old ordering bought was overlap on a single local file write, not a subagent round-trip.
65
+ *
49
66
  * The schema hint is rendered by ReviewJsonService — the single renderer — so the shape printed here
50
67
  * can never drift from the shape `wp-finish-upsert-pr` validates.
51
68
  */
52
69
  private nextSteps;
70
+ private writeReviewStep;
53
71
  /**
54
- * One copy-paste block per owed reviewer. The prompt is deliberately a POINTER and nothing else: the
55
- * generated instructions file is the contract, so anything restated here is a second copy that can go
56
- * stale — which is exactly how a removed `success` field outlived its own removal in print.
72
+ * STEP 2 — one copy-paste block per owed reviewer, and nothing at all when none is owed. The prompt is
73
+ * deliberately a POINTER and nothing else: the generated instructions file is the contract, so anything
74
+ * restated here is a second copy that can go stale — which is exactly how a removed `success` field
75
+ * outlived its own removal in print.
57
76
  */
58
- private spawnBlocks;
77
+ private spawnStep;
78
+ private finishStep;
79
+ private owedReviewers;
59
80
  private oneSpawnBlock;
60
81
  private why;
61
82
  }
@@ -45,7 +45,7 @@ exports.ReviewReportInput = ReviewReportInput;
45
45
  *
46
46
  * The invariants, enforced by review-report.spec.ts:
47
47
  * 1. `wp-finish-upsert-pr` is named as a thing to run EXACTLY ONCE in the whole block.
48
- * 2. The review.json instruction comes BEFORE it.
48
+ * 2. The review.json instruction comes BEFORE it — and BEFORE the spawn blocks (see nextSteps).
49
49
  * 3. With zero checklists the all-clear precedes any configuration guidance.
50
50
  *
51
51
  * Pure string building, no I/O. `@injectable(bindingScopeValues.Singleton)` so it is injected by type.
@@ -58,50 +58,27 @@ let ReviewReport = class ReviewReport {
58
58
  this.reviewerInstructions = reviewerInstructions;
59
59
  }
60
60
  render(input) {
61
- return '\n' + SEP + this.header(input) + SEP + '\n'
62
- + this.checklistSection(input)
63
- + this.nextSteps(input.reviewPath);
61
+ return '\n' + SEP + this.header(input) + SEP
62
+ + this.scanVerdict(input)
63
+ + this.nextSteps(input);
64
64
  }
65
65
  // Name what this block is actually about. A repo with reviewers owed is being told to SPAWN; a repo
66
66
  // with none is not, and promising subagents it does not have is the same kind of noise as explaining
67
- // checklist configuration to a repo that configured none.
67
+ // checklist configuration to a repo that configured none. Keyed on what is actually OWED rather than on
68
+ // the applicable count: every applicable checklist already having a verdict means nothing to spawn.
68
69
  header(input) {
69
- if (input.applicableCount === 0)
70
+ if (this.owedReviewers(input).length === 0)
70
71
  return '② Review, then finish\n';
71
- return '② Spawn Subagent Reviews, then finish\n';
72
- }
73
- // Either "nothing applies here" or the copy-paste spawn blocks — never both, and neither one ends with
74
- // a command to run: the single next step lives in nextSteps() below.
75
- checklistSection(input) {
76
- if (input.applicableCount === 0)
77
- return this.checklistNotice.build(input.definedCount);
78
- return this.spawnBlocks(input);
79
- }
80
- /**
81
- * The ONE instruction block, and the last thing the stage prints. Numbered rather than prose-linked
82
- * ("Then… Finally…") so that skipping step 1 is visibly skipping a step, and worded so no earlier line
83
- * can be mistaken for the real next action.
84
- *
85
- * The schema hint is rendered by ReviewJsonService — the single renderer — so the shape printed here
86
- * can never drift from the shape `wp-finish-upsert-pr` validates.
87
- */
88
- nextSteps(reviewPath) {
89
- return ('\n' + SEP +
90
- '▶ NEXT — two steps, in this order. Step 1 is NOT optional:\n' + SEP + '\n' +
91
- 'STEP 1 — review your own changes, then write the review file (finish REFUSES without it).\n' +
92
- ' Do this WHILE any reviewer subagents above are still running:\n\n' +
93
- (0, rules_config_1.reviewJsonSchemaHint)(reviewPath) + '\n\n' +
94
- 'STEP 2 — only once that file exists, run: pnpm wp-finish-upsert-pr\n' +
95
- ' (The build gate is already green for this commit — finish reuses it unless HEAD moves.)\n\n');
72
+ return '② Review, spawn subagent reviewers, then finish\n';
96
73
  }
97
74
  /**
98
- * One copy-paste block per owed reviewer. The prompt is deliberately a POINTER and nothing else: the
99
- * generated instructions file is the contract, so anything restated here is a second copy that can go
100
- * stale which is exactly how a removed `success` field outlived its own removal in print.
75
+ * What the SCAN found: either "nothing applies here" or the already-reviewed / unreadable-verdict lines.
76
+ * Verdicts, not instructions every instruction lives in nextSteps() below, so no line up here can be
77
+ * mistaken for the next action.
101
78
  */
102
- spawnBlocks(input) {
103
- const reviewedIds = new Set(input.reviewed.map((r) => r.id));
104
- const owed = input.briefings.filter((b) => !reviewedIds.has(b.checklistId));
79
+ scanVerdict(input) {
80
+ if (input.applicableCount === 0)
81
+ return '\n' + this.checklistNotice.build(input.definedCount);
105
82
  const lines = [];
106
83
  for (const r of input.reviewed) {
107
84
  lines.push(` ✓ ${r.subagent} — already reviewed on this branch (reusing its review-${r.id}.json)`);
@@ -111,15 +88,83 @@ let ReviewReport = class ReviewReport {
111
88
  // correcting the file sitting right there.
112
89
  for (const e of input.formatErrors)
113
90
  lines.push(` ⛔ ${e}`);
114
- if (owed.length === 0) {
91
+ if (this.owedReviewers(input).length === 0) {
115
92
  lines.push('', '✅ Every checklist that applies is already reviewed — nothing to spawn.');
116
- return lines.join('\n') + '\n';
117
93
  }
118
- lines.push('', `Spawn these ${owed.length} reviewer subagent(s) — a SEPARATE one each. You may NOT review your own`, 'work, and you may NOT write a reviewer\'s verdict file on its behalf.', '');
94
+ if (lines.length === 0)
95
+ return '';
96
+ return '\n' + lines.join('\n') + '\n';
97
+ }
98
+ /**
99
+ * The ONE instruction block, and the last thing the stage prints. Numbered rather than prose-linked
100
+ * ("Then… Finally…") so that skipping step 1 is visibly skipping a step, and worded so no earlier line
101
+ * can be mistaken for the real next action.
102
+ *
103
+ * review.json is STEP 1 and the spawn blocks are STEP 2 — that ORDER is the contract, not a preference.
104
+ * This block used to print the spawn blocks first and then say to write review.json "WHILE any reviewer
105
+ * subagents above are still running", which does not merely permit spawning first, it instructs it.
106
+ * Harmless for a reviewer that only reads the diff; wrong for one that judges the PR's stated INTENT —
107
+ * its title, summary or risk level — because review.json is the only place that intent lives. Such a
108
+ * reviewer either finds no file (a false RED and a wasted reviewer run) or, on a second run of this
109
+ * stage on the same branch, finds the PREVIOUS run's file and validates a title that no longer exists —
110
+ * a false GREEN, with nothing in the output saying which of the two happened. A consuming repo had to
111
+ * write itself a rule telling its agents to DISOBEY this block to work around it.
112
+ *
113
+ * What the old ordering bought was overlap on a single local file write, not a subagent round-trip.
114
+ *
115
+ * The schema hint is rendered by ReviewJsonService — the single renderer — so the shape printed here
116
+ * can never drift from the shape `wp-finish-upsert-pr` validates.
117
+ */
118
+ nextSteps(input) {
119
+ const owed = this.owedReviewers(input);
120
+ const stepCount = owed.length === 0 ? 2 : 3;
121
+ return '\n' + SEP
122
+ + `▶ NEXT — ${stepCount} steps, in this order. Step 1 is NOT optional:\n` + SEP + '\n'
123
+ + this.writeReviewStep(input.reviewPath)
124
+ + this.spawnStep(input, owed)
125
+ + this.finishStep(stepCount);
126
+ }
127
+ writeReviewStep(reviewPath) {
128
+ return ('STEP 1 — review your own changes, then write the review file. Write it FIRST — BEFORE you spawn\n' +
129
+ ' anything below. finish REFUSES without it, and a reviewer subagent may READ it: a\n' +
130
+ ' checklist that judges the PR title, summary or risk level reads exactly this file, so\n' +
131
+ ' writing it afterwards races that reviewer into seeing nothing — or, on a re-run of this\n' +
132
+ ' stage, into judging the PREVIOUS run\'s review of code that has since changed.\n\n' +
133
+ (0, rules_config_1.reviewJsonSchemaHint)(reviewPath) + '\n\n');
134
+ }
135
+ /**
136
+ * STEP 2 — one copy-paste block per owed reviewer, and nothing at all when none is owed. The prompt is
137
+ * deliberately a POINTER and nothing else: the generated instructions file is the contract, so anything
138
+ * restated here is a second copy that can go stale — which is exactly how a removed `success` field
139
+ * outlived its own removal in print.
140
+ */
141
+ spawnStep(input, owed) {
142
+ if (owed.length === 0)
143
+ return '';
144
+ const lines = [
145
+ `STEP 2 — only once that file is written, spawn these ${owed.length} reviewer subagent(s) — a SEPARATE`,
146
+ ' one each. You may NOT review your own work, and you may NOT write a reviewer\'s verdict',
147
+ ' file on its behalf.',
148
+ '',
149
+ ];
119
150
  for (const b of owed)
120
151
  lines.push(...this.oneSpawnBlock(input, b));
152
+ lines.push('');
121
153
  return lines.join('\n');
122
154
  }
155
+ finishStep(stepNumber) {
156
+ const precondition = stepNumber === 3
157
+ ? 'once every reviewer above has written its verdict file'
158
+ : 'once that file exists';
159
+ return (`STEP ${stepNumber} — only ${precondition}, run: pnpm wp-finish-upsert-pr\n` +
160
+ ' (The build gate is already green for this commit — finish reuses it unless HEAD moves.)\n\n');
161
+ }
162
+ // The briefings with no passing verdict yet — the ONE definition of "owed", shared by the header, the
163
+ // scan verdict and the step numbering, so they cannot disagree about whether there is anything to spawn.
164
+ owedReviewers(input) {
165
+ const reviewedIds = new Set(input.reviewed.map((r) => r.id));
166
+ return input.briefings.filter((b) => !reviewedIds.has(b.checklistId));
167
+ }
123
168
  oneSpawnBlock(input, b) {
124
169
  return [
125
170
  ` ▶ ${b.subagent} — ${this.why(b)}`,
@@ -1 +1 @@
1
- {"version":3,"file":"review-report.js","sourceRoot":"","sources":["../../../../../../../packages/tooling/pr-gate/src/scripts/workflow/review-report.ts"],"names":[],"mappings":"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","sourcesContent":["import { injectable, bindingScopeValues } from 'inversify';\nimport { reviewJsonSchemaHint, RequiredChecklist, ReviewerBriefing, ReviewerInstructionsService } from '@webpieces/rules-config';\nimport { ChecklistNotice } from './checklist-notice';\n\nconst SEP = '━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\\n';\n\n/**\n * Everything the closing block of `wp-review-upsert-pr` needs. Data-only, and a class rather than an\n * object literal per CLAUDE.md. The three identifying paths are constructor args; the rest are optional\n * facts about the scan that default to \"nothing\", so a repo with no checklists constructs it in one line.\n */\nexport class ReviewReportInput {\n repoRoot: string;\n featureName: string;\n reviewPath: string; // the branch's review.json — the file the AI must write next\n definedCount: number; // how many checklists pr-gate.checklists defines\n applicableCount: number; // how many of them apply to THIS diff (0 ⇒ the notice, not spawn blocks)\n reviewed: RequiredChecklist[]; // already have a passing verdict on this branch\n formatErrors: string[]; // verdict files that exist but cannot be read as verdicts\n briefings: ReviewerBriefing[]; // one per applicable checklist, already written to disk\n\n constructor(repoRoot: string, featureName: string, reviewPath: string) {\n this.repoRoot = repoRoot;\n this.featureName = featureName;\n this.reviewPath = reviewPath;\n this.definedCount = 0;\n this.applicableCount = 0;\n this.reviewed = [];\n this.formatErrors = [];\n this.briefings = [];\n }\n}\n\n/**\n * Renders the closing block of `wp-review-upsert-pr` — the checklist verdict, then EXACTLY ONE \"what to do\n * next\".\n *\n * Extracted from the command so it can be asserted on as a rendered string, because the ordering IS the\n * contract. The bug it was extracted to fix: the zero-checklist notice ended with \"Carry on and run: pnpm\n * wp-finish-upsert-pr\", and the block printed directly beneath it said to write review.json first and\n * finish afterwards. Two next-steps, in the wrong order, and an agent that follows instructions literally —\n * which is the entire reason this command prints them — took the first one and opened a PR with no review.\n * That is precisely the failure the three-stage flow exists to prevent (reported on PR #519).\n *\n * The invariants, enforced by review-report.spec.ts:\n * 1. `wp-finish-upsert-pr` is named as a thing to run EXACTLY ONCE in the whole block.\n * 2. The review.json instruction comes BEFORE it.\n * 3. With zero checklists the all-clear precedes any configuration guidance.\n *\n * Pure string building, no I/O. `@injectable(bindingScopeValues.Singleton)` so it is injected by type.\n */\n@injectable(bindingScopeValues.Singleton)\nexport class ReviewReport {\n constructor(\n private readonly checklistNotice: ChecklistNotice,\n private readonly reviewerInstructions: ReviewerInstructionsService,\n ) {}\n\n render(input: ReviewReportInput): string {\n return '\\n' + SEP + this.header(input) + SEP + '\\n'\n + this.checklistSection(input)\n + this.nextSteps(input.reviewPath);\n }\n\n // Name what this block is actually about. A repo with reviewers owed is being told to SPAWN; a repo\n // with none is not, and promising subagents it does not have is the same kind of noise as explaining\n // checklist configuration to a repo that configured none.\n private header(input: ReviewReportInput): string {\n if (input.applicableCount === 0) return '② Review, then finish\\n';\n return '② Spawn Subagent Reviews, then finish\\n';\n }\n\n // Either \"nothing applies here\" or the copy-paste spawn blocks — never both, and neither one ends with\n // a command to run: the single next step lives in nextSteps() below.\n private checklistSection(input: ReviewReportInput): string {\n if (input.applicableCount === 0) return this.checklistNotice.build(input.definedCount);\n return this.spawnBlocks(input);\n }\n\n /**\n * The ONE instruction block, and the last thing the stage prints. Numbered rather than prose-linked\n * (\"Then… Finally…\") so that skipping step 1 is visibly skipping a step, and worded so no earlier line\n * can be mistaken for the real next action.\n *\n * The schema hint is rendered by ReviewJsonService — the single renderer — so the shape printed here\n * can never drift from the shape `wp-finish-upsert-pr` validates.\n */\n private nextSteps(reviewPath: string): string {\n return (\n '\\n' + SEP +\n '▶ NEXT — two steps, in this order. Step 1 is NOT optional:\\n' + SEP + '\\n' +\n 'STEP 1 — review your own changes, then write the review file (finish REFUSES without it).\\n' +\n ' Do this WHILE any reviewer subagents above are still running:\\n\\n' +\n reviewJsonSchemaHint(reviewPath) + '\\n\\n' +\n 'STEP 2 — only once that file exists, run: pnpm wp-finish-upsert-pr\\n' +\n ' (The build gate is already green for this commit — finish reuses it unless HEAD moves.)\\n\\n'\n );\n }\n\n /**\n * One copy-paste block per owed reviewer. The prompt is deliberately a POINTER and nothing else: the\n * generated instructions file is the contract, so anything restated here is a second copy that can go\n * stale — which is exactly how a removed `success` field outlived its own removal in print.\n */\n private spawnBlocks(input: ReviewReportInput): string {\n const reviewedIds = new Set(input.reviewed.map((r: RequiredChecklist): string => r.id));\n const owed = input.briefings.filter((b: ReviewerBriefing): boolean => !reviewedIds.has(b.checklistId));\n const lines: string[] = [];\n for (const r of input.reviewed) {\n lines.push(` ✓ ${r.subagent} — already reviewed on this branch (reusing its review-${r.id}.json)`);\n }\n // A verdict file that EXISTS but is unreadable as a verdict is called out here. Without it this\n // reports the checklist as simply owed, and the AI re-runs a reviewer that already ran instead of\n // correcting the file sitting right there.\n for (const e of input.formatErrors) lines.push(` ⛔ ${e}`);\n if (owed.length === 0) {\n lines.push('', '✅ Every checklist that applies is already reviewed — nothing to spawn.');\n return lines.join('\\n') + '\\n';\n }\n lines.push('',\n `Spawn these ${owed.length} reviewer subagent(s) — a SEPARATE one each. You may NOT review your own`,\n 'work, and you may NOT write a reviewer\\'s verdict file on its behalf.',\n '');\n for (const b of owed) lines.push(...this.oneSpawnBlock(input, b));\n return lines.join('\\n');\n }\n\n private oneSpawnBlock(input: ReviewReportInput, b: ReviewerBriefing): string[] {\n return [\n ` ▶ ${b.subagent} — ${this.why(b)}`,\n ` subagent_type: ${b.subagent}`,\n ' prompt: Read your instructions file FIRST and follow it exactly:',\n ` ${this.reviewerInstructions.pathFor(input.repoRoot, input.featureName, b.subagent)}`,\n '',\n ];\n }\n\n // Why this one is in scope. A patternless checklist is NOT \"matched\" — it always runs, over the whole\n // diff, and saying so is what tells a repo its checklist is firing on docs-only PRs by design.\n private why(b: ReviewerBriefing): string {\n if (b.matchedPatterns.length === 0) {\n return `ALWAYS RUNS (no \"patterns\" configured), whole diff in scope — ${b.myFiles.length} file(s)`;\n }\n return `${b.myFiles.length} file(s) matched ${b.matchedPatterns.map((p: string): string => `\"${p}\"`).join(', ')}`;\n }\n}\n"]}
1
+ {"version":3,"file":"review-report.js","sourceRoot":"","sources":["../../../../../../../packages/tooling/pr-gate/src/scripts/workflow/review-report.ts"],"names":[],"mappings":"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","sourcesContent":["import { injectable, bindingScopeValues } from 'inversify';\nimport { reviewJsonSchemaHint, RequiredChecklist, ReviewerBriefing, ReviewerInstructionsService } from '@webpieces/rules-config';\nimport { ChecklistNotice } from './checklist-notice';\n\nconst SEP = '━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\\n';\n\n/**\n * Everything the closing block of `wp-review-upsert-pr` needs. Data-only, and a class rather than an\n * object literal per CLAUDE.md. The three identifying paths are constructor args; the rest are optional\n * facts about the scan that default to \"nothing\", so a repo with no checklists constructs it in one line.\n */\nexport class ReviewReportInput {\n repoRoot: string;\n featureName: string;\n reviewPath: string; // the branch's review.json — the file the AI must write next\n definedCount: number; // how many checklists pr-gate.checklists defines\n applicableCount: number; // how many of them apply to THIS diff (0 ⇒ the notice, not spawn blocks)\n reviewed: RequiredChecklist[]; // already have a passing verdict on this branch\n formatErrors: string[]; // verdict files that exist but cannot be read as verdicts\n briefings: ReviewerBriefing[]; // one per applicable checklist, already written to disk\n\n constructor(repoRoot: string, featureName: string, reviewPath: string) {\n this.repoRoot = repoRoot;\n this.featureName = featureName;\n this.reviewPath = reviewPath;\n this.definedCount = 0;\n this.applicableCount = 0;\n this.reviewed = [];\n this.formatErrors = [];\n this.briefings = [];\n }\n}\n\n/**\n * Renders the closing block of `wp-review-upsert-pr` — the checklist verdict, then EXACTLY ONE \"what to do\n * next\".\n *\n * Extracted from the command so it can be asserted on as a rendered string, because the ordering IS the\n * contract. The bug it was extracted to fix: the zero-checklist notice ended with \"Carry on and run: pnpm\n * wp-finish-upsert-pr\", and the block printed directly beneath it said to write review.json first and\n * finish afterwards. Two next-steps, in the wrong order, and an agent that follows instructions literally —\n * which is the entire reason this command prints them — took the first one and opened a PR with no review.\n * That is precisely the failure the three-stage flow exists to prevent (reported on PR #519).\n *\n * The invariants, enforced by review-report.spec.ts:\n * 1. `wp-finish-upsert-pr` is named as a thing to run EXACTLY ONCE in the whole block.\n * 2. The review.json instruction comes BEFORE it — and BEFORE the spawn blocks (see nextSteps).\n * 3. With zero checklists the all-clear precedes any configuration guidance.\n *\n * Pure string building, no I/O. `@injectable(bindingScopeValues.Singleton)` so it is injected by type.\n */\n@injectable(bindingScopeValues.Singleton)\nexport class ReviewReport {\n constructor(\n private readonly checklistNotice: ChecklistNotice,\n private readonly reviewerInstructions: ReviewerInstructionsService,\n ) {}\n\n render(input: ReviewReportInput): string {\n return '\\n' + SEP + this.header(input) + SEP\n + this.scanVerdict(input)\n + this.nextSteps(input);\n }\n\n // Name what this block is actually about. A repo with reviewers owed is being told to SPAWN; a repo\n // with none is not, and promising subagents it does not have is the same kind of noise as explaining\n // checklist configuration to a repo that configured none. Keyed on what is actually OWED rather than on\n // the applicable count: every applicable checklist already having a verdict means nothing to spawn.\n private header(input: ReviewReportInput): string {\n if (this.owedReviewers(input).length === 0) return '② Review, then finish\\n';\n return '② Review, spawn subagent reviewers, then finish\\n';\n }\n\n /**\n * What the SCAN found: either \"nothing applies here\" or the already-reviewed / unreadable-verdict lines.\n * Verdicts, not instructions — every instruction lives in nextSteps() below, so no line up here can be\n * mistaken for the next action.\n */\n private scanVerdict(input: ReviewReportInput): string {\n if (input.applicableCount === 0) return '\\n' + this.checklistNotice.build(input.definedCount);\n const lines: string[] = [];\n for (const r of input.reviewed) {\n lines.push(` ✓ ${r.subagent} — already reviewed on this branch (reusing its review-${r.id}.json)`);\n }\n // A verdict file that EXISTS but is unreadable as a verdict is called out here. Without it this\n // reports the checklist as simply owed, and the AI re-runs a reviewer that already ran instead of\n // correcting the file sitting right there.\n for (const e of input.formatErrors) lines.push(` ⛔ ${e}`);\n if (this.owedReviewers(input).length === 0) {\n lines.push('', '✅ Every checklist that applies is already reviewed — nothing to spawn.');\n }\n if (lines.length === 0) return '';\n return '\\n' + lines.join('\\n') + '\\n';\n }\n\n /**\n * The ONE instruction block, and the last thing the stage prints. Numbered rather than prose-linked\n * (\"Then… Finally…\") so that skipping step 1 is visibly skipping a step, and worded so no earlier line\n * can be mistaken for the real next action.\n *\n * review.json is STEP 1 and the spawn blocks are STEP 2 — that ORDER is the contract, not a preference.\n * This block used to print the spawn blocks first and then say to write review.json \"WHILE any reviewer\n * subagents above are still running\", which does not merely permit spawning first, it instructs it.\n * Harmless for a reviewer that only reads the diff; wrong for one that judges the PR's stated INTENT —\n * its title, summary or risk level — because review.json is the only place that intent lives. Such a\n * reviewer either finds no file (a false RED and a wasted reviewer run) or, on a second run of this\n * stage on the same branch, finds the PREVIOUS run's file and validates a title that no longer exists —\n * a false GREEN, with nothing in the output saying which of the two happened. A consuming repo had to\n * write itself a rule telling its agents to DISOBEY this block to work around it.\n *\n * What the old ordering bought was overlap on a single local file write, not a subagent round-trip.\n *\n * The schema hint is rendered by ReviewJsonService — the single renderer — so the shape printed here\n * can never drift from the shape `wp-finish-upsert-pr` validates.\n */\n private nextSteps(input: ReviewReportInput): string {\n const owed = this.owedReviewers(input);\n const stepCount = owed.length === 0 ? 2 : 3;\n return '\\n' + SEP\n + `▶ NEXT — ${stepCount} steps, in this order. Step 1 is NOT optional:\\n` + SEP + '\\n'\n + this.writeReviewStep(input.reviewPath)\n + this.spawnStep(input, owed)\n + this.finishStep(stepCount);\n }\n\n private writeReviewStep(reviewPath: string): string {\n return (\n 'STEP 1 — review your own changes, then write the review file. Write it FIRST — BEFORE you spawn\\n' +\n ' anything below. finish REFUSES without it, and a reviewer subagent may READ it: a\\n' +\n ' checklist that judges the PR title, summary or risk level reads exactly this file, so\\n' +\n ' writing it afterwards races that reviewer into seeing nothing — or, on a re-run of this\\n' +\n ' stage, into judging the PREVIOUS run\\'s review of code that has since changed.\\n\\n' +\n reviewJsonSchemaHint(reviewPath) + '\\n\\n'\n );\n }\n\n /**\n * STEP 2 — one copy-paste block per owed reviewer, and nothing at all when none is owed. The prompt is\n * deliberately a POINTER and nothing else: the generated instructions file is the contract, so anything\n * restated here is a second copy that can go stale — which is exactly how a removed `success` field\n * outlived its own removal in print.\n */\n private spawnStep(input: ReviewReportInput, owed: readonly ReviewerBriefing[]): string {\n if (owed.length === 0) return '';\n const lines: string[] = [\n `STEP 2 — only once that file is written, spawn these ${owed.length} reviewer subagent(s) — a SEPARATE`,\n ' one each. You may NOT review your own work, and you may NOT write a reviewer\\'s verdict',\n ' file on its behalf.',\n '',\n ];\n for (const b of owed) lines.push(...this.oneSpawnBlock(input, b));\n lines.push('');\n return lines.join('\\n');\n }\n\n private finishStep(stepNumber: number): string {\n const precondition = stepNumber === 3\n ? 'once every reviewer above has written its verdict file'\n : 'once that file exists';\n return (\n `STEP ${stepNumber} — only ${precondition}, run: pnpm wp-finish-upsert-pr\\n` +\n ' (The build gate is already green for this commit — finish reuses it unless HEAD moves.)\\n\\n'\n );\n }\n\n // The briefings with no passing verdict yet — the ONE definition of \"owed\", shared by the header, the\n // scan verdict and the step numbering, so they cannot disagree about whether there is anything to spawn.\n private owedReviewers(input: ReviewReportInput): ReviewerBriefing[] {\n const reviewedIds = new Set(input.reviewed.map((r: RequiredChecklist): string => r.id));\n return input.briefings.filter((b: ReviewerBriefing): boolean => !reviewedIds.has(b.checklistId));\n }\n\n private oneSpawnBlock(input: ReviewReportInput, b: ReviewerBriefing): string[] {\n return [\n ` ▶ ${b.subagent} — ${this.why(b)}`,\n ` subagent_type: ${b.subagent}`,\n ' prompt: Read your instructions file FIRST and follow it exactly:',\n ` ${this.reviewerInstructions.pathFor(input.repoRoot, input.featureName, b.subagent)}`,\n '',\n ];\n }\n\n // Why this one is in scope. A patternless checklist is NOT \"matched\" — it always runs, over the whole\n // diff, and saying so is what tells a repo its checklist is firing on docs-only PRs by design.\n private why(b: ReviewerBriefing): string {\n if (b.matchedPatterns.length === 0) {\n return `ALWAYS RUNS (no \"patterns\" configured), whole diff in scope — ${b.myFiles.length} file(s)`;\n }\n return `${b.myFiles.length} file(s) matched ${b.matchedPatterns.map((p: string): string => `\"${p}\"`).join(', ')}`;\n }\n}\n"]}