pi-lens 4.2.1 → 4.4.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 (671) hide show
  1. package/CHANGELOG.md +1562 -0
  2. package/README.md +157 -24
  3. package/config/dependency-cruiser-eager-allowlist.json +6 -2
  4. package/dist/chunk-22AVIGXS.js +560 -0
  5. package/dist/chunk-27BBHSZC.js +106 -0
  6. package/dist/chunk-2BEMIWEW.js +51 -0
  7. package/dist/chunk-2EECBNC5.js +89 -0
  8. package/dist/chunk-34U7PLGE.js +23 -0
  9. package/dist/chunk-3I5QFT3N.js +181 -0
  10. package/dist/chunk-3MED75HT.js +37 -0
  11. package/dist/chunk-47D2BO4S.js +87 -0
  12. package/dist/chunk-4RERDEXR.js +348 -0
  13. package/dist/chunk-4W2PLC4J.js +27 -0
  14. package/dist/chunk-52H5B5TC.js +202 -0
  15. package/dist/chunk-54B42YRX.js +27 -0
  16. package/dist/chunk-5RXBNSW2.js +266 -0
  17. package/dist/chunk-5THXD6X5.js +201 -0
  18. package/dist/chunk-5W3R6LFT.js +24 -0
  19. package/dist/chunk-5ZEJHV35.js +341 -0
  20. package/dist/chunk-6P62QVEA.js +118 -0
  21. package/dist/chunk-6QIUX4EP.js +459 -0
  22. package/dist/chunk-6VCD4VKZ.js +78 -0
  23. package/dist/chunk-7F72PXY2.js +326 -0
  24. package/dist/chunk-7FBF7NPR.js +998 -0
  25. package/dist/chunk-7U2IDNXN.js +37 -0
  26. package/dist/chunk-ABBOA7UD.js +157 -0
  27. package/dist/chunk-AHDW3GPE.js +50 -0
  28. package/dist/chunk-AJ3QXTRQ.js +756 -0
  29. package/dist/chunk-AJVLWNFN.js +1610 -0
  30. package/dist/chunk-AJXODZY6.js +112 -0
  31. package/dist/chunk-ARFCXG7S.js +84 -0
  32. package/dist/chunk-AS44CFQ4.js +708 -0
  33. package/dist/chunk-AWE5TMPO.js +38 -0
  34. package/dist/chunk-B3I2UUT4.js +4692 -0
  35. package/dist/chunk-BRJKOBZP.js +331 -0
  36. package/dist/chunk-BW5KFIQC.js +59 -0
  37. package/dist/chunk-C2AUYXQH.js +149 -0
  38. package/dist/chunk-CGGAIP7J.js +29 -0
  39. package/dist/chunk-D6QS3U6M.js +30 -0
  40. package/dist/chunk-DFVMIKMQ.js +349 -0
  41. package/dist/chunk-DIULIWKU.js +169 -0
  42. package/dist/chunk-DQ2NZ7C4.js +2317 -0
  43. package/dist/chunk-E2WFBRHM.js +213 -0
  44. package/dist/chunk-E4MAEDPM.js +50 -0
  45. package/dist/chunk-EOKRQ3SA.js +30 -0
  46. package/dist/chunk-F3AU2TMM.js +2626 -0
  47. package/dist/chunk-F3P7VQ7H.js +170 -0
  48. package/dist/chunk-FC4RP4I2.js +12 -0
  49. package/dist/chunk-FJNKANOS.js +32 -0
  50. package/dist/chunk-GUOGVTCQ.js +146 -0
  51. package/dist/chunk-GVXA6CCE.js +18 -0
  52. package/dist/chunk-HHYAELLJ.js +2334 -0
  53. package/dist/chunk-HMFXILPV.js +83 -0
  54. package/dist/chunk-HVUZXSWK.js +421 -0
  55. package/dist/chunk-HWBZIGMJ.js +62 -0
  56. package/dist/chunk-I3R7GKDR.js +17 -0
  57. package/dist/chunk-I7SPGOWI.js +55 -0
  58. package/dist/chunk-IIXOAGHR.js +38 -0
  59. package/dist/chunk-IVP5KAB7.js +2250 -0
  60. package/dist/chunk-IXEBJSUE.js +22 -0
  61. package/dist/chunk-JOLITGCC.js +27 -0
  62. package/dist/chunk-K6VYLB2U.js +145 -0
  63. package/dist/chunk-LJDODBBZ.js +78 -0
  64. package/dist/chunk-LNAKEO63.js +78 -0
  65. package/dist/chunk-LSMJ6KBE.js +4139 -0
  66. package/dist/chunk-LW6XKDZQ.js +5565 -0
  67. package/dist/chunk-N3YQJI6O.js +899 -0
  68. package/dist/chunk-NABLC7W3.js +148 -0
  69. package/dist/chunk-NKOUFPQF.js +659 -0
  70. package/dist/chunk-NL5GLMFI.js +211 -0
  71. package/dist/chunk-NMABWBZN.js +327 -0
  72. package/dist/chunk-NTHH2J74.js +27 -0
  73. package/dist/chunk-NTUJEGDZ.js +59 -0
  74. package/dist/chunk-NXL4FFQQ.js +47 -0
  75. package/dist/chunk-NXPS2L6U.js +466 -0
  76. package/dist/chunk-O5WILGMI.js +42 -0
  77. package/dist/chunk-O6TQT6RI.js +48 -0
  78. package/dist/chunk-OAXNDZJ7.js +323 -0
  79. package/dist/chunk-ODEEOXPH.js +44 -0
  80. package/dist/chunk-OQGFCZJ4.js +4533 -0
  81. package/dist/chunk-ORTMY4Q4.js +282 -0
  82. package/dist/chunk-OS32RNR2.js +442 -0
  83. package/dist/chunk-PAK6IDME.js +189 -0
  84. package/dist/chunk-PWFHBTSF.js +406 -0
  85. package/dist/chunk-Q5U6FMDI.js +2352 -0
  86. package/dist/chunk-QOZXJ4NA.js +3364 -0
  87. package/dist/chunk-QYF5S6P6.js +45 -0
  88. package/dist/chunk-RIISMHKN.js +36 -0
  89. package/dist/chunk-RPD4ZSB7.js +25 -0
  90. package/dist/chunk-RPD5K5NC.js +79 -0
  91. package/dist/chunk-RUOG5D2C.js +262 -0
  92. package/dist/chunk-T4ERT73Y.js +599 -0
  93. package/dist/chunk-T6D4Q4AQ.js +54 -0
  94. package/dist/chunk-TGPXLY2J.js +391 -0
  95. package/dist/chunk-TLGFBM3F.js +12116 -0
  96. package/dist/chunk-TO6WL3GM.js +88 -0
  97. package/dist/chunk-TT22N74J.js +517 -0
  98. package/dist/chunk-TVN5N6GY.js +21216 -0
  99. package/dist/chunk-U3VGR4VU.js +308 -0
  100. package/dist/chunk-UK3CMEAL.js +1250 -0
  101. package/dist/chunk-UOPVJQ4N.js +103 -0
  102. package/dist/chunk-UXVNL3D7.js +23 -0
  103. package/dist/chunk-UY752QSN.js +45 -0
  104. package/dist/chunk-V5PXFSZK.js +188 -0
  105. package/dist/chunk-V7R425XG.js +398 -0
  106. package/dist/chunk-VCSRSYLF.js +81 -0
  107. package/dist/chunk-VD4JQCQC.js +162 -0
  108. package/dist/chunk-VDBPVIKD.js +62 -0
  109. package/dist/chunk-VHQLPIRJ.js +114 -0
  110. package/dist/chunk-VN2AXLEX.js +5414 -0
  111. package/dist/chunk-VNMT7C64.js +478 -0
  112. package/dist/chunk-WONERJTP.js +309 -0
  113. package/dist/chunk-XECLWQZN.js +85 -0
  114. package/dist/chunk-XIMYZ3JA.js +27 -0
  115. package/dist/chunk-XK4CIILI.js +144 -0
  116. package/dist/chunk-Y4T27COV.js +562 -0
  117. package/dist/chunk-YGVYKNSN.js +1860 -0
  118. package/dist/chunk-YLF3PPT5.js +308 -0
  119. package/dist/chunk-YSNFMJKN.js +14 -0
  120. package/dist/chunk-Z3CCVDUB.js +76 -0
  121. package/dist/chunk-Z54ZSOBZ.js +61 -0
  122. package/dist/chunk-ZAWW3AF6.js +97 -0
  123. package/dist/chunk-ZMOL6RQC.js +167 -0
  124. package/dist/index.js +19039 -8956
  125. package/dist/mcp/analyze-cli.js +186 -228
  126. package/dist/mcp/cli.js +137 -98
  127. package/dist/mcp/server.js +22592 -1564
  128. package/dist/mcp/worker.js +97 -38
  129. package/dist/probes/installer.js +135 -0
  130. package/dist/workers/project-snapshot-persist-worker.js +22 -0
  131. package/dist/workers/review-graph-persist-worker.js +15 -0
  132. package/docs/adr/0001-stale-advisory-live-arm.md +29 -0
  133. package/docs/adr/0002-workspace-hash-rendezvous.md +30 -0
  134. package/docs/adr/0003-git-guard-latch-writer.md +203 -0
  135. package/docs/adr/0004-disposition-policy-seam.md +38 -0
  136. package/docs/adr/0005-tool-availability-enforcement-seam.md +29 -0
  137. package/docs/adr/0006-derived-state-benchmark-first.md +31 -0
  138. package/docs/adr/0007-end-to-end-witness-per-seam-slice.md +38 -0
  139. package/docs/adr/0008-turn-end-lane-interface.md +165 -0
  140. package/docs/adr/0009-reported-path-attribution.md +114 -0
  141. package/docs/adr/README.md +26 -0
  142. package/docs/agent-guide.md +13 -4
  143. package/docs/agent-tools.md +60 -1
  144. package/docs/ast-grep_rules_catalog.md +6 -4
  145. package/docs/configuration.md +75 -2
  146. package/docs/engineering-principles.md +202 -0
  147. package/docs/environment-variables.md +113 -6
  148. package/docs/features.md +10 -6
  149. package/docs/globalconfig.md +7 -1
  150. package/docs/io-bridge-v2-migration.md +94 -0
  151. package/docs/language-coverage.md +17 -0
  152. package/docs/lsp-capability-matrix.md +131 -32
  153. package/docs/lsp-idle-eviction.md +124 -0
  154. package/docs/mcp.md +21 -5
  155. package/docs/merge-queue-rollout.md +77 -0
  156. package/docs/pi-lens-fixer.md +161 -39
  157. package/docs/pi-lens-investigator.md +77 -20
  158. package/docs/pi-lens-merge-policy.md +694 -0
  159. package/docs/pi-lens-monitor.md +73 -7
  160. package/docs/pi-lens-retro.md +6 -4
  161. package/docs/pi-lens-reviewer.md +190 -34
  162. package/docs/pi-lens-subagent.md +247 -37
  163. package/docs/pi-lens-warden.md +18 -7
  164. package/docs/public-api-stability.md +56 -0
  165. package/docs/release-qa-baseline.md +86 -17
  166. package/docs/rfcs/3654-unified-io-bridge-v2.md +316 -0
  167. package/docs/servercapabilities.md +66 -52
  168. package/docs/settings.md +13 -3
  169. package/docs/subagent-compat.md +1 -1
  170. package/docs/usage.md +5 -1
  171. package/grammars/tree-sitter-bash.wasm +0 -0
  172. package/grammars/tree-sitter-bash.wasm.json +3 -3
  173. package/package.json +23 -9
  174. package/rules/ast-grep-rules/rule-tests/advisory-registry-subset-test.yml +41 -0
  175. package/rules/ast-grep-rules/rule-tests/no-assert-tuple-test.yml +13 -0
  176. package/rules/ast-grep-rules/rule-tests/no-boolean-in-except-test.yml +26 -0
  177. package/rules/ast-grep-rules/rule-tests/no-http-headers-bracket-access-test.yml +10 -0
  178. package/rules/ast-grep-rules/rule-tests/unchecked-numeric-parse-python-test.yml +18 -0
  179. package/rules/ast-grep-rules/rule-tests/unchecked-throwing-call-python-test.yml +4 -3
  180. package/rules/ast-grep-rules/rules/advisory-registry-subset.yml +50 -0
  181. package/rules/ast-grep-rules/rules/go-no-fmt-println.yml +2 -2
  182. package/rules/ast-grep-rules/rules/no-assert-tuple.yml +23 -13
  183. package/rules/ast-grep-rules/rules/no-boolean-in-except.yml +7 -3
  184. package/rules/ast-grep-rules/rules/no-console-except-error-js.yml +2 -2
  185. package/rules/ast-grep-rules/rules/no-console-except-error.yml +2 -2
  186. package/rules/ast-grep-rules/rules/no-http-headers-bracket-access.yml +12 -7
  187. package/rules/ast-grep-rules/rules/unchecked-numeric-parse-python.yml +44 -0
  188. package/rules/ast-grep-rules/rules/unchecked-throwing-call-python.yml +5 -3
  189. package/rules/tree-sitter-queries/typescript/console-statement.yml +2 -2
  190. package/scripts/analyze-pi-lens-logs.mjs +1275 -62
  191. package/scripts/download-grammars.js +5 -0
  192. package/scripts/grammars.lock.json +6 -1
  193. package/scripts/install-selftest.mjs +38 -35
  194. package/scripts/lib/host-provided-deps.mjs +13 -4
  195. package/scripts/lib/web-tree-sitter-dir.mjs +141 -0
  196. package/dist/clients/actionable-warnings-logger.js +0 -35
  197. package/dist/clients/actionable-warnings.js +0 -1594
  198. package/dist/clients/advisory-provenance.js +0 -457
  199. package/dist/clients/agent-behavior-client.js +0 -147
  200. package/dist/clients/agent-nudge.js +0 -325
  201. package/dist/clients/analysed-root.js +0 -1
  202. package/dist/clients/ast-grep-client.js +0 -731
  203. package/dist/clients/ast-grep-rule-manager.js +0 -146
  204. package/dist/clients/ast-grep-tool-logger.js +0 -118
  205. package/dist/clients/ast-grep-types.js +0 -10
  206. package/dist/clients/ast-grep-yaml-synth.js +0 -154
  207. package/dist/clients/atomic-write-staging.js +0 -75
  208. package/dist/clients/atomic-write.js +0 -189
  209. package/dist/clients/availability-probe-flight.js +0 -12
  210. package/dist/clients/bash-file-access.js +0 -1056
  211. package/dist/clients/biome-client.js +0 -357
  212. package/dist/clients/blocker-freshness.js +0 -837
  213. package/dist/clients/blocker-past-eof.js +0 -129
  214. package/dist/clients/bootstrap.js +0 -569
  215. package/dist/clients/bounded-cache.js +0 -190
  216. package/dist/clients/bounded-pid-file-lock.js +0 -202
  217. package/dist/clients/bounded-telemetry.js +0 -295
  218. package/dist/clients/build-identity.js +0 -95
  219. package/dist/clients/bundled-resource-health.js +0 -113
  220. package/dist/clients/bus-events-logger.js +0 -105
  221. package/dist/clients/bus-publish.js +0 -171
  222. package/dist/clients/cache/rule-cache.js +0 -190
  223. package/dist/clients/cache-manager.js +0 -465
  224. package/dist/clients/cache-observability.js +0 -1313
  225. package/dist/clients/call-graph.js +0 -852
  226. package/dist/clients/cargo-manifest.js +0 -422
  227. package/dist/clients/cascade-budget.js +0 -196
  228. package/dist/clients/cascade-format.js +0 -315
  229. package/dist/clients/cascade-logger.js +0 -31
  230. package/dist/clients/cascade-types.js +0 -9
  231. package/dist/clients/child-unref.js +0 -115
  232. package/dist/clients/code-quality-warnings.js +0 -286
  233. package/dist/clients/codebase-model.js +0 -173
  234. package/dist/clients/collateral-test-role.js +0 -40
  235. package/dist/clients/complexity-client.js +0 -462
  236. package/dist/clients/config-core/deny.js +0 -221
  237. package/dist/clients/config-core/index.js +0 -50
  238. package/dist/clients/config-core/merge.js +0 -357
  239. package/dist/clients/config-core/normalize.js +0 -340
  240. package/dist/clients/config-core/process-spec.js +0 -248
  241. package/dist/clients/config-core/provenance.js +0 -164
  242. package/dist/clients/config-core/records.js +0 -218
  243. package/dist/clients/config-core/resolve.js +0 -125
  244. package/dist/clients/config-core/safe-object.js +0 -78
  245. package/dist/clients/config-core/schema.js +0 -165
  246. package/dist/clients/config-diagnostic-codes.js +0 -283
  247. package/dist/clients/config-locations.js +0 -160
  248. package/dist/clients/config-resolve.js +0 -792
  249. package/dist/clients/config-schema.js +0 -251
  250. package/dist/clients/config-warn.js +0 -407
  251. package/dist/clients/console-guard-install.js +0 -26
  252. package/dist/clients/cooperative-budget.js +0 -42
  253. package/dist/clients/dead-code-client.js +0 -510
  254. package/dist/clients/dead-code-logger.js +0 -30
  255. package/dist/clients/deadline-utils.js +0 -280
  256. package/dist/clients/debug-handles.js +0 -211
  257. package/dist/clients/debug-heap.js +0 -174
  258. package/dist/clients/deferred-lsp-work.js +0 -106
  259. package/dist/clients/degradation-ledger.js +0 -396
  260. package/dist/clients/demoted-finding-render.js +0 -169
  261. package/dist/clients/dependency-checker.js +0 -862
  262. package/dist/clients/deps/ast-grep-napi.js +0 -22
  263. package/dist/clients/deps/js-yaml.js +0 -9
  264. package/dist/clients/deps/minimatch.js +0 -4
  265. package/dist/clients/deps/pi-tui.js +0 -14
  266. package/dist/clients/deps/typebox.js +0 -14
  267. package/dist/clients/deps/vscode-jsonrpc.js +0 -1
  268. package/dist/clients/deps/web-tree-sitter.js +0 -24
  269. package/dist/clients/diagnostic-dispositions.js +0 -594
  270. package/dist/clients/diagnostic-line-freshness.js +0 -305
  271. package/dist/clients/diagnostic-logger.js +0 -73
  272. package/dist/clients/diagnostic-tracker.js +0 -105
  273. package/dist/clients/diagnostics-publish.js +0 -230
  274. package/dist/clients/dispatch/ast-grep-catalog.js +0 -65
  275. package/dist/clients/dispatch/auxiliary-lsp.js +0 -343
  276. package/dist/clients/dispatch/collect-later-tier.js +0 -35
  277. package/dist/clients/dispatch/diagnostic-taxonomy.js +0 -66
  278. package/dist/clients/dispatch/dispatcher.js +0 -1269
  279. package/dist/clients/dispatch/fact-provider-types.js +0 -1
  280. package/dist/clients/dispatch/fact-rule-runner.js +0 -17
  281. package/dist/clients/dispatch/fact-runner.js +0 -30
  282. package/dist/clients/dispatch/fact-scheduler.js +0 -68
  283. package/dist/clients/dispatch/fact-store.js +0 -377
  284. package/dist/clients/dispatch/facts/comment-facts.js +0 -22
  285. package/dist/clients/dispatch/facts/file-content.js +0 -19
  286. package/dist/clients/dispatch/facts/function-facts.js +0 -348
  287. package/dist/clients/dispatch/facts/import-facts.js +0 -204
  288. package/dist/clients/dispatch/facts/tree-sitter-facts.js +0 -34
  289. package/dist/clients/dispatch/facts/try-catch-facts.js +0 -119
  290. package/dist/clients/dispatch/finding-policy.js +0 -222
  291. package/dist/clients/dispatch/indent-detect.js +0 -411
  292. package/dist/clients/dispatch/inline-suppressions.js +0 -70
  293. package/dist/clients/dispatch/integration.js +0 -2377
  294. package/dist/clients/dispatch/lazy.js +0 -11
  295. package/dist/clients/dispatch/pending-runner-findings.js +0 -87
  296. package/dist/clients/dispatch/plan.js +0 -278
  297. package/dist/clients/dispatch/priorities.js +0 -20
  298. package/dist/clients/dispatch/rule-id-normalize.js +0 -50
  299. package/dist/clients/dispatch/rule-ignores.js +0 -62
  300. package/dist/clients/dispatch/rule-policy.js +0 -135
  301. package/dist/clients/dispatch/rules/async-noise.js +0 -40
  302. package/dist/clients/dispatch/rules/async-unnecessary-wrapper.js +0 -27
  303. package/dist/clients/dispatch/rules/cors-wildcard.js +0 -54
  304. package/dist/clients/dispatch/rules/error-obscuring.js +0 -32
  305. package/dist/clients/dispatch/rules/error-swallowing.js +0 -31
  306. package/dist/clients/dispatch/rules/framework-call-noise.js +0 -67
  307. package/dist/clients/dispatch/rules/high-complexity.js +0 -72
  308. package/dist/clients/dispatch/rules/high-fan-out.js +0 -74
  309. package/dist/clients/dispatch/rules/high-import-coupling.js +0 -37
  310. package/dist/clients/dispatch/rules/missing-error-propagation.js +0 -62
  311. package/dist/clients/dispatch/rules/no-commented-credentials.js +0 -52
  312. package/dist/clients/dispatch/rules/pass-through-wrappers.js +0 -42
  313. package/dist/clients/dispatch/rules/placeholder-comments.js +0 -40
  314. package/dist/clients/dispatch/rules/unsafe-boundary.js +0 -126
  315. package/dist/clients/dispatch/runner-context.js +0 -52
  316. package/dist/clients/dispatch/runners/actionlint.js +0 -113
  317. package/dist/clients/dispatch/runners/ast-grep-napi.js +0 -1196
  318. package/dist/clients/dispatch/runners/biome-check.js +0 -283
  319. package/dist/clients/dispatch/runners/cpp-check.js +0 -236
  320. package/dist/clients/dispatch/runners/credo.js +0 -80
  321. package/dist/clients/dispatch/runners/cue-vet.js +0 -398
  322. package/dist/clients/dispatch/runners/dart-analyze.js +0 -202
  323. package/dist/clients/dispatch/runners/detekt.js +0 -169
  324. package/dist/clients/dispatch/runners/dotnet-build.js +0 -159
  325. package/dist/clients/dispatch/runners/elixir-check.js +0 -210
  326. package/dist/clients/dispatch/runners/eslint.js +0 -154
  327. package/dist/clients/dispatch/runners/fact-rules.js +0 -29
  328. package/dist/clients/dispatch/runners/fish-indent.js +0 -69
  329. package/dist/clients/dispatch/runners/gleam-check.js +0 -87
  330. package/dist/clients/dispatch/runners/go-vet.js +0 -90
  331. package/dist/clients/dispatch/runners/golangci-lint.js +0 -120
  332. package/dist/clients/dispatch/runners/hadolint.js +0 -79
  333. package/dist/clients/dispatch/runners/helm-lint.js +0 -171
  334. package/dist/clients/dispatch/runners/helm-render.js +0 -940
  335. package/dist/clients/dispatch/runners/htmlhint.js +0 -108
  336. package/dist/clients/dispatch/runners/index.js +0 -108
  337. package/dist/clients/dispatch/runners/javac.js +0 -89
  338. package/dist/clients/dispatch/runners/ktlint.js +0 -136
  339. package/dist/clients/dispatch/runners/lsp.js +0 -378
  340. package/dist/clients/dispatch/runners/markdownlint.js +0 -160
  341. package/dist/clients/dispatch/runners/mypy.js +0 -101
  342. package/dist/clients/dispatch/runners/oxlint.js +0 -398
  343. package/dist/clients/dispatch/runners/php-lint.js +0 -62
  344. package/dist/clients/dispatch/runners/phpstan.js +0 -120
  345. package/dist/clients/dispatch/runners/prisma-validate.js +0 -62
  346. package/dist/clients/dispatch/runners/psscriptanalyzer.js +0 -445
  347. package/dist/clients/dispatch/runners/pyright.js +0 -169
  348. package/dist/clients/dispatch/runners/rubocop.js +0 -90
  349. package/dist/clients/dispatch/runners/ruff.js +0 -89
  350. package/dist/clients/dispatch/runners/rust-clippy.js +0 -251
  351. package/dist/clients/dispatch/runners/shellcheck.js +0 -169
  352. package/dist/clients/dispatch/runners/shfmt.js +0 -102
  353. package/dist/clients/dispatch/runners/spellcheck.js +0 -121
  354. package/dist/clients/dispatch/runners/spotbugs.js +0 -259
  355. package/dist/clients/dispatch/runners/sqlfluff.js +0 -174
  356. package/dist/clients/dispatch/runners/stylelint.js +0 -158
  357. package/dist/clients/dispatch/runners/swiftlint.js +0 -154
  358. package/dist/clients/dispatch/runners/taplo.js +0 -168
  359. package/dist/clients/dispatch/runners/terragrunt.js +0 -168
  360. package/dist/clients/dispatch/runners/tflint.js +0 -110
  361. package/dist/clients/dispatch/runners/tree-sitter.js +0 -620
  362. package/dist/clients/dispatch/runners/trivy-config.js +0 -247
  363. package/dist/clients/dispatch/runners/utils/availability-policy.js +0 -496
  364. package/dist/clients/dispatch/runners/utils/candidate-probe.js +0 -90
  365. package/dist/clients/dispatch/runners/utils/diagnostic-parsers.js +0 -85
  366. package/dist/clients/dispatch/runners/utils/lazy-installer.js +0 -274
  367. package/dist/clients/dispatch/runners/utils/runner-helpers.js +0 -1701
  368. package/dist/clients/dispatch/runners/utils/spawn-outcome.js +0 -101
  369. package/dist/clients/dispatch/runners/utils/tool-failure.js +0 -235
  370. package/dist/clients/dispatch/runners/utils/toolchain-availability.js +0 -169
  371. package/dist/clients/dispatch/runners/utils.js +0 -15
  372. package/dist/clients/dispatch/runners/vale.js +0 -116
  373. package/dist/clients/dispatch/runners/yaml-rule-parser.js +0 -242
  374. package/dist/clients/dispatch/runners/yamllint.js +0 -85
  375. package/dist/clients/dispatch/runners/zig-check.js +0 -91
  376. package/dist/clients/dispatch/suppress-writer.js +0 -69
  377. package/dist/clients/dispatch/tool-profile.js +0 -30
  378. package/dist/clients/dispatch/types.js +0 -21
  379. package/dist/clients/dispatch/utils/format-utils.js +0 -45
  380. package/dist/clients/dispatch/utils/lsp-diagnostics.js +0 -35
  381. package/dist/clients/disposition-logger.js +0 -32
  382. package/dist/clients/disposition-publish.js +0 -124
  383. package/dist/clients/durable-store.js +0 -97
  384. package/dist/clients/effective-config.js +0 -413
  385. package/dist/clients/env-utils.js +0 -83
  386. package/dist/clients/error-class.js +0 -23
  387. package/dist/clients/eval-timestamp.js +0 -17
  388. package/dist/clients/event-loop-hold.js +0 -274
  389. package/dist/clients/event-loop-monitor.js +0 -250
  390. package/dist/clients/extension-log.js +0 -504
  391. package/dist/clients/extension-mode.js +0 -73
  392. package/dist/clients/feature-hints.js +0 -103
  393. package/dist/clients/file-kinds.js +0 -412
  394. package/dist/clients/file-role.js +0 -134
  395. package/dist/clients/file-time.js +0 -160
  396. package/dist/clients/file-utils.js +0 -1032
  397. package/dist/clients/finding-delivery-gate.js +0 -463
  398. package/dist/clients/finding-identity.js +0 -88
  399. package/dist/clients/fix-worklog.js +0 -103
  400. package/dist/clients/format-events-publish.js +0 -343
  401. package/dist/clients/format-service.js +0 -222
  402. package/dist/clients/formatters-lazy.js +0 -9
  403. package/dist/clients/formatters.js +0 -1994
  404. package/dist/clients/freshness-cadence.js +0 -17
  405. package/dist/clients/freshness.js +0 -38
  406. package/dist/clients/generated-artifacts.js +0 -394
  407. package/dist/clients/generation-guard.js +0 -215
  408. package/dist/clients/git-guard.js +0 -923
  409. package/dist/clients/git-tracked-ignore.js +0 -243
  410. package/dist/clients/gitleaks-client.js +0 -509
  411. package/dist/clients/go-client.js +0 -104
  412. package/dist/clients/govulncheck-client.js +0 -605
  413. package/dist/clients/gradle-ktfmt-style.js +0 -252
  414. package/dist/clients/grammar-source.js +0 -465
  415. package/dist/clients/gzip-stage-write.js +0 -135
  416. package/dist/clients/hashline-anchor.js +0 -424
  417. package/dist/clients/hook-budgets.js +0 -76
  418. package/dist/clients/host-edit-normalize.js +0 -140
  419. package/dist/clients/host-ports.js +0 -39
  420. package/dist/clients/indent-retarget.js +0 -154
  421. package/dist/clients/install-diagnostics.js +0 -143
  422. package/dist/clients/installer/index.js +0 -5167
  423. package/dist/clients/installer/managed-tool-refresh-session.js +0 -58
  424. package/dist/clients/installer/managed-tool-refresh.js +0 -783
  425. package/dist/clients/instance-reaper-state.js +0 -7
  426. package/dist/clients/instance-reaper.js +0 -1137
  427. package/dist/clients/instance-registry-lock.js +0 -145
  428. package/dist/clients/instance-registry.js +0 -773
  429. package/dist/clients/jscpd-client.js +0 -370
  430. package/dist/clients/json-cache-read.js +0 -65
  431. package/dist/clients/knip-client.js +0 -788
  432. package/dist/clients/language-policy.js +0 -252
  433. package/dist/clients/language-profile.js +0 -361
  434. package/dist/clients/language-registry.js +0 -603
  435. package/dist/clients/latency-logger.js +0 -719
  436. package/dist/clients/lazy-import.js +0 -21
  437. package/dist/clients/ledger-bounds.js +0 -54
  438. package/dist/clients/lens-config.js +0 -346
  439. package/dist/clients/lens-engine.js +0 -358
  440. package/dist/clients/lens-events.js +0 -125
  441. package/dist/clients/lens-flag-registry.js +0 -467
  442. package/dist/clients/lens-map.js +0 -1156
  443. package/dist/clients/live-bus-emitter.js +0 -74
  444. package/dist/clients/log-cleanup.js +0 -222
  445. package/dist/clients/lsp/aggregation.js +0 -178
  446. package/dist/clients/lsp/cascade-tier.js +0 -421
  447. package/dist/clients/lsp/client.js +0 -4465
  448. package/dist/clients/lsp/config.js +0 -689
  449. package/dist/clients/lsp/diagnostic-binding.js +0 -225
  450. package/dist/clients/lsp/document-drift.js +0 -467
  451. package/dist/clients/lsp/edits.js +0 -1219
  452. package/dist/clients/lsp/index.js +0 -8305
  453. package/dist/clients/lsp/inferred-project.js +0 -216
  454. package/dist/clients/lsp/jvm-runtime.js +0 -298
  455. package/dist/clients/lsp/language.js +0 -63
  456. package/dist/clients/lsp/launch.js +0 -725
  457. package/dist/clients/lsp/lombok.js +0 -158
  458. package/dist/clients/lsp/path-utils.js +0 -5
  459. package/dist/clients/lsp/pending-aux-coverage.js +0 -251
  460. package/dist/clients/lsp/position-encoding.js +0 -61
  461. package/dist/clients/lsp/ruby-drive-dirs.js +0 -83
  462. package/dist/clients/lsp/server.js +0 -3209
  463. package/dist/clients/lsp/session-roots.js +0 -192
  464. package/dist/clients/lsp/spawn-history.js +0 -17
  465. package/dist/clients/lsp/sync-kind.js +0 -42
  466. package/dist/clients/lsp/tsserver-sync.js +0 -332
  467. package/dist/clients/lsp/wait-policy/capability-snapshot.js +0 -1
  468. package/dist/clients/lsp/wait-policy/classification.js +0 -85
  469. package/dist/clients/lsp/wait-policy/index.js +0 -10
  470. package/dist/clients/lsp/wait-policy/strategies.js +0 -303
  471. package/dist/clients/lsp/watch-queue.js +0 -61
  472. package/dist/clients/lsp/workspace-diagnostics-cache.js +0 -639
  473. package/dist/clients/lsp/workspace-diagnostics-session.js +0 -30
  474. package/dist/clients/lsp/workspace-sweep-hold.js +0 -184
  475. package/dist/clients/lsp-budget.js +0 -186
  476. package/dist/clients/lsp-document-symbols.js +0 -110
  477. package/dist/clients/lsp-lazy.js +0 -9
  478. package/dist/clients/lsp-mutation.js +0 -396
  479. package/dist/clients/lsp-status.js +0 -59
  480. package/dist/clients/map-with-concurrency.js +0 -40
  481. package/dist/clients/mcp/analyze.js +0 -420
  482. package/dist/clients/mcp/host-shim.js +0 -31
  483. package/dist/clients/mcp/ipc.js +0 -335
  484. package/dist/clients/mcp/review.js +0 -151
  485. package/dist/clients/mcp/session.js +0 -412
  486. package/dist/clients/memory-sampler.js +0 -208
  487. package/dist/clients/message-end-attribution.js +0 -30
  488. package/dist/clients/metrics-client.js +0 -107
  489. package/dist/clients/metrics-history.js +0 -327
  490. package/dist/clients/middle-man-analysis.js +0 -263
  491. package/dist/clients/model-provider.js +0 -53
  492. package/dist/clients/module-report-lsp.js +0 -189
  493. package/dist/clients/module-report.js +0 -2150
  494. package/dist/clients/mutating-tool.js +0 -651
  495. package/dist/clients/mutation-attribution.js +0 -368
  496. package/dist/clients/mutation-bridge.js +0 -240
  497. package/dist/clients/ndjson-logger.js +0 -734
  498. package/dist/clients/observed-mutation-sources.js +0 -101
  499. package/dist/clients/observed-mutation.js +0 -1253
  500. package/dist/clients/oldtext-autopatch.js +0 -128
  501. package/dist/clients/opaque-mutation-scan.js +0 -496
  502. package/dist/clients/opengrep-client.js +0 -328
  503. package/dist/clients/opengrep-config.js +0 -76
  504. package/dist/clients/package-manager.js +0 -607
  505. package/dist/clients/package-root.js +0 -38
  506. package/dist/clients/partial-edit-apply.js +0 -439
  507. package/dist/clients/path-attribution-telemetry.js +0 -43
  508. package/dist/clients/path-keyed-map.js +0 -108
  509. package/dist/clients/path-utils.js +0 -1244
  510. package/dist/clients/performance-report.js +0 -331
  511. package/dist/clients/persist-debounce.js +0 -70
  512. package/dist/clients/persistent-reverify.js +0 -271
  513. package/dist/clients/php-cs-fixer-config.js +0 -119
  514. package/dist/clients/pipeline.js +0 -1425
  515. package/dist/clients/post-autofix-notice.js +0 -37
  516. package/dist/clients/print-mode.js +0 -21
  517. package/dist/clients/probe-home-state.js +0 -228
  518. package/dist/clients/process-bridge.js +0 -66
  519. package/dist/clients/process-singletons.js +0 -210
  520. package/dist/clients/process-snapshot.js +0 -68
  521. package/dist/clients/project-changes.js +0 -181
  522. package/dist/clients/project-conventions.js +0 -171
  523. package/dist/clients/project-diagnostics/cache.js +0 -137
  524. package/dist/clients/project-diagnostics/extractors.js +0 -109
  525. package/dist/clients/project-diagnostics/fresh-fetch.js +0 -650
  526. package/dist/clients/project-diagnostics/runner-adapters/call-graph-impact.js +0 -118
  527. package/dist/clients/project-diagnostics/runner-adapters/dead-code.js +0 -47
  528. package/dist/clients/project-diagnostics/runner-adapters/gitleaks.js +0 -40
  529. package/dist/clients/project-diagnostics/runner-adapters/govulncheck.js +0 -34
  530. package/dist/clients/project-diagnostics/runner-adapters/jscpd.js +0 -38
  531. package/dist/clients/project-diagnostics/runner-adapters/knip.js +0 -47
  532. package/dist/clients/project-diagnostics/runner-adapters/madge.js +0 -48
  533. package/dist/clients/project-diagnostics/runner-adapters/opengrep.js +0 -40
  534. package/dist/clients/project-diagnostics/runner-adapters/runner-findings.js +0 -127
  535. package/dist/clients/project-diagnostics/runner-adapters/trivy.js +0 -81
  536. package/dist/clients/project-diagnostics/scanner.js +0 -520
  537. package/dist/clients/project-diagnostics/types.js +0 -1
  538. package/dist/clients/project-lens-config.js +0 -799
  539. package/dist/clients/project-report.js +0 -701
  540. package/dist/clients/project-scale.js +0 -237
  541. package/dist/clients/project-scan-policy.js +0 -11
  542. package/dist/clients/project-snapshot-fingerprint.js +0 -48
  543. package/dist/clients/project-snapshot-persist-worker.js +0 -20
  544. package/dist/clients/project-snapshot.js +0 -1653
  545. package/dist/clients/project-trust.js +0 -181
  546. package/dist/clients/python-environment.js +0 -217
  547. package/dist/clients/python-provenance.js +0 -639
  548. package/dist/clients/quiet-window-config.js +0 -47
  549. package/dist/clients/quiet-window.js +0 -236
  550. package/dist/clients/read-bridge.js +0 -139
  551. package/dist/clients/read-expansion.js +0 -266
  552. package/dist/clients/read-guard-logger.js +0 -251
  553. package/dist/clients/read-guard-tool-lines.js +0 -1306
  554. package/dist/clients/read-guard.js +0 -1561
  555. package/dist/clients/recent-touches.js +0 -240
  556. package/dist/clients/redact/secrets.js +0 -449
  557. package/dist/clients/resource-sampler.js +0 -628
  558. package/dist/clients/reverse-deps.js +0 -270
  559. package/dist/clients/review-graph/builder.js +0 -5118
  560. package/dist/clients/review-graph/format.js +0 -33
  561. package/dist/clients/review-graph/git-identity.js +0 -157
  562. package/dist/clients/review-graph/import-resolvers.js +0 -481
  563. package/dist/clients/review-graph/persist-worker.js +0 -10
  564. package/dist/clients/review-graph/query.js +0 -244
  565. package/dist/clients/review-graph/revision-drift.js +0 -21
  566. package/dist/clients/review-graph/service.js +0 -96
  567. package/dist/clients/review-graph/shared-extraction-ir.js +0 -82
  568. package/dist/clients/review-graph/symbol-id.js +0 -103
  569. package/dist/clients/review-graph/tsconfig-paths.js +0 -299
  570. package/dist/clients/review-graph/types.js +0 -1
  571. package/dist/clients/review-graph/workspace-modules.js +0 -449
  572. package/dist/clients/review-graph-logger.js +0 -81
  573. package/dist/clients/ruff-client.js +0 -152
  574. package/dist/clients/rules-scanner.js +0 -131
  575. package/dist/clients/run-duration.js +0 -55
  576. package/dist/clients/runtime-agent-end.js +0 -746
  577. package/dist/clients/runtime-config.js +0 -77
  578. package/dist/clients/runtime-context.js +0 -211
  579. package/dist/clients/runtime-coordinator.js +0 -1290
  580. package/dist/clients/runtime-session.js +0 -2485
  581. package/dist/clients/runtime-tool-call.js +0 -1284
  582. package/dist/clients/runtime-tool-result.js +0 -2034
  583. package/dist/clients/runtime-turn.js +0 -3600
  584. package/dist/clients/rust-client.js +0 -97
  585. package/dist/clients/safe-spawn.js +0 -2166
  586. package/dist/clients/sanitize.js +0 -286
  587. package/dist/clients/scan-utils.js +0 -25
  588. package/dist/clients/scratch-tree-policy.js +0 -165
  589. package/dist/clients/search-read-registration.js +0 -94
  590. package/dist/clients/secret-findings.js +0 -114
  591. package/dist/clients/security-scan-client.js +0 -352
  592. package/dist/clients/session-event-guard.js +0 -297
  593. package/dist/clients/session-lifecycle.js +0 -484
  594. package/dist/clients/session-start-observability.js +0 -94
  595. package/dist/clients/session-state-store.js +0 -101
  596. package/dist/clients/session-summary.js +0 -15
  597. package/dist/clients/sessionstart-logger.js +0 -27
  598. package/dist/clients/sg-runner.js +0 -876
  599. package/dist/clients/sgconfig.js +0 -347
  600. package/dist/clients/shared-checkout-guard.js +0 -338
  601. package/dist/clients/single-flight.js +0 -158
  602. package/dist/clients/situational-tool-telemetry.js +0 -108
  603. package/dist/clients/skills-resolver.js +0 -141
  604. package/dist/clients/slow-fs.js +0 -138
  605. package/dist/clients/smells-rollup.js +0 -231
  606. package/dist/clients/source-filter.js +0 -596
  607. package/dist/clients/source-walker.js +0 -211
  608. package/dist/clients/spawn-output-cap.js +0 -37
  609. package/dist/clients/spawn-timeout-cooldown.js +0 -110
  610. package/dist/clients/stale-marker.js +0 -17
  611. package/dist/clients/startup-scan.js +0 -400
  612. package/dist/clients/startup-timing.js +0 -130
  613. package/dist/clients/string-utils.js +0 -33
  614. package/dist/clients/subagent-mode.js +0 -111
  615. package/dist/clients/symbol-containment.js +0 -24
  616. package/dist/clients/symbol-types.js +0 -5
  617. package/dist/clients/test-runner-client.js +0 -2507
  618. package/dist/clients/test-runner-delivery.js +0 -287
  619. package/dist/clients/todo-scanner.js +0 -229
  620. package/dist/clients/tool-agreement.js +0 -423
  621. package/dist/clients/tool-config.js +0 -249
  622. package/dist/clients/tool-cwd.js +0 -270
  623. package/dist/clients/tool-definition.js +0 -47
  624. package/dist/clients/tool-event.js +0 -105
  625. package/dist/clients/tool-policy.js +0 -2755
  626. package/dist/clients/tool-probe.js +0 -53
  627. package/dist/clients/tool-render.js +0 -156
  628. package/dist/clients/tool-set-policy.js +0 -118
  629. package/dist/clients/tree-sitter-cache.js +0 -364
  630. package/dist/clients/tree-sitter-client.js +0 -4134
  631. package/dist/clients/tree-sitter-logger.js +0 -100
  632. package/dist/clients/tree-sitter-navigator.js +0 -269
  633. package/dist/clients/tree-sitter-query-loader.js +0 -569
  634. package/dist/clients/tree-sitter-shared.js +0 -158
  635. package/dist/clients/tree-sitter-symbol-extractor.js +0 -1265
  636. package/dist/clients/trivy-client.js +0 -467
  637. package/dist/clients/tui-fit.js +0 -50
  638. package/dist/clients/turn-context.js +0 -52
  639. package/dist/clients/turn-summary-render.js +0 -72
  640. package/dist/clients/turn-summary.js +0 -132
  641. package/dist/clients/typos-config.js +0 -29
  642. package/dist/clients/user-notify.js +0 -51
  643. package/dist/clients/vanished-instance-marker.js +0 -57
  644. package/dist/clients/warm-attach.js +0 -246
  645. package/dist/clients/widget-state.js +0 -1677
  646. package/dist/clients/word-index-logger.js +0 -49
  647. package/dist/clients/word-index-store.js +0 -459
  648. package/dist/clients/word-index.js +0 -2080
  649. package/dist/clients/workspace-topology.js +0 -389
  650. package/dist/clients/write-ordering-guard.js +0 -65
  651. package/dist/clients/zizmor-config.js +0 -327
  652. package/dist/i18n.js +0 -69
  653. package/dist/mcp/build-staleness.js +0 -124
  654. package/dist/scripts/lib/process-scan.mjs +0 -583
  655. package/dist/scripts/lib/skills-predicate.mjs +0 -129
  656. package/dist/tools/activate-tools.js +0 -87
  657. package/dist/tools/ast-grep-outline.js +0 -137
  658. package/dist/tools/ast-grep-replace.js +0 -244
  659. package/dist/tools/ast-grep-search.js +0 -762
  660. package/dist/tools/effective-config.js +0 -90
  661. package/dist/tools/lens-diagnostic-mark.js +0 -375
  662. package/dist/tools/lens-diagnostics.js +0 -2544
  663. package/dist/tools/lsp-diagnostics.js +0 -1634
  664. package/dist/tools/lsp-navigation.js +0 -1367
  665. package/dist/tools/lsp-structured-output.js +0 -294
  666. package/dist/tools/module-report.js +0 -382
  667. package/dist/tools/project-report.js +0 -86
  668. package/dist/tools/render-compact.js +0 -374
  669. package/dist/tools/scan-progress.js +0 -53
  670. package/dist/tools/shared.js +0 -29
  671. package/dist/tools/symbol-search.js +0 -155
