gentle-pi 3.7.0 → 4.1.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 (590) hide show
  1. package/README.md +155 -10
  2. package/assets/agents/gentle-ai-explore.md +13 -6
  3. package/assets/agents/gentle-ai-verify.md +27 -6
  4. package/assets/agents/gentle-ai-worker.md +13 -15
  5. package/assets/install-wizard/index.html +47 -0
  6. package/assets/install-wizard/wizard.css +1279 -0
  7. package/assets/install-wizard/wizard.js +951 -0
  8. package/assets/orchestrator-delegation.md +75 -169
  9. package/assets/orchestrator-memory.md +12 -26
  10. package/assets/orchestrator-prompts.md +48 -0
  11. package/assets/orchestrator-skills.md +1 -1
  12. package/assets/orchestrator-tracking.md +53 -0
  13. package/assets/orchestrator-verification.md +28 -0
  14. package/assets/orchestrator-writer.md +38 -0
  15. package/assets/orchestrator.md +30 -38
  16. package/assets/sounds/LICENSE.md +52 -0
  17. package/assets/sounds/attention.wav +0 -0
  18. package/assets/sounds/error.wav +0 -0
  19. package/assets/sounds/success.wav +0 -0
  20. package/assets/support/strict-tdd-verify.md +4 -266
  21. package/assets/support/strict-tdd.md +8 -360
  22. package/bin/engram-guard +9 -0
  23. package/bin/gentle-shell-install.mjs +302 -0
  24. package/bin/gentle-shell.mjs +956 -50
  25. package/contracts/review-provider-contract-mirror/provider-contract.lock.json +7 -7
  26. package/contracts/review-provider-contract-mirror/{v1.2.0 → v1.3.0}/bundle/manifest.json +2 -2
  27. package/contracts/review-provider-contract-mirror/{v1.2.0 → v1.3.0}/bundle/orchestration/pi.md +16 -4
  28. package/contracts/review-provider-contract-mirror/{v1.2.0 → v1.3.0}/generated/provider-capabilities.baseline.json +2 -2
  29. package/contracts/review-provider-contract-mirror/{v1.2.0 → v1.3.0}/generated/provider-roles.baseline.json +1 -1
  30. package/docs/bundled-install.md +397 -0
  31. package/docs/delegated-verification.md +27 -4
  32. package/docs/gentle-agents-activity.md +537 -0
  33. package/docs/gentle-shell-uninstall.md +136 -0
  34. package/docs/gentle-shell.md +165 -51
  35. package/docs/install-wizard.md +2040 -0
  36. package/docs/native-authority-architecture.md +3 -3
  37. package/docs/permission-modes.md +82 -0
  38. package/docs/prompt-history.md +280 -0
  39. package/docs/readme-reference.md +364 -231
  40. package/docs/render-cache-performance.md +28 -0
  41. package/docs/sound-notifications-proposal.md +191 -0
  42. package/docs/sound-notifications.md +114 -0
  43. package/docs/telemetry.md +1 -1
  44. package/docs/yolo-mode.md +86 -0
  45. package/extensions/child-context.ts +35 -0
  46. package/extensions/child-safety.ts +25 -0
  47. package/extensions/codegraph-tools.ts +18 -5
  48. package/extensions/gentle-agents.ts +1093 -326
  49. package/extensions/gentle-ai.ts +1636 -890
  50. package/extensions/gentle-herdr-activity.ts +81 -0
  51. package/extensions/gentle-notifications.ts +104 -0
  52. package/extensions/gentle-shell.ts +1619 -136
  53. package/extensions/gentle-stats.ts +101 -0
  54. package/extensions/gentle-todo.ts +126 -20
  55. package/extensions/history/atomic-write.ts +38 -0
  56. package/extensions/history/hide-prompts.ts +183 -0
  57. package/extensions/history/index.ts +1424 -0
  58. package/extensions/history/load-shared-history.ts +39 -0
  59. package/extensions/history/selector-helpers.ts +538 -0
  60. package/extensions/history/session-scan.ts +233 -0
  61. package/extensions/history/store.ts +1119 -0
  62. package/extensions/nan-provider.ts +6 -0
  63. package/extensions/pi-pretty.ts +39 -3
  64. package/extensions/quiet-tools.ts +254 -92
  65. package/extensions/resume-hint.ts +60 -0
  66. package/extensions/skill-registry.ts +191 -58
  67. package/extensions/startup-banner.ts +71 -33
  68. package/lib/agent-assets.ts +604 -0
  69. package/lib/agent-home.ts +10 -1
  70. package/lib/agent-model-resolution.ts +80 -0
  71. package/lib/agent-profile-pin.ts +12 -0
  72. package/lib/agent-profiles.ts +13 -3
  73. package/lib/agents-completion-delivery.ts +11 -3
  74. package/lib/agents-message-delivery.ts +181 -0
  75. package/lib/agents-messaging.ts +1 -1
  76. package/lib/agents-protocol.ts +99 -0
  77. package/lib/agents-runner.ts +180 -107
  78. package/lib/agents-view.ts +26 -3
  79. package/lib/agents-widget.ts +16 -9
  80. package/lib/append-system-prompt.ts +21 -0
  81. package/lib/auto-permission-classifier.ts +280 -0
  82. package/lib/auto-permission-runtime.ts +268 -0
  83. package/lib/background-jobs-tools.ts +202 -0
  84. package/lib/background-jobs.ts +253 -0
  85. package/lib/background-monitor.ts +154 -0
  86. package/lib/bounded-writer-admission.ts +220 -0
  87. package/lib/builtin-codemode-optout.ts +166 -0
  88. package/lib/card-content-policy.ts +85 -0
  89. package/lib/card-style-policy.ts +60 -0
  90. package/lib/child-context-files.ts +166 -0
  91. package/lib/child-package-injection.ts +62 -0
  92. package/lib/codemode-renderer.ts +195 -0
  93. package/lib/command-palette-catalog.ts +5 -10
  94. package/lib/command-palette.ts +25 -14
  95. package/lib/context-threshold.ts +26 -0
  96. package/lib/destructive-command-guard.ts +144 -0
  97. package/lib/gentle-ai-binary.ts +109 -4
  98. package/lib/gentle-ai-elapsed-store.ts +87 -0
  99. package/lib/gentle-ai-renderer.ts +196 -39
  100. package/lib/gentle-shell-bundled.ts +517 -0
  101. package/lib/gentle-shell-launcher.ts +89 -27
  102. package/lib/gentle-shell-resume-hint.ts +176 -0
  103. package/lib/gentle-shell-startup-flow.ts +54 -0
  104. package/lib/gentle-shell-startup-update.ts +92 -0
  105. package/lib/gentle-shell-uninstall.ts +840 -0
  106. package/lib/gentle-shell-update-panel.ts +231 -0
  107. package/lib/herdr-activity.ts +183 -0
  108. package/lib/history-capture-policy.ts +95 -0
  109. package/lib/inprocess-reviewer.ts +3 -0
  110. package/lib/jobs-sidebar-state.ts +20 -0
  111. package/lib/jobs-view.ts +161 -0
  112. package/lib/model-price-ratio.ts +83 -0
  113. package/lib/model-routing-authority.ts +5 -1
  114. package/lib/nan-provider.ts +249 -0
  115. package/lib/native-review-cli.ts +242 -180
  116. package/lib/notification-audio-native.ts +162 -0
  117. package/lib/notification-audio-windows.ts +399 -0
  118. package/lib/notification-audio.ts +332 -0
  119. package/lib/notification-customize.ts +241 -0
  120. package/lib/notification-events.ts +113 -0
  121. package/lib/notification-policy.ts +148 -0
  122. package/lib/notification-pulse-client.ts +367 -0
  123. package/lib/notification-pulse-protocol.ts +305 -0
  124. package/lib/notification-pulse-stream.ts +213 -0
  125. package/lib/notification-pulse-worker.ts +66 -0
  126. package/lib/notification-scheduler.ts +173 -0
  127. package/lib/notification-service.ts +202 -0
  128. package/lib/notification-ui.ts +87 -0
  129. package/lib/odd-phase-inference.ts +231 -0
  130. package/lib/odd-phase.ts +141 -0
  131. package/lib/orchestrator-alias.ts +20 -0
  132. package/lib/orchestrator-catalog.ts +79 -0
  133. package/lib/orchestrator-consultation.ts +61 -0
  134. package/lib/orchestrator-discovery.ts +49 -0
  135. package/lib/orchestrator-helper-consent.ts +122 -0
  136. package/lib/orchestrator-helper.ts +167 -0
  137. package/lib/orchestrator-message-card.ts +105 -0
  138. package/lib/orchestrator-presence.ts +115 -14
  139. package/lib/orchestrator-scope.ts +80 -0
  140. package/lib/orchestrator-state.ts +107 -0
  141. package/lib/orchestrator-tool-card.ts +280 -0
  142. package/lib/orchestrator-work-search.ts +218 -0
  143. package/lib/orchestrator-work.ts +79 -0
  144. package/lib/overlay-repaint.ts +26 -0
  145. package/lib/permission-mode-policy.ts +59 -0
  146. package/lib/pi-tui-keys.ts +53 -0
  147. package/lib/review-candidate-view-owner.ts +73 -21
  148. package/lib/review-candidate-view.ts +115 -27
  149. package/lib/review-compact-contract.ts +2 -2
  150. package/lib/review-host-relay.ts +7 -2
  151. package/lib/review-integration-v2.ts +100 -22
  152. package/lib/review-publication-gate.ts +1 -1
  153. package/lib/review-reminder-receipt.ts +48 -8
  154. package/lib/review-risk-assessment.ts +227 -56
  155. package/lib/review-sidebar-state.ts +224 -0
  156. package/lib/review-transaction.ts +72 -3
  157. package/lib/runtime-metrics-children.ts +1 -1
  158. package/lib/runtime-metrics-native.ts +3 -2
  159. package/lib/selection-engine.ts +527 -0
  160. package/lib/session-change-capture.ts +5 -4
  161. package/lib/session-changes.ts +27 -22
  162. package/lib/session-messaging-grants.ts +135 -0
  163. package/lib/session-profile-binding.ts +83 -0
  164. package/lib/session-profile-freeze.ts +266 -0
  165. package/lib/session-worktree-registry.ts +87 -9
  166. package/lib/shell-bar.ts +215 -30
  167. package/lib/shell-card.ts +287 -18
  168. package/lib/shell-changes-view.ts +42 -14
  169. package/lib/shell-changes.ts +86 -71
  170. package/lib/shell-prompt.ts +102 -6
  171. package/lib/shell-sidebar-layout.ts +83 -15
  172. package/lib/shell-sidebar.ts +15 -1
  173. package/lib/shell-todo.ts +84 -31
  174. package/lib/shell-usage-view.ts +9 -4
  175. package/lib/shell-usage.ts +70 -13
  176. package/lib/stats-collector.ts +381 -0
  177. package/lib/stats-view.ts +431 -0
  178. package/lib/status-timing-diagnostics.ts +201 -0
  179. package/lib/telemetry-trigger.ts +3 -1
  180. package/lib/theme-customization.ts +52 -0
  181. package/lib/vim-editor-adapter.ts +383 -0
  182. package/lib/vim-normal-engine.ts +154 -0
  183. package/lib/vim-operator-engine.ts +416 -0
  184. package/lib/vim-policy.ts +49 -0
  185. package/lib/vim-visual-engine.ts +107 -0
  186. package/lib/visual-customization-policy.ts +119 -0
  187. package/lib/visual-customize-view.ts +481 -0
  188. package/lib/visual-profiles.ts +228 -0
  189. package/lib/writer-surfaces.ts +162 -0
  190. package/lib/yolo-session-policy.ts +317 -0
  191. package/package.json +20 -8
  192. package/runtime/child-package-injection.mjs +63 -0
  193. package/runtime/gentle-ai-binary.mjs +109 -4
  194. package/runtime/gentle-shell-bundled.mjs +518 -0
  195. package/runtime/gentle-shell-launcher.mjs +87 -25
  196. package/runtime/gentle-shell-resume-hint.mjs +177 -0
  197. package/runtime/gentle-shell-startup-flow.mjs +55 -0
  198. package/runtime/gentle-shell-startup-update.mjs +93 -0
  199. package/runtime/gentle-shell-uninstall.mjs +841 -0
  200. package/runtime/gentle-shell-update-panel.mjs +232 -0
  201. package/runtime/native-review-cli.mjs +239 -177
  202. package/runtime/review-integration-v2.mjs +100 -22
  203. package/runtime/review-risk-assessment.mjs +225 -54
  204. package/runtime/status-timing-diagnostics.mjs +202 -0
  205. package/runtime/telemetry-trigger.mjs +3 -1
  206. package/scripts/bootstrap.cmd +255 -0
  207. package/scripts/bootstrap.sh +168 -0
  208. package/scripts/build-distribution.mjs +157 -0
  209. package/scripts/build-installer-bundles.mjs +136 -0
  210. package/scripts/build-runtime-modules.mjs +8 -0
  211. package/scripts/bundled-install.mjs +1308 -0
  212. package/scripts/bundled-wizard.mjs +399 -0
  213. package/scripts/check-types.mjs +4 -6
  214. package/scripts/gentle-ai-installer.mjs +83 -35
  215. package/scripts/install-gentle-ai.mjs +48 -1
  216. package/scripts/install-tui-mode-setting.mjs +10 -1
  217. package/scripts/install-wizard-preview.mjs +154 -0
  218. package/scripts/installer-downloads.mjs +648 -0
  219. package/scripts/installer-preflight.mjs +387 -0
  220. package/scripts/installer-probes.mjs +564 -0
  221. package/scripts/installer-runner.mjs +1102 -0
  222. package/scripts/installer-server.mjs +881 -0
  223. package/scripts/installer-windows-artifacts.json +15 -0
  224. package/scripts/installer-windows.mjs +752 -0
  225. package/scripts/main-channel.mjs +452 -0
  226. package/scripts/mirror-odd-routing.mjs +2 -2
  227. package/scripts/npm-pack-result.mjs +31 -0
  228. package/scripts/render-cache-performance-worker.mjs +205 -0
  229. package/scripts/render-cache-performance.mjs +115 -0
  230. package/scripts/run-test-suite.mjs +90 -0
  231. package/scripts/test-installer-acceptance.sh +161 -0
  232. package/scripts/test-packed-runner.mjs +54 -19
  233. package/scripts/types-baseline.json +2 -92
  234. package/scripts/verify-package-files.mjs +91 -38
  235. package/skills/branch-pr/SKILL.md +24 -52
  236. package/skills/chained-pr/SKILL.md +31 -15
  237. package/skills/chained-pr/references/chaining-details.md +31 -20
  238. package/skills/gentle-ai/SKILL.md +16 -21
  239. package/skills/issue-creation/SKILL.md +8 -2
  240. package/skills/issue-creation/references/delegated-workflow-actions.md +19 -0
  241. package/skills/work-unit-commits/SKILL.md +4 -3
  242. package/tests/agent-home.test.ts +56 -3
  243. package/tests/agent-model-resolution.test.ts +113 -0
  244. package/tests/agent-profiles.test.ts +30 -0
  245. package/tests/agent-risk-escalation.test.ts +123 -0
  246. package/tests/agents-completion-delivery.test.ts +17 -0
  247. package/tests/agents-fake-child.ts +2 -2
  248. package/tests/agents-message-delivery.test.ts +106 -0
  249. package/tests/agents-protocol.test.ts +97 -0
  250. package/tests/agents-queries.test.ts +9 -9
  251. package/tests/agents-runner-process.test.ts +31 -0
  252. package/tests/agents-runner.test.ts +467 -93
  253. package/tests/agents-view-thread-identity.test.ts +169 -0
  254. package/tests/agents-view.test.ts +8 -2
  255. package/tests/agents-widget.test.ts +154 -15
  256. package/tests/append-system-prompt-route.test.ts +160 -0
  257. package/tests/append-system-prompt.test.ts +46 -0
  258. package/tests/artifact-language.test.ts +19 -213
  259. package/tests/ask-user-question.test.ts +44 -1
  260. package/tests/asset-installation-runtime.test.ts +5 -16
  261. package/tests/auto-mode-invariants.test.ts +258 -0
  262. package/tests/auto-mode-sdk.test.ts +57 -0
  263. package/tests/auto-mode.test.ts +49 -0
  264. package/tests/auto-permission-classifier.test.ts +283 -0
  265. package/tests/auto-permission-runtime.test.ts +196 -0
  266. package/tests/autonomous-guard.test.ts +69 -1
  267. package/tests/background-cache-warming.test.ts +2 -1
  268. package/tests/background-jobs.test.ts +227 -0
  269. package/tests/background-monitor.test.ts +195 -0
  270. package/tests/background-subagents-default-mode.test.ts +28 -5
  271. package/tests/bounded-stop-contract.test.ts +85 -0
  272. package/tests/bounded-writer-admission.test.ts +146 -0
  273. package/tests/branch-pr-skill.test.ts +43 -0
  274. package/tests/bridge-wake-lifecycle.test.ts +129 -0
  275. package/tests/bridge-wake-rendering.test.ts +56 -0
  276. package/tests/build-distribution.test.ts +269 -0
  277. package/tests/builtin-codemode-optout.test.ts +242 -0
  278. package/tests/bundled-install.test.ts +1319 -0
  279. package/tests/bundled-wizard.test.ts +505 -0
  280. package/tests/card-content-policy.test.ts +68 -0
  281. package/tests/card-style-policy.test.ts +87 -0
  282. package/tests/chained-pr-skill.test.ts +124 -0
  283. package/tests/child-codegraph-bootstrap.test.ts +74 -0
  284. package/tests/child-context-files.test.ts +255 -0
  285. package/tests/child-package-entrypoints.test.ts +65 -0
  286. package/tests/child-package-injection.test.ts +74 -0
  287. package/tests/child-safety.test.ts +94 -0
  288. package/tests/child-web-package.test.ts +224 -0
  289. package/tests/codegraph-tools.test.ts +35 -0
  290. package/tests/codemode-rendering.test.ts +596 -0
  291. package/tests/command-palette.test.ts +43 -7
  292. package/tests/context-threshold.test.ts +31 -0
  293. package/tests/delegate-for-reason-contract.test.ts +327 -0
  294. package/tests/delegated-key-learnings-contract.test.ts +3 -78
  295. package/tests/destructive-command-guard.test.ts +84 -0
  296. package/tests/devbinary/native-review-parity.devtest.ts +171 -3
  297. package/tests/devbinary/non-git-subagent-bootstrap.devtest.ts +193 -0
  298. package/tests/devbinary/pi-host-relay.devtest.ts +173 -3
  299. package/tests/engram-safety.test.ts +288 -0
  300. package/tests/fixtures/stats/sessions/--work-alpha--/2026-09-28T10-00-00-000Z_aaa.jsonl +7 -0
  301. package/tests/fixtures/stats/sessions/--work-alpha--/2026-09-29T23-00-00-000Z_bbb.jsonl +3 -0
  302. package/tests/fixtures/stats/sessions/--work-alpha--/2026-09-30T08-00-00-000Z_ddd.jsonl +2 -0
  303. package/tests/fixtures/stats/sessions/--work-alpha--/2026-09-30T09-00-00-000Z_eee.jsonl +3 -0
  304. package/tests/fixtures/stats/sessions/--work-alpha--/run-1/session.jsonl +2 -0
  305. package/tests/fixtures/stats/sessions/--work-beta--/2026-09-01T12-00-00-000Z_ccc.jsonl +2 -0
  306. package/tests/fixtures/stats/user-pi/sessions/--work-alpha--/2026-09-28T10-00-00-000Z_aaa.jsonl +2 -0
  307. package/tests/fixtures/stats/user-pi/sessions/--work-alpha--/2026-09-29T23-00-00-000Z_bbb.jsonl +4 -0
  308. package/tests/fixtures/stats/user-pi/sessions/--work-gamma--/2026-09-20T09-00-00-000Z_fff.jsonl +3 -0
  309. package/tests/generic-agent-tools.test.ts +69 -0
  310. package/tests/gentle-agents.test.ts +2804 -346
  311. package/tests/gentle-ai-binary-isolation.test.ts +135 -0
  312. package/tests/gentle-ai-binary.test.ts +21 -4
  313. package/tests/gentle-ai-child-guards.test.ts +202 -0
  314. package/tests/gentle-ai-dev-binary-surfacing.test.ts +125 -15
  315. package/tests/gentle-ai-elapsed-store.test.ts +68 -0
  316. package/tests/gentle-ai-installer.test.ts +566 -62
  317. package/tests/gentle-ai-prompt-model-routing.test.ts +123 -0
  318. package/tests/gentle-ai-renderer.test.ts +493 -14
  319. package/tests/gentle-ai.test.ts +1427 -236
  320. package/tests/gentle-card-text.ts +2 -1
  321. package/tests/gentle-herdr-activity.test.ts +100 -0
  322. package/tests/gentle-notifications.test.ts +427 -0
  323. package/tests/gentle-shell-bin.test.ts +896 -115
  324. package/tests/gentle-shell-bundled.test.ts +1002 -0
  325. package/tests/gentle-shell-launcher.test.ts +333 -65
  326. package/tests/gentle-shell-resume-hint.test.ts +270 -0
  327. package/tests/gentle-shell-startup-flow.test.ts +75 -0
  328. package/tests/gentle-shell-startup-update.test.ts +85 -0
  329. package/tests/gentle-shell-uninstall.test.ts +978 -0
  330. package/tests/gentle-shell-update-panel.test.ts +158 -0
  331. package/tests/gentle-shell.test.ts +4216 -119
  332. package/tests/gentle-stats.test.ts +152 -0
  333. package/tests/gentle-theme.test.ts +4 -1
  334. package/tests/gentle-todo.test.ts +333 -10
  335. package/tests/herdr-activity.test.ts +243 -0
  336. package/tests/history-agent-home.test.ts +81 -0
  337. package/tests/history-atomic-write.test.ts +57 -0
  338. package/tests/history-capture-policy.test.ts +102 -0
  339. package/tests/history-child-guard.test.ts +70 -0
  340. package/tests/history-command-registration.test.ts +164 -0
  341. package/tests/history-dedupe-entries.test.ts +123 -0
  342. package/tests/history-delete-backfill.test.ts +190 -0
  343. package/tests/history-delete-confirm.test.ts +460 -0
  344. package/tests/history-dispatch.test.ts +180 -0
  345. package/tests/history-drain-hidden.test.ts +110 -0
  346. package/tests/history-drain-order.test.ts +98 -0
  347. package/tests/history-expanded-globals.test.ts +62 -0
  348. package/tests/history-gc.test.ts +832 -0
  349. package/tests/history-header-layout.test.ts +265 -0
  350. package/tests/history-hide-prompts.test.ts +275 -0
  351. package/tests/history-lazy-windowing.test.ts +508 -0
  352. package/tests/history-legacy-migrate-v2.test.ts +297 -0
  353. package/tests/history-load-shared-history.test.ts +53 -0
  354. package/tests/history-max-results-cap.test.ts +76 -0
  355. package/tests/history-multi-reader.test.ts +203 -0
  356. package/tests/history-off-path.test.ts +170 -0
  357. package/tests/history-openflow-integration.test.ts +173 -0
  358. package/tests/history-overlay-margin.test.ts +326 -0
  359. package/tests/history-preview-layout.test.ts +93 -0
  360. package/tests/history-registry.test.ts +143 -0
  361. package/tests/history-scope-delete.test.ts +411 -0
  362. package/tests/history-search-caret-keys.test.ts +142 -0
  363. package/tests/history-seed-bootstrap.test.ts +170 -0
  364. package/tests/history-seed-regen.test.ts +129 -0
  365. package/tests/history-selector-windowing.test.ts +94 -0
  366. package/tests/history-session-scan-directory.test.ts +87 -0
  367. package/tests/history-session-scan-extract.test.ts +583 -0
  368. package/tests/history-session-writer.test.ts +351 -0
  369. package/tests/history-store-paths.test.ts +79 -0
  370. package/tests/history-tombstone-exact.test.ts +139 -0
  371. package/tests/history-wheel-mouse.test.ts +242 -0
  372. package/tests/inprocess-reviewer.test.ts +49 -19
  373. package/tests/install-gentle-ai-failure.test.ts +69 -0
  374. package/tests/install-tui-mode-setting.test.ts +15 -0
  375. package/tests/install-wizard.test.ts +1223 -0
  376. package/tests/installer-bundles.test.ts +122 -0
  377. package/tests/installer-posix-bootstrap.test.ts +1201 -0
  378. package/tests/installer-preflight.test.ts +750 -0
  379. package/tests/installer-probes.test.ts +1106 -0
  380. package/tests/installer-runner.test.ts +2158 -0
  381. package/tests/installer-server.test.ts +1567 -0
  382. package/tests/installer-windows-bootstrap.test.ts +2410 -0
  383. package/tests/issue-creation-skill.test.ts +61 -0
  384. package/tests/jobs-view.test.ts +160 -0
  385. package/tests/main-channel-upgrade.test.ts +389 -0
  386. package/tests/main-channel.test.ts +344 -0
  387. package/tests/maintainer/provider-relay.maintest.ts +13 -12
  388. package/tests/model-price-ratio.test.ts +116 -0
  389. package/tests/model-profiles-preservation.test.ts +153 -0
  390. package/tests/model-routing-authority.test.ts +16 -0
  391. package/tests/model-routing-package.test.ts +10 -0
  392. package/tests/nan-provider-runtime.test.ts +156 -0
  393. package/tests/nan-provider.test.ts +481 -0
  394. package/tests/native-binary-gate.test.ts +2 -0
  395. package/tests/native-review-capability-contract.test.ts +13 -1
  396. package/tests/native-review-cli.test.ts +239 -118
  397. package/tests/native-review-consent.test.ts +2 -2
  398. package/tests/native-review-parity-runtime.test.ts +101 -4
  399. package/tests/native-review-parity.test.ts +12 -48
  400. package/tests/native-risk-evidence-parity.test.ts +21 -0
  401. package/tests/no-self-pause-contract.test.ts +87 -0
  402. package/tests/notification-audio-native.test.ts +281 -0
  403. package/tests/notification-audio-windows.test.ts +581 -0
  404. package/tests/notification-audio.test.ts +548 -0
  405. package/tests/notification-customize.test.ts +655 -0
  406. package/tests/notification-events.test.ts +115 -0
  407. package/tests/notification-policy.test.ts +201 -0
  408. package/tests/notification-pulse-client.test.ts +356 -0
  409. package/tests/notification-pulse-protocol.test.ts +213 -0
  410. package/tests/notification-pulse-stream.test.ts +320 -0
  411. package/tests/notification-scheduler.test.ts +258 -0
  412. package/tests/notification-ui.test.ts +157 -0
  413. package/tests/npm-pack-result.test.ts +41 -0
  414. package/tests/odd-integration.test.ts +76 -0
  415. package/tests/odd-phase-inference.test.ts +213 -0
  416. package/tests/odd-phase-loader.test.ts +253 -0
  417. package/tests/odd-phase.test.ts +307 -0
  418. package/tests/odd-routing-canonical-ratchet.test.ts +60 -14
  419. package/tests/odd-routing-contract.test.ts +158 -50
  420. package/tests/orchestrator-budget.test.ts +43 -45
  421. package/tests/orchestrator-catalog.test.ts +146 -0
  422. package/tests/orchestrator-consultation-sdk.test.ts +614 -0
  423. package/tests/orchestrator-consultation.test.ts +111 -0
  424. package/tests/orchestrator-discovery.test.ts +241 -0
  425. package/tests/orchestrator-helper-consent.test.ts +171 -0
  426. package/tests/orchestrator-helper.test.ts +297 -0
  427. package/tests/orchestrator-message-card.test.ts +190 -0
  428. package/tests/orchestrator-presence.test.ts +23 -0
  429. package/tests/orchestrator-rdd-ownership.test.ts +8 -7
  430. package/tests/orchestrator-scope.test.ts +107 -0
  431. package/tests/orchestrator-state.test.ts +114 -0
  432. package/tests/orchestrator-status-publication-contract.test.ts +34 -0
  433. package/tests/orchestrator-tool-card.test.ts +398 -0
  434. package/tests/orchestrator-work-search.test.ts +318 -0
  435. package/tests/orchestrator-work.test.ts +147 -0
  436. package/tests/overlay-repaint.test.ts +74 -0
  437. package/tests/package-manifest.test.ts +344 -123
  438. package/tests/packed-runner-owned-path.test.ts +80 -0
  439. package/tests/parallel-reason-contract.test.ts +21 -0
  440. package/tests/parallel-writer-admission.test.ts +210 -0
  441. package/tests/permission-mode-policy.test.ts +194 -0
  442. package/tests/persona-single-channel.test.ts +10 -18
  443. package/tests/pi-pretty.test.ts +56 -0
  444. package/tests/provider-defect-handoff.test.ts +7 -14
  445. package/tests/quiet-bash-runtime.test.ts +76 -0
  446. package/tests/quiet-tool-rendering.test.ts +569 -187
  447. package/tests/rdd-aware-verification-contract.test.ts +103 -40
  448. package/tests/rdd-status-line.test.ts +9 -4
  449. package/tests/render-cache-performance.test.ts +48 -0
  450. package/tests/resume-hint-extension.test.ts +122 -0
  451. package/tests/review-agent-end-preflight.test.ts +237 -21
  452. package/tests/review-candidate-owner-retry.test.ts +22 -1
  453. package/tests/review-candidate-view.test.ts +399 -12
  454. package/tests/review-contract-prompt.test.ts +138 -44
  455. package/tests/review-controller-lock-status.test.ts +0 -1
  456. package/tests/review-controller-native-recovery.test.ts +327 -17
  457. package/tests/review-controller-native-routing.test.ts +866 -6
  458. package/tests/review-controller-workspace-root.test.ts +206 -6
  459. package/tests/review-controller.test.ts +2 -2
  460. package/tests/review-correction-lifecycle.test.ts +2 -1
  461. package/tests/review-gate.test.ts +7 -4
  462. package/tests/review-graph-schema.test.ts +2 -2
  463. package/tests/review-host-relay-routing.test.ts +342 -4
  464. package/tests/review-host-relay.test.ts +49 -2
  465. package/tests/review-integration-v2-forward.test.ts +221 -1
  466. package/tests/review-json-arguments.test.ts +167 -0
  467. package/tests/review-last-event-closure.test.ts +157 -8
  468. package/tests/review-ledger-contract.test.ts +14 -37
  469. package/tests/review-policy-judgment-day.test.ts +1 -1
  470. package/tests/review-policy-ordinary.test.ts +2 -2
  471. package/tests/review-relay-transport-agent.test.ts +66 -1
  472. package/tests/review-reminder-receipt.test.ts +47 -1
  473. package/tests/review-risk-assessment.test.ts +594 -26
  474. package/tests/review-session-standing-permission-controller.test.ts +16 -17
  475. package/tests/review-session-standing-permission-ipc.test.ts +6 -5
  476. package/tests/review-sidebar-state.test.ts +402 -0
  477. package/tests/review-test-fixtures.ts +7 -1
  478. package/tests/review-transaction.test.ts +18 -1
  479. package/tests/run-test-suite.test.ts +202 -0
  480. package/tests/runtime-harness.mjs +186 -800
  481. package/tests/runtime-metrics-children.test.ts +16 -23
  482. package/tests/runtime-metrics-extension.test.ts +1 -1
  483. package/tests/runtime-metrics-native.test.ts +31 -1
  484. package/tests/selection-engine.test.ts +451 -0
  485. package/tests/session-change-capture.test.ts +10 -10
  486. package/tests/session-changes-shell.test.ts +242 -48
  487. package/tests/session-changes.test.ts +17 -24
  488. package/tests/session-messaging-grants.test.ts +255 -0
  489. package/tests/session-profile-binding.test.ts +163 -0
  490. package/tests/session-profile-freeze.test.ts +381 -0
  491. package/tests/session-subject-routing-contract.test.ts +34 -0
  492. package/tests/session-worktree-registry.test.ts +134 -2
  493. package/tests/shell-bar.test.ts +422 -1
  494. package/tests/shell-card.test.ts +353 -1
  495. package/tests/shell-changes-view.test.ts +135 -32
  496. package/tests/shell-changes.test.ts +61 -62
  497. package/tests/shell-prompt.test.ts +94 -2
  498. package/tests/shell-render-cache-runtime.test.ts +69 -0
  499. package/tests/shell-render-cache.test.ts +129 -0
  500. package/tests/shell-sidebar-layout.test.ts +351 -22
  501. package/tests/shell-sidebar-scroll-benchmark.test.ts +255 -0
  502. package/tests/shell-todo.test.ts +207 -3
  503. package/tests/shell-usage-view.test.ts +28 -1
  504. package/tests/shell-usage.test.ts +108 -0
  505. package/tests/short-check-routing-contract.test.ts +49 -0
  506. package/tests/skill-registry-watcher.test.ts +119 -0
  507. package/tests/skill-registry.test.ts +357 -2
  508. package/tests/startup-banner.test.ts +246 -4
  509. package/tests/startup-home-repo.test.ts +170 -0
  510. package/tests/stats-collector.test.ts +195 -0
  511. package/tests/stats-view.test.ts +202 -0
  512. package/tests/status-timing-diagnostics.test.ts +283 -0
  513. package/tests/support/orchestrator-modules.ts +19 -0
  514. package/tests/task-size-routing-contract.test.ts +241 -0
  515. package/tests/telemetry-trigger.test.ts +107 -20
  516. package/tests/test-strength-contract.test.ts +124 -0
  517. package/tests/theme-customization.test.ts +72 -0
  518. package/tests/verify-agent-contract.test.ts +90 -0
  519. package/tests/verify-first-launch-contract.test.ts +139 -0
  520. package/tests/verify-package-files.test.ts +56 -0
  521. package/tests/vim-editor-adapter-host-resolution.test.ts +37 -0
  522. package/tests/vim-editor-adapter.test.ts +804 -0
  523. package/tests/vim-normal-engine.test.ts +101 -0
  524. package/tests/vim-operator-engine.test.ts +215 -0
  525. package/tests/vim-policy.test.ts +19 -0
  526. package/tests/vim-visual-engine.test.ts +52 -0
  527. package/tests/visual-customization-policy.test.ts +139 -0
  528. package/tests/visual-customize-view.test.ts +696 -0
  529. package/tests/visual-profiles.test.ts +87 -0
  530. package/tests/writer-edit-surface-scope.test.ts +59 -2
  531. package/tests/writer-surfaces.test.ts +199 -0
  532. package/tests/yolo-customize.test.ts +271 -0
  533. package/tests/yolo-mode-runtime.test.ts +188 -0
  534. package/tests/yolo-mode.test.ts +289 -0
  535. package/tests/yolo-session-policy.test.ts +59 -0
  536. package/themes/Gentle.json +2 -1
  537. package/themes/Gentleman-Cute.json +2 -1
  538. package/themes/Gentleman-Sexy.json +2 -1
  539. package/assets/agents/sdd-apply.md +0 -159
  540. package/assets/agents/sdd-archive.md +0 -228
  541. package/assets/agents/sdd-design.md +0 -49
  542. package/assets/agents/sdd-explore.md +0 -48
  543. package/assets/agents/sdd-init.md +0 -56
  544. package/assets/agents/sdd-onboard.md +0 -52
  545. package/assets/agents/sdd-proposal.md +0 -64
  546. package/assets/agents/sdd-remediate.md +0 -37
  547. package/assets/agents/sdd-research.md +0 -49
  548. package/assets/agents/sdd-spec.md +0 -192
  549. package/assets/agents/sdd-status.md +0 -54
  550. package/assets/agents/sdd-tasks.md +0 -108
  551. package/assets/agents/sdd-verify.md +0 -124
  552. package/assets/chains/sdd-full.chain.md +0 -83
  553. package/assets/chains/sdd-plan.chain.md +0 -56
  554. package/assets/chains/sdd-verify.chain.md +0 -43
  555. package/assets/sdd-orchestrator-workflow.md +0 -319
  556. package/assets/support/sdd-status-contract.md +0 -77
  557. package/docs/assets/diagrams/sdd-cycle.svg +0 -14
  558. package/extensions/sdd-init.ts +0 -816
  559. package/lib/openspec-deltas.ts +0 -156
  560. package/lib/sdd-preflight.ts +0 -1066
  561. package/lib/sdd-research-capabilities.ts +0 -94
  562. package/lib/sdd-status.ts +0 -26
  563. package/tests/fixtures/legacy/sdd-research-v2.5.0.md +0 -54
  564. package/tests/fixtures/native-review-cli/v2.1.3/bind-sdd.json +0 -25
  565. package/tests/fixtures/v0.10.7/assets/agents/sdd-apply.md +0 -132
  566. package/tests/openspec-deltas.test.ts +0 -209
  567. package/tests/sdd-agent-tools.test.ts +0 -156
  568. package/tests/sdd-archive-replay.test.ts +0 -82
  569. package/tests/sdd-classical-continuation.test.ts +0 -74
  570. package/tests/sdd-execution-routing-contract.test.ts +0 -44
  571. package/tests/sdd-managed-runtime-settlement.test.ts +0 -155
  572. package/tests/sdd-native-managed-uptake.test.ts +0 -243
  573. package/tests/sdd-no-attempts-contract.test.ts +0 -15
  574. package/tests/sdd-odd-integration.test.ts +0 -33
  575. package/tests/sdd-optional-research.test.ts +0 -124
  576. package/tests/sdd-planning-routing-contract.test.ts +0 -45
  577. package/tests/sdd-preflight-rpc-input.test.ts +0 -125
  578. package/tests/sdd-preflight.test.ts +0 -541
  579. package/tests/sdd-research-capabilities.test.ts +0 -114
  580. package/tests/sdd-research-live.test.ts +0 -241
  581. package/tests/sdd-selection-transport.test.ts +0 -653
  582. package/tests/sdd-status.test.ts +0 -9
  583. package/tests/sdd-task-truth.test.ts +0 -43
  584. /package/contracts/review-provider-contract-mirror/{v1.2.0 → v1.3.0}/bundle/README.md +0 -0
  585. /package/contracts/review-provider-contract-mirror/{v1.2.0 → v1.3.0}/bundle/schemas/lens.schema.json +0 -0
  586. /package/contracts/review-provider-contract-mirror/{v1.2.0 → v1.3.0}/bundle/schemas/refuter.schema.json +0 -0
  587. /package/contracts/review-provider-contract-mirror/{v1.2.0 → v1.3.0}/bundle/schemas/targeted-validator.schema.json +0 -0
  588. /package/contracts/review-provider-contract-mirror/{v1.2.0 → v1.3.0}/bundle/vectors/lens.json +0 -0
  589. /package/contracts/review-provider-contract-mirror/{v1.2.0 → v1.3.0}/bundle/vectors/refuter.json +0 -0
  590. /package/contracts/review-provider-contract-mirror/{v1.2.0 → v1.3.0}/bundle/vectors/targeted-validator.json +0 -0
