gentle-pi 2.1.2 → 2.2.0

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.
Files changed (171) hide show
  1. package/README.md +70 -12
  2. package/assets/agents/gentle-ai-worker.md +7 -3
  3. package/assets/agents/jd-fix-agent.md +1 -1
  4. package/assets/agents/jd-judge-a.md +3 -1
  5. package/assets/agents/jd-judge-b.md +3 -1
  6. package/assets/agents/review-readability.md +4 -1
  7. package/assets/agents/review-reliability.md +4 -1
  8. package/assets/agents/review-resilience.md +4 -1
  9. package/assets/agents/review-risk.md +4 -1
  10. package/assets/agents/sdd-apply.md +6 -1
  11. package/assets/agents/sdd-archive.md +6 -1
  12. package/assets/agents/sdd-design.md +6 -1
  13. package/assets/agents/sdd-explore.md +6 -2
  14. package/assets/agents/sdd-init.md +10 -2
  15. package/assets/agents/sdd-onboard.md +6 -1
  16. package/assets/agents/sdd-proposal.md +6 -1
  17. package/assets/agents/sdd-spec.md +6 -1
  18. package/assets/agents/sdd-status.md +6 -1
  19. package/assets/agents/sdd-sync.md +6 -1
  20. package/assets/agents/sdd-tasks.md +6 -1
  21. package/assets/agents/sdd-verify.md +6 -1
  22. package/assets/chains/4r-review.chain.md +2 -0
  23. package/assets/chains/sdd-full.chain.md +1 -1
  24. package/assets/chains/sdd-plan.chain.md +1 -1
  25. package/assets/chains/sdd-verify.chain.md +1 -1
  26. package/assets/orchestrator-delegation.md +246 -67
  27. package/assets/orchestrator.md +7 -14
  28. package/assets/sdd-orchestrator-workflow.md +154 -9
  29. package/assets/support/sdd-status-contract.md +19 -1
  30. package/contracts/review-integration/v1/fixtures/consent.fixture.json +3 -3
  31. package/contracts/review-integration/v1/fixtures/start-v2.fixture.json +19 -28
  32. package/contracts/review-integration/v1/fixtures/start.fixture.json +1 -10
  33. package/contracts/review-integration/v1/fixtures/status-v2.fixture.json +12 -21
  34. package/contracts/review-integration/v1/schemas/correction-plan-request.schema.json +49 -0
  35. package/contracts/review-integration/v1/schemas/operation.schema.json +76 -0
  36. package/contracts/review-integration/v1/schemas/repair.schema.json +39 -0
  37. package/contracts/review-integration/v1/schemas/status-v2.schema.json +4 -2
  38. package/contracts/review-integration/v1/schemas/status.schema.json +4 -2
  39. package/contracts/review-integration/v2/fixtures/consent.fixture.json +1 -1
  40. package/contracts/review-integration/v2/fixtures/start.fixture.json +1 -10
  41. package/contracts/review-integration/v2/fixtures/status.fixture.json +1 -10
  42. package/contracts/review-integration/v2/schemas/failure.schema.json +5 -1
  43. package/contracts/review-integration/v2/schemas/operation.schema.json +6 -1
  44. package/contracts/review-integration/v2/schemas/repair.schema.json +4 -2
  45. package/contracts/review-integration/v2/schemas/start.schema.json +5 -2
  46. package/contracts/review-integration/v2/schemas/status.schema.json +4 -2
  47. package/contracts/review-provider-contract-mirror/provider-contract.lock.json +30 -0
  48. package/contracts/review-provider-contract-mirror/v1.1.0/bundle/README.md +12 -0
  49. package/contracts/review-provider-contract-mirror/v1.1.0/bundle/manifest.json +65 -0
  50. package/contracts/review-provider-contract-mirror/v1.1.0/bundle/schemas/lens.schema.json +16 -0
  51. package/contracts/review-provider-contract-mirror/v1.1.0/bundle/schemas/refuter.schema.json +1 -0
  52. package/contracts/review-provider-contract-mirror/v1.1.0/bundle/schemas/targeted-validator.schema.json +1 -0
  53. package/contracts/review-provider-contract-mirror/v1.1.0/bundle/vectors/lens.json +1 -0
  54. package/contracts/review-provider-contract-mirror/v1.1.0/bundle/vectors/refuter.json +1 -0
  55. package/contracts/review-provider-contract-mirror/v1.1.0/bundle/vectors/targeted-validator.json +1 -0
  56. package/contracts/review-provider-contract-mirror/v1.1.0/generated/provider-capabilities.baseline.json +15 -0
  57. package/contracts/review-provider-contract-mirror/v1.1.0/generated/provider-roles.baseline.json +42 -0
  58. package/docs/native-authority-architecture.md +5 -5
  59. package/docs/review-integration.md +22 -2
  60. package/extensions/gentle-ai.ts +1595 -201
  61. package/extensions/sdd-init.ts +19 -6
  62. package/extensions/skill-registry.ts +10 -2
  63. package/extensions/startup-banner.ts +10 -4
  64. package/lib/gentle-ai-binary.ts +173 -2
  65. package/lib/git-commit-transaction.ts +77 -17
  66. package/lib/native-review-cli.ts +528 -65
  67. package/lib/provider-contract-bundle.ts +704 -0
  68. package/lib/review-candidate-view.ts +527 -18
  69. package/lib/review-compact-contract.ts +59 -248
  70. package/lib/review-host-relay.ts +436 -0
  71. package/lib/review-integration-v2.ts +537 -36
  72. package/lib/review-relay-contract.ts +16 -0
  73. package/lib/sdd-preflight.ts +53 -1
  74. package/package.json +5 -2
  75. package/runtime/gentle-ai-binary.mjs +173 -2
  76. package/runtime/git-commit-transaction.mjs +75 -15
  77. package/runtime/native-review-cli.mjs +524 -61
  78. package/runtime/review-integration-v2.mjs +536 -35
  79. package/runtime/review-relay-contract.mjs +17 -0
  80. package/scripts/build-git-commit-transaction-runner.mjs +1 -0
  81. package/scripts/check-provider-contract.mjs +138 -0
  82. package/scripts/gentle-ai-installer.mjs +23 -13
  83. package/scripts/maintainer/provider-relay-matrix.mjs +219 -0
  84. package/scripts/mirror-provider-contract.mjs +143 -0
  85. package/scripts/test-packed-runner.mjs +16 -2
  86. package/scripts/verify-package-files.mjs +110 -33
  87. package/skills/_shared/review-ledger-contract.md +4 -6
  88. package/skills/gentle-ai/SKILL.md +4 -4
  89. package/skills/issue-creation/SKILL.md +94 -168
  90. package/skills/judgment-day/SKILL.md +7 -1
  91. package/skills/judgment-day/references/prompts-and-formats.md +2 -0
  92. package/skills/rdd-defect-workflow/SKILL.md +54 -0
  93. package/tests/background-subagents.test.ts +771 -0
  94. package/tests/crosslane/cross-lane.mjs +1169 -0
  95. package/tests/delegated-key-learnings-contract.test.ts +238 -0
  96. package/tests/fixtures/devbinary/capabilities-v2.1.derived.json +331 -0
  97. package/tests/fixtures/devbinary/capabilities-v2.2.captured.json +340 -0
  98. package/tests/fixtures/devbinary/consent-v3.captured.json +37 -0
  99. package/tests/fixtures/devbinary/failure-v2-capture-evidence.captured.json +16 -0
  100. package/tests/fixtures/devbinary/result-artifact-v2-path.captured.json +12 -0
  101. package/tests/fixtures/devbinary/result-artifact-v2.captured.json +12 -0
  102. package/tests/fixtures/devbinary/start-v3-consent-declined.captured.json +19 -0
  103. package/tests/fixtures/devbinary/start-v3-consent-granted.captured.json +109 -0
  104. package/tests/fixtures/devbinary/status-v5-capture-result-submission.captured.json +184 -0
  105. package/tests/fixtures/devbinary/status-v5-repository-context.captured.json +138 -0
  106. package/tests/fixtures/devbinary/status-v5.captured.json +88 -0
  107. package/tests/fixtures/provider-contract-bundle/v1.1.0/README.md +12 -0
  108. package/tests/fixtures/provider-contract-bundle/v1.1.0/manifest.json +65 -0
  109. package/tests/fixtures/provider-contract-bundle/v1.1.0/schemas/lens.schema.json +16 -0
  110. package/tests/fixtures/provider-contract-bundle/v1.1.0/schemas/refuter.schema.json +1 -0
  111. package/tests/fixtures/provider-contract-bundle/v1.1.0/schemas/targeted-validator.schema.json +1 -0
  112. package/tests/fixtures/provider-contract-bundle/v1.1.0/vectors/lens.json +1 -0
  113. package/tests/fixtures/provider-contract-bundle/v1.1.0/vectors/refuter.json +1 -0
  114. package/tests/fixtures/provider-contract-bundle/v1.1.0/vectors/targeted-validator.json +1 -0
  115. package/tests/gentle-ai-binary.test.ts +1 -1
  116. package/tests/gentle-ai-dev-binary-surfacing.test.ts +195 -0
  117. package/tests/gentle-ai-dev-binary.test.ts +336 -0
  118. package/tests/gentle-ai-installer.test.ts +46 -46
  119. package/tests/git-commit-transaction.test.ts +229 -1
  120. package/tests/maintainer/provider-relay.maintest.ts +265 -0
  121. package/tests/native-review-capability-contract.test.ts +48 -2
  122. package/tests/native-review-cli.test.ts +56 -0
  123. package/tests/native-review-consent.test.ts +164 -3
  124. package/tests/native-review-parity-runtime.test.ts +37 -0
  125. package/tests/native-review-parity.test.ts +218 -15
  126. package/tests/native-sdd-attempt-authority.test.ts +235 -0
  127. package/tests/orchestrator-budget.test.ts +30 -5
  128. package/tests/package-manifest.test.ts +98 -72
  129. package/tests/provider-contract-bundle.test.ts +385 -0
  130. package/tests/provider-contract-mirror.test.ts +206 -0
  131. package/tests/provider-defect-handoff.test.ts +355 -0
  132. package/tests/review-actor-tool-deny.test.ts +12 -13
  133. package/tests/review-candidate-view.test.ts +489 -9
  134. package/tests/review-compact-contract.test.ts +52 -119
  135. package/tests/review-controller-native-recovery.test.ts +643 -47
  136. package/tests/review-controller-native-routing.test.ts +1667 -222
  137. package/tests/review-controller-workspace-root.test.ts +17 -2
  138. package/tests/review-corrected-finalize-binding.test.ts +175 -0
  139. package/tests/review-dispatch-hydration-gap.test.ts +197 -0
  140. package/tests/review-host-relay-routing.test.ts +317 -0
  141. package/tests/review-host-relay.test.ts +520 -0
  142. package/tests/review-integration-v2-forward.test.ts +631 -0
  143. package/tests/review-integration-v2.test.ts +114 -0
  144. package/tests/review-ledger-contract.test.ts +12 -28
  145. package/tests/review-recovered-lineage-routing.test.ts +246 -0
  146. package/tests/review-relay-transport-agent.test.ts +249 -0
  147. package/tests/runtime-harness.mjs +242 -14
  148. package/tests/sdd-agent-tools.test.ts +18 -33
  149. package/tests/skill-collision-prefixes.test.ts +1 -0
  150. package/tests/skill-registry.test.ts +50 -1
  151. package/tests/verify-package-files.test.ts +62 -0
  152. package/assets/agents/review-refuter.md +0 -40
  153. package/assets/agents/review-validator.md +0 -23
  154. package/lib/native-review-remediation.ts +0 -49
  155. package/lib/review-compact.ts +0 -947
  156. package/lib/review-refuter-adapter.ts +0 -129
  157. package/lib/review-runtime-contract.ts +0 -68
  158. package/prompts/gcl.md +0 -54
  159. package/prompts/gis.md +0 -25
  160. package/prompts/gpr.md +0 -41
  161. package/prompts/gwr.md +0 -31
  162. package/tests/fixtures/native-review-cli/v2.1.2/bind-sdd.json +0 -25
  163. package/tests/fixtures/native-review-cli/v2.1.2/finalize.json +0 -8
  164. package/tests/fixtures/native-review-cli/v2.1.2/sdd-status-engram.json +0 -139
  165. package/tests/fixtures/native-review-cli/v2.1.2/sdd-status.json +0 -200
  166. package/tests/fixtures/native-review-cli/v2.1.2/start.json +0 -12
  167. package/tests/fixtures/native-review-cli/v2.1.2/validate-allow.json +0 -24
  168. package/tests/fixtures/native-review-cli/v2.1.2/validate-deny-empty-context.json +0 -20
  169. package/tests/fixtures/native-review-cli/v2.1.2/validate-deny.json +0 -28
  170. package/tests/review-compact.test.ts +0 -243
  171. package/tests/review-refuter-adapter.test.ts +0 -89
