harnery 0.38.0 → 0.40.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 (378) hide show
  1. package/dist/commands/agents.d.ts.map +1 -1
  2. package/dist/commands/agents.js +32 -8
  3. package/dist/commands/artifacts.d.ts.map +1 -1
  4. package/dist/commands/artifacts.js +97 -6
  5. package/dist/commands/backup.d.ts +16 -0
  6. package/dist/commands/backup.d.ts.map +1 -1
  7. package/dist/commands/backup.js +239 -33
  8. package/dist/commands/browse.d.ts +8 -0
  9. package/dist/commands/browse.d.ts.map +1 -1
  10. package/dist/commands/browse.js +466 -231
  11. package/dist/commands/diagnostics.d.ts.map +1 -1
  12. package/dist/commands/diagnostics.js +6 -3
  13. package/dist/commands/ledger-v3.d.ts.map +1 -1
  14. package/dist/commands/ledger-v3.js +20 -4
  15. package/dist/commands/qa-run.d.ts.map +1 -1
  16. package/dist/commands/qa-run.js +26 -3
  17. package/dist/commands/qa-status.d.ts.map +1 -1
  18. package/dist/commands/qa-status.js +7 -2
  19. package/dist/commands/resources.d.ts.map +1 -1
  20. package/dist/commands/resources.js +23 -3
  21. package/dist/commands/review-pack.d.ts.map +1 -1
  22. package/dist/commands/review-pack.js +98 -23
  23. package/dist/commands/tunnel.d.ts.map +1 -1
  24. package/dist/commands/tunnel.js +2 -2
  25. package/dist/core/adapters/profiles.d.ts +1 -1
  26. package/dist/core/agents/canonical-emit.d.ts +3 -2
  27. package/dist/core/agents/canonical-emit.d.ts.map +1 -1
  28. package/dist/core/agents/canonical-emit.js +2 -0
  29. package/dist/core/agents/cli.js +13 -6
  30. package/dist/core/agents/live-authority-v3.d.ts.map +1 -1
  31. package/dist/core/agents/live-authority-v3.js +5 -3
  32. package/dist/core/agents/live-lifecycle-v3.d.ts +2 -2
  33. package/dist/core/agents/live-lifecycle-v3.d.ts.map +1 -1
  34. package/dist/core/agents/render/prompt-context.d.ts +7 -5
  35. package/dist/core/agents/render/prompt-context.d.ts.map +1 -1
  36. package/dist/core/agents/render/prompt-context.js +63 -8
  37. package/dist/core/agents/session-finalizer-v3.d.ts +2 -2
  38. package/dist/core/agents/session-finalizer-v3.d.ts.map +1 -1
  39. package/dist/core/agents/state/live-coordination-view.d.ts +3 -3
  40. package/dist/core/agents/state/live-coordination-view.d.ts.map +1 -1
  41. package/dist/core/agents/state/live-coordination-view.js +2 -1
  42. package/dist/core/agents/state/names.d.ts +35 -2
  43. package/dist/core/agents/state/names.d.ts.map +1 -1
  44. package/dist/core/agents/state/names.js +80 -5
  45. package/dist/core/agents/state/stale-sweep.d.ts +2 -1
  46. package/dist/core/agents/state/stale-sweep.d.ts.map +1 -1
  47. package/dist/core/agents/state/stale-sweep.js +23 -6
  48. package/dist/core/agents/turn-elapsed.d.ts +51 -0
  49. package/dist/core/agents/turn-elapsed.d.ts.map +1 -0
  50. package/dist/core/agents/turn-elapsed.js +91 -0
  51. package/dist/core/artifacts/activity.d.ts +14 -0
  52. package/dist/core/artifacts/activity.d.ts.map +1 -0
  53. package/dist/core/artifacts/activity.js +52 -0
  54. package/dist/core/artifacts/delivery-card.d.ts +39 -0
  55. package/dist/core/artifacts/delivery-card.d.ts.map +1 -0
  56. package/dist/core/artifacts/delivery-card.js +282 -0
  57. package/dist/core/artifacts/index.d.ts +42 -7
  58. package/dist/core/artifacts/index.d.ts.map +1 -1
  59. package/dist/core/artifacts/index.js +288 -76
  60. package/dist/core/artifacts/mutation-lock.d.ts +2 -0
  61. package/dist/core/artifacts/mutation-lock.d.ts.map +1 -0
  62. package/dist/core/artifacts/mutation-lock.js +91 -0
  63. package/dist/core/backup/host-snapshot.d.ts +18 -0
  64. package/dist/core/backup/host-snapshot.d.ts.map +1 -0
  65. package/dist/core/backup/host-snapshot.js +64 -0
  66. package/dist/core/config.d.ts +20 -5
  67. package/dist/core/config.d.ts.map +1 -1
  68. package/dist/core/config.js +44 -10
  69. package/dist/core/diagnostics/advice.d.ts +38 -3
  70. package/dist/core/diagnostics/advice.d.ts.map +1 -1
  71. package/dist/core/diagnostics/advice.js +103 -99
  72. package/dist/core/diagnostics/bundle.d.ts.map +1 -1
  73. package/dist/core/diagnostics/bundle.js +111 -47
  74. package/dist/core/diagnostics/comparison.d.ts.map +1 -1
  75. package/dist/core/diagnostics/comparison.js +3 -2
  76. package/dist/core/diagnostics/contract.d.ts +15 -31
  77. package/dist/core/diagnostics/contract.d.ts.map +1 -1
  78. package/dist/core/diagnostics/contract.js +2 -5
  79. package/dist/core/diagnostics/index.d.ts +2 -0
  80. package/dist/core/diagnostics/index.d.ts.map +1 -1
  81. package/dist/core/diagnostics/index.js +2 -0
  82. package/dist/core/diagnostics/pressure-contract.d.ts +260 -0
  83. package/dist/core/diagnostics/pressure-contract.d.ts.map +1 -0
  84. package/dist/core/diagnostics/pressure-contract.js +70 -0
  85. package/dist/core/diagnostics/pressure.d.ts +25 -0
  86. package/dist/core/diagnostics/pressure.d.ts.map +1 -0
  87. package/dist/core/diagnostics/pressure.js +1138 -0
  88. package/dist/core/diagnostics/replay.d.ts.map +1 -1
  89. package/dist/core/diagnostics/replay.js +90 -10
  90. package/dist/core/events/v3/adapter-id.d.ts +6 -0
  91. package/dist/core/events/v3/adapter-id.d.ts.map +1 -0
  92. package/dist/core/events/v3/adapter-id.js +7 -0
  93. package/dist/core/events/v3/archive-retention.d.ts.map +1 -1
  94. package/dist/core/events/v3/archive-retention.js +3 -2
  95. package/dist/core/events/v3/bootstrap.d.ts +41 -4
  96. package/dist/core/events/v3/bootstrap.d.ts.map +1 -1
  97. package/dist/core/events/v3/bootstrap.js +120 -17
  98. package/dist/core/events/v3/capabilities.d.ts +16 -9
  99. package/dist/core/events/v3/capabilities.d.ts.map +1 -1
  100. package/dist/core/events/v3/capabilities.js +37 -2
  101. package/dist/core/events/v3/capability-drift.d.ts +2 -2
  102. package/dist/core/events/v3/capability-drift.d.ts.map +1 -1
  103. package/dist/core/events/v3/control-witness.d.ts +48 -5
  104. package/dist/core/events/v3/control-witness.d.ts.map +1 -1
  105. package/dist/core/events/v3/control-witness.js +91 -36
  106. package/dist/core/events/v3/control.d.ts.map +1 -1
  107. package/dist/core/events/v3/control.js +22 -2
  108. package/dist/core/events/v3/index.d.ts +2 -1
  109. package/dist/core/events/v3/index.d.ts.map +1 -1
  110. package/dist/core/events/v3/index.js +2 -1
  111. package/dist/core/events/v3/live-feed.d.ts +7 -1
  112. package/dist/core/events/v3/live-feed.d.ts.map +1 -1
  113. package/dist/core/events/v3/live-feed.js +21 -3
  114. package/dist/core/events/v3/live-routing.d.ts.map +1 -1
  115. package/dist/core/events/v3/live-routing.js +10 -2
  116. package/dist/core/events/v3/producers/command-recorder.d.ts +2 -2
  117. package/dist/core/events/v3/producers/command-recorder.d.ts.map +1 -1
  118. package/dist/core/events/v3/producers/command-recorder.js +2 -1
  119. package/dist/core/events/v3/producers/coordination-recorder.d.ts +2 -2
  120. package/dist/core/events/v3/producers/coordination-recorder.d.ts.map +1 -1
  121. package/dist/core/events/v3/producers/coordination-recorder.js +2 -1
  122. package/dist/core/events/v3/producers/hook-base.d.ts +2 -2
  123. package/dist/core/events/v3/producers/hook-base.d.ts.map +1 -1
  124. package/dist/core/events/v3/producers/hook-base.js +15 -5
  125. package/dist/core/events/v3/producers/hook.d.ts.map +1 -1
  126. package/dist/core/events/v3/producers/hook.js +17 -4
  127. package/dist/core/events/v3/producers/intake.d.ts +4 -4
  128. package/dist/core/events/v3/producers/intake.d.ts.map +1 -1
  129. package/dist/core/events/v3/producers/intake.js +3 -2
  130. package/dist/core/events/v3/producers/producer-state-observer.d.ts.map +1 -1
  131. package/dist/core/events/v3/producers/producer-state-observer.js +2 -1
  132. package/dist/core/events/v3/producers/recorder.d.ts +16 -5
  133. package/dist/core/events/v3/producers/recorder.d.ts.map +1 -1
  134. package/dist/core/events/v3/producers/recorder.js +31 -9
  135. package/dist/core/events/v3/reader.d.ts.map +1 -1
  136. package/dist/core/events/v3/reader.js +10 -13
  137. package/dist/core/events/v3/runtime-build.d.ts.map +1 -1
  138. package/dist/core/events/v3/runtime-build.js +3 -2
  139. package/dist/core/events/v3/runtime-telemetry-capabilities.d.ts +2 -2
  140. package/dist/core/events/v3/runtime-telemetry-capabilities.d.ts.map +1 -1
  141. package/dist/core/events/v3/turn-telemetry.d.ts +2 -2
  142. package/dist/core/events/v3/turn-telemetry.d.ts.map +1 -1
  143. package/dist/core/hooks/adapter/output.d.ts +16 -14
  144. package/dist/core/hooks/adapter/output.d.ts.map +1 -1
  145. package/dist/core/hooks/adapter/output.js +36 -38
  146. package/dist/core/hooks/backup-schedule.d.ts +34 -0
  147. package/dist/core/hooks/backup-schedule.d.ts.map +1 -0
  148. package/dist/core/hooks/backup-schedule.js +114 -0
  149. package/dist/core/hooks/cli.js +61 -18
  150. package/dist/core/hooks/codex-wsl-bridge.d.ts +2 -0
  151. package/dist/core/hooks/codex-wsl-bridge.d.ts.map +1 -1
  152. package/dist/core/hooks/codex-wsl-bridge.js +18 -4
  153. package/dist/core/hooks/index.d.ts +1 -0
  154. package/dist/core/hooks/index.d.ts.map +1 -1
  155. package/dist/core/hooks/index.js +1 -0
  156. package/dist/core/hooks/prompt-context/contract.d.ts +61 -0
  157. package/dist/core/hooks/prompt-context/contract.d.ts.map +1 -0
  158. package/dist/core/hooks/prompt-context/contract.js +102 -0
  159. package/dist/core/hooks/prompt-context/index.d.ts +5 -0
  160. package/dist/core/hooks/prompt-context/index.d.ts.map +1 -0
  161. package/dist/core/hooks/prompt-context/index.js +2 -0
  162. package/dist/core/hooks/prompt-context/runner.d.ts +24 -0
  163. package/dist/core/hooks/prompt-context/runner.d.ts.map +1 -0
  164. package/dist/core/hooks/prompt-context/runner.js +249 -0
  165. package/dist/core/qa-artifacts.d.ts +3 -0
  166. package/dist/core/qa-artifacts.d.ts.map +1 -1
  167. package/dist/core/qa-artifacts.js +25 -3
  168. package/dist/core/resources/contract.d.ts +69 -3
  169. package/dist/core/resources/contract.d.ts.map +1 -1
  170. package/dist/core/resources/contract.js +1 -1
  171. package/dist/core/resources/index.d.ts +1 -0
  172. package/dist/core/resources/index.d.ts.map +1 -1
  173. package/dist/core/resources/index.js +1 -0
  174. package/dist/core/resources/native.d.ts +36 -0
  175. package/dist/core/resources/native.d.ts.map +1 -0
  176. package/dist/core/resources/native.js +418 -0
  177. package/dist/core/resources/sampler.d.ts +2 -0
  178. package/dist/core/resources/sampler.d.ts.map +1 -1
  179. package/dist/core/resources/sampler.js +31 -1
  180. package/dist/core/resources/status.d.ts +61 -0
  181. package/dist/core/resources/status.d.ts.map +1 -0
  182. package/dist/core/resources/status.js +536 -0
  183. package/dist/core/resources/system.d.ts +27 -0
  184. package/dist/core/resources/system.d.ts.map +1 -0
  185. package/dist/core/resources/system.js +439 -0
  186. package/dist/core/semantic/contract.d.ts +13 -13
  187. package/dist/core/semantic/service.d.ts +2 -0
  188. package/dist/core/semantic/service.d.ts.map +1 -1
  189. package/dist/core/semantic/service.js +27 -4
  190. package/dist/core/storage/builtins.js +41 -0
  191. package/dist/core/supervisor/contract.d.ts +41 -3
  192. package/dist/core/supervisor/contract.d.ts.map +1 -1
  193. package/dist/core/supervisor/contract.js +3 -2
  194. package/dist/core/supervisor/findings.d.ts +3 -0
  195. package/dist/core/supervisor/findings.d.ts.map +1 -1
  196. package/dist/core/supervisor/findings.js +88 -0
  197. package/dist/core/supervisor/history.d.ts.map +1 -1
  198. package/dist/core/supervisor/history.js +14 -0
  199. package/dist/core/supervisor/ledger-state.d.ts +55 -0
  200. package/dist/core/supervisor/ledger-state.d.ts.map +1 -0
  201. package/dist/core/supervisor/ledger-state.js +0 -0
  202. package/dist/core/supervisor/service.d.ts.map +1 -1
  203. package/dist/core/supervisor/service.js +120 -7
  204. package/dist/core/supervisor/storage.d.ts +3 -1
  205. package/dist/core/supervisor/storage.d.ts.map +1 -1
  206. package/dist/core/supervisor/storage.js +4 -0
  207. package/dist/core/workflow/admission.d.ts +3 -0
  208. package/dist/core/workflow/admission.d.ts.map +1 -1
  209. package/dist/core/workflow/admission.js +28 -16
  210. package/dist/core/workflow/engine.js +2 -2
  211. package/dist/core/workflow/live-session-v3.d.ts.map +1 -1
  212. package/dist/core/workflow/live-session-v3.js +6 -1
  213. package/dist/core/workflow/proof.d.ts.map +1 -1
  214. package/dist/core/workflow/proof.js +4 -3
  215. package/dist/lib/browser/capture-fidelity.d.ts +7 -0
  216. package/dist/lib/browser/capture-fidelity.d.ts.map +1 -1
  217. package/dist/lib/browser/capture-fidelity.js +17 -0
  218. package/dist/lib/browser/client.d.ts +9 -0
  219. package/dist/lib/browser/client.d.ts.map +1 -1
  220. package/dist/lib/browser/client.js +85 -37
  221. package/dist/lib/browser/index.d.ts +3 -1
  222. package/dist/lib/browser/index.d.ts.map +1 -1
  223. package/dist/lib/browser/index.js +2 -1
  224. package/dist/lib/browser/page-review-budget.d.ts +13 -0
  225. package/dist/lib/browser/page-review-budget.d.ts.map +1 -0
  226. package/dist/lib/browser/page-review-budget.js +251 -0
  227. package/dist/lib/browser/page-review-contracts.d.ts +127 -0
  228. package/dist/lib/browser/page-review-contracts.d.ts.map +1 -0
  229. package/dist/lib/browser/page-review-contracts.js +5 -0
  230. package/dist/lib/browser/page-review-evidence.d.ts +48 -0
  231. package/dist/lib/browser/page-review-evidence.d.ts.map +1 -0
  232. package/dist/lib/browser/page-review-evidence.js +340 -0
  233. package/dist/lib/browser/page-review-judge.d.ts +1 -1
  234. package/dist/lib/browser/page-review-judge.d.ts.map +1 -1
  235. package/dist/lib/browser/page-review-judge.js +46 -38
  236. package/dist/lib/browser/page-review-pack.d.ts +44 -22
  237. package/dist/lib/browser/page-review-pack.d.ts.map +1 -1
  238. package/dist/lib/browser/page-review-pack.js +116 -36
  239. package/dist/lib/browser/page-review-source.d.ts +12 -0
  240. package/dist/lib/browser/page-review-source.d.ts.map +1 -0
  241. package/dist/lib/browser/page-review-source.js +22 -0
  242. package/dist/lib/browser/qa-run-contracts.d.ts +35 -9
  243. package/dist/lib/browser/qa-run-contracts.d.ts.map +1 -1
  244. package/dist/lib/browser/qa-run-contracts.js +48 -14
  245. package/dist/lib/browser/qa-run.d.ts.map +1 -1
  246. package/dist/lib/browser/qa-run.js +215 -68
  247. package/dist/lib/browser/qa-snapshot.d.ts +6 -0
  248. package/dist/lib/browser/qa-snapshot.d.ts.map +1 -1
  249. package/dist/lib/browser/qa-snapshot.js +259 -48
  250. package/dist/lib/browser/review-capture-transaction.d.ts +13 -0
  251. package/dist/lib/browser/review-capture-transaction.d.ts.map +1 -0
  252. package/dist/lib/browser/review-capture-transaction.js +79 -0
  253. package/dist/lib/browser/standalone-html.d.ts.map +1 -1
  254. package/dist/lib/browser/standalone-html.js +4 -2
  255. package/dist/lib/browser/thumbnail-association.d.ts +34 -0
  256. package/dist/lib/browser/thumbnail-association.d.ts.map +1 -0
  257. package/dist/lib/browser/thumbnail-association.js +158 -0
  258. package/dist/lib/browser/tiling.d.ts +30 -0
  259. package/dist/lib/browser/tiling.d.ts.map +1 -1
  260. package/dist/lib/browser/tiling.js +38 -0
  261. package/dist/lib/docs-metadata-managed.d.ts.map +1 -1
  262. package/dist/lib/docs-metadata-managed.js +4 -1
  263. package/dist/lib/identities/assume.d.ts.map +1 -1
  264. package/dist/lib/identities/assume.js +7 -1
  265. package/dist/lib/instructions/templates.d.ts.map +1 -1
  266. package/dist/lib/instructions/templates.js +1 -0
  267. package/dist/lib/local-file-url.d.ts +12 -0
  268. package/dist/lib/local-file-url.d.ts.map +1 -1
  269. package/dist/lib/local-file-url.js +16 -2
  270. package/dist/lib/tunnel/state.d.ts +19 -4
  271. package/dist/lib/tunnel/state.d.ts.map +1 -1
  272. package/dist/lib/tunnel/state.js +53 -13
  273. package/package.json +7 -4
  274. package/schemas/config.schema.json +69 -2
  275. package/src/commands/agents.ts +42 -9
  276. package/src/commands/artifacts.ts +130 -6
  277. package/src/commands/backup.ts +287 -34
  278. package/src/commands/browse.ts +564 -267
  279. package/src/commands/diagnostics.ts +6 -3
  280. package/src/commands/ledger-v3.ts +20 -3
  281. package/src/commands/qa-run.ts +37 -3
  282. package/src/commands/qa-status.ts +11 -2
  283. package/src/commands/resources.ts +23 -3
  284. package/src/commands/review-pack.ts +165 -62
  285. package/src/commands/tunnel.ts +2 -1
  286. package/src/core/agents/canonical-emit.ts +4 -2
  287. package/src/core/agents/cli.ts +14 -6
  288. package/src/core/agents/live-authority-v3.ts +7 -3
  289. package/src/core/agents/live-lifecycle-v3.ts +2 -2
  290. package/src/core/agents/render/prompt-context.ts +68 -14
  291. package/src/core/agents/session-finalizer-v3.ts +2 -2
  292. package/src/core/agents/state/live-coordination-view.ts +4 -4
  293. package/src/core/agents/state/names.ts +92 -7
  294. package/src/core/agents/state/stale-sweep.ts +22 -8
  295. package/src/core/agents/turn-elapsed.ts +135 -0
  296. package/src/core/artifacts/activity.ts +71 -0
  297. package/src/core/artifacts/delivery-card.ts +375 -0
  298. package/src/core/artifacts/index.ts +385 -91
  299. package/src/core/artifacts/mutation-lock.ts +106 -0
  300. package/src/core/backup/host-snapshot.ts +76 -0
  301. package/src/core/config.ts +66 -13
  302. package/src/core/diagnostics/advice.ts +148 -120
  303. package/src/core/diagnostics/bundle.ts +138 -52
  304. package/src/core/diagnostics/comparison.ts +6 -2
  305. package/src/core/diagnostics/contract.ts +39 -42
  306. package/src/core/diagnostics/index.ts +2 -0
  307. package/src/core/diagnostics/pressure-contract.ts +294 -0
  308. package/src/core/diagnostics/pressure.ts +1361 -0
  309. package/src/core/diagnostics/replay.ts +116 -11
  310. package/src/core/events/v3/adapter-id.ts +12 -0
  311. package/src/core/events/v3/archive-retention.ts +3 -6
  312. package/src/core/events/v3/bootstrap.ts +163 -16
  313. package/src/core/events/v3/capabilities.ts +75 -25
  314. package/src/core/events/v3/capability-drift.ts +2 -2
  315. package/src/core/events/v3/control-witness.ts +172 -41
  316. package/src/core/events/v3/control.ts +34 -2
  317. package/src/core/events/v3/index.ts +3 -0
  318. package/src/core/events/v3/live-feed.ts +23 -5
  319. package/src/core/events/v3/live-routing.ts +14 -2
  320. package/src/core/events/v3/producers/command-recorder.ts +4 -4
  321. package/src/core/events/v3/producers/coordination-recorder.ts +4 -4
  322. package/src/core/events/v3/producers/hook-base.ts +21 -16
  323. package/src/core/events/v3/producers/hook.ts +21 -4
  324. package/src/core/events/v3/producers/intake.ts +6 -6
  325. package/src/core/events/v3/producers/producer-state-observer.ts +2 -1
  326. package/src/core/events/v3/producers/recorder.ts +50 -21
  327. package/src/core/events/v3/reader.ts +14 -13
  328. package/src/core/events/v3/runtime-build.ts +3 -2
  329. package/src/core/events/v3/runtime-telemetry-capabilities.ts +3 -3
  330. package/src/core/events/v3/turn-telemetry.ts +4 -4
  331. package/src/core/hooks/adapter/output.ts +50 -36
  332. package/src/core/hooks/backup-schedule.ts +147 -0
  333. package/src/core/hooks/cli.ts +65 -14
  334. package/src/core/hooks/codex-wsl-bridge.ts +21 -5
  335. package/src/core/hooks/index.ts +1 -0
  336. package/src/core/hooks/prompt-context/contract.ts +177 -0
  337. package/src/core/hooks/prompt-context/index.ts +22 -0
  338. package/src/core/hooks/prompt-context/runner.ts +303 -0
  339. package/src/core/qa-artifacts.ts +29 -3
  340. package/src/core/resources/contract.ts +76 -3
  341. package/src/core/resources/index.ts +1 -0
  342. package/src/core/resources/native.ts +481 -0
  343. package/src/core/resources/sampler.ts +46 -1
  344. package/src/core/resources/status.ts +717 -0
  345. package/src/core/resources/system.ts +530 -0
  346. package/src/core/semantic/service.ts +37 -3
  347. package/src/core/storage/builtins.ts +41 -0
  348. package/src/core/supervisor/contract.ts +45 -3
  349. package/src/core/supervisor/findings.ts +159 -0
  350. package/src/core/supervisor/history.ts +15 -0
  351. package/src/core/supervisor/ledger-state.ts +0 -0
  352. package/src/core/supervisor/service.ts +133 -5
  353. package/src/core/supervisor/storage.ts +7 -0
  354. package/src/core/workflow/admission.ts +33 -17
  355. package/src/core/workflow/engine.ts +2 -2
  356. package/src/core/workflow/live-session-v3.ts +6 -8
  357. package/src/core/workflow/proof.ts +4 -3
  358. package/src/lib/browser/capture-fidelity.ts +23 -0
  359. package/src/lib/browser/client.ts +96 -44
  360. package/src/lib/browser/index.ts +15 -1
  361. package/src/lib/browser/page-review-budget.ts +309 -0
  362. package/src/lib/browser/page-review-contracts.ts +129 -0
  363. package/src/lib/browser/page-review-evidence.ts +465 -0
  364. package/src/lib/browser/page-review-judge.ts +56 -40
  365. package/src/lib/browser/page-review-pack.ts +181 -43
  366. package/src/lib/browser/page-review-source.ts +30 -0
  367. package/src/lib/browser/qa-run-contracts.ts +62 -18
  368. package/src/lib/browser/qa-run.ts +259 -71
  369. package/src/lib/browser/qa-snapshot.ts +289 -48
  370. package/src/lib/browser/review-capture-transaction.ts +106 -0
  371. package/src/lib/browser/standalone-html.ts +4 -2
  372. package/src/lib/browser/thumbnail-association.ts +190 -0
  373. package/src/lib/browser/tiling.ts +63 -0
  374. package/src/lib/docs-metadata-managed.ts +4 -1
  375. package/src/lib/identities/assume.ts +12 -4
  376. package/src/lib/instructions/templates.ts +1 -0
  377. package/src/lib/local-file-url.ts +17 -2
  378. package/src/lib/tunnel/state.ts +70 -13