@@ -78,8 +78,8 @@ export const REVIEW_START_STATE = {
78
78
  const START_ACTIONS = ["created", "resumed", "closed", "blocked-scope-action"] ;
79
79
  const RISK_LEVELS = ["low", "medium", "high"] ;
80
80
  const REVIEW_LENSES = ["review-risk", "review-resilience", "review-readability", "review-reliability"] ;
81
- const RISK_REASON_CODES = ["configuration_change", "empty_content", "executable_change", "executable_mode", "hot_path", "large_change", "non_executable_only", "process_boundary", "process_scan_limit", "service_token", "shell_source"] ;
82
- const RISK_SIGNALS = ["auth", "update", "security", "payments", "permissions", "shell_process"] ;
81
+ const RISK_REASON_CODES = ["agent_escalation", "configuration_change", "dangerous_sink", "empty_content", "executable_change", "executable_mode", "hot_path", "large_change", "non_executable_only", "process_boundary", "process_scan_limit", "service_token", "shell_source"] ;
82
+ const RISK_SIGNALS = ["auth", "update", "security", "payments", "permissions", "shell_process", "dangerous_sink", "agent_escalation"] ;
83
83
  // "collect" and "execute" are the v2 envelope's projection of a live
84
84
  // transaction whose next_transition is mandatory: the root action names the
85
85
  // transition kind instead of reading as a terminal stop.
@@ -637,6 +637,23 @@ const ESCALATION_REFUTER_OUTCOMES = ["corroborated", "refuted", "inconclusive"]
637
637
 
638
638
 
639
639
 
640
+ function decodeReviewEscalationV1(value , label ) {
641
+ const source = exactRecord(value, label, ["cause", "finding_ids"], ["refuter_outcomes"]);
642
+ const escalation = {
643
+ cause: enumeration(source.cause, ESCALATION_CAUSES, `${label}.cause`),
644
+ findingIds: stringArray(source.finding_ids, `${label}.finding_ids`),
645
+ };
646
+ if (Object.hasOwn(source, "refuter_outcomes")) escalation.refuterOutcomes = array(source.refuter_outcomes, `${label}.refuter_outcomes`, (entry, itemLabel) => {
647
+ const row = exactRecord(entry, itemLabel, ["finding_id", "outcome", "proof"]);
648
+ return {
649
+ findingId: nonempty(row.finding_id, `${itemLabel}.finding_id`),
650
+ outcome: enumeration(row.outcome, ESCALATION_REFUTER_OUTCOMES, `${itemLabel}.outcome`),
651
+ proof: nonempty(row.proof, `${itemLabel}.proof`),
652
+ };
653
+ });
654
+ return escalation;
655
+ }
656
+
640
657
 
641
658
 
642
659
 
@@ -2105,23 +2122,9 @@ export function decodeReviewStatusV3(value ) {
2105
2122
  };
2106
2123
  }