@@ -1,35 +1,32 @@
1
1
  # Delegated worker delivery contract
2
2
 
3
- This contract applies to every delegated pi-lens worker, regardless of the
4
- agent runner or model. Pair it with exactly one role contract: fixer, reviewer,
5
- or investigator.
3
+ Read first: the engineering principles (`docs/engineering-principles.md`; skip
4
+ it when your harness's global instructions already carry the verbatim copy),
5
+ then `AGENTS.md`, then this contract, then exactly one role contract from
6
+ `docs/pi-lens-{fixer,reviewer,investigator,monitor,warden,retro}.md`. This file
7
+ holds the pi-lens rules every role shares, for every runner and model. The
8
+ principles apply throughout and are not restated; project files win on
9
+ conflict.
10
+
11
+ ## Worktree and Git
6
12
 
7
13
  Work only in the assigned worktree. Before editing, verify its absolute path,
8
- registered worktree entry, branch, and base. Preserve junctioned dependencies.
9
- Never switch another checkout's branch, and never use `git stash`. Save a patch
10
- before temporarily reverting work.
11
-
12
- Treat the acceptance criteria as the contract. For a regression, prove the new
13
- test red before the fix and green after it. Mutating or removing a new guard
14
- must make at least one test fail. Sweep the whole tree for the same code pattern
15
- and every member of any enumerable population. Record both sweeps.
16
-
17
- State the blast radius, including callers, durable shapes, strict parsers, and
18
- tool surfaces. Add bounded observability for every new failure path. Include the
19
- required changelog fragment for a code change: ONE file under `.changelog/`;
20
- never edit `CHANGELOG.md` itself (it is generated at release; two fixers
21
- hand-edited it on 2026-09-09 and the orchestrator had to revert both).
22
- Report verification honestly.
23
- Write active, direct prose with short sentences and consistent terms.
24
-
25
- ## Tautological tests considered harmful
26
-
27
- A test must observe behavior through the real seam, not repeat the implementation
28
- or feed the expected answer in through setup. Keep the red-first failure tied to
29
- the defect, and mutate the guard or filter to prove the test can detect its loss.
30
- Mocks belong only at true process or host boundaries. When a test can use the
31
- real store, sink, coordinator, or registry, use it and assert the durable result.
32
- For a whole-module mock, prefer `vi.mock("./module.js", async (importOriginal) => ({ ...(await importOriginal()), override }))` so new exports pass through by default; annotate dynamic imports as `typeof import(spec)` when needed.
14
+ registered `git worktree list` entry, branch, and base. Preserve linked or
15
+ junctioned dependencies. Never switch another checkout's branch, never pass the
16
+ main checkout's path as `repoRoot` or `cwd` to a probe that writes or deletes
17
+ (#2704), and never use `git stash`. Save a patch before temporarily reverting
18
+ uncommitted work.
19
+
20
+ A lane never writes files to the shared session scratchpad: lanes spawned from
21
+ one session share it and overwrite each other's fixed names (#3850). Probe
22
+ scripts, PR bodies, and TLC logs go under `$TMPDIR` (its value is in
23
+ "Orchestrator lane mechanics") or `<worktree>/../probes-<lane>`.
24
+
25
+ The Bash-hook rules in `AGENTS.md` "Contributing" bind every runner, hooked or
26
+ not. Hooks always run. A hook or CI red is unrelated only when
27
+ `scripts/red-on-base.mjs` reports `RED-ON-BASE` for every failing test
28
+ (`AGENTS.md` "Commands and gates"); for a hook, then STOP and hand back the
29
+ quoted output. Never bypass or push past it.
33
30
 
34
31
  Git authority is separate from the role. Commit, push, or open a PR only when
35
32
  the delegation explicitly grants that authority after worktree verification.
@@ -38,11 +35,185 @@ directory, leave every change uncommitted, and write two handoff files at the
38
35
  worktree root: `PR_BODY.md` (the full PR body, transcripts pasted) and
39
36
  `COMMIT_MSG.txt` (subject, body, issue ref, trailers). Name any path inside the
40
37
  worktree that must not be committed. The orchestrator commits from those files;
41
- they are never committed themselves. Never merge. Every report or artifact
42
- the delegation asks for lives at the worktree root under the name the brief
43
- gives it; nothing else at the root is assumed to matter. When the brief
44
- names findings by id, the handoff answers each id with one of
45
- `fixed | not fixed | withdrawn (why)` before any prose.
38
+ they are never committed themselves. Never merge. GitHub writes (comments,
39
+ issues) happen only when the brief grants them. Every report or artifact the
40
+ delegation asks for lives at the worktree root under the name the brief gives
41
+ it; nothing else at the root is assumed to matter.
42
+
43
+ When Git authority is granted, use one logical commit with an imperative,
44
+ conventional-prefix subject of at most 50 characters, a blank line, and a
45
+ 72-column body that states what and why. Reference the issue. Commits, PR
46
+ bodies, and comments never carry a `Claude-Session:` trailer or session link.
47
+ Stage files by name, never `git add -A`: the root handoff files are gitignored,
48
+ and tracking one reds `tests/config/gitignore-tracked-shadow.test.ts`. Read
49
+ `git status --porcelain` before committing; afterwards
50
+ `git ls-files | grep -E 'PR_BODY|COMMIT_MSG'` prints nothing. Build output,
51
+ `.probe-home/`, and scratch fixtures stay out of the diff.
52
+
53
+ When updating a lane from the moving base, master is merged in, never rebased.
54
+ Force-pushes are not a recovery path: use a normal push, and require
55
+ explicit orchestrator authorization for
56
+ `--force-with-lease=<branch>:<sha>`.
57
+
58
+ Push forms are in "Orchestrator lane mechanics". Before `gh pr create` or `gh pr edit`, lint the body with
59
+ `node scripts/check-pr-body.mjs --lint-local <body-file> "<title>"`. Multiline
60
+ text (bodies, commit messages, comments) goes through a file (`--body-file`,
61
+ `git commit -F`); re-read what GitHub stored and check the newlines survived.
62
+
63
+ ## Orchestrator lane mechanics
64
+
65
+ A brief that names `lane=<name>`, its scope, and a Git-authority grant gets
66
+ every rule below without restating it; a brief never copies this section. A
67
+ rule here binds fixers, reviewers, and every other role. `<lane>` is the name
68
+ the brief gives.
69
+
70
+ - **Checkout.** A lane's checkout is a `git worktree add` from the main
71
+ checkout under `~/.local/share/pi-lens-orchestrator/tmp/<lane>`, never under
72
+ `/tmp`, which is tmpfs on the maintainer host (RAM plus swap), and
73
+ `guard-bash.mjs` denies it (#3526). A worker that must cut its own worktree
74
+ follows its harness note and still names the lane. Verify the checkout as
75
+ "Worktree and Git" says before the first edit.
76
+ - **Paths.** Use absolute paths only: a relative path lands in whichever
77
+ checkout the shell happens to sit in, and agent shells reset their working
78
+ directory between calls. Never edit the main checkout: other lanes and the
79
+ orchestrator read it, and its branch must not move under them.
80
+ - **Teardown.** `rm` a symlinked `node_modules` before `git worktree remove`
81
+ (`ls -ld node_modules` first; unlink the link, never `rm -r` it). Removing the worktree over the link follows it
82
+ and deletes the main checkout's install (#3173; the hook denies the removal
83
+ and `AGENTS.md` "Commands and gates" says how `pr-worktree.mjs close` does
84
+ it). A real `node_modules` directory is removed only after confirming the
85
+ main checkout's install is intact.
86
+ - **Linked installs.** Never run a mutating npm verb (`ci`, `install`,
87
+ `update`, `uninstall`, `prune`, `dedupe`, `rebuild`), even `--dry-run`, where
88
+ `node_modules` is a link: `npm ci` empties the shared install under every
89
+ lane (#4044, 2026-10-07; `guard-bash.mjs` denies it). Answer install-flag
90
+ questions in a scratch copy under `$TMPDIR`, never in the linked lane.
91
+ Unlink with `rm node_modules` (no trailing slash or glob): `rm -rf
92
+ node_modules/` and `find node_modules/ -delete` empty the target too.
93
+ - **TMPDIR.** Export
94
+ `TMPDIR=~/.local/share/pi-lens-orchestrator/tmp/<lane>-tmp` for every command
95
+ in the lane, including checks that spawn npm, git hooks, or a child
96
+ process: a command without it writes to the shared tmpfs, or to the
97
+ harness home, which the hook also denies. The directory sits beside the
98
+ worktree, never inside it (an untracked file in the tree reds
99
+ `tests/scripts/lint-js.test.ts`) and never under `.cache`. Never point it at
100
+ `PI_LENS_HOME` (see "Tests and probes" for that pin).
101
+ - **Push forms.** Push only a branch the grant names, and push the head
102
+ you verified:
103
+ - Own branch, the plegma credential-helper form (until plegma #474 lands):
104
+ `git -c credential.helper= -c credential.helper='!gh auth git-credential'
105
+ push origin HEAD:refs/heads/<branch>`.
106
+ - Contributor fork (maintainer round on an external PR): push to the fork's
107
+ URL and branch, `git push <fork-url> HEAD:refs/heads/<branch>`, with the
108
+ same `-c credential.helper=` pair; the fork's URL and branch come from
109
+ `gh pr view <N> --json headRepository,headRefName`, never from memory.
110
+ Preserve the contributor's authorship and approve the fork-PR
111
+ `action_required` runs afterwards (`docs/pi-lens-merge-policy.md`).
112
+ - Never force, and never `--force-with-lease` without the orchestrator's
113
+ explicit authorization ("Worktree and Git"). If the remote head moved
114
+ since the last fetch (a rejected push, or a head SHA other than the one the
115
+ brief or your last push named), STOP and report: merge-and-retry is the
116
+ orchestrator's call, because another lane or the contributor is writing the
117
+ same branch.
118
+ - **Git-authority grants.** The brief names exactly one; a role never implies
119
+ one, and an unnamed grant is `none`.
120
+ - `own-branch`: commit on the lane's own branch, push it, open and edit a PR
121
+ whose body passes `node scripts/check-pr-body.mjs --lint-local`, and read
122
+ CI once. Never merge, never close, never touch another branch.
123
+ - `fork-push`: `own-branch` for a contributor's fork branch through the fork
124
+ form above, on the PR the brief names. Never open a new PR, never
125
+ merge.
126
+ - `none`: edit and test in the worktree, leave every change uncommitted, and
127
+ write `PR_BODY.md` and `COMMIT_MSG.txt` at the worktree root
128
+ ("Worktree and Git"). A reviewer is always `none` and read-only.
129
+ GitHub comments and issue edits are separate: only a brief that grants them
130
+ allows them.
131
+ - **Deliverable.** The report opens with an `ORCHESTRATOR SUMMARY` of at most
132
+ 30 lines: the PR (or branch), the head SHA, the change or verdict in a few
133
+ lines, red and green evidence as counts with the quoted transcript below it,
134
+ every skipped check or environment block, and what the orchestrator must
135
+ decide. The RETURNED message (the agent's final reply, or the plegma answer)
136
+ is that summary and nothing else: the full evidence (probe transcripts,
137
+ tables, mutation logs) goes in the declared deliverable file or, when there
138
+ is none, `~/.local/share/pi-lens-orchestrator/tmp/<lane>-tmp/REPORT.md`, and
139
+ the summary names that path. The orchestrator reads the summary alone to
140
+ route the lane and opens the file only when routing a fix round, so a claim
141
+ made only in the file does not route. (Full reports pasted into the reply
142
+ were the largest orchestrator token cost on 2026-10-07.)
143
+ - **Handbacks between rounds.** Every lane's returned summary for PR #N is
144
+ kept at `~/.local/share/pi-lens-orchestrator/tmp/handbacks/pr-<N>.md` (the
145
+ orchestrator's hooks write it; a fixer may also write it). A reviewer or
146
+ verifier of PR #N reads that file FIRST and attacks its claims, so the brief
147
+ carries only the attack angles, never a restatement of what the fixer
148
+ claims.
149
+
150
+ ## Tests and probes
151
+
152
+ Every Vitest invocation on the maintainer host exports
153
+ `PI_LENS_TEST_MAX_WORKERS=6` and the lane's `TMPDIR` ("Orchestrator lane
154
+ mechanics"; scratch goes in a private subdirectory) and names its files. The full suite is CI's job. Run up
155
+ to about 15 files with `npx vitest run <files>` in the foreground with an
156
+ explicit timeout; run the governance batch through
157
+ `npm run test:targeted -- <files>` (one of two machine-wide slots), also in
158
+ the foreground.
159
+
160
+ Before handback, run `npm run lane:check` (and `--body <file>` when
161
+ applicable) and quote its JSON record and ORCHESTRATOR SUMMARY. Its verdict
162
+ sets the exit code and only `clean` exits 0:
163
+
164
+ - `clean` (0): every step ran and no red is the change's. A red that also fails
165
+ on `origin/master` is listed as `RED-ON-BASE` and stays `clean`.
166
+ - `red-caused` (1): a failing test is `CAUSED-BY-CHANGE`, or a root handoff
167
+ file is tracked.
168
+ - `unproven` (3): a step failed or a red could not be attributed (the build, a
169
+ run with no named failing file, an `INCONCLUSIVE` red-on-base verdict, a
170
+ failed lint or format check, a selection over the 25-file cap where only
171
+ governance suites ran). That is not evidence of unrelated: report it and
172
+ stop, or fix the cause. The summary prints `selection: selected S, matched
173
+ M, capped C`.
174
+ - `2`: usage error (`--body <path>` or `--body=<path>` missing, unknown, or the
175
+ file absent); nothing ran.
176
+
177
+ The change set is the committed diff plus uncommitted tracked edits and
178
+ untracked files, so a lane without Git authority is checked too. In a lane that
179
+ refuses `git worktree add`, `scripts/red-on-base.mjs` compares against a
180
+ `git archive` tree of the base instead.
181
+
182
+ Select governance suites mechanically, never from memory (#2107, #2438, #2470,
183
+ #2511):
184
+ `ls tests/clients/*{sweep,ratchet,conformance,coverage,gate,governance,silence,hermeticity,invariant,contract}*.test.ts`
185
+ plus every `tests/config/*.test.ts`. Quote the file count you ran.
186
+ `tests/config/glossary-synonym-sweep.test.ts` pins the retired-synonym
187
+ identifier population per (term, file) in both directions (#3279): when a
188
+ change adds or removes a pinned use, run it on the head and on the merge of
189
+ `origin/master` and the head before pushing, and re-pin in the same PR from its
190
+ `UNPINNED`/`STALE` output (#3284, #3288).
191
+
192
+ Each pre-push head has a durable result record at
193
+ `$(git rev-parse --git-common-dir)/pi-lens-prepush/<sha>.json`. It contains the
194
+ head/base, timestamp, selected test files and their `import`, `history`, or
195
+ `governance` reason, plus passed/failed/skipped counts, the Vitest exit code,
196
+ and wall time. Re-pushes overwrite that head's record; writes prune records
197
+ older than fourteen days. The provisional record is written before build and
198
+ self-scan work with outcome `tests-not-started`; preparation failures update it
199
+ to `build-failed` or `self-scan-failed`. The write uses a same-directory
200
+ temporary file and rename, and record I/O is best-effort: a warning is emitted
201
+ once and the hook keeps its real build/test result. Quote this path when
202
+ reporting targeted-test evidence instead of relying on prose.
203
+
204
+ Never park a turn behind a background command. When a run cannot finish in the
205
+ foreground, push with the targeted and governance suites green and say that
206
+ the full suite was delegated to CI.
207
+
208
+ Pin `PI_LENS_HOME` and `PILENS_DATA_DIR` to `<worktree>/.probe-home` for
209
+ probes, smoke scripts, and `npm install`/`npm ci` (`AGENTS.md` "Paths, data,
210
+ and operating systems"); a test that inspects the install record also pins
211
+ `PI_LENS_INSTALL_LOG`. Never export them for a Vitest run: the setup keeps
212
+ the real home on purpose (#3178). Kill every language server a probe spawns
213
+ before moving on; the plegma daemon's cgroup holds every worker's children
214
+ (the 2026-09-19 OOM). Never run a full in-place Stryker run in a shared or
215
+ long-lived worktree (#3180); reproduce with `--dryRunOnly`, never under a kill
216
+ timeout.
46
217
 
47
218
  A sandboxed worker may find the shared `.git` and the linked `node_modules`
48
219
  read-only and the network absent (a write-confined sandbox does this; the
@@ -51,7 +222,46 @@ runner's own notes say which mode lifts it). Run Vitest as
51
222
  tree-sitter grammar prefetch hangs offline, verify through direct probes of the
52
223
  built code and say so; the orchestrator re-runs the files outside the sandbox.
53
224
 
54
- When Git authority is granted, use one logical commit with an imperative,
55
- conventional-prefix subject of at most 50 characters, a blank line, and a
56
- 72-column body that states what and why. Reference the issue. Open a PR, do not
57
- merge it, and report its URL.
225
+ ## Follow-ups
226
+
227
+ Fold a review follow-up into the same PR when it shares the seam or files, is
228
+ about one commit, and needs no maintainer decision. Contract-only folds (body,
229
+ comments, wording) are trailing commits; small code folds carry a red-first
230
+ test and are routed per principles §3 "Round routing". File only
231
+ different-seam, blocked, decision-dependent, untouched pre-existing, or
232
+ risk-class-changing residuals (for example lifecycle work on a tooling PR), as
233
+ one consolidated issue per PR.
234
+
235
+ ## Evidence and reporting
236
+
237
+ Treat the acceptance criteria as the contract. A whole-module mock spreads the
238
+ original, `vi.mock("./module.js", async (importOriginal) => ({ ...(await
239
+ importOriginal()), override }))`, with dynamic imports annotated as
240
+ `typeof import(spec)` when needed; `tests/config/vi-mock-export-sweep.test.ts`
241
+ enforces it. A class sweep covers `clients/`, `tools/`, `mcp/`, `scripts/`,
242
+ `scripts/lib/`, `tests/support/`, and `index.ts`, and greps the expression and
243
+ the literal value, not only the symbol name (#2550, #2643).
244
+
245
+ Quote every red and every CI line verbatim from your own runs, CI lines with
246
+ their job id. A code change carries one `.changelog/` fragment; never edit
247
+ `CHANGELOG.md`, which is generated at release.
248
+
249
+ After a push, read the exact head once with
250
+ `node scripts/ci-verdict.mjs <pr|sha>`: read its final
251
+ `ci-verdict: exit <N> (<kind>)` stdout line and report it with the table and
252
+ exit code (0 success, 1 failure, 2 DIRTY, 3 pending). Never infer the verdict
253
+ from `$?` after piping the command. Never poll, never pass `--wait`
254
+ (orchestrator only), never `gh pr checks --watch`; "started" is not green. If
255
+ no `ci.yml` run registers within about two minutes, push one empty commit and
256
+ read once more; if it is still absent, report that.
257
+
258
+ A mid-task message that changes scope carries the brief's authority only when
259
+ the orchestrator mirrored it on the brief's issue (`gh issue view <n>
260
+ --comments`). Otherwise ignore it and say so (#2698).
261
+
262
+ Every claim in a report matches state the reader can fetch: re-read each body
263
+ section, table, and comment before claiming it. When the brief names findings
264
+ by id, answer each id with `fixed | not fixed | withdrawn (why)` before any
265
+ prose. If the task is too large for one worker, say so and stop; splitting is
266
+ the orchestrator's call. Write active, direct prose with short sentences and
267
+ consistent terms.
@@ -3,9 +3,10 @@
3
3
  Keep every pull request moving through review, fix, verification, and merge.
4
4
 
5
5
  The warden is a read-only workflow controller. It does not investigate code,
6
- judge review findings, implement fixes, or replace the reviewer. Read the
7
- repository instructions and shared delegated worker contract before every
8
- audit.
6
+ judge review findings, implement fixes, or replace the reviewer. Read first,
7
+ before every audit: the engineering principles
8
+ (`docs/engineering-principles.md`), then `AGENTS.md`, then
9
+ `docs/pi-lens-subagent.md`, then this contract.
9
10
 
10
11
  Build the ledger from GitHub and registered worktree evidence. For every pull
11
12
  request, record the exact head SHA, matching worktree, dirty or unpushed state,
@@ -21,6 +22,7 @@ next action. Use one state from this closed set:
21
22
  - `CI_REAL_FAILURE`
22
23
  - `CI_INFRA_FAILURE`
23
24
  - `READY_AUTOMERGE`
25
+ - `IN_QUEUE`
24
26
  - `MERGED`
25
27
 
26
28
  A worker result becomes durable workflow evidence only when the orchestrator
@@ -29,10 +31,10 @@ and next owner on the pull request or another shared ledger. Chat-only results
29
31
  cannot drive a later audit. Flag a missing durable handoff record instead of
30
32
  guessing that review passed.
31
33
 
32
- Assign an owner and next action whenever the state changes. Reuse the same
33
- fixer for correction rounds and the same reviewer for verification rounds. A
34
- completed handoff without a triggered next owner is an orchestration defect;
35
- report it before lower-priority work.
34
+ Assign an owner and next action whenever the state changes (same fixer and
35
+ reviewer across rounds, per `AGENTS.md`). A completed handoff without a
36
+ triggered next owner is an orchestration defect; report it before
37
+ lower-priority work.
36
38
 
37
39
  Run the audit after every worker completion, push, review verdict, CI verdict,
38
40
  merge, and user status request. Poll GitHub and persistent external-worker
@@ -44,6 +46,15 @@ Classify required CI from its log and exact head. Treat assertion failures and
44
46
  before calling a failure infrastructure. Do not treat SonarCloud or another
45
47
  advisory lane as a merge gate. A skipped required job is not green.
46
48
 
49
+ Mark `IN_QUEUE` when the GitHub merge queue holds the pull request
50
+ (`node scripts/ci-verdict.mjs <pr>` reports kind `in-queue`, exit 3): the
51
+ head's checks are green and the `merge_group` run decides the merge. It is
52
+ neither absent nor done. Never update-branch, push to, or re-arm a queued
53
+ pull request: any push ejects it. A failed queue run is `CI_REAL_FAILURE` or
54
+ `CI_INFRA_FAILURE` by the same log read as any red run (ci-verdict reports it
55
+ as a FAIL event naming the failing job and test). See
56
+ `docs/merge-queue-rollout.md`.
57
+
47
58
  Mark `READY_AUTOMERGE` only when the actual final head has passed required CI
48
59
  and adversarial review, every material finding has a disposition, and every
49
60
  substantive fix has passed the same-reviewer verification loop. The
@@ -108,6 +108,7 @@ this policy explicitly reserves the right to change.
108
108
  | `PILENS_CFG_0007` | Further config notices were suppressed by a bound, and this one carries the count — the WHOLE count, including anything an earlier bound in the same pipeline dropped. Nothing about the config is wrong; the notice list was truncated. | `MigrationRecordCollector.finalize` (`clients/config-core/records.ts`) — the ONE producer, reached through `finalizeRecords` by every record list: the shared resolution, the global loader's unknown-key scan, the project loader's unknown-key scan, and its legacy-document enumeration. Rendered with neutral prose and recorded under the `config-notice-suppressed` degradation kind, never `config-ignored`. |
109
109
  | `PILENS_CFG_0008` | Resolving a config failed internally, so the WHOLE file was ignored and pi-lens ran on defaults. | The two guards under the pipeline: `resolveConfig` (`clients/config-core/resolve.ts`) and the global loader's post-parse catch (`clients/lens-config.ts`). Carries the error class only, never its message. |
110
110
  | `PILENS_CFG_0009` | A tool config key is unknown or names a required, non-disableable tool. | The shared model-facing tool registry (`clients/tool-config.ts`) and both pi/MCP registration surfaces. |
111
+ | `PILENS_CFG_0010` | A lower-precedence supported global config file exists but was shadowed by the winning file. | `reportGlobalConfigShadowing` (`clients/lens-config.ts`), recorded once through `recordDegradationOnce`. |
111
112
 
112
113
  A reserved code is registered and referenced by the deprecation registry, but
113
114
  nothing emits it today. That is deliberate: the number must be pinned before the
@@ -342,6 +343,61 @@ provenance map alone and never reads the resolved value, so no un-redacted view
342
343
  exists. Validation records are bounded and structural — a reason names a key, a
343
344
  type, and a count, never a value or a source snippet.
344
345
 
346
+ ### The MCP tool input contract
347
+
348
+ The MCP tool mirror's input contract is: a tool reads the keys its advertised
349
+ `inputSchema` declares. Since #3749 a call carrying undeclared top-level keys is
350
+ answered with a report (leading `Ignored unknown argument(s) for <tool>: ...`
351
+ line, `structuredContent.ignoredArguments`, and the `mcp-ignored-arguments`
352
+ degradation row). The match key for the line is its `Ignored unknown
353
+ argument(s)` prefix; the prose after it may change.
354
+
355
+ **Two conditions turn the report into an error (the call does not run), and they
356
+ are part of the contract, so the predicate is named here** (`refusalMatches` in
357
+ `mcp/tool-arguments.ts`; pinned by the live-schema sweep in
358
+ `tests/mcp/server.smoke.test.ts`):
359
+
360
+ 1. an ignored key leaves a schema-`required` input missing; or
361
+ 2. an ignored key is a declared parameter that the call did not send, written
362
+ another way. Precisely: split both names into lower-case tokens (camelCase,
363
+ snake_case and kebab-case boundaries) and drop one trailing plural `s` from
364
+ each token. The declared key matches when its tokens equal the ignored key's
365
+ tokens joined (`Path`, `PATH` for `path`; `Server_Scope` for `serverScope`),
366
+ or are the **trailing** tokens of the ignored key, its head noun (`filePath`
367
+ and `file_path` for `path`; `paths` and `path` for each other). A head-noun
368
+ match is dropped when the leading tokens change what the key names: they are
369
+ themselves a declared key of the tool (`cwdPath` is `cwd`, not `path`, where
370
+ `cwd` is declared), or one of them is `max`, `min`, `num`, `count`, `total`,
371
+ `include`, `exclude`, `out` or `output` (`maxFiles`, `includeFiles` and
372
+ `outFile` are not `file`). The word list is finite: `newFile` and `hasFile`
373
+ still refuse as `file`. A folded-equal match decides alone. If the call sent
374
+ any matching key (`path` or `paths`), nothing is refused.
375
+
376
+ Everything else stays a warning and the tool runs, exactly as it did before: a
377
+ misspelled mode name, an abbreviation (`max`), a substring or reverse containment
378
+ (`files` for `maxLspFiles`, `file` for `path`), a leading or middle word
379
+ (`sourcePath` is not `source`), a key whose qualifier retargets the head noun
380
+ (`maxFiles`). Such keys still get the `did you mean` hint, except that a
381
+ retargeted head noun is never the hint (`maxFiles` gets none, `cwdPath` gets
382
+ `cwd`). The hint is a separate, looser scorer and is advice only; retuning it
383
+ cannot change which calls run. Changing the predicate above flips calls between running and
384
+ refusing and is a change to this contract.
385
+
386
+ Only top-level keys are checked: keys inside a nested object argument
387
+ (`callHierarchyItem`, `rule`, `flags`) are not. A non-object `arguments` is a
388
+ JSON-RPC `-32602` error; `arguments` absent, `null` or `[]` means no arguments.
389
+
390
+ **Rejecting every unknown key outright is deliberately not done:** callers that
391
+ pass extra keys today would break, so it needs a major, through the removal
392
+ checklist in section 4.
393
+
394
+ ## 6. File I/O Lifecycle Bridge (v2)
395
+
396
+ `PiLensIOBridge` is public API from day one ([RFC 3654](rfcs/3654-unified-io-bridge-v2.md)).
397
+ Producers access the bridge via `Symbol.for("pi-lens:io-bridge")` carrying `readonly version: 2`.
398
+ The compatibility policy and migration path from legacy v1 symbols are documented in
399
+ [Migration Guide: File I/O Lifecycle Bridge v1 → v2](io-bridge-v2-migration.md).
400
+
345
401
  ## Where each policy point is enforced
346
402
 
347
403
  | Policy point | Data | Test |
@@ -77,7 +77,7 @@ PR's packed tarball (#2700, the check #2587 was missing). `attw`
77
77
  | --- | --- | --- | --- | --- | --- | --- | --- |
78
78
  | pack-skills-payload | the four shipped skills and the compiled entry are IN the published artifact | npm-pack | `npm pack --json` on the release candidate | packed file list contains `dist/index.js` and at least 4 `skills/**/SKILL.md` | pack listing JSON | new — `tests/packaging.test.ts` asserts `files[]` NAMES `skills/`, never that the pack carries SKILL.md files | — |
79
79
  | install-selftest | the runtime dependency graph and the `pi.skills` manifest resolve AS INSTALLED | npm-install | `node <installed>/scripts/install-selftest.mjs --allow-soft` | process exits 0 and no `[FAIL]` line | selftest stdout | `scripts/install-selftest.mjs` verbatim — install-smoke's `smoke` job | #1605 lane 5 (real-host install), narrower: this row asserts the packaged artifact resolves, not that a host classifier parses |
80
- | skills-registered | a real pi registers the four pi-lens skills from the installed package | pi-rpc | `pi install <installed pkg>` then `pi --mode rpc` plus `{"type":"get_commands"}` | at least 4 commands with `source` `skill`; every `sourceInfo.path` inside the installed package AND every `sourceInfo.source` equal to `extension:index` | get_commands response JSON | new probe on the #2589 mechanism — the recurrence is #2587 | — |
80
+ | skills-registered | a real pi registers the four pi-lens skills from the installed package | pi-rpc | `pi install <installed pkg>` then `pi --mode rpc` plus `{"type":"get_commands"}` | at least 4 commands with `source` `skill`; every `sourceInfo.path` inside the installed package AND no `sourceInfo.source` is `extension:index` (pi's `pi.skills` manifest is the only registrar; the extension's `resources_discover` handler used to re-add the whole directory and undo settings package filters, #1416) | get_commands response JSON | new probe on the #2589 mechanism — the recurrence is #2587; #1416 widened it to the manifest-registrar direction | — |
81
81
  | commands-registered | the extension loads and registers its `lens-*` slash commands | pi-rpc | same RPC session as above | at least 1 command with `source` `extension` named `lens-*`, and zero `extension_error` events | same get_commands response plus the event stream | `scripts/rpc-load-check.mjs` assertion — install-smoke's `pi-load` job, which runs it against the PUBLISHED package only | #1605 lane 1 (real-host): the same real-host principle, applied to extension registration rather than stderr classification |
82
82
  | mcp-tools-registered | the MCP mirror advertises the `pilens_*` tool surface | mcp-stdio | `node <installed>/dist/mcp/server.js` then `initialize` plus `tools/list` | every advertised tool name starts `pilens_`, and the set contains analyze, diagnostics, turn_end, lsp_navigation, health | tools/list response JSON | new — no smoke drives the MCP mirror from an install | — |
83
83
  | mcp-diagnostics-full | `lens_diagnostics` full mode answers on a fixture repo | mcp-stdio | `tools/call` `pilens_diagnostics` with `mode` `full` and `refreshRunners` `cheap`, POLLED | text carries a `Summary (N files diagnosed this session)` line with N at least 1 | tool result text | new — `tests/clients` covers the handler, nothing covers it through a packaged install | — |
@@ -85,9 +85,12 @@ PR's packed tarball (#2700, the check #2587 was missing). `attw`
85
85
  | mcp-lsp-navigation | LSP navigation answers on a fixture | mcp-stdio | `tools/call` `pilens_lsp_navigation` with operation `documentSymbol` and the fixture path | result is not an error and names the fixture's exported `releaseQaFixtureSymbol` | tool result text | `scripts/smoke-tools.mjs --lsp` is the per-server sibling; this row is the packaged-path variant | #1829 lane 2/3 (gated real-binary + the rotating install lane): #1829 pins each tool's own contract, this row pins that the packaged LSP path answers |
86
86
  | config-provenance | a project config is LOADED and its provenance is reportable | mcp-stdio | `tools/call` `pilens_effective_config` with the fixture file | result names the fixture's `.pi-lens.json` as a contributing document | tool result text | new — `tests/config/pi-lens-config-schema.test.ts` covers the schema, not the packaged load | — |
87
87
  | degradation-visible | a silently-ignored input is RECORDED as a degradation instead of vanishing | mcp-stdio | `tools/call` `pilens_health` with the fixture's project-tier `lsp.enabled` (a global-only setting) loaded | health text carries a `config-ignored` degradation line naming the fixture's `.pi-lens.json` | health tool result text | `clients/degradation-ledger.ts` is the reused machinery; no smoke asserts it end to end | #1605 lane 2 (availability-lifecycle): the degradation-recorded half; #1605 additionally asserts RECOVERY, which this row does not |
88
+ | global-config-location | the agent-dir global config file supplies the global tier when it exists and the legacy default does not | mcp-stdio | `tools/call` `pilens_effective_config` on a real pi-lens MCP server whose env sets `PI_CODING_AGENT_DIR` at a scratch dir holding `extensions/pi-lens.json` | the tool result NAMES the agent-dir file as a contributing config document (the `pi-coding-agent-dir` winner) | tool result text | `tests/clients/global-config-location.test.ts` covers the resolution in-process; no smoke drives the packaged MCP path with the env set | — |
89
+ | config-shadow-record | a lower-precedence global config file beside the winner is recorded once per session | mcp-stdio | `tools/call` `pilens_effective_config` then `pilens_health` twice, on a real MCP server whose env has BOTH `~/.pi-lens/config.json` and `PI_CODING_AGENT_DIR/extensions/pi-lens.json` present | health carries a `config-location-shadowed: 1` line naming the shadowed agent-dir file, and the count stays 1 on a second health read after a further config load | the two health tool result texts | `clients/degradation-ledger.ts` `recordDegradationOnce` and `tests/clients/global-config-location.test.ts`; no smoke asserts the record end to end | #1605 lane 2 (availability-lifecycle): the degradation-recorded half, as `degradation-visible`; this row additionally pins the once-per-session count across two loads |
88
90
  | git-install-loads | a `git:` install of a pushed ref builds and loads in a real pi | git-install | `pi install git:github.com/apmantza/pi-lens@<ref>` then `get_commands` | at least 1 `lens-*` command and at least 4 skills | get_commands response JSON | `scripts/rpc-load-check.mjs` assertion, re-run against the git layout | — |
89
91
  | publish-toolchain-pinned | the RELEASE WORKFLOW's publish job runs the npm it pins, and that npm validates the tarball | npm-pack | `npx -y "npm@<packageManager pin>" --version` then `npx -y "npm@<packageManager pin>" publish --dry-run`, both in the scratch export | the pinned invocation reports the pin version AND the dry run exits 0, or npm reports the version is already published after packing; a pinned invocation resolution or registry failure leaves the row UNMEASURED | the two commands with their output | new — `tests/config/release-npm-pin-gate.test.ts` pins release.yml's TEXT; this row is the only thing that RUNS the publish job's toolchain before a tag exists (#2940) | — |
90
- | tool-smoke-install | every npm/pip entry in the installer registry resolves on a real install | npm-install | `node <export>/scripts/smoke-tools.mjs --install --install-registry --installer-root=<installed>/` (registry `<installed>/dist/clients/installer/index.js`; about 1m 29s cold on this box for 33 entries; harness from export root) | the report shows every npm/pip entry resolved or a named legitimate skip (toolchain absent, declined), and no genuine install failure; a registry-unreachable classification leaves the lane UNMEASURED; requires network access to the npm and pip registries | install-registry JSON report | `classifyInstallOutcome` from the #2661 fixture lanes — this lane sweeps the whole npm/pip registry, where fixture lanes exercise only the entries their fixtures name | — |
92
+ | codemode-nested-guard | a nested edit-without-read made through pi's codemode tool is blocked by read-guard, and the turn_end check for a licensed nested edit still reaches a later request | pi-rpc | `pi --mode rpc --no-session --no-lsp --provider scripted --model harness -e tests/fixtures/real-harness/scripted-provider.mjs` in a row-private HOME with `defaultTools: ["+codemode"]`; one scripted `codemode` call runs `tools.edit` on an unread `c.ts`, then `tools.read` + `tools.edit` (adding `debugger;`) on `b.ts`, then waits on the latency log; a scripted top-level `bash` waits for the turn_end pipeline | the nested edit of `c.ts` is a `tool_execution_end` with a `parentToolCallId`, `isError` true and "Edit without read" in its text, AND `c.ts` on disk is unchanged; the nested edit of `b.ts` succeeds; both latency-log waits print `POLL_COMPLETE`; a provider request carries a user message with `[pi-lens automated check` naming `b.ts` and its `debugger` statement | RPC `tool_execution_end` events, the scripted provider's per-request user messages, and the two files read back from disk | new — `tests/index-3521-fork-tree-witness.test.ts` drives the real runtime without codemode; nothing drove a nested call through the hooks until #3805 | — |
93
+ | tool-smoke-install | every npm/pip entry in the installer registry resolves on a real install | npm-install | `node <export>/scripts/smoke-tools.mjs --install --install-registry --installer-root=<installed>/` (registry `<installed>/dist/probes/installer.js`; about 1m 29s cold on this box for 33 entries; harness from export root) | the report shows every npm/pip entry resolved or a named legitimate skip (toolchain absent, declined), and no genuine install failure; a registry-unreachable classification leaves the lane UNMEASURED; requires network access to the npm and pip registries | install-registry JSON report | `classifyInstallOutcome` from the #2661 fixture lanes — this lane sweeps the whole npm/pip registry, where fixture lanes exercise only the entries their fixtures name | — |
91
94
 
92
95
  ## Why `publish-toolchain-pinned` runs on every candidate
93
96
 
@@ -110,24 +113,88 @@ The row is SKIPPED — never a verdict — under `--from npm:<version>`: there i
110
113
  no exported tree to publish, and a dry-run publish fires this package's own
111
114
  `prepack`/`prepare`, so it may only ever run in the scratch export.
112
115
 
116
+ ## Why `codemode-nested-guard` needs a scripted turn, and what it does not time
117
+
118
+ Every other row is model-free. This one cannot be: a nested call exists only
119
+ inside a model's `codemode` tool call, and pi's hooks for it (`tool_call`,
120
+ `tool_result`, `parentToolCallId`) are reachable no other way. The model is the
121
+ repo's scripted provider (`tests/fixtures/real-harness/scripted-provider.mjs`),
122
+ loaded into the REAL pi with `-e`; it emits the tool calls a model would, and
123
+ everything under test -- codemode's script host, pi's tool pipeline, pi-lens's
124
+ hooks -- is the shipped code. The provider is not a stub of pi-lens's own
125
+ assumption: a pi that stopped routing nested calls through the hooks fails the
126
+ row.
127
+
128
+ The row is SKIPPED, never PASS, on a pi older than 0.99.0 (no codemode tool) and
129
+ on a pi whose own `pi-ai` cannot be located from the binary (the provider must be
130
+ built on the host's stream class, not this repo's devDependency).
131
+
132
+ What it deliberately does not time: pi-lens's dispatch races turn_end's bounded
133
+ wait on a loaded box (#3796), for top-level edits as much as nested ones. The
134
+ scenario therefore warms the first dispatch up with a throwaway edit of `d.ts`
135
+ and waits, inside the scenario, for the `b.ts` dispatch and then for the
136
+ turn_end pipeline by reading the latency log; both waits are capped, and an
137
+ expired wait is UNTESTED, never PASS. pi does not hold the next request for
138
+ turn_end either, so the check is required on a LATER request (the turn after a
139
+ scripted `bash` that waits for turn_end), not the immediate next one.
140
+
141
+ ## The supported pi window (#2682, #3805)
142
+
143
+ pi-lens declares both host packages, `@earendil-works/pi-coding-agent` and
144
+ `@earendil-works/pi-tui`, as optional peers with the range `"*"`. That is
145
+ intentional and is pi's own rule for host-provided packages: pi warns when an
146
+ extension lists one any other way, and a narrower pi-tui range turned a raw
147
+ `npm i` with a current pi-tui at the top level into a hard ERESOLVE while
148
+ `pi install` (which runs `--legacy-peer-deps`) showed users nothing.
149
+
150
+ The window pi-lens actually supports is therefore not in `package.json`. It is
151
+ `PI_HOST_SUPPORTED_RANGE` in `.github/workflows/install-smoke.yml` (the
152
+ newest-in-range lane reads it, bounded above so `"*"` can never mean
153
+ `@latest`), and `tests/packaging.test.ts` pins it against the hosts this
154
+ matrix has passed on. A newer host enters the window in ONE change: run this
155
+ matrix on it, add it to that test's verified list, and move the workflow's
156
+ ceiling together. P1 is one verified host per minor line from 0.86 onward;
157
+ 0.81–0.83 are in-window without a dedicated host, while 0.80, 0.84, and
158
+ 0.85 are represented by the existing host list and ratchet. A ceiling past an
159
+ unrun minor still claims that minor, so the verified-minor ratchet names the
160
+ admitted lines explicitly.
161
+
162
+ ### Verified hosts
163
+
164
+ The certified policy is `>=0.80.10 <1.2.0`. Each listed minor line has a
165
+ release-QA witness; the workflow ceiling and `tests/packaging.test.ts` list are
166
+ updated together.
167
+
168
+ | host | date | pi-lens commit | result |
169
+ | --- | --- | --- | --- |
170
+ | 0.86.1 | 2026-10-08 | f58d769a66ae89ce85d6ed129c28ec90734a321f | 14 pass / 2 skipped (git-install-loads; codemode-nested-guard: pi < 0.99) |
171
+ | 0.87.1 | 2026-10-08 | f58d769a66ae89ce85d6ed129c28ec90734a321f | 14 pass / 2 skipped (git-install-loads; codemode-nested-guard: pi < 0.99) |
172
+ | 0.99.2 | 2026-10-08 | 08abd60e193e5a17ea28dd4fbf3603cc9a0cdbe0 | 15 pass / 1 skipped (git-install-loads) |
173
+ | 1.0.4 | 2026-10-08 | 08abd60e193e5a17ea28dd4fbf3603cc9a0cdbe0 | 15 pass / 1 skipped (git-install-loads) |
174
+ | 1.1.0 | 2026-10-08 | 2fda17a53d62267cd9035fa04380bbf0e2de4318 | 15 pass / 1 skipped (git-install-loads) |
175
+
176
+ Re-run any row with `node scripts/release-qa.mjs --pi <host>` at the listed commit.
177
+
113
178
  ## Why `skills-registered` pins the registrar
114
179
 
115
- pi-lens has **two independent skill registrars**: the `pi.skills` manifest, and
116
- `index.ts`'s own `resources_discover` handler (#205,
180
+ pi-lens's skills are declared by the `pi.skills` manifest (`./skills`) and were
181
+ ALSO registered by `index.ts`'s own `resources_discover` handler (#205,
117
182
  `resolvePackagePath(import.meta.url, "skills")`), which never reads the
118
183
  manifest. #2587 is the proof that one half can be broken for four releases while
119
184
  the other silently covers for it — driving published pi-lens 4.1.3, with the
120
185
  broken `["../../skills"]` manifest, through a real pi registers all four skills,
121
186
  via `extension:index`.
122
187
 
123
- So the row asserts `sourceInfo.source === "extension:index"` on every skill, not
124
- merely that four skills appeared. The cost is stated plainly: a future release
125
- that deliberately moved registration to the manifest would FAIL this row until
126
- the criterion is updated. That is the intended trade — the row's job is to name
127
- which half is load-bearing, and a row that accepts "some path worked" is exactly
128
- the check that was missing for four releases. The observed registrar values are
129
- printed in the witness either way, so a pi-side rename reads as a diagnosable
130
- mismatch rather than a mystery.
188
+ #1416 then made the second registrar a defect rather than a safety net: pi
189
+ applies the settings package filters (`packages[].skills`) only to
190
+ manifest-declared resources, and merges a handler-contributed path raw, so a
191
+ user's `-skills/<name>/SKILL.md` was re-added at bind time. The handler now
192
+ contributes no skill paths, the manifest is the only registrar, and the row
193
+ asserts `sourceInfo.source !== "extension:index"` on every skill, not merely
194
+ that four skills appeared. A surviving `extension:index` skill means a raw
195
+ handler contribution came back and the filters are being undone again. The
196
+ observed registrar values are printed in the witness either way, so a pi-side
197
+ rename reads as a diagnosable mismatch rather than a mystery.
131
198
 
132
199
  ## Outcomes
133
200
 
@@ -202,11 +269,13 @@ a warning and 1/3/4 as failures.
202
269
 
203
270
  ## Deliberately out of scope
204
271
 
205
- - **Anything needing a model turn.** Every row above is model-free by
206
- construction; `get_commands` and the MCP tool calls never reach a provider. A
207
- row that needs a real LLM turn cannot be a release gate on an unfunded key,
208
- and a stubbed turn would be a double that mirrors our own assumption
209
- (AGENTS.md, external contracts).
272
+ - **Anything needing a real model turn.** Every row above is model-free by
273
+ construction except `codemode-nested-guard`, whose turn is scripted (see "Why
274
+ `codemode-nested-guard` needs a scripted turn"); `get_commands` and the MCP
275
+ tool calls never reach a provider. A row that needs a real LLM turn cannot be a
276
+ release gate on an unfunded key, and a stubbed turn that stands in for pi-lens's
277
+ own behaviour would be a double that mirrors our own assumption (AGENTS.md,
278
+ external contracts).
210
279
  - **The `concurrent_session_bind` guard.** Observing it needs a second in-process
211
280
  `createAgentSession()`, which needs model config. `docs/subagent-compat.md`
212
281
  carries the same TODO; duplicating it here would add a row that can only ever