@@ -366,6 +366,29 @@ export class Browser {
366
366
  async fullPageScreenshotBuffer() {
367
367
  return await this.currentPage.screenshot({ type: "png", fullPage: true });
368
368
  }
369
+ /** Wait for font-driven DOM/layout initialization, with a bounded convergence check. */
370
+ async waitForReviewReady(timeoutMs = 15_000) {
371
+ if (!Number.isInteger(timeoutMs) || timeoutMs < 1 || timeoutMs > 60_000)
372
+ throw new RangeError("waitForReviewReady timeoutMs must be an integer from 1 to 60000");
373
+ const settled = await this.currentPage.evaluate(async (timeoutMs) => {
374
+ await document.fonts.ready;
375
+ const deadline = performance.now() + timeoutMs;
376
+ let previous = "";
377
+ let consecutive = 0;
378
+ while (performance.now() < deadline) {
379
+ await new Promise((resolve) => requestAnimationFrame(() => resolve()));
380
+ const geometry = `${document.documentElement.scrollWidth},${document.documentElement.scrollHeight},${document.body?.scrollWidth},${document.body?.scrollHeight}`;
381
+ const current = geometry + document.documentElement.outerHTML;
382
+ consecutive = current === previous ? consecutive + 1 : 0;
383
+ if (consecutive >= 8)
384
+ return true;
385
+ previous = current;
386
+ }
387
+ return false;
388
+ }, timeoutMs);
389
+ if (!settled)
390
+ throw new Error("Page review source or layout did not settle; rerun when page initialization completes.");
391
+ }
369
392
  /** Base64 PNG of a document-space clip rect. Used to capture one critique tile. */
370
393
  async screenshotClipBase64(rect) {
371
394
  const buf = await this.currentPage.screenshot({ type: "png", clip: rect });
@@ -400,10 +423,18 @@ export class Browser {
400
423
  * full-page screenshot would show it, without the full-page raster.
401
424
  */
402
425
  async captureRegionByScroll(rect) {
426
+ const [image] = await this.captureRegionsByScroll([rect]);
427
+ return image;
428
+ }
429
+ /** Capture a document-ordered group with one pinned-element inventory and restore. */
430
+ async captureRegionsByScroll(rects) {
431
+ if (!rects.length)
432
+ return [];
403
433
  const page = this.currentPage;
404
- if (!(rect.width > 0) || !(rect.height > 0)) {
405
- throw new Error(`captureRegionByScroll: rect must have a positive size (got ${rect.width}×${rect.height})`);
406
- }
434
+ for (const rect of rects)
435
+ if (!(rect.width > 0) || !(rect.height > 0)) {
436
+ throw new Error(`captureRegionByScroll: rect must have a positive size (got ${rect.width}×${rect.height})`);
437
+ }
407
438
  const settle = (top) => page.evaluate(async (target) => {
408
439
  window.scrollTo({ left: window.scrollX, top: target, behavior: "instant" });
409
440
  const frame = () => new Promise((r) => requestAnimationFrame(() => r()));
@@ -423,7 +454,7 @@ export class Browser {
423
454
  };
424
455
  }, top);
425
456
  const original = await page.evaluate(() => ({ x: window.scrollX, y: window.scrollY }));
426
- const pieces = [];
457
+ const captures = [];
427
458
  // Viewport-pinned candidates, measured at scroll 0 so each later capture
428
459
  // can tell "still where the full page shows it" from "riding along".
429
460
  await settle(0);
@@ -434,10 +465,19 @@ export class Browser {
434
465
  // switched off inline so the capture never lands mid-fade.
435
466
  const pinned = await page.evaluateHandle(() => {
436
467
  const out = [];
437
- const all = document.querySelectorAll("body *");
438
- const limit = Math.min(all.length, 20_000);
439
- for (let i = 0; i < limit; i++) {
440
- const el = all[i];
468
+ // Fixed controls can live inside a static shadow host. Walk open roots
469
+ // without hiding their ordinary content or exceeding the total node cap.
470
+ const walkers = [document.createTreeWalker(document.body, NodeFilter.SHOW_ELEMENT)];
471
+ let visited = 0;
472
+ while (walkers.length && visited < 20_000) {
473
+ const el = walkers[walkers.length - 1].nextNode();
474
+ if (!el) {
475
+ walkers.pop();
476
+ continue;
477
+ }
478
+ visited++;
479
+ if (el.shadowRoot)
480
+ walkers.push(document.createTreeWalker(el.shadowRoot, NodeFilter.SHOW_ELEMENT));
441
481
  const position = getComputedStyle(el).position;
442
482
  if (position !== "fixed" && position !== "sticky")
443
483
  continue;
@@ -455,7 +495,11 @@ export class Browser {
455
495
  const syncPinned = (mode) => page.evaluate(async ([entries, action]) => {
456
496
  for (const entry of entries) {
457
497
  const restore = () => {
498
+ // Restore opacity while transitions are still disabled. Restoring both
499
+ // declarations in one style flush starts a new fade from zero.
500
+ entry.el.style.setProperty("transition", "none", "important");
458
501
  entry.el.style.setProperty("opacity", entry.priorOpacity, entry.priorOpacityPriority);
502
+ void getComputedStyle(entry.el).opacity;
459
503
  entry.el.style.setProperty("transition", entry.priorTransition, entry.priorTransitionPriority);
460
504
  };
461
505
  if (action === "restore") {
@@ -475,35 +519,39 @@ export class Browser {
475
519
  await new Promise((r) => requestAnimationFrame(() => r()));
476
520
  }, [pinned, mode]);
477
521
  try {
478
- const bottom = rect.y + rect.height;
479
- let cursor = rect.y;
480
- let first = true;
481
- while (cursor < bottom) {
482
- const remaining = bottom - cursor;
483
- // Top-align the piece; a final partial piece is then re-anchored to
484
- // the viewport bottom once the viewport height is known.
485
- let view = await settle(cursor);
486
- if (!first && remaining < view.innerHeight) {
487
- view = await settle(Math.max(0, bottom - view.innerHeight));
488
- }
489
- await syncPinned("hide-moved");
490
- const offset = cursor - view.scrollY;
491
- if (offset < 0 || offset >= view.innerHeight) {
492
- throw new Error(`captureRegionByScroll: document y ${cursor} is not reachable in the viewport ` +
493
- `(scrollY ${view.scrollY}, innerHeight ${view.innerHeight})`);
494
- }
495
- const pieceHeight = Math.min(remaining, view.innerHeight - offset);
496
- const clipX = Math.max(0, rect.x - view.scrollX);
497
- const clipWidth = Math.min(rect.width, view.innerWidth - clipX);
498
- if (!(clipWidth > 0)) {
499
- throw new Error(`captureRegionByScroll: document x ${rect.x} is outside the viewport (innerWidth ${view.innerWidth})`);
522
+ for (const rect of rects) {
523
+ const pieces = [];
524
+ const bottom = rect.y + rect.height;
525
+ let cursor = rect.y;
526
+ let first = true;
527
+ while (cursor < bottom) {
528
+ const remaining = bottom - cursor;
529
+ // Top-align the piece; a final partial piece is then re-anchored to
530
+ // the viewport bottom once the viewport height is known.
531
+ let view = await settle(cursor);
532
+ if (!first && remaining < view.innerHeight) {
533
+ view = await settle(Math.max(0, bottom - view.innerHeight));
534
+ }
535
+ await syncPinned("hide-moved");
536
+ const offset = cursor - view.scrollY;
537
+ if (offset < 0 || offset >= view.innerHeight) {
538
+ throw new Error(`captureRegionByScroll: document y ${cursor} is not reachable in the viewport ` +
539
+ `(scrollY ${view.scrollY}, innerHeight ${view.innerHeight})`);
540
+ }
541
+ const pieceHeight = Math.min(remaining, view.innerHeight - offset);
542
+ const clipX = Math.max(0, rect.x - view.scrollX);
543
+ const clipWidth = Math.min(rect.width, view.innerWidth - clipX);
544
+ if (!(clipWidth > 0)) {
545
+ throw new Error(`captureRegionByScroll: document x ${rect.x} is outside the viewport (innerWidth ${view.innerWidth})`);
546
+ }
547
+ pieces.push(await page.screenshot({
548
+ type: "png",
549
+ clip: { x: clipX, y: offset, width: clipWidth, height: pieceHeight },
550
+ }));
551
+ cursor += pieceHeight;
552
+ first = false;
500
553
  }
501
- pieces.push(await page.screenshot({
502
- type: "png",
503
- clip: { x: clipX, y: offset, width: clipWidth, height: pieceHeight },
504
- }));
505
- cursor += pieceHeight;
506
- first = false;
554
+ captures.push(stitchPngRows(pieces));
507
555
  }
508
556
  }
509
557
  finally {
@@ -515,7 +563,7 @@ export class Browser {
515
563
  await page.evaluate(({ x, y }) => window.scrollTo({ left: x, top: y, behavior: "instant" }), original);
516
564
  }
517
565
  }
518
- return stitchPngRows(pieces);
566
+ return captures;
519
567
  }
520
568
  /** Document-space rects + labels for each element matching `selector` (semantic tiling). */
521
569
  async elementTiles(selector) {
@@ -8,8 +8,10 @@ export { buildLayoutLintCheck } from "./geometry.js";
8
8
  export { isWSL, wslHeadedLaunchArgs } from "./launch-args.js";
9
9
  export type { OverflowElement, OverflowResult, WidthResult, } from "./layout.js";
10
10
  export { serializeNetscapeCookies, writeNetscapeCookieFile, } from "./netscape-cookies.js";
11
+ export type { PageReviewBudgetCoverage, PageReviewCandidate, PageReviewCapturePlan, PageReviewContextAllocation, PageReviewDecisionSlot, PageReviewDurableDecision, PageReviewEvidenceContext, PageReviewNativeEvidence, PageReviewNativeTile, PageReviewRect, PageReviewTileBudgetAllocation, } from "./page-review-contracts.js";
12
+ export { nativePixelDigest } from "./page-review-evidence.js";
11
13
  export { type JudgedContext, type JudgePageReviewPackOptions, type JudgePageReviewPackResult, judgePageReviewPack, toCritiqueRecords, } from "./page-review-judge.js";
12
- export { buildInspectionPlan, type FinalizePageReviewPackInput, finalizePageReviewPack, findingsSchemaDocument, listPackContexts, PAGE_REVIEW_FINDINGS_SCHEMA, PAGE_REVIEW_PACK_DIRNAME, PAGE_REVIEW_PACK_SCHEMA, type PageReviewContextCapture, type PageReviewContextRecord, type PageReviewCritiqueRecord, type PageReviewGateRecord, type PageReviewInspectionPlan, type PageReviewPackManifest, type PageReviewTileRecord, packPaths, readPackContext, readPackDom, readPackFullPage, readPackManifest, readPackSignature, readPackTiles, renderReviewMarkdown, writePackContext, } from "./page-review-pack.js";
14
+ export { buildInspectionPlan, type FinalizePageReviewPackInput, finalizePageReviewPack, findingsSchemaDocument, listPackContexts, PAGE_REVIEW_FINDINGS_SCHEMA, PAGE_REVIEW_PACK_DIRNAME, PAGE_REVIEW_PACK_SCHEMA, type PageReviewContextCapture, type PageReviewContextRecord, type PageReviewCritiqueRecord, type PageReviewGateRecord, type PageReviewInspectionPlan, type PageReviewPackManifest, type PageReviewTileRecord, packPaths, readPackContext, readPackDom, readPackManifest, readPackOverview, readPackSignature, readPackTiles, renderReviewMarkdown, writePackContext, } from "./page-review-pack.js";
13
15
  export { type BrowserProxy, type BrowserProxyGate, browserProxyFromEnv, browserProxyGateFromEnv, extractObservedIp, WEBRTC_PROXY_ONLY_ARG, } from "./proxy.js";
14
16
  export { buildQaManifest, type ChangeClass, type ClassifyOptions, classifySignatures, fnv1a32, type ManifestOptions, type QaClassification, type QaContext, type QaManifest, type QaNodeSignature, type QaScope, type QaSignature, type QaStylesheetSignature, } from "./qa-plan.js";
15
17
  export { defaultQaRunExec, QA_RUN_HEADLESS_ONLY_ENV, QA_RUN_RESULT_FILENAME, type QaRunExec, type QaRunExecOptions, type QaRunExecResult, type QaRunMatrixOptions, runQaMatrix, } from "./qa-run.js";
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/lib/browser/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/lib/browser/index.ts"],"names":[],"mappings":"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"}
@@ -5,8 +5,9 @@ export { captureDevOverlay, } from "./dev-overlay.js";
5
5
  export { buildLayoutLintCheck } from "./geometry.js";
6
6
  export { isWSL, wslHeadedLaunchArgs } from "./launch-args.js";
7
7
  export { serializeNetscapeCookies, writeNetscapeCookieFile, } from "./netscape-cookies.js";
8
+ export { nativePixelDigest } from "./page-review-evidence.js";
8
9
  export { judgePageReviewPack, toCritiqueRecords, } from "./page-review-judge.js";
9
- export { buildInspectionPlan, finalizePageReviewPack, findingsSchemaDocument, listPackContexts, PAGE_REVIEW_FINDINGS_SCHEMA, PAGE_REVIEW_PACK_DIRNAME, PAGE_REVIEW_PACK_SCHEMA, packPaths, readPackContext, readPackDom, readPackFullPage, readPackManifest, readPackSignature, readPackTiles, renderReviewMarkdown, writePackContext, } from "./page-review-pack.js";
10
+ export { buildInspectionPlan, finalizePageReviewPack, findingsSchemaDocument, listPackContexts, PAGE_REVIEW_FINDINGS_SCHEMA, PAGE_REVIEW_PACK_DIRNAME, PAGE_REVIEW_PACK_SCHEMA, packPaths, readPackContext, readPackDom, readPackManifest, readPackOverview, readPackSignature, readPackTiles, renderReviewMarkdown, writePackContext, } from "./page-review-pack.js";
10
11
  export { browserProxyFromEnv, browserProxyGateFromEnv, extractObservedIp, WEBRTC_PROXY_ONLY_ARG, } from "./proxy.js";
11
12
  export { buildQaManifest, classifySignatures, fnv1a32, } from "./qa-plan.js";
12
13
  export { defaultQaRunExec, QA_RUN_HEADLESS_ONLY_ENV, QA_RUN_RESULT_FILENAME, runQaMatrix, } from "./qa-run.js";
@@ -0,0 +1,13 @@
1
+ import { type PageReviewBudgetCoverage, type PageReviewCapturePlan, type PageReviewContextAllocation, type PageReviewRect, type PageReviewTileBudgetAllocation } from "./page-review-contracts.js";
2
+ export declare function validatePageReviewCapturePlan(value: unknown): PageReviewCapturePlan;
3
+ export declare function intervalUnion(rects: readonly PageReviewRect[]): Array<{
4
+ start: number;
5
+ end: number;
6
+ }>;
7
+ export declare function allocationCoverage(plan: PageReviewCapturePlan, selectedIds: readonly string[]): PageReviewBudgetCoverage;
8
+ /** Reserve edges, prioritize gate hits, then distribute by remaining height. */
9
+ export declare function allocateTileBudget(plans: PageReviewCapturePlan[], budget?: number, ceilings?: Record<string, number>): PageReviewTileBudgetAllocation;
10
+ /** Gate-hit annotations are planning results; geometry and page state are authoritative at capture. */
11
+ export declare function capturePlanDigest(plan: PageReviewCapturePlan): string;
12
+ export declare function validatePageReviewAllocation(value: unknown, current: PageReviewCapturePlan): PageReviewContextAllocation;
13
+ //# sourceMappingURL=page-review-budget.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"page-review-budget.d.ts","sourceRoot":"","sources":["../../../src/lib/browser/page-review-budget.ts"],"names":[],"mappings":"AACA,OAAO,EAIL,KAAK,wBAAwB,EAE7B,KAAK,qBAAqB,EAC1B,KAAK,2BAA2B,EAChC,KAAK,cAAc,EACnB,KAAK,8BAA8B,EACpC,MAAM,4BAA4B,CAAC;AAMpC,wBAAgB,6BAA6B,CAAC,KAAK,EAAE,OAAO,GAAG,qBAAqB,CAiEnF;AAED,wBAAgB,aAAa,CAC3B,KAAK,EAAE,SAAS,cAAc,EAAE,GAC/B,KAAK,CAAC;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,CAAC,CAQvC;AAED,wBAAgB,kBAAkB,CAChC,IAAI,EAAE,qBAAqB,EAC3B,WAAW,EAAE,SAAS,MAAM,EAAE,GAC7B,wBAAwB,CAsC1B;AAED,gFAAgF;AAChF,wBAAgB,kBAAkB,CAChC,KAAK,EAAE,qBAAqB,EAAE,EAC9B,MAAM,SAAkC,EACxC,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAChC,8BAA8B,CAqHhC;AAED,uGAAuG;AACvG,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,qBAAqB,GAAG,MAAM,CAKrE;AAED,wBAAgB,4BAA4B,CAC1C,KAAK,EAAE,OAAO,EACd,OAAO,EAAE,qBAAqB,GAC7B,2BAA2B,CAkC7B"}
@@ -0,0 +1,251 @@
1
+ import { createHash } from "node:crypto";
2
+ import { PAGE_REVIEW_CAPTURE_PLAN_SCHEMA, PAGE_REVIEW_DEFAULT_TILE_BUDGET, PAGE_REVIEW_MAX_TILE_BUDGET, } from "./page-review-contracts.js";
3
+ const severityRank = { critical: 0, high: 1, medium: 2, low: 3, info: 4 };
4
+ const position = (a, b) => a.rect.y - b.rect.y || a.rect.x - b.rect.x || a.index - b.index || a.id.localeCompare(b.id);
5
+ export function validatePageReviewCapturePlan(value) {
6
+ const fail = (detail) => {
7
+ throw new Error(`Invalid page review capture plan: ${detail}; rerun planning.`);
8
+ };
9
+ if (!value || typeof value !== "object")
10
+ fail("expected an object");
11
+ const p = value;
12
+ if (p.schema !== PAGE_REVIEW_CAPTURE_PLAN_SCHEMA)
13
+ fail("unsupported schema");
14
+ for (const key of [
15
+ "context_id",
16
+ "viewport",
17
+ "state",
18
+ "source_digest",
19
+ "recipe_version",
20
+ ]) {
21
+ if (typeof p[key] !== "string" || !p[key].trim())
22
+ fail(`missing ${key}`);
23
+ }
24
+ if (p.theme !== "light" && p.theme !== "dark")
25
+ fail("invalid theme");
26
+ if (!Number.isFinite(p.dpr) || p.dpr <= 0)
27
+ fail("invalid DPR");
28
+ for (const key of ["viewport_width", "viewport_height", "page_width", "page_height"]) {
29
+ if (!Number.isSafeInteger(p[key]) || p[key] <= 0)
30
+ fail(`invalid ${key}`);
31
+ }
32
+ if (!Array.isArray(p.candidates) || !p.candidates.length)
33
+ fail("no candidates");
34
+ const seen = new Set();
35
+ for (const c of p.candidates) {
36
+ if (!c || typeof c.id !== "string" || !c.id || seen.has(c.id))
37
+ fail("missing or duplicate candidate ID");
38
+ seen.add(c.id);
39
+ if (!Number.isSafeInteger(c.index) || c.index < 0 || typeof c.label !== "string")
40
+ fail(`invalid candidate ${c.id}`);
41
+ const r = c.rect;
42
+ if (!r ||
43
+ ![r.x, r.y, r.width, r.height].every(Number.isSafeInteger) ||
44
+ r.x < 0 ||
45
+ r.y < 0 ||
46
+ r.width <= 0 ||
47
+ r.height <= 0 ||
48
+ r.x + r.width > p.page_width ||
49
+ r.y + r.height > p.page_height)
50
+ fail(`invalid rectangle ${c.id}`);
51
+ if (c.scope !== undefined && (typeof c.scope !== "string" || !c.scope))
52
+ fail(`invalid scope ${c.id}`);
53
+ if (!Array.isArray(c.gate_hits) ||
54
+ c.gate_hits.some((h) => !h || typeof h.check_id !== "string" || !h.check_id || !(h.severity in severityRank)))
55
+ fail(`invalid gate hits ${c.id}`);
56
+ }
57
+ if (p.required_scopes !== undefined &&
58
+ (!Array.isArray(p.required_scopes) ||
59
+ p.required_scopes.some((s) => typeof s !== "string" || !s)))
60
+ fail("invalid required scopes");
61
+ const bands = p.candidates.filter((c) => c.scope === undefined).sort(position);
62
+ if (!bands.length ||
63
+ bands[0].rect.y !== 0 ||
64
+ bands.at(-1).rect.y + bands.at(-1).rect.height !== p.page_height)
65
+ fail("top and bottom page bands are required");
66
+ return p;
67
+ }
68
+ export function intervalUnion(rects) {
69
+ const out = [];
70
+ for (const r of [...rects].sort((a, b) => a.y - b.y || a.height - b.height)) {
71
+ const last = out.at(-1);
72
+ if (last && r.y <= last.end)
73
+ last.end = Math.max(last.end, r.y + r.height);
74
+ else
75
+ out.push({ start: r.y, end: r.y + r.height });
76
+ }
77
+ return out;
78
+ }
79
+ export function allocationCoverage(plan, selectedIds) {
80
+ const selected = new Set(selectedIds);
81
+ const kept = plan.candidates.filter((c) => selected.has(c.id));
82
+ // A narrow scope cannot stand in for a full-width document band.
83
+ const reviewed = intervalUnion(kept
84
+ .filter((c) => !c.scope && c.rect.x === 0 && c.rect.width === plan.page_width)
85
+ .map((c) => c.rect));
86
+ const uncovered = [];
87
+ let cursor = 0;
88
+ for (const r of reviewed) {
89
+ if (r.start > cursor)
90
+ uncovered.push({ start: cursor, end: r.start });
91
+ cursor = r.end;
92
+ }
93
+ if (cursor < plan.page_height)
94
+ uncovered.push({ start: cursor, end: plan.page_height });
95
+ const missed = plan.candidates.filter((c) => !selected.has(c.id));
96
+ const scopes = new Set([
97
+ ...(plan.required_scopes ?? []),
98
+ ...plan.candidates.flatMap((c) => (c.scope ? [c.scope] : [])),
99
+ ]);
100
+ const omittedScopes = [...scopes]
101
+ .filter((s) => !plan.candidates.some((c) => c.scope === s) || missed.some((c) => c.scope === s))
102
+ .sort();
103
+ return {
104
+ page_height_px: plan.page_height,
105
+ reviewed_height_px: reviewed.reduce((sum, r) => sum + r.end - r.start, 0),
106
+ bands_total: plan.candidates.filter((c) => !c.scope).length,
107
+ bands_reviewed: kept.filter((c) => !c.scope).length,
108
+ capped: uncovered.length > 0 || omittedScopes.length > 0 || missed.some((c) => !c.scope),
109
+ selected_rectangles: kept.map((c) => ({ ...c.rect })),
110
+ reviewed_intervals: reviewed,
111
+ uncovered_intervals: uncovered,
112
+ omitted_gate_hits: [
113
+ ...new Set(missed.flatMap((c) => c.gate_hits.map((h) => h.check_id))),
114
+ ].sort(),
115
+ omitted_scopes: omittedScopes,
116
+ };
117
+ }
118
+ /** Reserve edges, prioritize gate hits, then distribute by remaining height. */
119
+ export function allocateTileBudget(plans, budget = PAGE_REVIEW_DEFAULT_TILE_BUDGET, ceilings) {
120
+ if (!Number.isSafeInteger(budget) || budget < 1 || budget > PAGE_REVIEW_MAX_TILE_BUDGET)
121
+ throw new Error(`Tile budget must be an integer from 1 to ${PAGE_REVIEW_MAX_TILE_BUDGET}.`);
122
+ const rows = [...plans]
123
+ .map(validatePageReviewCapturePlan)
124
+ .sort((a, b) => a.context_id.localeCompare(b.context_id))
125
+ .map((plan) => {
126
+ const bands = plan.candidates.filter((c) => !c.scope).sort(position);
127
+ const edges = [bands[0], bands.at(-1)].filter((c, i, a) => a.findIndex((x) => x.id === c.id) === i);
128
+ const ceiling = ceilings?.[plan.context_id] ?? budget;
129
+ if (!Number.isSafeInteger(ceiling) || ceiling < edges.length)
130
+ throw new Error(`Context ${plan.context_id} requires a tile ceiling of at least ${edges.length} for its top and bottom bands (got ${ceiling}).`);
131
+ return { plan, ceiling, selected: new Set(edges.map((c) => c.id)) };
132
+ });
133
+ if (new Set(rows.map((r) => r.plan.context_id)).size !== rows.length)
134
+ throw new Error("Duplicate page review context ID.");
135
+ let used = rows.reduce((s, r) => s + r.selected.size, 0);
136
+ if (used > budget)
137
+ throw new Error(`Tile budget requires at least ${used} to reserve every context's top and bottom bands (got ${budget}).`);
138
+ const hits = rows.flatMap((row) => row.plan.candidates
139
+ .filter((c) => c.gate_hits.length && !row.selected.has(c.id))
140
+ .map((c) => ({
141
+ row,
142
+ c,
143
+ rank: Math.min(...c.gate_hits.map((h) => severityRank[h.severity])),
144
+ })));
145
+ hits.sort((a, b) => a.rank - b.rank ||
146
+ a.row.plan.context_id.localeCompare(b.row.plan.context_id) ||
147
+ position(a.c, b.c));
148
+ for (const { row, c } of hits) {
149
+ if (used >= budget)
150
+ break;
151
+ if (row.selected.size >= row.ceiling)
152
+ continue;
153
+ row.selected.add(c.id);
154
+ used++;
155
+ }
156
+ const remaining = (row) => row.plan.candidates.filter((c) => !row.selected.has(c.id)).sort(position);
157
+ while (used < budget) {
158
+ const eligible = rows
159
+ .map((row) => {
160
+ const candidates = remaining(row);
161
+ return {
162
+ row,
163
+ candidates,
164
+ capacity: Math.min(candidates.length, row.ceiling - row.selected.size),
165
+ height: intervalUnion(candidates.map((c) => c.rect)).reduce((s, r) => s + r.end - r.start, 0),
166
+ quota: 0,
167
+ fraction: 0,
168
+ };
169
+ })
170
+ .filter((r) => r.capacity > 0);
171
+ if (!eligible.length)
172
+ break;
173
+ const slots = budget - used, totalHeight = eligible.reduce((s, r) => s + r.height, 0);
174
+ for (const r of eligible) {
175
+ const exact = (slots * r.height) / totalHeight;
176
+ r.quota = Math.min(r.capacity, Math.floor(exact));
177
+ r.fraction = exact - Math.floor(exact);
178
+ }
179
+ let spare = slots - eligible.reduce((s, r) => s + r.quota, 0);
180
+ for (const r of [...eligible].sort((a, b) => b.fraction - a.fraction || a.row.plan.context_id.localeCompare(b.row.plan.context_id))) {
181
+ if (spare > 0 && r.quota < r.capacity) {
182
+ r.quota++;
183
+ spare--;
184
+ }
185
+ }
186
+ for (const r of eligible) {
187
+ for (let i = 0; i < r.quota; i++) {
188
+ const index = Math.floor(((i + 0.5) * r.candidates.length) / r.quota);
189
+ r.row.selected.add(r.candidates[index].id);
190
+ used++;
191
+ }
192
+ }
193
+ }
194
+ return {
195
+ budget,
196
+ used,
197
+ contexts: rows.map(({ plan, ceiling, selected }) => {
198
+ const selected_ids = plan.candidates
199
+ .filter((c) => selected.has(c.id))
200
+ .sort(position)
201
+ .map((c) => c.id);
202
+ return {
203
+ context_id: plan.context_id,
204
+ plan,
205
+ selected_ids,
206
+ ceiling,
207
+ omitted_candidates: plan.candidates
208
+ .filter((c) => !selected.has(c.id))
209
+ .map((c) => ({
210
+ id: c.id,
211
+ reason: ceilings?.[plan.context_id] !== undefined && selected.size >= ceiling
212
+ ? "ceiling"
213
+ : "budget",
214
+ })),
215
+ coverage: allocationCoverage(plan, selected_ids),
216
+ };
217
+ }),
218
+ };
219
+ }
220
+ /** Gate-hit annotations are planning results; geometry and page state are authoritative at capture. */
221
+ export function capturePlanDigest(plan) {
222
+ const { candidates, ...rest } = plan;
223
+ return createHash("sha256")
224
+ .update(JSON.stringify({ ...rest, candidates: candidates.map(({ gate_hits, ...c }) => c) }))
225
+ .digest("hex");
226
+ }
227
+ export function validatePageReviewAllocation(value, current) {
228
+ const allocation = value;
229
+ if (!allocation || typeof allocation !== "object")
230
+ throw new Error("Missing page review allocation; rerun planning.");
231
+ validatePageReviewCapturePlan(allocation.plan);
232
+ if (allocation.context_id !== current.context_id ||
233
+ capturePlanDigest(allocation.plan) !== capturePlanDigest(current))
234
+ throw new Error("Page review capture geometry or source changed since planning; rerun the review.");
235
+ if (!Array.isArray(allocation.selected_ids) ||
236
+ !allocation.selected_ids.length ||
237
+ new Set(allocation.selected_ids).size !== allocation.selected_ids.length ||
238
+ allocation.selected_ids.some((id) => !current.candidates.some((c) => c.id === id)))
239
+ throw new Error("Invalid selected tile IDs in page review allocation.");
240
+ if (!Number.isSafeInteger(allocation.ceiling) ||
241
+ allocation.selected_ids.length > allocation.ceiling)
242
+ throw new Error("Page review allocation exceeds its context ceiling.");
243
+ const bands = current.candidates.filter((c) => !c.scope).sort(position);
244
+ if (!allocation.selected_ids.includes(bands[0].id) ||
245
+ !allocation.selected_ids.includes(bands.at(-1).id))
246
+ throw new Error("Page review allocation must include top and bottom bands.");
247
+ const coverage = allocationCoverage(allocation.plan, allocation.selected_ids);
248
+ if (JSON.stringify(coverage) !== JSON.stringify(allocation.coverage))
249
+ throw new Error("Page review allocation coverage is inconsistent with selected tiles.");
250
+ return { ...allocation, coverage };
251
+ }
@@ -0,0 +1,127 @@
1
+ import type { CritiqueCoverage, CritiqueFinding } from "./critique.js";
2
+ export declare const PAGE_REVIEW_CAPTURE_PLAN_SCHEMA = "harnery-page-review-capture-plan/v1";
3
+ export declare const PAGE_REVIEW_NATIVE_EVIDENCE_SCHEMA = "harnery-page-review-native-evidence/v2";
4
+ export declare const PAGE_REVIEW_DECISIONS_SCHEMA = "harnery-page-review-decisions/v1";
5
+ export declare const PAGE_REVIEW_DEFAULT_TILE_BUDGET = 96;
6
+ export declare const PAGE_REVIEW_MAX_TILE_BUDGET = 400;
7
+ /** Rectangles are native image pixels, never CSS pixels or overview pixels. */
8
+ export interface PageReviewRect {
9
+ x: number;
10
+ y: number;
11
+ width: number;
12
+ height: number;
13
+ }
14
+ export interface PageReviewCandidate {
15
+ id: string;
16
+ index: number;
17
+ label: string;
18
+ rect: PageReviewRect;
19
+ scope?: string;
20
+ gate_hits: Array<{
21
+ check_id: string;
22
+ severity: "critical" | "high" | "medium" | "low" | "info";
23
+ }>;
24
+ }
25
+ /** Private diagnostic receipt, not an additional acceptance condition. Hash
26
+ * the referenced file bytes directly to reproduce source_digest. */
27
+ export interface PageReviewSourceEvidence {
28
+ path: string;
29
+ sha256: string;
30
+ bytes: number;
31
+ encoding: "utf8";
32
+ }
33
+ export interface PageReviewCapturePlan {
34
+ schema: typeof PAGE_REVIEW_CAPTURE_PLAN_SCHEMA;
35
+ context_id: string;
36
+ viewport: string;
37
+ viewport_width: number;
38
+ viewport_height: number;
39
+ theme: "light" | "dark";
40
+ state: string;
41
+ dpr: number;
42
+ page_width: number;
43
+ page_height: number;
44
+ /** Stable content/geometry signature; excludes capture timestamps. */
45
+ source_digest: string;
46
+ recipe_version: string;
47
+ required_scopes: string[];
48
+ candidates: PageReviewCandidate[];
49
+ }
50
+ export interface PageReviewBudgetCoverage extends CritiqueCoverage {
51
+ selected_rectangles: PageReviewRect[];
52
+ reviewed_intervals: Array<{
53
+ start: number;
54
+ end: number;
55
+ }>;
56
+ uncovered_intervals: Array<{
57
+ start: number;
58
+ end: number;
59
+ }>;
60
+ omitted_gate_hits: string[];
61
+ omitted_scopes: string[];
62
+ }
63
+ export interface PageReviewContextAllocation {
64
+ context_id: string;
65
+ plan: PageReviewCapturePlan;
66
+ selected_ids: string[];
67
+ ceiling: number;
68
+ omitted_candidates: Array<{
69
+ id: string;
70
+ reason: "budget" | "ceiling";
71
+ }>;
72
+ coverage: PageReviewBudgetCoverage;
73
+ }
74
+ export interface PageReviewTileBudgetAllocation {
75
+ budget: number;
76
+ used: number;
77
+ contexts: PageReviewContextAllocation[];
78
+ }
79
+ /** Pixel identity is meaningful only within an identical rendering contract. */
80
+ export interface PageReviewEvidenceContext {
81
+ viewport: string;
82
+ viewport_width: number;
83
+ viewport_height: number;
84
+ theme: "light" | "dark";
85
+ state: string;
86
+ dpr: number;
87
+ recipe_version: string;
88
+ rubric_digest: string;
89
+ critique_contract_version: number;
90
+ }
91
+ /** In-memory form. The snapshot store writes PNGs separately from metadata. */
92
+ export interface PageReviewNativeTile {
93
+ tile_id: string;
94
+ index: number;
95
+ label: string;
96
+ rect: PageReviewRect;
97
+ pixel_digest: string;
98
+ png: Buffer;
99
+ }
100
+ export interface PageReviewNativeEvidence {
101
+ schema: typeof PAGE_REVIEW_NATIVE_EVIDENCE_SCHEMA;
102
+ context: PageReviewEvidenceContext;
103
+ tiles: PageReviewNativeTile[];
104
+ }
105
+ export interface PageReviewDurableDecision {
106
+ finding_key: string;
107
+ tile_pixel_digest: string;
108
+ rect: PageReviewRect;
109
+ finding: Pick<CritiqueFinding, "severity" | "category" | "description">;
110
+ disposition: "artifact" | "not-a-defect" | "confirmed" | "duplicate-of-gate";
111
+ reviewer: string;
112
+ at: string;
113
+ note?: string;
114
+ }
115
+ /** Stored independently of baseline replacement and expiring pack directories. */
116
+ export interface PageReviewDecisionSlot {
117
+ schema: typeof PAGE_REVIEW_DECISIONS_SCHEMA;
118
+ target: string;
119
+ context: PageReviewEvidenceContext;
120
+ source_run: string;
121
+ source_revision: string | null;
122
+ reviewer: string;
123
+ reviewed_at: string;
124
+ complete: true;
125
+ decisions: PageReviewDurableDecision[];
126
+ }
127
+ //# sourceMappingURL=page-review-contracts.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"page-review-contracts.d.ts","sourceRoot":"","sources":["../../../src/lib/browser/page-review-contracts.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ export const PAGE_REVIEW_CAPTURE_PLAN_SCHEMA = "harnery-page-review-capture-plan/v1";
2
+ export const PAGE_REVIEW_NATIVE_EVIDENCE_SCHEMA = "harnery-page-review-native-evidence/v2";
3
+ export const PAGE_REVIEW_DECISIONS_SCHEMA = "harnery-page-review-decisions/v1";
4
+ export const PAGE_REVIEW_DEFAULT_TILE_BUDGET = 96;
5
+ export const PAGE_REVIEW_MAX_TILE_BUDGET = 400;