2107
2124
 
2108
- let escalation ;
2109
- if (Object.hasOwn(body, "escalation")) {
2110
- const label = "status.escalation";
2111
- const source = exactRecord(body.escalation, label, ["cause", "finding_ids"], ["refuter_outcomes"]);
2112
- escalation = {
2113
- cause: enumeration(source.cause, ESCALATION_CAUSES, `${label}.cause`),
2114
- findingIds: stringArray(source.finding_ids, `${label}.finding_ids`),
2115
- };
2116
- if (Object.hasOwn(source, "refuter_outcomes")) escalation.refuterOutcomes = array(source.refuter_outcomes, `${label}.refuter_outcomes`, (entry, itemLabel) => {
2117
- const row = exactRecord(entry, itemLabel, ["finding_id", "outcome", "proof"]);
2118
- return {
2119
- findingId: nonempty(row.finding_id, `${itemLabel}.finding_id`),
2120
- outcome: enumeration(row.outcome, ESCALATION_REFUTER_OUTCOMES, `${itemLabel}.outcome`),
2121
- proof: nonempty(row.proof, `${itemLabel}.proof`),
2122
- };
2123
- });
2124
- }
2125
+ const escalation = Object.hasOwn(body, "escalation")
2126
+ ? decodeReviewEscalationV1(body.escalation, "status.escalation")
2127
+ : undefined;
2125
2128
 