@@ -158,13 +158,29 @@ const DISPOSITION_MAP: DispositionRange[] = [
158
158
  { lines: [25, 29], target: "delegation", label: "Language Boundary LB5 (exceptions)" },
159
159
  { lines: [31, 40], target: "core", label: "Mental Model" },
160
160
  { lines: [42, 42], target: "core", label: "Work Routing Ladder heading" },
161
- { lines: [44, 110], target: "delegation", label: "Work Routing Ladder body + Pi Subagent Model Routing" },
161
+ { lines: [44, 97], target: "delegation", label: "Work Routing Ladder body + Pi Subagent Model Routing" },
162
+ {
163
+ lines: [98, 107],
164
+ target: "obsolete",
165
+ label: "Size/risk-selected SDD tier replaced by explicit-request/accepted-proposal selection (#312)",
166
+ },
167
+ { lines: [108, 108], target: "delegation", label: "SDD explicit-request trigger" },
168
+ {
169
+ lines: [109, 110],
170
+ target: "obsolete",
171
+ label: "Size-gated SDD entry replaced by explicit-selection gating (#312)",
172
+ },
162
173
  { lines: [112, 112], target: "core", label: "Delegation Rules heading" },
163
174
  { lines: [114, 114], target: "core", label: "Delegation Rules core question" },
164
175
  {
165
- lines: [116, 132],
176
+ lines: [116, 126],
177
+ target: "obsolete",
178
+ label: "Pre-canon delegation table replaced by the mirrored gentle-ai canon table (#312)",
179
+ },
180
+ {
181
+ lines: [128, 132],
166
182
  target: "delegation",
167
- label: "Delegation Rules table + Mandatory Triggers preamble",
183
+ label: "Mandatory Triggers heading + Pi trigger preamble + 4-file binding",
168
184
  },
169
185
  {
170
186
  lines: [133, 133],
@@ -172,9 +188,14 @@ const DISPOSITION_MAP: DispositionRange[] = [
172
188
  label: "Superseded no-runtime inline exception",
173
189
  },
174
190
  {
175
- lines: [134, 181],
191
+ lines: [134, 167],
176
192
  target: "delegation",
177
- label: "Mandatory Triggers remainder + Cost/Context Balance + Canonical Workflows + Review Lens Selection",
193
+ label: "Mandatory Triggers remainder + Cost/Context Balance + Canonical Workflows",
194
+ },
195
+ {
196
+ lines: [169, 181],
197
+ target: "obsolete",
198
+ label: "Parent-selected review lens table replaced by native RAR lens ownership (#312)",
178
199
  },
179
200
  { lines: [183, 191], target: "core", label: "SDD Workflow pointer" },
180
201
  { lines: [193, 193], target: "core", label: "Memory Contract heading" },
@@ -200,7 +221,11 @@ function isNormativeLine(line: string): boolean {
200
221
  const fixtureLines = readFileSync(FIXTURE_PATH, "utf8").split("\n");
201
222
  const SUPERSEDED_LIFECYCLE_REVIEW_LINES = new Set([
202
223
  70,
224
+ // 74/77: the loose mode-choice background lines were replaced by the
225
+ // marked gentle-pi:background-subagents policy block (issue #256).
226
+ 74,
203
227
  76,
228
+ 77,
204
229
  92,
205
230
  125,
206
231
  126,
@@ -17,7 +17,8 @@ import { applyModelConfig } from "../extensions/gentle-ai.ts";
17
17
  import { installSddAssets } from "../lib/sdd-preflight.ts";
18
18
 
19
19
  const PACKAGE_ROOT = dirname(dirname(fileURLToPath(import.meta.url)));
20
- const REVIEW_REFUTER_FILE = "review-refuter.md";
20
+ const MANAGED_EXEMPLAR_FILE = "gentle-ai-explore.md";
21
+ const RETIRED_REFUTER_FILE = "review-refuter.md";
21
22
  const REVIEW_RISK_FILE = "review-risk.md";
22
23
  const V013_REVIEW_RISK_FIXTURE = join(
23
24
  PACKAGE_ROOT,
@@ -49,17 +50,12 @@ const V014_MANAGED_ASSETS = join(
49
50
  "migrations",
50
51
  "managed-assets-v0.14.json",
51
52
  );
52
- const REVIEW_REFUTER_TOOLS = ["read", "grep", "find"];
53
- const FORBIDDEN_REFUTER_TOOLS = [
54
- "bash",
55
- "edit",
56
- "write",
57
- "task",
58
- "subagent",
59
- "subagent_run",
60
- "mem_save",
61
- "mem_update",
62
- ];
53
+ // gentle-pi#311 P5: the managed-asset installer mechanism tests use
54
+ // gentle-ai-explore.md as their exemplar (packaged, absent from the v0.13
55
+ // manifest) after review-refuter.md was retired together with every
56
+ // Pi-authored adversarial review verdict.
57
+ const MANAGED_EXEMPLAR_TOOLS = ["read", "grep", "find", "codegraph"];
58
+ const RETIRED_ADVERSARIAL_AGENTS = ["review-refuter.md", "review-validator.md"];
63
59
 
64
60
  interface ManagedAssetsManifest {
65
61
  schemaVersion: number;
@@ -270,20 +266,20 @@ test("package manifest installs pi-pretty through a wrapper without bundling nat
270
266
  );
271
267
  });
272
268
 
273
- test("package verification binds the published Gentle AI v2.2.2 runtime pin", () => {
269
+ test("package verification binds the published Gentle AI v2.4.0 runtime pin", () => {
274
270
  const installer = readFileSync(join(PACKAGE_ROOT, "scripts", "gentle-ai-installer.mjs"), "utf8");
275
271
  const binary = readFileSync(join(PACKAGE_ROOT, "lib", "gentle-ai-binary.ts"), "utf8");
276
272
  const verifier = readFileSync(join(PACKAGE_ROOT, "scripts", "verify-package-files.mjs"), "utf8");
277
273
 
278
- assert.match(installer, /INSTALLER_VERSION = "2\.2\.2"/);
274
+ assert.match(installer, /INSTALLER_VERSION = "2\.4\.0"/);
279
275
  assert.match(installer, /GENTLE_AI_WINDOWS_SOURCE_PACKAGE.*GENTLE_AI_WINDOWS_SOURCE_MODULE/);
280
- assert.match(installer, /GENTLE_AI_WINDOWS_SOURCE_MODULE_CHECKSUM = "h1:YZcI5dRvoHm82I2CULvgBkB2M3UQQGarYO\/u\/Nt5LSc="/);
276
+ assert.match(installer, /GENTLE_AI_WINDOWS_SOURCE_MODULE_CHECKSUM = "h1:XKkcy\+t76cyUKQnRwL1UnqHbhh8o416I8HQ1UsdvWSI="/);
281
277
  assert.match(installer, /GOTOOLCHAIN: "local"/);
282
278
  assert.match(installer, /GOSUMDB: "sum\.golang\.org"/);
283
- assert.match(binary, /GENTLE_AI_VERSION = "2\.2\.2"/);
279
+ assert.match(binary, /GENTLE_AI_VERSION = INSTALLER_VERSION/);
284
280
  assert.match(binary, /GO_SUMDB_SOURCE_BUILD/);
285
281
  assert.match(binary, /GENTLE_AI_WINDOWS_SOURCE_MODULE_CHECKSUM/);
286
- assert.match(verifier, /v2\.2\.2/);
282
+ assert.match(verifier, /v2\.4\.0/);
287
283
  });
288
284
 
289
285
 
@@ -439,25 +435,52 @@ test("packaged agents use YAML list syntax for tool allowlists", () => {
439
435
  }
440
436
  });
441
437
 
442
- test("package source defines review-refuter with the exact read-only boundary", () => {
443
- const refuterPath = join(PACKAGE_ROOT, "assets", "agents", REVIEW_REFUTER_FILE);
444
- assert.ok(existsSync(refuterPath), "gentle-pi must package review-refuter.md");
438
+ // The Pi child-session tool registry exposes `find` for filesystem discovery
439
+ // and has no `glob` or `webfetch` builtin (see tests/runtime-harness.mjs and
440
+ // the working builtin `reviewer` canary in issue #62). A packaged agent that
441
+ // declares a name the runtime cannot resolve does not fail loudly: the SDK
442
+ // silently drops it and the child starts with a reduced allowlist, so the
443
+ // agent reports itself blocked instead of naming the missing tool.
444
+ const UNSUPPORTED_CHILD_SESSION_TOOLS = ["glob", "webfetch"];
445
445
 
446
- const { name, tools } = readAgentDefinition(refuterPath);
447
- assert.equal(name, "review-refuter");
448
- assert.deepEqual(tools, REVIEW_REFUTER_TOOLS);
449
- for (const tool of FORBIDDEN_REFUTER_TOOLS) {
450
- assert.ok(!tools.includes(tool), `review-refuter must deny ${tool}`);
446
+ test("packaged agents declare only tool names a Pi child session can resolve", () => {
447
+ const agentsDir = join(PACKAGE_ROOT, "assets", "agents");
448
+ const agentFiles = readdirSync(agentsDir).flatMap((entry) =>
449
+ entry.endsWith(".md") ? [join(agentsDir, entry)] : [],
450
+ );
451
+
452
+ assert.ok(agentFiles.length > 0, "gentle-pi must ship packaged agents");
453
+
454
+ for (const file of agentFiles) {
455
+ const { tools } = readAgentDefinition(file);
456
+ for (const unsupported of UNSUPPORTED_CHILD_SESSION_TOOLS) {
457
+ assert.ok(
458
+ !tools.includes(unsupported),
459
+ `${file} declares ${unsupported}, which no Pi child session exposes; use find for discovery`,
460
+ );
461
+ }
462
+ }
463
+ });
464
+
465
+ test("the retired Pi adversarial role agents are not packaged", () => {
466
+ // gentle-pi#311 P5: the refuter and targeted validator verdicts execute
467
+ // through Go-owned pi processes via provider-rendered self-contained
468
+ // vectors; the Pi-authored agent definitions must stay deleted.
469
+ for (const retired of RETIRED_ADVERSARIAL_AGENTS) {
470
+ assert.ok(!existsSync(join(PACKAGE_ROOT, "assets", "agents", retired)), `${retired} must stay deleted`);
451
471
  }
452
472
  });
453
473
 
454
- test("forced package installation preserves same-path user-authored agents and separate shadows", () => {
474
+ test("forced package installation preserves same-path user-authored agents and separate shadows, including on retired asset paths", () => {
475
+ // The user-authored file below sits on the RETIRED review-refuter.md path:
476
+ // this also pins that gentle-pi#311 P5 asset retirement deletes only
477
+ // hash-proven package-managed copies, never user content.
455
478
  const temporaryAgentHome = mkdtempSync(join(tmpdir(), "gentle-pi-refuter-home-"));
456
479
  const temporaryProject = mkdtempSync(join(tmpdir(), "gentle-pi-refuter-project-"));
457
480
  const previousAgentHome = process.env.GENTLE_PI_AGENT_HOME;
458
- const samePathUserAgent = join(temporaryAgentHome, "agents", REVIEW_REFUTER_FILE);
459
- const userShadow = join(temporaryAgentHome, "subagents", REVIEW_REFUTER_FILE);
460
- const projectOverride = join(temporaryProject, ".pi", "agents", REVIEW_REFUTER_FILE);
481
+ const samePathUserAgent = join(temporaryAgentHome, "agents", RETIRED_REFUTER_FILE);
482
+ const userShadow = join(temporaryAgentHome, "subagents", RETIRED_REFUTER_FILE);
483
+ const projectOverride = join(temporaryProject, ".pi", "agents", RETIRED_REFUTER_FILE);
461
484
  const userAgentSource = [
462
485
  "---",
463
486
  "name: review-refuter",
@@ -538,7 +561,7 @@ test("first forced sync migrates untouched v0.13 assets, preserves routing, and
538
561
  const temporaryAgentHome = mkdtempSync(join(tmpdir(), "gentle-pi-v013-upgrade-"));
539
562
  const previousAgentHome = process.env.GENTLE_PI_AGENT_HOME;
540
563
  const installedReviewRisk = join(temporaryAgentHome, "agents", REVIEW_RISK_FILE);
541
- const installedRefuter = join(temporaryAgentHome, "agents", REVIEW_REFUTER_FILE);
564
+ const installedExemplar = join(temporaryAgentHome, "agents", MANAGED_EXEMPLAR_FILE);
542
565
  const managedAssetsManifest = join(
543
566
  temporaryAgentHome,
544
567
  "gentle-ai",
@@ -572,8 +595,8 @@ test("first forced sync migrates untouched v0.13 assets, preserves routing, and
572
595
  "migration must update the package body without losing user routing",
573
596
  );
574
597
  assert.equal(
575
- readFileSync(installedRefuter, "utf8"),
576
- readFileSync(join(PACKAGE_ROOT, "assets", "agents", REVIEW_REFUTER_FILE), "utf8"),
598
+ readFileSync(installedExemplar, "utf8"),
599
+ readFileSync(join(PACKAGE_ROOT, "assets", "agents", MANAGED_EXEMPLAR_FILE), "utf8"),
577
600
  "an asset missing from v0.13 must install normally",
578
601
  );
579
602
 
@@ -582,8 +605,8 @@ test("first forced sync migrates untouched v0.13 assets, preserves routing, and
582
605
  ) as ManagedAssetsManifest;
583
606
  assert.equal(manifest.assets[`agents/${REVIEW_RISK_FILE}`], sha256(migrated));
584
607
  assert.equal(
585
- manifest.assets[`agents/${REVIEW_REFUTER_FILE}`],
586
- sha256(readFileSync(installedRefuter, "utf8")),
608
+ manifest.assets[`agents/${MANAGED_EXEMPLAR_FILE}`],
609
+ sha256(readFileSync(installedExemplar, "utf8")),
587
610
  );
588
611
 
589
612
  const userEditedMigration = migrated.replace(
@@ -684,23 +707,23 @@ test("first forced sync preserves a body-edited v0.13 asset byte-for-byte", () =
684
707
  test("forced package installation refreshes an asset recorded as package-managed", () => {
685
708
  const temporaryAgentHome = mkdtempSync(join(tmpdir(), "gentle-pi-malformed-refuter-"));
686
709
  const previousAgentHome = process.env.GENTLE_PI_AGENT_HOME;
687
- const installedRefuter = join(temporaryAgentHome, "agents", REVIEW_REFUTER_FILE);
710
+ const installedExemplar = join(temporaryAgentHome, "agents", MANAGED_EXEMPLAR_FILE);
688
711
  const managedAssetsManifest = join(
689
712
  temporaryAgentHome,
690
713
  "gentle-ai",
691
714
  "managed-assets.json",
692
715
  );
693
716
  const previousPackageSource =
694
- "---\nname: review-refuter\ntools:\n - read\n - bash\n---\nprevious package version\n";
717
+ "---\nname: gentle-ai-explore\ntools:\n - read\n - bash\n---\nprevious package version\n";
695
718
  const routedPreviousPackageSource = previousPackageSource.replace(
696
- "name: review-refuter\n",
697
- "name: review-refuter\nmodel: openai/previous-package\nthinking: high\n",
719
+ "name: gentle-ai-explore\n",
720
+ "name: gentle-ai-explore\nmodel: openai/previous-package\nthinking: high\n",
698
721
  );
699
722
 
700
723
  try {
701
724
  process.env.GENTLE_PI_AGENT_HOME = temporaryAgentHome;
702
725
  installSddAssets(PACKAGE_ROOT, true);
703
- assert.ok(existsSync(installedRefuter), "a missing package asset must install");
726
+ assert.ok(existsSync(installedExemplar), "a missing package asset must install");
704
727
  assert.ok(
705
728
  existsSync(managedAssetsManifest),
706
729
  "the installer must record ownership independently from the filename",
@@ -709,16 +732,16 @@ test("forced package installation refreshes an asset recorded as package-managed
709
732
  const manifest = JSON.parse(
710
733
  readFileSync(managedAssetsManifest, "utf8"),
711
734
  ) as ManagedAssetsManifest;
712
- writeFileSync(installedRefuter, routedPreviousPackageSource);
713
- manifest.assets[`agents/${REVIEW_REFUTER_FILE}`] = sha256(
735
+ writeFileSync(installedExemplar, routedPreviousPackageSource);
736
+ manifest.assets[`agents/${MANAGED_EXEMPLAR_FILE}`] = sha256(
714
737
  routedPreviousPackageSource,
715
738
  );
716
739
  writeFileSync(managedAssetsManifest, JSON.stringify(manifest, null, 2));
717
740
 
718
741
  installSddAssets(PACKAGE_ROOT, true);
719
742
 
720
- const refreshed = readAgentDefinition(installedRefuter);
721
- assert.deepEqual(refreshed.tools, REVIEW_REFUTER_TOOLS);
743
+ const refreshed = readAgentDefinition(installedExemplar);
744
+ assert.deepEqual(refreshed.tools, MANAGED_EXEMPLAR_TOOLS);
722
745
  assert.doesNotMatch(refreshed.source, /^ - bash$/m);
723
746
  } finally {
724
747
  if (previousAgentHome === undefined) {
@@ -736,7 +759,7 @@ function assertManagedAgentUserEditIsPreserved(
736
759
  ): void {
737
760
  const temporaryAgentHome = mkdtempSync(join(tmpdir(), "gentle-pi-managed-edit-"));
738
761
  const previousAgentHome = process.env.GENTLE_PI_AGENT_HOME;
739
- const installedRefuter = join(temporaryAgentHome, "agents", REVIEW_REFUTER_FILE);
762
+ const installedExemplar = join(temporaryAgentHome, "agents", MANAGED_EXEMPLAR_FILE);
740
763
  const managedAssetsManifest = join(
741
764
  temporaryAgentHome,
742
765
  "gentle-ai",
@@ -746,15 +769,15 @@ function assertManagedAgentUserEditIsPreserved(
746
769
  try {
747
770
  process.env.GENTLE_PI_AGENT_HOME = temporaryAgentHome;
748
771
  installSddAssets(PACKAGE_ROOT, true);
749
- const installedSource = readFileSync(installedRefuter, "utf8");
772
+ const installedSource = readFileSync(installedExemplar, "utf8");
750
773
  const userEditedSource = editSource(installedSource);
751
774
  assert.notEqual(userEditedSource, installedSource, `${editLabel} must alter the asset`);
752
- writeFileSync(installedRefuter, userEditedSource);
775
+ writeFileSync(installedExemplar, userEditedSource);
753
776
 
754
777
  installSddAssets(PACKAGE_ROOT, true);
755
778
 
756
779
  assert.deepEqual(
757
- readFileSync(installedRefuter),
780
+ readFileSync(installedExemplar),
758
781
  Buffer.from(userEditedSource),
759
782
  `${editLabel} must invalidate ownership and survive force refresh byte-for-byte`,
760
783
  );
@@ -762,7 +785,7 @@ function assertManagedAgentUserEditIsPreserved(
762
785
  readFileSync(managedAssetsManifest, "utf8"),
763
786
  ) as ManagedAssetsManifest;
764
787
  assert.equal(
765
- manifest.assets[`agents/${REVIEW_REFUTER_FILE}`],
788
+ manifest.assets[`agents/${MANAGED_EXEMPLAR_FILE}`],
766
789
  undefined,
767
790
  `${editLabel} must remove package ownership`,
768
791
  );
@@ -779,8 +802,8 @@ function assertManagedAgentUserEditIsPreserved(
779
802
  test("forced package installation preserves a model-only edit to a managed agent", () => {
780
803
  assertManagedAgentUserEditIsPreserved("a model-only user edit", (source) =>
781
804
  source.replace(
782
- "name: review-refuter\n",
783
- "name: review-refuter\nmodel: private/user-model\n",
805
+ "name: gentle-ai-explore\n",
806
+ "name: gentle-ai-explore\nmodel: private/user-model\n",
784
807
  ),
785
808
  );
786
809
  });
@@ -788,8 +811,8 @@ test("forced package installation preserves a model-only edit to a managed agent
788
811
  test("forced package installation preserves a thinking-only edit to a managed agent", () => {
789
812
  assertManagedAgentUserEditIsPreserved("a thinking-only user edit", (source) =>
790
813
  source.replace(
791
- "name: review-refuter\n",
792
- "name: review-refuter\nthinking: xhigh\n",
814
+ "name: gentle-ai-explore\n",
815
+ "name: gentle-ai-explore\nthinking: xhigh\n",
793
816
  ),
794
817
  );
795
818
  });
@@ -797,8 +820,8 @@ test("forced package installation preserves a thinking-only edit to a managed ag
797
820
  test("forced package installation preserves an ordinary body edit to a managed agent", () => {
798
821
  assertManagedAgentUserEditIsPreserved("an ordinary body edit", (source) =>
799
822
  source.replace(
800
- "Challenge the supplied inferential claims",
801
- "Preserve this user-authored body change and challenge the supplied inferential claims",
823
+ "You are the read-only explorer for generic non-SDD work.",
824
+ "Preserve this user-authored body change. You are the read-only explorer for generic non-SDD work.",
802
825
  ),
803
826
  );
804
827
  });
@@ -806,7 +829,7 @@ test("forced package installation preserves an ordinary body edit to a managed a
806
829
  test("package model assignment keeps only package-managed agents owned", () => {
807
830
  const temporaryAgentHome = mkdtempSync(join(tmpdir(), "gentle-pi-model-ownership-"));
808
831
  const previousAgentHome = process.env.GENTLE_PI_AGENT_HOME;
809
- const installedRefuter = join(temporaryAgentHome, "agents", REVIEW_REFUTER_FILE);
832
+ const installedExemplar = join(temporaryAgentHome, "agents", MANAGED_EXEMPLAR_FILE);
810
833
  const userAgent = join(temporaryAgentHome, "agents", "user-router.md");
811
834
  const managedAssetsManifest = join(
812
835
  temporaryAgentHome,
@@ -821,14 +844,14 @@ test("package model assignment keeps only package-managed agents owned", () => {
821
844
  writeFileSync(userAgent, userAgentSource);
822
845
 
823
846
  applyModelConfig(PACKAGE_ROOT, {
824
- "review-refuter": { model: "package/selected-model", thinking: "high" },
847
+ "gentle-ai-explore": { model: "package/selected-model", thinking: "high" },
825
848
  "user-router": { model: "user/selected-model", thinking: "low" },
826
849
  });
827
850
 
828
- const routedRefuter = readFileSync(installedRefuter, "utf8");
851
+ const routedExemplar = readFileSync(installedExemplar, "utf8");
829
852
  const routedUserAgent = readFileSync(userAgent, "utf8");
830
- assert.match(routedRefuter, /^model: package\/selected-model$/m);
831
- assert.match(routedRefuter, /^thinking: high$/m);
853
+ assert.match(routedExemplar, /^model: package\/selected-model$/m);
854
+ assert.match(routedExemplar, /^thinking: high$/m);
832
855
  assert.match(routedUserAgent, /^model: user\/selected-model$/m);
833
856
  assert.match(routedUserAgent, /^thinking: low$/m);
834
857
 
@@ -836,8 +859,8 @@ test("package model assignment keeps only package-managed agents owned", () => {
836
859
  readFileSync(managedAssetsManifest, "utf8"),
837
860
  ) as ManagedAssetsManifest;
838
861
  assert.equal(
839
- manifest.assets[`agents/${REVIEW_REFUTER_FILE}`],
840
- sha256(routedRefuter),
862
+ manifest.assets[`agents/${MANAGED_EXEMPLAR_FILE}`],
863
+ sha256(routedExemplar),
841
864
  "package-controlled routing must update the managed asset hash coherently",
842
865
  );
843
866
  assert.equal(
@@ -848,8 +871,8 @@ test("package model assignment keeps only package-managed agents owned", () => {
848
871
 
849
872
  installSddAssets(PACKAGE_ROOT, true);
850
873
  assert.equal(
851
- readFileSync(installedRefuter, "utf8"),
852
- readFileSync(join(PACKAGE_ROOT, "assets", "agents", REVIEW_REFUTER_FILE), "utf8"),
874
+ readFileSync(installedExemplar, "utf8"),
875
+ readFileSync(join(PACKAGE_ROOT, "assets", "agents", MANAGED_EXEMPLAR_FILE), "utf8"),
853
876
  "a routed package-managed agent must remain eligible for package refresh",
854
877
  );
855
878
  assert.equal(
@@ -1137,18 +1160,21 @@ test("pi-pretty wrapper uses real package path resolution for pnpm symlink insta
1137
1160
  assert.match(wrapper, /quietToolsEnabled/);
1138
1161
  });
1139
1162
 
1140
- test("v2.1.2 release package and runtime stop before publication", () => {
1163
+ test("v2.2.0 release package and runtime stop before publication", () => {
1141
1164
  const packageJson = readPackageJson();
1142
- assert.equal(packageJson.version, "2.1.2", "the release manifest must remain explicitly pinned to v2.1.2");
1165
+ assert.equal(packageJson.version, "2.2.0", "the release manifest must remain explicitly pinned to v2.2.0");
1143
1166
  assert.equal(
1144
1167
  packageJson.scripts?.test,
1145
- "node --experimental-strip-types --test tests/*.test.ts && pnpm run test:harness",
1168
+ "node --experimental-strip-types --test tests/*.test.ts && pnpm run check:provider-contract && pnpm run test:harness",
1146
1169
  );
1147
1170
  assert.ok(packageJson.files?.includes("assets/"));
1148
1171
  assert.ok(packageJson.files?.includes("contracts/"));
1149
1172
 
1150
1173
  const verifier = readFileSync(join(PACKAGE_ROOT, "scripts", "verify-package-files.mjs"), "utf8");
1151
- assert.match(verifier, /assets\/agents\/review-refuter\.md/);
1174
+ // gentle-pi#311 P5: the retired adversarial role agents must not be pinned
1175
+ // as required package files, while the append-only migration history stays.
1176
+ assert.doesNotMatch(verifier, /assets\/agents\/review-refuter\.md/);
1177
+ assert.doesNotMatch(verifier, /assets\/agents\/review-validator\.md/);
1152
1178
  assert.match(verifier, /assets\/migrations\/managed-assets-v0\.13\.json/);
1153
1179
  assert.match(verifier, /assets\/migrations\/managed-assets-v0\.14\.json/);
1154
1180
 
@@ -1157,13 +1183,13 @@ test("v2.1.2 release package and runtime stop before publication", () => {
1157
1183
  assert.doesNotMatch(runtime, /execFileSync\("(?:npm|pnpm)", \["publish"/);
1158
1184
  });
1159
1185
 
1160
- test("bounded review keeps the Judgment Day skill contract at metadata version 1.4", () => {
1186
+ test("bounded review keeps the Judgment Day skill contract at canon metadata version 1.7", () => {
1161
1187
  const frontmatter = readAgentFrontmatter(
1162
1188
  join(PACKAGE_ROOT, "skills", "judgment-day", "SKILL.md"),
1163
1189
  );
1164
1190
 
1165
- assert.match(frontmatter, /^ version: "1\.4"$/m);
1166
- assert.doesNotMatch(frontmatter, /^ version: "1\.5"$/m);
1191
+ assert.match(frontmatter, /^ version: "1\.7"$/m);
1192
+ assert.doesNotMatch(frontmatter, /^ version: "1\.4"$/m);
1167
1193
  });
1168
1194
 
1169
1195
  test("README documents bounded review transactions and the honest installed permission boundary", () => {
@@ -1173,9 +1199,9 @@ test("README documents bounded review transactions and the honest installed perm
1173
1199
  "Native compact gate validation is read-only.",
1174
1200
  "Release from protected `main` may bypass receipt validation only when the tag targets the current immutable `origin/main` SHA, required CI for that exact SHA is successful, the remote head is rechecked before tag push, and no fresh risk evidence exists; otherwise release fails closed through native receipt validation.",
1175
1201
  "Dangerous-command safety remains independent and authoritative.",
1176
- "`review-refuter` uses exactly `read`, `grep`, and `find`",
1202
+ "Adversarial review roles (the refuter and the targeted validator) are never Pi-authored",
1177
1203
  "package-managed isolated installation",
1178
- "Project and user overrides may shadow the package asset",
1204
+ "Project and user overrides may shadow a package asset",
1179
1205
  ]) {
1180
1206
  assert.ok(readme.includes(clause), `README missing review v2 clause: ${clause}`);
1181
1207
  }