2126
2129
  // status/v7 top-level optional digest (gentle-ai v2.6.0): resolves #4066's
2127
2130
  // closed loop where `sdd-attempt finish` named a digest status never
@@ -2584,7 +2587,11 @@ function assertReviewApprovedAcknowledgementExecuteShapeV1(execute
2584
2587
  if (execute.arguments.length !== REVIEW_APPROVED_ACKNOWLEDGEMENT_ARGUMENTS.length) throw new TypeError(`acknowledgement.execute.arguments must carry exactly ${REVIEW_APPROVED_ACKNOWLEDGEMENT_ARGUMENTS.length} provider-issued arguments`);
2585
2588
  const values = execute.arguments.map((argument, index) => { const name = REVIEW_APPROVED_ACKNOWLEDGEMENT_ARGUMENTS[index] ; if (argument.name !== name) throw new TypeError(`acknowledgement.execute.arguments[${index}].name must be ${name}`); const value = nonempty(argument.value, `acknowledgement.execute.arguments[${index}].value`); if (nonempty(argument.token, `acknowledgement.execute.arguments[${index}].token`) !== `--${name}=${value}`) throw new TypeError(`acknowledgement.execute.arguments[${index}].token must exactly match ${name}`); return value; });
2586
2589
  if (execute.preconditions.length !== 1 || execute.preconditions[0]?.name !== "state" || execute.preconditions[0]?.value !== "approved") throw new TypeError("acknowledgement.execute.preconditions must be the single approved state precondition");
2587
- return { tokens: execute.arguments.map((argument) => argument.token ) , values: values , lineageId: lineage(execute.binding.lineageId, "acknowledgement.execute.binding.lineage_id"), targetIdentity: sha256(execute.binding.targetIdentity, "acknowledgement.execute.binding.target_identity"), revision: sha256(execute.binding.revision, "acknowledgement.execute.binding.revision") };
2590
+ const tokens = execute.arguments.map((argument) => argument.token );
2591
+ // The exact five-argument check above validates both vectors before tuple construction.
2592
+ const tokenTuple = [tokens[0] , tokens[1] , tokens[2] , tokens[3] , tokens[4] ];
2593
+ const valueTuple = [values[0] , values[1] , values[2] , values[3] , values[4] ];
2594
+ return { tokens: tokenTuple, values: valueTuple, lineageId: lineage(execute.binding.lineageId, "acknowledgement.execute.binding.lineage_id"), targetIdentity: sha256(execute.binding.targetIdentity, "acknowledgement.execute.binding.target_identity"), revision: sha256(execute.binding.revision, "acknowledgement.execute.binding.revision") };
2588
2595
  }
2589
2596
 
2590
2597
  /**
@@ -2689,6 +2696,28 @@ const REVIEW_LAST_EVENT_CAUSAL_DISPOSITIONS = ["introduced", "behavior-activated
2689
2696
 
2690
2697
 
2691
2698
 
2699
+
2700
+
2701
+
2702
+
2703
+
2704
+
2705
+
2706
+
2707
+
2708
+
2709
+
2710
+
2711
+
2712
+
2713
+
2714
+
2715
+
2716
+
2717
+
2718
+
2719
+
2720
+
2692
2721
 
2693
2722
 
2694
2723
 
@@ -2836,18 +2865,67 @@ function decodeReviewLastEventReviewerResultV1(value , label )
2836
2865
  };
2837
2866
  }
2838
2867
 
2868
+ function decodeReviewTargetedValidatorCheckEvidenceV1(value , label ) {
2869
+ const check = exactRecord(value, label, ["passed", "evidence"], ["regressions"]);
2870
+ const regressions = Object.hasOwn(check, "regressions")
2871
+ ? array(check.regressions, `${label}.regressions`, (entry, entryLabel) => {
2872
+ const row = exactRecord(entry, entryLabel, ["location", "claim", "proof_refs"], ["id"]);
2873
+ return {
2874
+ ...(Object.hasOwn(row, "id") ? { id: nonempty(row.id, `${entryLabel}.id`) } : {}),
2875
+ location: nonempty(row.location, `${entryLabel}.location`),
2876
+ claim: nonempty(row.claim, `${entryLabel}.claim`),
2877
+ proofRefs: stringArray(row.proof_refs, `${entryLabel}.proof_refs`, { minimum: 1 }),
2878
+ };
2879
+ }) : undefined;
2880
+ return {
2881
+ passed: boolean(check.passed, `${label}.passed`),
2882
+ // Native admission rejects observations containing only Unicode whitespace.
2883
+ evidence: stringArray(check.evidence, `${label}.evidence`, { minimum: 1, pattern: /[^\p{White_Space}]/u }),
2884
+ ...(regressions === undefined ? {} : { regressions }),
2885
+ };
2886
+ }
2887
+
2888
+ function decodeReviewTargetedValidatorEvidenceV1(value , label ) {
2889
+ const body = exactRecord(value, label, ["targeted_validation_request_hash", "correction_target_identity", "original_criteria", "correction_regression", "follow_ups"]);
2890
+ return {
2891
+ targetedValidationRequestHash: sha256(body.targeted_validation_request_hash, `${label}.targeted_validation_request_hash`),
2892
+ correctionTargetIdentity: sha256(body.correction_target_identity, `${label}.correction_target_identity`),
2893
+ originalCriteria: decodeReviewTargetedValidatorCheckEvidenceV1(body.original_criteria, `${label}.original_criteria`),
2894
+ correctionRegression: decodeReviewTargetedValidatorCheckEvidenceV1(body.correction_regression, `${label}.correction_regression`),
2895
+ followUps: array(body.follow_ups, `${label}.follow_ups`, (entry, entryLabel) => {
2896
+ const row = exactRecord(entry, entryLabel, ["observation", "proof_refs"]);
2897
+ return { observation: nonempty(row.observation, `${entryLabel}.observation`), proofRefs: stringArray(row.proof_refs, `${entryLabel}.proof_refs`, { minimum: 1 }) };
2898
+ }),
2899
+ raw: body,
2900
+ };
2901
+ }
2902
+
2839
2903
  export function decodeReviewLastEventClosureV1(value ) {
2840
- const body = exactRecord(value, "last_event_closure", ["schema", "operation", "lineage_id", "state", "store_revision"], ["target_identity", "request_hash", "correction_lines", "action", "advisory_findings", "reviewer_results", "status_continuation", "acknowledgement"]);
2904
+ const body = exactRecord(value, "last_event_closure", ["schema", "operation", "lineage_id", "state", "store_revision"], ["target_identity", "request_hash", "correction_lines", "action", "escalation", "targeted_validator_evidence", "advisory_findings", "reviewer_results", "status_continuation", "acknowledgement"]);
2841
2905
  if (body.schema !== REVIEW_LAST_EVENT_CLOSURE_SCHEMA) throw new TypeError(`last_event_closure.schema must be ${REVIEW_LAST_EVENT_CLOSURE_SCHEMA}`);
2842
2906
  const operation = enumeration(body.operation, Object.values(REVIEW_LAST_EVENT_CLOSURE_OPERATION), "last_event_closure.operation") ;
2843
2907
  const state = enumeration(body.state, REVIEW_LAST_EVENT_TERMINAL_STATES, "last_event_closure.state") ;
2908
+ if (Object.hasOwn(body, "targeted_validator_evidence") && (operation !== REVIEW_LAST_EVENT_CLOSURE_OPERATION.CAPTURE_VALIDATION || state !== "escalated")) {
2909
+ throw new TypeError("last_event_closure targeted_validator_evidence requires escalated review/capture-validation");
2910
+ }
2911
+ // Diagnostic evidence is optional for older providers and never controls terminal authority.
2912
+ const targetedValidatorEvidence = Object.hasOwn(body, "targeted_validator_evidence")
2913
+ ? decodeReviewTargetedValidatorEvidenceV1(body.targeted_validator_evidence, "last_event_closure.targeted_validator_evidence")
2914
+ : undefined;
2915
+ if (Object.hasOwn(body, "escalation") && state !== "escalated") throw new TypeError("last_event_closure escalation requires escalated state");
2916
+ // Older native closures omit this diagnostic; its presence never grants a continuation.
2917
+ const escalation = Object.hasOwn(body, "escalation")
2918
+ ? decodeReviewEscalationV1(body.escalation, "last_event_closure.escalation")
2919
+ : undefined;
2844
2920
  const shared = {
2845
2921
  schema: REVIEW_LAST_EVENT_CLOSURE_SCHEMA,
2846
2922
  operation,
2847
2923
  lineageId: lineage(body.lineage_id, "last_event_closure.lineage_id"),
2848
2924
  state,
2849
2925
  storeRevision: sha256(body.store_revision, "last_event_closure.store_revision"),
2850
- };
2926
+ ...(escalation === undefined ? {} : { escalation }),
2927
+ ...(targetedValidatorEvidence === undefined ? {} : { targetedValidatorEvidence }),
2928
+ } ;
2851
2929
  if (operation === REVIEW_LAST_EVENT_CLOSURE_OPERATION.CAPTURE_CORRECTION_PLAN) {
2852
2930
  if (body.reviewer_results !== undefined) throw new TypeError("last_event_closure reviewer_results requires approved state");
2853
2931
  if (body.action !== undefined || body.advisory_findings !== undefined || body.status_continuation !== undefined) throw new TypeError("last_event_closure correction-plan cannot carry action, advisory_findings, or status_continuation");
@@ -11,6 +11,11 @@
11
11
  // prints `{"schema":"gentle-ai.review-assessment/v1","risk":"passive|medium|high",
12
12
  // "reasons":[{"code":"…","path":"…","detail":"…"}],"changed_paths":1,
13
13
  // "changed_lines":1,"candidate":{"kind":"current-changes|base-diff","base_ref":"…"}}`.
14
+ // gentle-pi#1175: the native v2 `assess.schema.json` requires only `code` on a
15
+ // reason (`path`/`detail` are optional) and adds `candidate.consumed`,
16
+ // `review_due`, `review_due_reason`, and an opaque `next_transition`. Older
17
+ // binaries (for example gentle-ai v3.7.0) predate those fields, so
18
+ // they decode as optional and stay absent rather than being defaulted.
14
19
  // A non-zero exit or a failure envelope means the candidate could not be
15
20
  // assessed; hosts treat that as `high`. Older binaries without the verb (or
16
21
  // any other decode/process failure) fail closed the same way -- see
@@ -31,6 +36,41 @@ export const REVIEW_ASSESSMENT_CANDIDATE_KIND = {
31
36
  } ;
32
37
 
33
38
 
39
+ export const REVIEW_DUE_REASON = {
40
+ HIGH_RISK: "high_risk",
41
+ SLICE_BUDGET_REACHED: "slice_budget_reached",
42
+ PASSIVE: "passive",
43
+ UNDER_BUDGET: "under_budget",
44
+ ALREADY_REVIEWED: "already_reviewed",
45
+ } ;
46
+
47
+
48
+ export const REVIEW_ASSESSMENT_NEXT_TRANSITION_OPERATION = "review.status" ;
49
+
50
+
51
+
52
+
53
+
54
+
55
+
56
+
57
+
58
+
59
+
60
+
61
+
62
+
63
+
64
+
65
+
66
+
67
+
68
+
69
+ /**
70
+ * The native, literally runnable `review status ... --next-transition`
71
+ * preflight continuation. Carried verbatim as an opaque value: hosts never
72
+ * rebuild, reorder, or synthesize it.
73
+ */
34
74
 
35
75
 
36
76
 
@@ -55,25 +95,104 @@ function isRecord(value ) {
55
95
  return typeof value === "object" && value !== null && !Array.isArray(value);
56
96
  }
57
97
 
98
+ function isNonEmptyString(value ) {
99
+ return typeof value === "string" && value.length > 0;
100
+ }
101
+
58
102
  function decodeReason(value ) {
59
103
  if (!isRecord(value)) throw new TypeError("review assessment reason must be an object");
60
104
  const { code, path, detail } = value;
61
- if (typeof code !== "string" || code.length === 0) throw new TypeError("review assessment reason.code must be a non-empty string");
62
- if (typeof path !== "string") throw new TypeError("review assessment reason.path must be a string");
63
- if (typeof detail !== "string") throw new TypeError("review assessment reason.detail must be a string");
64
- return Object.freeze({ code, path, detail });
105
+ if (!isNonEmptyString(code)) throw new TypeError("review assessment reason.code must be a non-empty string");
106
+ if (path !== undefined && !isNonEmptyString(path)) throw new TypeError("review assessment reason.path must be a non-empty string when present");
107
+ if (detail !== undefined && !isNonEmptyString(detail)) throw new TypeError("review assessment reason.detail must be a non-empty string when present");
108
+ // Absent path/detail stay absent: never synthesized (gentle-pi#1175).
109
+ return Object.freeze({
110
+ code,
111
+ ...(path === undefined ? {} : { path: path }),
112
+ ...(detail === undefined ? {} : { detail: detail }),
113
+ });
65
114
  }
66
115
 
67
116
  function decodeCandidate(value ) {
68
117
  if (!isRecord(value)) throw new TypeError("review assessment candidate must be an object");
69
- const { kind, base_ref: baseRef } = value;
118
+ const { kind, base_ref: baseRef, consumed } = value;
70
119
  if (kind !== REVIEW_ASSESSMENT_CANDIDATE_KIND.CURRENT_CHANGES && kind !== REVIEW_ASSESSMENT_CANDIDATE_KIND.BASE_DIFF) {
71
120
  throw new TypeError("review assessment candidate.kind must be current-changes or base-diff");
72
121
  }
73
- if (baseRef !== undefined && (typeof baseRef !== "string" || baseRef.length === 0)) {
122
+ if (baseRef !== undefined && !isNonEmptyString(baseRef)) {
74
123
  throw new TypeError("review assessment candidate.base_ref must be a non-empty string when present");
75
124
  }
76
- return Object.freeze({ kind, baseRef: baseRef });
125
+ if (consumed !== undefined && typeof consumed !== "boolean") {
126
+ throw new TypeError("review assessment candidate.consumed must be a boolean when present");
127
+ }
128
+ // An older binary omits consumed; it stays absent, never defaulted.
129
+ return Object.freeze({ kind, baseRef: baseRef , ...(consumed === undefined ? {} : { consumed: consumed }) });
130
+ }
131
+
132
+ function isReviewDueReason(value ) {
133
+ return Object.values(REVIEW_DUE_REASON).includes(value );
134
+ }
135
+
136
+ // The native schema fixes review_due by reason: due for high_risk and
137
+ // slice_budget_reached, not due for passive, under_budget, and
138
+ // already_reviewed (gentle-pi#1175).
139
+ const DUE_REVIEW_REASONS = [REVIEW_DUE_REASON.HIGH_RISK, REVIEW_DUE_REASON.SLICE_BUDGET_REACHED];
140
+
141
+ /**
142
+ * Rejects a review_due/review_due_reason/consumed combination the native
143
+ * schema can never produce. A consumed candidate must report
144
+ * `already_reviewed`, but that reason can also describe an acknowledged
145
+ * committed predecessor followed by a passive delta (#1954). It does not
146
+ * prove this exact candidate was consumed; preserve native's explicit false.
147
+ * Native v2 requires consumed, so missing evidence with already_reviewed is
148
+ * still rejected. Envelopes without the pair (older binaries) are unchecked.
149
+ */
150
+ function validateReviewDueConsistency(reviewDue , reviewDueReason , candidate ) {
151
+ if (reviewDue !== DUE_REVIEW_REASONS.includes(reviewDueReason)) {
152
+ throw new TypeError(`review assessment review_due ${reviewDue} contradicts review_due_reason ${reviewDueReason}`);
153
+ }
154
+ const alreadyReviewed = reviewDueReason === REVIEW_DUE_REASON.ALREADY_REVIEWED;
155
+ if (candidate.consumed === true && !alreadyReviewed) {
156
+ throw new TypeError("review assessment candidate.consumed true requires review_due_reason already_reviewed");
157
+ }
158
+ if (alreadyReviewed && candidate.consumed === undefined) {
159
+ throw new TypeError("review assessment review_due_reason already_reviewed requires explicit candidate.consumed evidence");
160
+ }
161
+ }
162
+
163
+ function hasOnlyKeys(value , allowed ) {
164
+ return Object.keys(value).every((key) => allowed.includes(key));
165
+ }
166
+
167
+ function validateNextTransitionArgument(value ) {
168
+ if (!isRecord(value) || !hasOnlyKeys(value, ["name", "value", "token"])) {
169
+ throw new TypeError("review assessment next_transition argument must be an object with only name, value, and token");
170
+ }
171
+ if (!isNonEmptyString(value.name)) throw new TypeError("review assessment next_transition argument name must be a non-empty string");
172
+ if (typeof value.value !== "string") throw new TypeError("review assessment next_transition argument value must be a string");
173
+ if (value.token !== undefined && !isNonEmptyString(value.token)) {
174
+ throw new TypeError("review assessment next_transition argument token must be a non-empty string when present");
175
+ }
176
+ }
177
+
178
+ /**
179
+ * Validates `next_transition` exactly as the native schema declares it and
180
+ * returns the native value itself, frozen -- validated, never rebuilt,
181
+ * reordered, or synthesized (gentle-pi#1175).
182
+ */
183
+ function decodeNextTransition(value ) {
184
+ if (!isRecord(value) || !hasOnlyKeys(value, ["operation", "command", "arguments"])) {
185
+ throw new TypeError("review assessment next_transition must be an object with only operation, command, and arguments");
186
+ }
187
+ if (value.operation !== REVIEW_ASSESSMENT_NEXT_TRANSITION_OPERATION) {
188
+ throw new TypeError(`review assessment next_transition.operation must be ${REVIEW_ASSESSMENT_NEXT_TRANSITION_OPERATION}`);
189
+ }
190
+ if (!isNonEmptyString(value.command)) throw new TypeError("review assessment next_transition.command must be a non-empty string");
191
+ if (!Array.isArray(value.arguments)) throw new TypeError("review assessment next_transition.arguments must be an array");
192
+ for (const argument of value.arguments) validateNextTransitionArgument(argument);
193
+ for (const argument of value.arguments) Object.freeze(argument);
194
+ Object.freeze(value.arguments);
195
+ return Object.freeze(value) ;
77
196
  }
78
197
 
79
198
  /**
@@ -82,24 +201,55 @@ function decodeCandidate(value ) {
82
201
  * native review CLI wrapper turns a thrown error here into the same
83
202
  * schema-incompatible failure it already produces for every other decoded
84
203
  * native response.
204
+ *
205
+ * `review_due` and `review_due_reason` were added together natively: both
206
+ * absent (an older binary) or both present are accepted; only one of them is
207
+ * rejected. When present, the pair must agree with each other and with
208
+ * `candidate.consumed` (see `validateReviewDueConsistency`).
209
+ * `next_transition` is accepted only alongside `review_due: true`.
210
+ * Unknown extra top-level fields are ignored and never projected, so a newer
211
+ * binary stays decodable (gentle-pi#1175).
85
212
  */
86
213
  export function decodeReviewAssessmentV1(value ) {
87
214
  if (!isRecord(value)) throw new TypeError("review assessment must be an object");
88
215
  if (value.schema !== REVIEW_ASSESSMENT_SCHEMA) throw new TypeError(`review assessment schema must be ${REVIEW_ASSESSMENT_SCHEMA}`);
89
- const { risk, reasons, changed_paths: changedPaths, changed_lines: changedLines, candidate } = value;
216
+ const {
217
+ risk,
218
+ reasons,
219
+ changed_paths: changedPaths,
220
+ changed_lines: changedLines,
221
+ candidate,
222
+ review_due: reviewDue,
223
+ review_due_reason: reviewDueReason,
224
+ next_transition: nextTransition,
225
+ } = value;
90
226
  if (risk !== REVIEW_ASSESSMENT_RISK.PASSIVE && risk !== REVIEW_ASSESSMENT_RISK.MEDIUM && risk !== REVIEW_ASSESSMENT_RISK.HIGH) {
91
227
  throw new TypeError("review assessment risk must be passive, medium, or high");
92
228
  }
93
229
  if (!Array.isArray(reasons)) throw new TypeError("review assessment reasons must be an array");
94
230
  if (!Number.isSafeInteger(changedPaths) || (changedPaths ) < 0) throw new TypeError("review assessment changed_paths must be a non-negative integer");
95
231
  if (!Number.isSafeInteger(changedLines) || (changedLines ) < 0) throw new TypeError("review assessment changed_lines must be a non-negative integer");
232
+ if ((reviewDue === undefined) !== (reviewDueReason === undefined)) {
233
+ throw new TypeError("review assessment review_due and review_due_reason must be both present or both absent");
234
+ }
235
+ if (reviewDue !== undefined && typeof reviewDue !== "boolean") throw new TypeError("review assessment review_due must be a boolean when present");
236
+ if (reviewDueReason !== undefined && !isReviewDueReason(reviewDueReason)) {
237
+ throw new TypeError(`review assessment review_due_reason must be one of ${Object.values(REVIEW_DUE_REASON).join(", ")}`);
238
+ }
239
+ if (nextTransition !== undefined && reviewDue !== true) {
240
+ throw new TypeError("review assessment next_transition is only valid when review_due is true");
241
+ }
242
+ const decodedCandidate = decodeCandidate(candidate);
243
+ if (reviewDue !== undefined) validateReviewDueConsistency(reviewDue , reviewDueReason , decodedCandidate);
96
244
  return Object.freeze({
97
245
  schema: REVIEW_ASSESSMENT_SCHEMA,
98
246
  risk,
99
247
  reasons: Object.freeze(reasons.map(decodeReason)),
100
248
  changedPaths: changedPaths ,
101
249
  changedLines: changedLines ,
102
- candidate: decodeCandidate(candidate),
250
+ candidate: decodedCandidate,
251
+ ...(reviewDue === undefined ? {} : { reviewDue: reviewDue , reviewDueReason: reviewDueReason }),
252
+ ...(nextTransition === undefined ? {} : { nextTransition: decodeNextTransition(nextTransition) }),
103
253
  });
104
254
  }
105
255
 
@@ -115,6 +265,53 @@ export const VERIFICATION_TIER = {
115
265
  } ;
116
266
 
117
267
 
268
+ // ---------------------------------------------------------------------------
269
+ // Agent-raised risk (gentle-shell#1494). The agent that made the change may
270
+ // raise its risk to high by citing one item of the high-risk list in the
271
+ // always-on Task Size section; it can never lower a tier. Lowering stays with
272
+ // the deterministic native assessment.
273
+ // ---------------------------------------------------------------------------
274
+
275
+ export const HIGH_RISK_ITEMS = Object.freeze({
276
+ 1: "data or irreversible effects",
277
+ 2: "security",
278
+ 3: "changing or removing contracts others already consume",
279
+ 4: "concurrency",
280
+ 5: "delivery or environment",
281
+ 6: "no test would catch a regression",
282
+ } );
283
+
284
+
285
+
286
+
287
+
288
+
289
+
290
+ export const AGENT_RISK_ESCALATION_REASON_MAX = 500;
291
+
292
+ export function decodeAgentRiskEscalation(value ) {
293
+ if (value === null || typeof value !== "object" || Array.isArray(value)) {
294
+ throw new Error("escalate must be an object with item and reason");
295
+ }
296
+ const record = value ;
297
+ const unexpected = Object.keys(record).find((key) => key !== "item" && key !== "reason");
298
+ if (unexpected !== undefined) throw new Error(`escalate does not accept ${unexpected}`);
299
+ const { item, reason } = record;
300
+ if (typeof item !== "number" || !Number.isInteger(item) || !(item in HIGH_RISK_ITEMS)) {
301
+ throw new Error("escalate item must be an integer from 1 to 6 naming a high-risk item");
302
+ }
303
+ if (typeof reason !== "string" || reason.trim() === "" || reason.length > AGENT_RISK_ESCALATION_REASON_MAX) {
304
+ throw new Error(`escalate reason must be a non-empty string of at most ${AGENT_RISK_ESCALATION_REASON_MAX} characters`);
305
+ }
306
+ return Object.freeze({ item: item , reason });
307
+ }
308
+
309
+ /** Raises passive or medium to high when the agent escalated; never lowers. */
310
+ export function escalatedRisk(risk , escalation ) {
311
+ if (escalation === undefined) return risk;
312
+ return risk === VERIFICATION_TIER.PASSIVE || risk === VERIFICATION_TIER.MEDIUM ? VERIFICATION_TIER.HIGH : risk;
313
+ }
314
+
118
315
  export const RDD_LINE = {
119
316
  ON: "on",
120
317
  OFF: "off",
@@ -219,59 +416,33 @@ function nonClosedOutcomeClause(outcome ) {
219
416
  }
220
417
 
221
418
  /**
222
- * Computes who verifies a delegated writer's change, exactly as
223
- * gentle-pi#662/#668 specify:
419
+ * Computes who verifies a delegated writer's change. Verification follows the
420
+ * native risk tier whatever the RDD line and native review outcome
421
+ * (verify-always-rdd-high S1, superseding the gentle-pi#662/#668 on-path): the
422
+ * native review is an additional outside view and never replaces or skips the
423
+ * tier's verification. `nativeReviewOutcome` only shapes the reason text.
224
424
  *
225
- * - `rdd: "on"` AND the native review reached `NATIVE_REVIEW_OUTCOME.CLOSED`
226
- * for this candidate: the writer self-verifies and no independent verifier
227
- * runs, because the closed native review is the check -- except `passive`,
228
- * which gets a structural readback by the parent instead.
229
- * - `rdd: "on"` with any other outcome (`declined`, `unavailable`, or the
230
- * fail-closed `unknown` default for an omitted/unrecognized outcome): the
231
- * `on` branch never held for this candidate, so the risk-gated path below
232
- * applies exactly as `off` -- declining a review is candidate-scoped and
233
- * never lowers the bar below the RDD-off path.
234
- * - `rdd: "off"` or `"unknown"` (both gate identically, so an unknown RDD line
235
- * never lowers a tier relative to `off`; `nativeReviewOutcome` is ignored
236
- * entirely on these lines):
237
- * - `passive`: structural readback by the parent only; no verifier, no
238
- * tests.
239
- * - `medium`: the writer self-verifies; a separate independent verifier
240
- * runs only when `writerProfile` is `"small"` -- the small-model bias
241
- * raises the tier by one for verification purposes (medium -> high). An
242
- * unknown or omitted writer profile resolves to `"small"` before it
243
- * reaches this function (see `resolveWriterProfile`), so an unrecognized
244
- * profile never lowers a tier below what a known small model would get.
245
- * - `high` or `unassessable` (a failed or unrecognized native assessment is
246
- * always treated as high): the writer self-verifies and an independent
247
- * verifier always runs.
425
+ * - `passive`: structural readback by the parent only; no verifier, no tests.
426
+ * - `medium`: the writer self-verifies; a separate independent verifier runs
427
+ * only when `writerProfile` is `"small"` -- the small-model bias raises the
428
+ * tier by one for verification purposes (medium -> high). An unknown or
429
+ * omitted writer profile resolves to `"small"` before it reaches this
430
+ * function (see `resolveWriterProfile`), so an unrecognized profile never
431
+ * lowers a tier below what a known small model would get.
432
+ * - `high` or `unassessable` (a failed or unrecognized native assessment is
433
+ * always treated as high): the writer self-verifies and an independent
434
+ * verifier always runs.
248
435
  */
249
436
  export function verificationPlan(input ) {
250
437
  const { rddLine, risk, writerProfile } = input;
251
438
 
252
439
  if (rddLine === RDD_LINE.ON) {
253
440
  const outcome = input.nativeReviewOutcome ?? NATIVE_REVIEW_OUTCOME.UNKNOWN;
254
- if (outcome === NATIVE_REVIEW_OUTCOME.CLOSED) {
255
- if (risk === VERIFICATION_TIER.PASSIVE) {
256
- return Object.freeze({
257
- writerSelfVerification: false,
258
- structuralReadbackOnly: true,
259
- independentVerifier: false,
260
- reason: "receipt-driven development is on and the native review closed for this candidate; the assessment also reports passive risk: a structural readback by the parent replaces both the writer's self-verification and any separate verifier.",
261
- });
262
- }
263
- return Object.freeze({
264
- writerSelfVerification: true,
265
- structuralReadbackOnly: false,
266
- independentVerifier: false,
267
- reason: "receipt-driven development is on and the native review closed for this candidate: the writer's self-verification is the record and the closed native review was the independent check the writer cannot influence, so no separate verifier is required.",
268
- });
269
- }
270
- // The on branch holds only while the native review reaches a terminal
271
- // outcome for this candidate. Anything else -- declined, unavailable, or
272
- // unknown -- falls back to the exact same risk-gated path as off.
441
+ const clause = outcome === NATIVE_REVIEW_OUTCOME.CLOSED
442
+ ? "the native review closed for this candidate"
443
+ : nonClosedOutcomeClause(outcome);
273
444
  return riskGatedPlan(
274
- `receipt-driven development is on, but ${nonClosedOutcomeClause(outcome)}, so the risk-gated path applies exactly as receipt-driven development off, and`,
445
+ `receipt-driven development is on and ${clause}; the native review is an additional outside view that never replaces verification, so the risk-gated path applies exactly as receipt-driven development off, and`,
275
446
  risk,
276
447
  writerProfile,
277
448
  );