@indigoai-us/hq-cloud 6.18.44-alpha.8 → 6.18.44

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 (1068) hide show
  1. package/dist/bin/sync-runner-planning.d.ts +12 -0
  2. package/dist/bin/sync-runner-planning.d.ts.map +1 -1
  3. package/dist/bin/sync-runner-planning.js +18 -0
  4. package/dist/bin/sync-runner-planning.js.map +1 -1
  5. package/dist/bin/sync-runner-watch-loop.d.ts +18 -0
  6. package/dist/bin/sync-runner-watch-loop.d.ts.map +1 -1
  7. package/dist/bin/sync-runner-watch-loop.js +75 -6
  8. package/dist/bin/sync-runner-watch-loop.js.map +1 -1
  9. package/dist/bin/sync-runner.d.ts +22 -1
  10. package/dist/bin/sync-runner.d.ts.map +1 -1
  11. package/dist/bin/sync-runner.js +33 -4
  12. package/dist/bin/sync-runner.js.map +1 -1
  13. package/dist/cli/conflict.d.ts.map +1 -1
  14. package/dist/cli/conflict.js +2 -1
  15. package/dist/cli/conflict.js.map +1 -1
  16. package/dist/cli/rescue-core.d.ts +6 -0
  17. package/dist/cli/rescue-core.d.ts.map +1 -1
  18. package/dist/cli/rescue-core.js +10 -1
  19. package/dist/cli/rescue-core.js.map +1 -1
  20. package/dist/cli/rescue-windows-test-harness.d.ts +19 -0
  21. package/dist/cli/rescue-windows-test-harness.d.ts.map +1 -0
  22. package/dist/cli/rescue-windows-test-harness.js +443 -0
  23. package/dist/cli/rescue-windows-test-harness.js.map +1 -0
  24. package/dist/company-resolver.d.ts +22 -0
  25. package/dist/company-resolver.d.ts.map +1 -1
  26. package/dist/company-resolver.js +1 -1
  27. package/dist/company-resolver.js.map +1 -1
  28. package/dist/ignore.d.ts +4 -1
  29. package/dist/ignore.d.ts.map +1 -1
  30. package/dist/ignore.js +10 -12
  31. package/dist/ignore.js.map +1 -1
  32. package/dist/journal-snapshot-decoder.js +15 -2
  33. package/dist/journal-snapshot-decoder.js.map +1 -1
  34. package/dist/sync/durable-apply.d.ts +2 -0
  35. package/dist/sync/durable-apply.d.ts.map +1 -1
  36. package/dist/sync/durable-apply.js +9 -12
  37. package/dist/sync/durable-apply.js.map +1 -1
  38. package/dist/sync/fsync-compat.d.ts +13 -0
  39. package/dist/sync/fsync-compat.d.ts.map +1 -0
  40. package/dist/sync/fsync-compat.js +33 -0
  41. package/dist/sync/fsync-compat.js.map +1 -0
  42. package/dist/sync/multipart-uploader.d.ts.map +1 -1
  43. package/dist/sync/multipart-uploader.js +2 -1
  44. package/dist/sync/multipart-uploader.js.map +1 -1
  45. package/dist/sync/scope-inventory-client.d.ts.map +1 -1
  46. package/dist/sync/scope-inventory-client.js +7 -2
  47. package/dist/sync/scope-inventory-client.js.map +1 -1
  48. package/dist/telemetry.d.ts +31 -0
  49. package/dist/telemetry.d.ts.map +1 -1
  50. package/dist/telemetry.js +177 -17
  51. package/dist/telemetry.js.map +1 -1
  52. package/dist/usage-company-fallback.d.ts +104 -0
  53. package/dist/usage-company-fallback.d.ts.map +1 -0
  54. package/dist/usage-company-fallback.js +599 -0
  55. package/dist/usage-company-fallback.js.map +1 -0
  56. package/dist/watch-owner-lease.d.ts +3 -0
  57. package/dist/watch-owner-lease.d.ts.map +1 -1
  58. package/dist/watch-owner-lease.js +14 -3
  59. package/dist/watch-owner-lease.js.map +1 -1
  60. package/package.json +2 -2
  61. package/dist/active-company.test.d.ts +0 -2
  62. package/dist/active-company.test.d.ts.map +0 -1
  63. package/dist/active-company.test.js +0 -149
  64. package/dist/active-company.test.js.map +0 -1
  65. package/dist/agent-codex-instructions.test.d.ts +0 -2
  66. package/dist/agent-codex-instructions.test.d.ts.map +0 -1
  67. package/dist/agent-codex-instructions.test.js +0 -271
  68. package/dist/agent-codex-instructions.test.js.map +0 -1
  69. package/dist/backup-prune.test.d.ts +0 -2
  70. package/dist/backup-prune.test.d.ts.map +0 -1
  71. package/dist/backup-prune.test.js +0 -154
  72. package/dist/backup-prune.test.js.map +0 -1
  73. package/dist/bandwidth.test.d.ts +0 -2
  74. package/dist/bandwidth.test.d.ts.map +0 -1
  75. package/dist/bandwidth.test.js +0 -342
  76. package/dist/bandwidth.test.js.map +0 -1
  77. package/dist/best-effort-error.test.d.ts +0 -2
  78. package/dist/best-effort-error.test.d.ts.map +0 -1
  79. package/dist/best-effort-error.test.js +0 -54
  80. package/dist/best-effort-error.test.js.map +0 -1
  81. package/dist/bin/area-ledger-migration.test.d.ts +0 -2
  82. package/dist/bin/area-ledger-migration.test.d.ts.map +0 -1
  83. package/dist/bin/area-ledger-migration.test.js +0 -410
  84. package/dist/bin/area-ledger-migration.test.js.map +0 -1
  85. package/dist/bin/backup-prune-runner.test.d.ts +0 -2
  86. package/dist/bin/backup-prune-runner.test.d.ts.map +0 -1
  87. package/dist/bin/backup-prune-runner.test.js +0 -22
  88. package/dist/bin/backup-prune-runner.test.js.map +0 -1
  89. package/dist/bin/journal-repair.test.d.ts +0 -2
  90. package/dist/bin/journal-repair.test.d.ts.map +0 -1
  91. package/dist/bin/journal-repair.test.js +0 -53
  92. package/dist/bin/journal-repair.test.js.map +0 -1
  93. package/dist/bin/layout-compatibility.test.d.ts +0 -2
  94. package/dist/bin/layout-compatibility.test.d.ts.map +0 -1
  95. package/dist/bin/layout-compatibility.test.js +0 -87
  96. package/dist/bin/layout-compatibility.test.js.map +0 -1
  97. package/dist/bin/outpost-heartbeat.test.d.ts +0 -7
  98. package/dist/bin/outpost-heartbeat.test.d.ts.map +0 -1
  99. package/dist/bin/outpost-heartbeat.test.js +0 -84
  100. package/dist/bin/outpost-heartbeat.test.js.map +0 -1
  101. package/dist/bin/outpost-session-host.test.d.ts +0 -7
  102. package/dist/bin/outpost-session-host.test.d.ts.map +0 -1
  103. package/dist/bin/outpost-session-host.test.js +0 -52
  104. package/dist/bin/outpost-session-host.test.js.map +0 -1
  105. package/dist/bin/sync-mutation.test.d.ts +0 -2
  106. package/dist/bin/sync-mutation.test.d.ts.map +0 -1
  107. package/dist/bin/sync-mutation.test.js +0 -64
  108. package/dist/bin/sync-mutation.test.js.map +0 -1
  109. package/dist/bin/sync-runner-args.test.d.ts +0 -2
  110. package/dist/bin/sync-runner-args.test.d.ts.map +0 -1
  111. package/dist/bin/sync-runner-args.test.js +0 -82
  112. package/dist/bin/sync-runner-args.test.js.map +0 -1
  113. package/dist/bin/sync-runner-auth-wait.test.d.ts +0 -2
  114. package/dist/bin/sync-runner-auth-wait.test.d.ts.map +0 -1
  115. package/dist/bin/sync-runner-auth-wait.test.js +0 -406
  116. package/dist/bin/sync-runner-auth-wait.test.js.map +0 -1
  117. package/dist/bin/sync-runner-backoff.regression.test.d.ts +0 -29
  118. package/dist/bin/sync-runner-backoff.regression.test.d.ts.map +0 -1
  119. package/dist/bin/sync-runner-backoff.regression.test.js +0 -224
  120. package/dist/bin/sync-runner-backoff.regression.test.js.map +0 -1
  121. package/dist/bin/sync-runner-company.test.d.ts +0 -2
  122. package/dist/bin/sync-runner-company.test.d.ts.map +0 -1
  123. package/dist/bin/sync-runner-company.test.js +0 -2439
  124. package/dist/bin/sync-runner-company.test.js.map +0 -1
  125. package/dist/bin/sync-runner-delete-snapshot-mixed.bench.test.d.ts +0 -2
  126. package/dist/bin/sync-runner-delete-snapshot-mixed.bench.test.d.ts.map +0 -1
  127. package/dist/bin/sync-runner-delete-snapshot-mixed.bench.test.js +0 -648
  128. package/dist/bin/sync-runner-delete-snapshot-mixed.bench.test.js.map +0 -1
  129. package/dist/bin/sync-runner-delete-snapshot.bench.test.d.ts +0 -2
  130. package/dist/bin/sync-runner-delete-snapshot.bench.test.d.ts.map +0 -1
  131. package/dist/bin/sync-runner-delete-snapshot.bench.test.js +0 -329
  132. package/dist/bin/sync-runner-delete-snapshot.bench.test.js.map +0 -1
  133. package/dist/bin/sync-runner-events.test.d.ts +0 -2
  134. package/dist/bin/sync-runner-events.test.d.ts.map +0 -1
  135. package/dist/bin/sync-runner-events.test.js +0 -364
  136. package/dist/bin/sync-runner-events.test.js.map +0 -1
  137. package/dist/bin/sync-runner-heap-telemetry.test.d.ts +0 -2
  138. package/dist/bin/sync-runner-heap-telemetry.test.d.ts.map +0 -1
  139. package/dist/bin/sync-runner-heap-telemetry.test.js +0 -1966
  140. package/dist/bin/sync-runner-heap-telemetry.test.js.map +0 -1
  141. package/dist/bin/sync-runner-manifest.test.d.ts +0 -12
  142. package/dist/bin/sync-runner-manifest.test.d.ts.map +0 -1
  143. package/dist/bin/sync-runner-manifest.test.js +0 -921
  144. package/dist/bin/sync-runner-manifest.test.js.map +0 -1
  145. package/dist/bin/sync-runner-planning.test.d.ts +0 -2
  146. package/dist/bin/sync-runner-planning.test.d.ts.map +0 -1
  147. package/dist/bin/sync-runner-planning.test.js +0 -448
  148. package/dist/bin/sync-runner-planning.test.js.map +0 -1
  149. package/dist/bin/sync-runner-post-sync-flags.test.d.ts +0 -2
  150. package/dist/bin/sync-runner-post-sync-flags.test.d.ts.map +0 -1
  151. package/dist/bin/sync-runner-post-sync-flags.test.js +0 -64
  152. package/dist/bin/sync-runner-post-sync-flags.test.js.map +0 -1
  153. package/dist/bin/sync-runner-publish-expansion.test.d.ts +0 -2
  154. package/dist/bin/sync-runner-publish-expansion.test.d.ts.map +0 -1
  155. package/dist/bin/sync-runner-publish-expansion.test.js +0 -54
  156. package/dist/bin/sync-runner-publish-expansion.test.js.map +0 -1
  157. package/dist/bin/sync-runner-receiver-unresolved-company.test.d.ts +0 -2
  158. package/dist/bin/sync-runner-receiver-unresolved-company.test.d.ts.map +0 -1
  159. package/dist/bin/sync-runner-receiver-unresolved-company.test.js +0 -379
  160. package/dist/bin/sync-runner-receiver-unresolved-company.test.js.map +0 -1
  161. package/dist/bin/sync-runner-rollup.test.d.ts +0 -2
  162. package/dist/bin/sync-runner-rollup.test.d.ts.map +0 -1
  163. package/dist/bin/sync-runner-rollup.test.js +0 -24
  164. package/dist/bin/sync-runner-rollup.test.js.map +0 -1
  165. package/dist/bin/sync-runner-watch-loop.test.d.ts +0 -2
  166. package/dist/bin/sync-runner-watch-loop.test.d.ts.map +0 -1
  167. package/dist/bin/sync-runner-watch-loop.test.js +0 -734
  168. package/dist/bin/sync-runner-watch-loop.test.js.map +0 -1
  169. package/dist/bin/sync-runner-watch-routes.test.d.ts +0 -2
  170. package/dist/bin/sync-runner-watch-routes.test.d.ts.map +0 -1
  171. package/dist/bin/sync-runner-watch-routes.test.js +0 -181
  172. package/dist/bin/sync-runner-watch-routes.test.js.map +0 -1
  173. package/dist/bin/sync-runner.test.d.ts +0 -10
  174. package/dist/bin/sync-runner.test.d.ts.map +0 -1
  175. package/dist/bin/sync-runner.test.js +0 -18984
  176. package/dist/bin/sync-runner.test.js.map +0 -1
  177. package/dist/cli/case-alias.test.d.ts +0 -2
  178. package/dist/cli/case-alias.test.d.ts.map +0 -1
  179. package/dist/cli/case-alias.test.js +0 -96
  180. package/dist/cli/case-alias.test.js.map +0 -1
  181. package/dist/cli/conflict-recovery.test.d.ts +0 -2
  182. package/dist/cli/conflict-recovery.test.d.ts.map +0 -1
  183. package/dist/cli/conflict-recovery.test.js +0 -201
  184. package/dist/cli/conflict-recovery.test.js.map +0 -1
  185. package/dist/cli/conflict-winner.test.d.ts +0 -7
  186. package/dist/cli/conflict-winner.test.d.ts.map +0 -1
  187. package/dist/cli/conflict-winner.test.js +0 -98
  188. package/dist/cli/conflict-winner.test.js.map +0 -1
  189. package/dist/cli/doctor.test.d.ts +0 -13
  190. package/dist/cli/doctor.test.d.ts.map +0 -1
  191. package/dist/cli/doctor.test.js +0 -607
  192. package/dist/cli/doctor.test.js.map +0 -1
  193. package/dist/cli/invite.test.d.ts +0 -5
  194. package/dist/cli/invite.test.d.ts.map +0 -1
  195. package/dist/cli/invite.test.js +0 -178
  196. package/dist/cli/invite.test.js.map +0 -1
  197. package/dist/cli/onepass-pull-planner-regressions.test.d.ts +0 -2
  198. package/dist/cli/onepass-pull-planner-regressions.test.d.ts.map +0 -1
  199. package/dist/cli/onepass-pull-planner-regressions.test.js +0 -300
  200. package/dist/cli/onepass-pull-planner-regressions.test.js.map +0 -1
  201. package/dist/cli/onepass-pull-planner.test.d.ts +0 -2
  202. package/dist/cli/onepass-pull-planner.test.d.ts.map +0 -1
  203. package/dist/cli/onepass-pull-planner.test.js +0 -266
  204. package/dist/cli/onepass-pull-planner.test.js.map +0 -1
  205. package/dist/cli/push-scan-exclusions.test.d.ts +0 -2
  206. package/dist/cli/push-scan-exclusions.test.d.ts.map +0 -1
  207. package/dist/cli/push-scan-exclusions.test.js +0 -99
  208. package/dist/cli/push-scan-exclusions.test.js.map +0 -1
  209. package/dist/cli/reindex-knowledge.test.d.ts +0 -12
  210. package/dist/cli/reindex-knowledge.test.d.ts.map +0 -1
  211. package/dist/cli/reindex-knowledge.test.js +0 -260
  212. package/dist/cli/reindex-knowledge.test.js.map +0 -1
  213. package/dist/cli/reindex.test.d.ts +0 -11
  214. package/dist/cli/reindex.test.d.ts.map +0 -1
  215. package/dist/cli/reindex.test.js +0 -811
  216. package/dist/cli/reindex.test.js.map +0 -1
  217. package/dist/cli/rescue-breaker.test.d.ts +0 -2
  218. package/dist/cli/rescue-breaker.test.d.ts.map +0 -1
  219. package/dist/cli/rescue-breaker.test.js +0 -812
  220. package/dist/cli/rescue-breaker.test.js.map +0 -1
  221. package/dist/cli/rescue-classify-ordering.test.d.ts +0 -2
  222. package/dist/cli/rescue-classify-ordering.test.d.ts.map +0 -1
  223. package/dist/cli/rescue-classify-ordering.test.js +0 -500
  224. package/dist/cli/rescue-classify-ordering.test.js.map +0 -1
  225. package/dist/cli/rescue-clone-diagnostics.test.d.ts +0 -2
  226. package/dist/cli/rescue-clone-diagnostics.test.d.ts.map +0 -1
  227. package/dist/cli/rescue-clone-diagnostics.test.js +0 -101
  228. package/dist/cli/rescue-clone-diagnostics.test.js.map +0 -1
  229. package/dist/cli/rescue-clone-network-retry.test.d.ts +0 -2
  230. package/dist/cli/rescue-clone-network-retry.test.d.ts.map +0 -1
  231. package/dist/cli/rescue-clone-network-retry.test.js +0 -415
  232. package/dist/cli/rescue-clone-network-retry.test.js.map +0 -1
  233. package/dist/cli/rescue-core-stamp.test.d.ts +0 -2
  234. package/dist/cli/rescue-core-stamp.test.d.ts.map +0 -1
  235. package/dist/cli/rescue-core-stamp.test.js +0 -364
  236. package/dist/cli/rescue-core-stamp.test.js.map +0 -1
  237. package/dist/cli/rescue-drift-reconcile.test.d.ts +0 -2
  238. package/dist/cli/rescue-drift-reconcile.test.d.ts.map +0 -1
  239. package/dist/cli/rescue-drift-reconcile.test.js +0 -162
  240. package/dist/cli/rescue-drift-reconcile.test.js.map +0 -1
  241. package/dist/cli/rescue-drop-dir-symlink.test.d.ts +0 -2
  242. package/dist/cli/rescue-drop-dir-symlink.test.d.ts.map +0 -1
  243. package/dist/cli/rescue-drop-dir-symlink.test.js +0 -255
  244. package/dist/cli/rescue-drop-dir-symlink.test.js.map +0 -1
  245. package/dist/cli/rescue-exec-bit-preserve.test.d.ts +0 -2
  246. package/dist/cli/rescue-exec-bit-preserve.test.d.ts.map +0 -1
  247. package/dist/cli/rescue-exec-bit-preserve.test.js +0 -177
  248. package/dist/cli/rescue-exec-bit-preserve.test.js.map +0 -1
  249. package/dist/cli/rescue-hq-root-guard.test.d.ts +0 -2
  250. package/dist/cli/rescue-hq-root-guard.test.d.ts.map +0 -1
  251. package/dist/cli/rescue-hq-root-guard.test.js +0 -210
  252. package/dist/cli/rescue-hq-root-guard.test.js.map +0 -1
  253. package/dist/cli/rescue-journal-reconcile.test.d.ts +0 -2
  254. package/dist/cli/rescue-journal-reconcile.test.d.ts.map +0 -1
  255. package/dist/cli/rescue-journal-reconcile.test.js +0 -186
  256. package/dist/cli/rescue-journal-reconcile.test.js.map +0 -1
  257. package/dist/cli/rescue-keep-local-ignore.test.d.ts +0 -2
  258. package/dist/cli/rescue-keep-local-ignore.test.d.ts.map +0 -1
  259. package/dist/cli/rescue-keep-local-ignore.test.js +0 -315
  260. package/dist/cli/rescue-keep-local-ignore.test.js.map +0 -1
  261. package/dist/cli/rescue-move.test.d.ts +0 -2
  262. package/dist/cli/rescue-move.test.d.ts.map +0 -1
  263. package/dist/cli/rescue-move.test.js +0 -166
  264. package/dist/cli/rescue-move.test.js.map +0 -1
  265. package/dist/cli/rescue-mtime-preserve.test.d.ts +0 -2
  266. package/dist/cli/rescue-mtime-preserve.test.d.ts.map +0 -1
  267. package/dist/cli/rescue-mtime-preserve.test.js +0 -186
  268. package/dist/cli/rescue-mtime-preserve.test.js.map +0 -1
  269. package/dist/cli/rescue-preserve-copy-symlink.test.d.ts +0 -2
  270. package/dist/cli/rescue-preserve-copy-symlink.test.d.ts.map +0 -1
  271. package/dist/cli/rescue-preserve-copy-symlink.test.js +0 -483
  272. package/dist/cli/rescue-preserve-copy-symlink.test.js.map +0 -1
  273. package/dist/cli/rescue-realpath.test.d.ts +0 -2
  274. package/dist/cli/rescue-realpath.test.d.ts.map +0 -1
  275. package/dist/cli/rescue-realpath.test.js +0 -109
  276. package/dist/cli/rescue-realpath.test.js.map +0 -1
  277. package/dist/cli/rescue-restore-flag.test.d.ts +0 -2
  278. package/dist/cli/rescue-restore-flag.test.d.ts.map +0 -1
  279. package/dist/cli/rescue-restore-flag.test.js +0 -82
  280. package/dist/cli/rescue-restore-flag.test.js.map +0 -1
  281. package/dist/cli/rescue-rsync-preflight.test.d.ts +0 -2
  282. package/dist/cli/rescue-rsync-preflight.test.d.ts.map +0 -1
  283. package/dist/cli/rescue-rsync-preflight.test.js +0 -579
  284. package/dist/cli/rescue-rsync-preflight.test.js.map +0 -1
  285. package/dist/cli/rescue-rsync-status.test.d.ts +0 -2
  286. package/dist/cli/rescue-rsync-status.test.d.ts.map +0 -1
  287. package/dist/cli/rescue-rsync-status.test.js +0 -406
  288. package/dist/cli/rescue-rsync-status.test.js.map +0 -1
  289. package/dist/cli/rescue-settings-reconcile.test.d.ts +0 -2
  290. package/dist/cli/rescue-settings-reconcile.test.d.ts.map +0 -1
  291. package/dist/cli/rescue-settings-reconcile.test.js +0 -610
  292. package/dist/cli/rescue-settings-reconcile.test.js.map +0 -1
  293. package/dist/cli/rescue-snapshot-copy.test.d.ts +0 -2
  294. package/dist/cli/rescue-snapshot-copy.test.d.ts.map +0 -1
  295. package/dist/cli/rescue-snapshot-copy.test.js +0 -790
  296. package/dist/cli/rescue-snapshot-copy.test.js.map +0 -1
  297. package/dist/cli/rescue-snapshot-recovery.test.d.ts +0 -2
  298. package/dist/cli/rescue-snapshot-recovery.test.d.ts.map +0 -1
  299. package/dist/cli/rescue-snapshot-recovery.test.js +0 -265
  300. package/dist/cli/rescue-snapshot-recovery.test.js.map +0 -1
  301. package/dist/cli/rescue-snapshot.test.d.ts +0 -2
  302. package/dist/cli/rescue-snapshot.test.d.ts.map +0 -1
  303. package/dist/cli/rescue-snapshot.test.js +0 -46
  304. package/dist/cli/rescue-snapshot.test.js.map +0 -1
  305. package/dist/cli/rescue-source-switch-floor.test.d.ts +0 -2
  306. package/dist/cli/rescue-source-switch-floor.test.d.ts.map +0 -1
  307. package/dist/cli/rescue-source-switch-floor.test.js +0 -247
  308. package/dist/cli/rescue-source-switch-floor.test.js.map +0 -1
  309. package/dist/cli/rescue-unchanged-delete.test.d.ts +0 -2
  310. package/dist/cli/rescue-unchanged-delete.test.d.ts.map +0 -1
  311. package/dist/cli/rescue-unchanged-delete.test.js +0 -305
  312. package/dist/cli/rescue-unchanged-delete.test.js.map +0 -1
  313. package/dist/cli/rescue.reindex.test.d.ts +0 -2
  314. package/dist/cli/rescue.reindex.test.d.ts.map +0 -1
  315. package/dist/cli/rescue.reindex.test.js +0 -72
  316. package/dist/cli/rescue.reindex.test.js.map +0 -1
  317. package/dist/cli/rescue.test.d.ts +0 -2
  318. package/dist/cli/rescue.test.d.ts.map +0 -1
  319. package/dist/cli/rescue.test.js +0 -127
  320. package/dist/cli/rescue.test.js.map +0 -1
  321. package/dist/cli/share-plan-limit-presign.test.d.ts +0 -2
  322. package/dist/cli/share-plan-limit-presign.test.d.ts.map +0 -1
  323. package/dist/cli/share-plan-limit-presign.test.js +0 -271
  324. package/dist/cli/share-plan-limit-presign.test.js.map +0 -1
  325. package/dist/cli/share-presign-transport.test.d.ts +0 -22
  326. package/dist/cli/share-presign-transport.test.d.ts.map +0 -1
  327. package/dist/cli/share-presign-transport.test.js +0 -388
  328. package/dist/cli/share-presign-transport.test.js.map +0 -1
  329. package/dist/cli/share.test.d.ts +0 -5
  330. package/dist/cli/share.test.d.ts.map +0 -1
  331. package/dist/cli/share.test.js +0 -12335
  332. package/dist/cli/share.test.js.map +0 -1
  333. package/dist/cli/streaming-pull-planner.bench.test.d.ts +0 -15
  334. package/dist/cli/streaming-pull-planner.bench.test.d.ts.map +0 -1
  335. package/dist/cli/streaming-pull-planner.bench.test.js +0 -273
  336. package/dist/cli/streaming-pull-planner.bench.test.js.map +0 -1
  337. package/dist/cli/sync-scope.test.d.ts +0 -22
  338. package/dist/cli/sync-scope.test.d.ts.map +0 -1
  339. package/dist/cli/sync-scope.test.js +0 -903
  340. package/dist/cli/sync-scope.test.js.map +0 -1
  341. package/dist/cli/sync.test.d.ts +0 -5
  342. package/dist/cli/sync.test.d.ts.map +0 -1
  343. package/dist/cli/sync.test.js +0 -9028
  344. package/dist/cli/sync.test.js.map +0 -1
  345. package/dist/cli/tombstones.test.d.ts +0 -2
  346. package/dist/cli/tombstones.test.d.ts.map +0 -1
  347. package/dist/cli/tombstones.test.js +0 -120
  348. package/dist/cli/tombstones.test.js.map +0 -1
  349. package/dist/cli/watch-event-push-conflict.test.d.ts +0 -25
  350. package/dist/cli/watch-event-push-conflict.test.d.ts.map +0 -1
  351. package/dist/cli/watch-event-push-conflict.test.js +0 -230
  352. package/dist/cli/watch-event-push-conflict.test.js.map +0 -1
  353. package/dist/client-info.test.d.ts +0 -11
  354. package/dist/client-info.test.d.ts.map +0 -1
  355. package/dist/client-info.test.js +0 -168
  356. package/dist/client-info.test.js.map +0 -1
  357. package/dist/cognito-auth-lock-no-hard-links.test.d.ts +0 -11
  358. package/dist/cognito-auth-lock-no-hard-links.test.d.ts.map +0 -1
  359. package/dist/cognito-auth-lock-no-hard-links.test.js +0 -76
  360. package/dist/cognito-auth-lock-no-hard-links.test.js.map +0 -1
  361. package/dist/cognito-auth.test.d.ts +0 -9
  362. package/dist/cognito-auth.test.d.ts.map +0 -1
  363. package/dist/cognito-auth.test.js +0 -745
  364. package/dist/cognito-auth.test.js.map +0 -1
  365. package/dist/company-resolver.test.d.ts +0 -7
  366. package/dist/company-resolver.test.d.ts.map +0 -1
  367. package/dist/company-resolver.test.js +0 -533
  368. package/dist/company-resolver.test.js.map +0 -1
  369. package/dist/company-slug.test.d.ts +0 -7
  370. package/dist/company-slug.test.d.ts.map +0 -1
  371. package/dist/company-slug.test.js +0 -43
  372. package/dist/company-slug.test.js.map +0 -1
  373. package/dist/company-vault-transport.test.d.ts +0 -12
  374. package/dist/company-vault-transport.test.d.ts.map +0 -1
  375. package/dist/company-vault-transport.test.js +0 -97
  376. package/dist/company-vault-transport.test.js.map +0 -1
  377. package/dist/context.test.d.ts +0 -7
  378. package/dist/context.test.d.ts.map +0 -1
  379. package/dist/context.test.js +0 -646
  380. package/dist/context.test.js.map +0 -1
  381. package/dist/entity-resolver.test.d.ts +0 -10
  382. package/dist/entity-resolver.test.d.ts.map +0 -1
  383. package/dist/entity-resolver.test.js +0 -244
  384. package/dist/entity-resolver.test.js.map +0 -1
  385. package/dist/getindigo-dead-refs-contract.test.d.ts +0 -2
  386. package/dist/getindigo-dead-refs-contract.test.d.ts.map +0 -1
  387. package/dist/getindigo-dead-refs-contract.test.js +0 -58
  388. package/dist/getindigo-dead-refs-contract.test.js.map +0 -1
  389. package/dist/hermetic-test-env.test.d.ts +0 -2
  390. package/dist/hermetic-test-env.test.d.ts.map +0 -1
  391. package/dist/hermetic-test-env.test.js +0 -61
  392. package/dist/hermetic-test-env.test.js.map +0 -1
  393. package/dist/hq-root-recovery.test.d.ts +0 -2
  394. package/dist/hq-root-recovery.test.d.ts.map +0 -1
  395. package/dist/hq-root-recovery.test.js +0 -65
  396. package/dist/hq-root-recovery.test.js.map +0 -1
  397. package/dist/ignore.test.d.ts +0 -10
  398. package/dist/ignore.test.d.ts.map +0 -1
  399. package/dist/ignore.test.js +0 -926
  400. package/dist/ignore.test.js.map +0 -1
  401. package/dist/index.test.d.ts +0 -2
  402. package/dist/index.test.d.ts.map +0 -1
  403. package/dist/index.test.js +0 -26
  404. package/dist/index.test.js.map +0 -1
  405. package/dist/journal-area-ledger-read-boundary.test.d.ts +0 -2
  406. package/dist/journal-area-ledger-read-boundary.test.d.ts.map +0 -1
  407. package/dist/journal-area-ledger-read-boundary.test.js +0 -420
  408. package/dist/journal-area-ledger-read-boundary.test.js.map +0 -1
  409. package/dist/journal-baseline.test.d.ts +0 -2
  410. package/dist/journal-baseline.test.d.ts.map +0 -1
  411. package/dist/journal-baseline.test.js +0 -218
  412. package/dist/journal-baseline.test.js.map +0 -1
  413. package/dist/journal-decode-window.test.d.ts +0 -2
  414. package/dist/journal-decode-window.test.d.ts.map +0 -1
  415. package/dist/journal-decode-window.test.js +0 -99
  416. package/dist/journal-decode-window.test.js.map +0 -1
  417. package/dist/journal-delta-writes.test.d.ts +0 -2
  418. package/dist/journal-delta-writes.test.d.ts.map +0 -1
  419. package/dist/journal-delta-writes.test.js +0 -159
  420. package/dist/journal-delta-writes.test.js.map +0 -1
  421. package/dist/journal-ledger-index.test.d.ts +0 -15
  422. package/dist/journal-ledger-index.test.d.ts.map +0 -1
  423. package/dist/journal-ledger-index.test.js +0 -269
  424. package/dist/journal-ledger-index.test.js.map +0 -1
  425. package/dist/journal-public-boundary.test.d.ts +0 -2
  426. package/dist/journal-public-boundary.test.d.ts.map +0 -1
  427. package/dist/journal-public-boundary.test.js +0 -216
  428. package/dist/journal-public-boundary.test.js.map +0 -1
  429. package/dist/journal-row-store.test.d.ts +0 -2
  430. package/dist/journal-row-store.test.d.ts.map +0 -1
  431. package/dist/journal-row-store.test.js +0 -729
  432. package/dist/journal-row-store.test.js.map +0 -1
  433. package/dist/journal-snapshot-memory-helpers.d.ts +0 -33
  434. package/dist/journal-snapshot-memory-helpers.d.ts.map +0 -1
  435. package/dist/journal-snapshot-memory-helpers.js +0 -212
  436. package/dist/journal-snapshot-memory-helpers.js.map +0 -1
  437. package/dist/journal-snapshot-memory.test.d.ts +0 -2
  438. package/dist/journal-snapshot-memory.test.d.ts.map +0 -1
  439. package/dist/journal-snapshot-memory.test.js +0 -47
  440. package/dist/journal-snapshot-memory.test.js.map +0 -1
  441. package/dist/journal-snapshot-v4-memory.test.d.ts +0 -2
  442. package/dist/journal-snapshot-v4-memory.test.d.ts.map +0 -1
  443. package/dist/journal-snapshot-v4-memory.test.js +0 -24
  444. package/dist/journal-snapshot-v4-memory.test.js.map +0 -1
  445. package/dist/journal-snapshot-v4-writer-memory.test.d.ts +0 -2
  446. package/dist/journal-snapshot-v4-writer-memory.test.d.ts.map +0 -1
  447. package/dist/journal-snapshot-v4-writer-memory.test.js +0 -76
  448. package/dist/journal-snapshot-v4-writer-memory.test.js.map +0 -1
  449. package/dist/journal-snapshot-v4-writer.test.d.ts +0 -2
  450. package/dist/journal-snapshot-v4-writer.test.d.ts.map +0 -1
  451. package/dist/journal-snapshot-v4-writer.test.js +0 -282
  452. package/dist/journal-snapshot-v4-writer.test.js.map +0 -1
  453. package/dist/journal-snapshot-v4.test.d.ts +0 -2
  454. package/dist/journal-snapshot-v4.test.d.ts.map +0 -1
  455. package/dist/journal-snapshot-v4.test.js +0 -281
  456. package/dist/journal-snapshot-v4.test.js.map +0 -1
  457. package/dist/journal-store.test.d.ts +0 -2
  458. package/dist/journal-store.test.d.ts.map +0 -1
  459. package/dist/journal-store.test.js +0 -1227
  460. package/dist/journal-store.test.js.map +0 -1
  461. package/dist/journal-streaming.heap.test.d.ts +0 -2
  462. package/dist/journal-streaming.heap.test.d.ts.map +0 -1
  463. package/dist/journal-streaming.heap.test.js +0 -190
  464. package/dist/journal-streaming.heap.test.js.map +0 -1
  465. package/dist/journal.test.d.ts +0 -9
  466. package/dist/journal.test.d.ts.map +0 -1
  467. package/dist/journal.test.js +0 -1074
  468. package/dist/journal.test.js.map +0 -1
  469. package/dist/kms10-etag-safe-pull.test.d.ts +0 -2
  470. package/dist/kms10-etag-safe-pull.test.d.ts.map +0 -1
  471. package/dist/kms10-etag-safe-pull.test.js +0 -53
  472. package/dist/kms10-etag-safe-pull.test.js.map +0 -1
  473. package/dist/lib/cloud-authoritative.test.d.ts +0 -2
  474. package/dist/lib/cloud-authoritative.test.d.ts.map +0 -1
  475. package/dist/lib/cloud-authoritative.test.js +0 -42
  476. package/dist/lib/cloud-authoritative.test.js.map +0 -1
  477. package/dist/lib/conflict-reconcile.test.d.ts +0 -7
  478. package/dist/lib/conflict-reconcile.test.d.ts.map +0 -1
  479. package/dist/lib/conflict-reconcile.test.js +0 -246
  480. package/dist/lib/conflict-reconcile.test.js.map +0 -1
  481. package/dist/lib/conflict.test.d.ts +0 -9
  482. package/dist/lib/conflict.test.d.ts.map +0 -1
  483. package/dist/lib/conflict.test.js +0 -340
  484. package/dist/lib/conflict.test.js.map +0 -1
  485. package/dist/lib/describe-error.test.d.ts +0 -2
  486. package/dist/lib/describe-error.test.d.ts.map +0 -1
  487. package/dist/lib/describe-error.test.js +0 -148
  488. package/dist/lib/describe-error.test.js.map +0 -1
  489. package/dist/lib/machine-id.test.d.ts +0 -8
  490. package/dist/lib/machine-id.test.d.ts.map +0 -1
  491. package/dist/lib/machine-id.test.js +0 -228
  492. package/dist/lib/machine-id.test.js.map +0 -1
  493. package/dist/lib/net-errors.test.d.ts +0 -2
  494. package/dist/lib/net-errors.test.d.ts.map +0 -1
  495. package/dist/lib/net-errors.test.js +0 -111
  496. package/dist/lib/net-errors.test.js.map +0 -1
  497. package/dist/lib/ontology-entity-meta.test.d.ts +0 -2
  498. package/dist/lib/ontology-entity-meta.test.d.ts.map +0 -1
  499. package/dist/lib/ontology-entity-meta.test.js +0 -79
  500. package/dist/lib/ontology-entity-meta.test.js.map +0 -1
  501. package/dist/lib/ontology-entity-push.test.d.ts +0 -2
  502. package/dist/lib/ontology-entity-push.test.d.ts.map +0 -1
  503. package/dist/lib/ontology-entity-push.test.js +0 -156
  504. package/dist/lib/ontology-entity-push.test.js.map +0 -1
  505. package/dist/lib/personal-connector-settings-sync.test.d.ts +0 -2
  506. package/dist/lib/personal-connector-settings-sync.test.d.ts.map +0 -1
  507. package/dist/lib/personal-connector-settings-sync.test.js +0 -34
  508. package/dist/lib/personal-connector-settings-sync.test.js.map +0 -1
  509. package/dist/lib/readlink-safe.test.d.ts +0 -2
  510. package/dist/lib/readlink-safe.test.d.ts.map +0 -1
  511. package/dist/lib/readlink-safe.test.js +0 -34
  512. package/dist/lib/readlink-safe.test.js.map +0 -1
  513. package/dist/lib/s3-content-checksum.test.d.ts +0 -2
  514. package/dist/lib/s3-content-checksum.test.d.ts.map +0 -1
  515. package/dist/lib/s3-content-checksum.test.js +0 -26
  516. package/dist/lib/s3-content-checksum.test.js.map +0 -1
  517. package/dist/lib/skill-register-landed-bytes.test.d.ts +0 -2
  518. package/dist/lib/skill-register-landed-bytes.test.d.ts.map +0 -1
  519. package/dist/lib/skill-register-landed-bytes.test.js +0 -83
  520. package/dist/lib/skill-register-landed-bytes.test.js.map +0 -1
  521. package/dist/local-path-codec.test.d.ts +0 -14
  522. package/dist/local-path-codec.test.d.ts.map +0 -1
  523. package/dist/local-path-codec.test.js +0 -122
  524. package/dist/local-path-codec.test.js.map +0 -1
  525. package/dist/machine-auth.test.d.ts +0 -14
  526. package/dist/machine-auth.test.d.ts.map +0 -1
  527. package/dist/machine-auth.test.js +0 -1482
  528. package/dist/machine-auth.test.js.map +0 -1
  529. package/dist/machine-token-cache-isolation.test.d.ts +0 -24
  530. package/dist/machine-token-cache-isolation.test.d.ts.map +0 -1
  531. package/dist/machine-token-cache-isolation.test.js +0 -284
  532. package/dist/machine-token-cache-isolation.test.js.map +0 -1
  533. package/dist/manifest/US-002.acceptance.test.d.ts +0 -11
  534. package/dist/manifest/US-002.acceptance.test.d.ts.map +0 -1
  535. package/dist/manifest/US-002.acceptance.test.js +0 -160
  536. package/dist/manifest/US-002.acceptance.test.js.map +0 -1
  537. package/dist/manifest/US-004.acceptance.test.d.ts +0 -12
  538. package/dist/manifest/US-004.acceptance.test.d.ts.map +0 -1
  539. package/dist/manifest/US-004.acceptance.test.js +0 -173
  540. package/dist/manifest/US-004.acceptance.test.js.map +0 -1
  541. package/dist/manifest/build-manifest-resident-parity.test.d.ts +0 -2
  542. package/dist/manifest/build-manifest-resident-parity.test.d.ts.map +0 -1
  543. package/dist/manifest/build-manifest-resident-parity.test.js +0 -69
  544. package/dist/manifest/build-manifest-resident-parity.test.js.map +0 -1
  545. package/dist/manifest/build-manifest.bench.test.d.ts +0 -22
  546. package/dist/manifest/build-manifest.bench.test.d.ts.map +0 -1
  547. package/dist/manifest/build-manifest.bench.test.js +0 -930
  548. package/dist/manifest/build-manifest.bench.test.js.map +0 -1
  549. package/dist/manifest/build-manifest.test.d.ts +0 -10
  550. package/dist/manifest/build-manifest.test.d.ts.map +0 -1
  551. package/dist/manifest/build-manifest.test.js +0 -1217
  552. package/dist/manifest/build-manifest.test.js.map +0 -1
  553. package/dist/manifest/contract.test.d.ts +0 -17
  554. package/dist/manifest/contract.test.d.ts.map +0 -1
  555. package/dist/manifest/contract.test.js +0 -346
  556. package/dist/manifest/contract.test.js.map +0 -1
  557. package/dist/manifest/import-graph.test.d.ts +0 -25
  558. package/dist/manifest/import-graph.test.d.ts.map +0 -1
  559. package/dist/manifest/import-graph.test.js +0 -120
  560. package/dist/manifest/import-graph.test.js.map +0 -1
  561. package/dist/manifest/ledger-shard-isolation.test.d.ts +0 -18
  562. package/dist/manifest/ledger-shard-isolation.test.d.ts.map +0 -1
  563. package/dist/manifest/ledger-shard-isolation.test.js +0 -153
  564. package/dist/manifest/ledger-shard-isolation.test.js.map +0 -1
  565. package/dist/manifest/snapshot-store.test.d.ts +0 -11
  566. package/dist/manifest/snapshot-store.test.d.ts.map +0 -1
  567. package/dist/manifest/snapshot-store.test.js +0 -206
  568. package/dist/manifest/snapshot-store.test.js.map +0 -1
  569. package/dist/manifest/upload-manifest.test.d.ts +0 -10
  570. package/dist/manifest/upload-manifest.test.d.ts.map +0 -1
  571. package/dist/manifest/upload-manifest.test.js +0 -1335
  572. package/dist/manifest/upload-manifest.test.js.map +0 -1
  573. package/dist/manifest-reconcile.test.d.ts +0 -2
  574. package/dist/manifest-reconcile.test.d.ts.map +0 -1
  575. package/dist/manifest-reconcile.test.js +0 -1029
  576. package/dist/manifest-reconcile.test.js.map +0 -1
  577. package/dist/object-io.test.d.ts +0 -11
  578. package/dist/object-io.test.d.ts.map +0 -1
  579. package/dist/object-io.test.js +0 -2376
  580. package/dist/object-io.test.js.map +0 -1
  581. package/dist/operation-lock.test.d.ts +0 -5
  582. package/dist/operation-lock.test.d.ts.map +0 -1
  583. package/dist/operation-lock.test.js +0 -796
  584. package/dist/operation-lock.test.js.map +0 -1
  585. package/dist/outcome-telemetry.test.d.ts +0 -9
  586. package/dist/outcome-telemetry.test.d.ts.map +0 -1
  587. package/dist/outcome-telemetry.test.js +0 -663
  588. package/dist/outcome-telemetry.test.js.map +0 -1
  589. package/dist/outposts/client.test.d.ts +0 -9
  590. package/dist/outposts/client.test.d.ts.map +0 -1
  591. package/dist/outposts/client.test.js +0 -415
  592. package/dist/outposts/client.test.js.map +0 -1
  593. package/dist/outposts/command.test.d.ts +0 -18
  594. package/dist/outposts/command.test.d.ts.map +0 -1
  595. package/dist/outposts/command.test.js +0 -1230
  596. package/dist/outposts/command.test.js.map +0 -1
  597. package/dist/outposts/replica-sync.test.d.ts +0 -2
  598. package/dist/outposts/replica-sync.test.d.ts.map +0 -1
  599. package/dist/outposts/replica-sync.test.js +0 -224
  600. package/dist/outposts/replica-sync.test.js.map +0 -1
  601. package/dist/outposts/self-deploy.test.d.ts +0 -2
  602. package/dist/outposts/self-deploy.test.d.ts.map +0 -1
  603. package/dist/outposts/self-deploy.test.js +0 -218
  604. package/dist/outposts/self-deploy.test.js.map +0 -1
  605. package/dist/outposts/session-heartbeat-bounds.test.d.ts +0 -25
  606. package/dist/outposts/session-heartbeat-bounds.test.d.ts.map +0 -1
  607. package/dist/outposts/session-heartbeat-bounds.test.js +0 -156
  608. package/dist/outposts/session-heartbeat-bounds.test.js.map +0 -1
  609. package/dist/outposts/session-heartbeat-guard.test.d.ts +0 -16
  610. package/dist/outposts/session-heartbeat-guard.test.d.ts.map +0 -1
  611. package/dist/outposts/session-heartbeat-guard.test.js +0 -88
  612. package/dist/outposts/session-heartbeat-guard.test.js.map +0 -1
  613. package/dist/outposts/session-heartbeat-publisher.test.d.ts +0 -10
  614. package/dist/outposts/session-heartbeat-publisher.test.d.ts.map +0 -1
  615. package/dist/outposts/session-heartbeat-publisher.test.js +0 -153
  616. package/dist/outposts/session-heartbeat-publisher.test.js.map +0 -1
  617. package/dist/outposts/session-heartbeat-retain-guard.test.d.ts +0 -18
  618. package/dist/outposts/session-heartbeat-retain-guard.test.d.ts.map +0 -1
  619. package/dist/outposts/session-heartbeat-retain-guard.test.js +0 -106
  620. package/dist/outposts/session-heartbeat-retain-guard.test.js.map +0 -1
  621. package/dist/outposts/session-heartbeat-scan.test.d.ts +0 -20
  622. package/dist/outposts/session-heartbeat-scan.test.d.ts.map +0 -1
  623. package/dist/outposts/session-heartbeat-scan.test.js +0 -241
  624. package/dist/outposts/session-heartbeat-scan.test.js.map +0 -1
  625. package/dist/outposts/session-heartbeat.test.d.ts +0 -11
  626. package/dist/outposts/session-heartbeat.test.d.ts.map +0 -1
  627. package/dist/outposts/session-heartbeat.test.js +0 -370
  628. package/dist/outposts/session-heartbeat.test.js.map +0 -1
  629. package/dist/outposts/session-host-auth.test.d.ts +0 -16
  630. package/dist/outposts/session-host-auth.test.d.ts.map +0 -1
  631. package/dist/outposts/session-host-auth.test.js +0 -284
  632. package/dist/outposts/session-host-auth.test.js.map +0 -1
  633. package/dist/outposts/session-host-command.test.d.ts +0 -10
  634. package/dist/outposts/session-host-command.test.d.ts.map +0 -1
  635. package/dist/outposts/session-host-command.test.js +0 -180
  636. package/dist/outposts/session-host-command.test.js.map +0 -1
  637. package/dist/outposts/session-host-connection.test.d.ts +0 -18
  638. package/dist/outposts/session-host-connection.test.d.ts.map +0 -1
  639. package/dist/outposts/session-host-connection.test.js +0 -392
  640. package/dist/outposts/session-host-connection.test.js.map +0 -1
  641. package/dist/outposts/session-host-fakes.d.ts +0 -61
  642. package/dist/outposts/session-host-fakes.d.ts.map +0 -1
  643. package/dist/outposts/session-host-fakes.js +0 -115
  644. package/dist/outposts/session-host-fakes.js.map +0 -1
  645. package/dist/outposts/session-host-ndjson.test.d.ts +0 -11
  646. package/dist/outposts/session-host-ndjson.test.d.ts.map +0 -1
  647. package/dist/outposts/session-host-ndjson.test.js +0 -73
  648. package/dist/outposts/session-host-ndjson.test.js.map +0 -1
  649. package/dist/outposts/session-host-protocol.test.d.ts +0 -15
  650. package/dist/outposts/session-host-protocol.test.d.ts.map +0 -1
  651. package/dist/outposts/session-host-protocol.test.js +0 -0
  652. package/dist/outposts/session-host-protocol.test.js.map +0 -1
  653. package/dist/outposts/session-host-server.test.d.ts +0 -10
  654. package/dist/outposts/session-host-server.test.d.ts.map +0 -1
  655. package/dist/outposts/session-host-server.test.js +0 -118
  656. package/dist/outposts/session-host-server.test.js.map +0 -1
  657. package/dist/outposts/session-host-sessions.test.d.ts +0 -18
  658. package/dist/outposts/session-host-sessions.test.d.ts.map +0 -1
  659. package/dist/outposts/session-host-sessions.test.js +0 -439
  660. package/dist/outposts/session-host-sessions.test.js.map +0 -1
  661. package/dist/outposts/terminal.test.d.ts +0 -2
  662. package/dist/outposts/terminal.test.d.ts.map +0 -1
  663. package/dist/outposts/terminal.test.js +0 -146
  664. package/dist/outposts/terminal.test.js.map +0 -1
  665. package/dist/outposts/transport.test.d.ts +0 -10
  666. package/dist/outposts/transport.test.d.ts.map +0 -1
  667. package/dist/outposts/transport.test.js +0 -205
  668. package/dist/outposts/transport.test.js.map +0 -1
  669. package/dist/packed-journal-phase2.test.d.ts +0 -2
  670. package/dist/packed-journal-phase2.test.d.ts.map +0 -1
  671. package/dist/packed-journal-phase2.test.js +0 -273
  672. package/dist/packed-journal-phase2.test.js.map +0 -1
  673. package/dist/path-ancestors.test.d.ts +0 -2
  674. package/dist/path-ancestors.test.d.ts.map +0 -1
  675. package/dist/path-ancestors.test.js +0 -21
  676. package/dist/path-ancestors.test.js.map +0 -1
  677. package/dist/personal-vault-exclusions.test.d.ts +0 -22
  678. package/dist/personal-vault-exclusions.test.d.ts.map +0 -1
  679. package/dist/personal-vault-exclusions.test.js +0 -294
  680. package/dist/personal-vault-exclusions.test.js.map +0 -1
  681. package/dist/personal-vault.test.d.ts +0 -18
  682. package/dist/personal-vault.test.d.ts.map +0 -1
  683. package/dist/personal-vault.test.js +0 -1099
  684. package/dist/personal-vault.test.js.map +0 -1
  685. package/dist/plan-limit-pause.test.d.ts +0 -2
  686. package/dist/plan-limit-pause.test.d.ts.map +0 -1
  687. package/dist/plan-limit-pause.test.js +0 -150
  688. package/dist/plan-limit-pause.test.js.map +0 -1
  689. package/dist/plan-limit.fixtures.d.ts +0 -34
  690. package/dist/plan-limit.fixtures.d.ts.map +0 -1
  691. package/dist/plan-limit.fixtures.js +0 -96
  692. package/dist/plan-limit.fixtures.js.map +0 -1
  693. package/dist/plan-limit.test.d.ts +0 -2
  694. package/dist/plan-limit.test.d.ts.map +0 -1
  695. package/dist/plan-limit.test.js +0 -132
  696. package/dist/plan-limit.test.js.map +0 -1
  697. package/dist/prefix-coalesce.test.d.ts +0 -2
  698. package/dist/prefix-coalesce.test.d.ts.map +0 -1
  699. package/dist/prefix-coalesce.test.js +0 -260
  700. package/dist/prefix-coalesce.test.js.map +0 -1
  701. package/dist/private-folder-transport.test.d.ts +0 -2
  702. package/dist/private-folder-transport.test.d.ts.map +0 -1
  703. package/dist/private-folder-transport.test.js +0 -33
  704. package/dist/private-folder-transport.test.js.map +0 -1
  705. package/dist/public-surface.test.d.ts +0 -15
  706. package/dist/public-surface.test.d.ts.map +0 -1
  707. package/dist/public-surface.test.js +0 -110
  708. package/dist/public-surface.test.js.map +0 -1
  709. package/dist/qmd-reindex.test.d.ts +0 -14
  710. package/dist/qmd-reindex.test.d.ts.map +0 -1
  711. package/dist/qmd-reindex.test.js +0 -899
  712. package/dist/qmd-reindex.test.js.map +0 -1
  713. package/dist/read-only-state-dir.test.d.ts +0 -27
  714. package/dist/read-only-state-dir.test.d.ts.map +0 -1
  715. package/dist/read-only-state-dir.test.js +0 -167
  716. package/dist/read-only-state-dir.test.js.map +0 -1
  717. package/dist/remote-pull.test.d.ts +0 -2
  718. package/dist/remote-pull.test.d.ts.map +0 -1
  719. package/dist/remote-pull.test.js +0 -1147
  720. package/dist/remote-pull.test.js.map +0 -1
  721. package/dist/s3-download-stream-hash.test.d.ts +0 -2
  722. package/dist/s3-download-stream-hash.test.d.ts.map +0 -1
  723. package/dist/s3-download-stream-hash.test.js +0 -70
  724. package/dist/s3-download-stream-hash.test.js.map +0 -1
  725. package/dist/s3.list-cost.test.d.ts +0 -2
  726. package/dist/s3.list-cost.test.d.ts.map +0 -1
  727. package/dist/s3.list-cost.test.js +0 -51
  728. package/dist/s3.list-cost.test.js.map +0 -1
  729. package/dist/s3.rename-retry.test.d.ts +0 -2
  730. package/dist/s3.rename-retry.test.d.ts.map +0 -1
  731. package/dist/s3.rename-retry.test.js +0 -217
  732. package/dist/s3.rename-retry.test.js.map +0 -1
  733. package/dist/s3.symlink-materialize.test.d.ts +0 -18
  734. package/dist/s3.symlink-materialize.test.d.ts.map +0 -1
  735. package/dist/s3.symlink-materialize.test.js +0 -579
  736. package/dist/s3.symlink-materialize.test.js.map +0 -1
  737. package/dist/s3.test.d.ts +0 -9
  738. package/dist/s3.test.d.ts.map +0 -1
  739. package/dist/s3.test.js +0 -2047
  740. package/dist/s3.test.js.map +0 -1
  741. package/dist/s3.windows-portability.test.d.ts +0 -12
  742. package/dist/s3.windows-portability.test.d.ts.map +0 -1
  743. package/dist/s3.windows-portability.test.js +0 -223
  744. package/dist/s3.windows-portability.test.js.map +0 -1
  745. package/dist/schemas/signal-types.test.d.ts +0 -2
  746. package/dist/schemas/signal-types.test.d.ts.map +0 -1
  747. package/dist/schemas/signal-types.test.js +0 -65
  748. package/dist/schemas/signal-types.test.js.map +0 -1
  749. package/dist/schemas/source-channels.test.d.ts +0 -2
  750. package/dist/schemas/source-channels.test.d.ts.map +0 -1
  751. package/dist/schemas/source-channels.test.js +0 -65
  752. package/dist/schemas/source-channels.test.js.map +0 -1
  753. package/dist/scope-shrink.test.d.ts +0 -13
  754. package/dist/scope-shrink.test.d.ts.map +0 -1
  755. package/dist/scope-shrink.test.js +0 -558
  756. package/dist/scope-shrink.test.js.map +0 -1
  757. package/dist/session-log-capture.test.d.ts +0 -2
  758. package/dist/session-log-capture.test.d.ts.map +0 -1
  759. package/dist/session-log-capture.test.js +0 -533
  760. package/dist/session-log-capture.test.js.map +0 -1
  761. package/dist/session-log-retention.test.d.ts +0 -2
  762. package/dist/session-log-retention.test.d.ts.map +0 -1
  763. package/dist/session-log-retention.test.js +0 -383
  764. package/dist/session-log-retention.test.js.map +0 -1
  765. package/dist/signals/get.test.d.ts +0 -5
  766. package/dist/signals/get.test.d.ts.map +0 -1
  767. package/dist/signals/get.test.js +0 -254
  768. package/dist/signals/get.test.js.map +0 -1
  769. package/dist/signals/list.test.d.ts +0 -9
  770. package/dist/signals/list.test.d.ts.map +0 -1
  771. package/dist/signals/list.test.js +0 -330
  772. package/dist/signals/list.test.js.map +0 -1
  773. package/dist/skill-telemetry.test.d.ts +0 -2
  774. package/dist/skill-telemetry.test.d.ts.map +0 -1
  775. package/dist/skill-telemetry.test.js +0 -1484
  776. package/dist/skill-telemetry.test.js.map +0 -1
  777. package/dist/sources/get.test.d.ts +0 -5
  778. package/dist/sources/get.test.d.ts.map +0 -1
  779. package/dist/sources/get.test.js +0 -236
  780. package/dist/sources/get.test.js.map +0 -1
  781. package/dist/sources/list.test.d.ts +0 -8
  782. package/dist/sources/list.test.d.ts.map +0 -1
  783. package/dist/sources/list.test.js +0 -318
  784. package/dist/sources/list.test.js.map +0 -1
  785. package/dist/sts-credential-refresh.test.d.ts +0 -2
  786. package/dist/sts-credential-refresh.test.d.ts.map +0 -1
  787. package/dist/sts-credential-refresh.test.js +0 -181
  788. package/dist/sts-credential-refresh.test.js.map +0 -1
  789. package/dist/swallowed-error-sites.test.d.ts +0 -2
  790. package/dist/swallowed-error-sites.test.d.ts.map +0 -1
  791. package/dist/swallowed-error-sites.test.js +0 -199
  792. package/dist/swallowed-error-sites.test.js.map +0 -1
  793. package/dist/swallowed-error-w32.test.d.ts +0 -2
  794. package/dist/swallowed-error-w32.test.d.ts.map +0 -1
  795. package/dist/swallowed-error-w32.test.js +0 -171
  796. package/dist/swallowed-error-w32.test.js.map +0 -1
  797. package/dist/swallowed-error-w33.test.d.ts +0 -2
  798. package/dist/swallowed-error-w33.test.d.ts.map +0 -1
  799. package/dist/swallowed-error-w33.test.js +0 -125
  800. package/dist/swallowed-error-w33.test.js.map +0 -1
  801. package/dist/swallowed-error-w34.test.d.ts +0 -2
  802. package/dist/swallowed-error-w34.test.d.ts.map +0 -1
  803. package/dist/swallowed-error-w34.test.js +0 -110
  804. package/dist/swallowed-error-w34.test.js.map +0 -1
  805. package/dist/swallowed-error-w35.test.d.ts +0 -2
  806. package/dist/swallowed-error-w35.test.d.ts.map +0 -1
  807. package/dist/swallowed-error-w35.test.js +0 -223
  808. package/dist/swallowed-error-w35.test.js.map +0 -1
  809. package/dist/sync/area-ledger-auto-migration.test.d.ts +0 -2
  810. package/dist/sync/area-ledger-auto-migration.test.d.ts.map +0 -1
  811. package/dist/sync/area-ledger-auto-migration.test.js +0 -291
  812. package/dist/sync/area-ledger-auto-migration.test.js.map +0 -1
  813. package/dist/sync/area-ledger-migration.test.d.ts +0 -2
  814. package/dist/sync/area-ledger-migration.test.d.ts.map +0 -1
  815. package/dist/sync/area-ledger-migration.test.js +0 -554
  816. package/dist/sync/area-ledger-migration.test.js.map +0 -1
  817. package/dist/sync/area-ledger-recovery.bench.test.d.ts +0 -2
  818. package/dist/sync/area-ledger-recovery.bench.test.d.ts.map +0 -1
  819. package/dist/sync/area-ledger-recovery.bench.test.js +0 -60
  820. package/dist/sync/area-ledger-recovery.bench.test.js.map +0 -1
  821. package/dist/sync/area-ledger-writer-lock.bench.test.d.ts +0 -2
  822. package/dist/sync/area-ledger-writer-lock.bench.test.d.ts.map +0 -1
  823. package/dist/sync/area-ledger-writer-lock.bench.test.js +0 -57
  824. package/dist/sync/area-ledger-writer-lock.bench.test.js.map +0 -1
  825. package/dist/sync/area-ledger.test.d.ts +0 -2
  826. package/dist/sync/area-ledger.test.d.ts.map +0 -1
  827. package/dist/sync/area-ledger.test.js +0 -1401
  828. package/dist/sync/area-ledger.test.js.map +0 -1
  829. package/dist/sync/area-resolver.test.d.ts +0 -2
  830. package/dist/sync/area-resolver.test.d.ts.map +0 -1
  831. package/dist/sync/area-resolver.test.js +0 -234
  832. package/dist/sync/area-resolver.test.js.map +0 -1
  833. package/dist/sync/base-version-resolver.test.d.ts +0 -2
  834. package/dist/sync/base-version-resolver.test.d.ts.map +0 -1
  835. package/dist/sync/base-version-resolver.test.js +0 -24
  836. package/dist/sync/base-version-resolver.test.js.map +0 -1
  837. package/dist/sync/candidate-uploader.test.d.ts +0 -2
  838. package/dist/sync/candidate-uploader.test.d.ts.map +0 -1
  839. package/dist/sync/candidate-uploader.test.js +0 -132
  840. package/dist/sync/candidate-uploader.test.js.map +0 -1
  841. package/dist/sync/child-process-sync-worker-env.test.d.ts +0 -2
  842. package/dist/sync/child-process-sync-worker-env.test.d.ts.map +0 -1
  843. package/dist/sync/child-process-sync-worker-env.test.js +0 -38
  844. package/dist/sync/child-process-sync-worker-env.test.js.map +0 -1
  845. package/dist/sync/child-process-sync-worker-errors.test.d.ts +0 -2
  846. package/dist/sync/child-process-sync-worker-errors.test.d.ts.map +0 -1
  847. package/dist/sync/child-process-sync-worker-errors.test.js +0 -121
  848. package/dist/sync/child-process-sync-worker-errors.test.js.map +0 -1
  849. package/dist/sync/child-process-sync-worker.test.d.ts +0 -2
  850. package/dist/sync/child-process-sync-worker.test.d.ts.map +0 -1
  851. package/dist/sync/child-process-sync-worker.test.js +0 -262
  852. package/dist/sync/child-process-sync-worker.test.js.map +0 -1
  853. package/dist/sync/content-hash.test.d.ts +0 -2
  854. package/dist/sync/content-hash.test.d.ts.map +0 -1
  855. package/dist/sync/content-hash.test.js +0 -16
  856. package/dist/sync/content-hash.test.js.map +0 -1
  857. package/dist/sync/delta-client.test.d.ts +0 -2
  858. package/dist/sync/delta-client.test.d.ts.map +0 -1
  859. package/dist/sync/delta-client.test.js +0 -97
  860. package/dist/sync/delta-client.test.js.map +0 -1
  861. package/dist/sync/durable-apply.test.d.ts +0 -2
  862. package/dist/sync/durable-apply.test.d.ts.map +0 -1
  863. package/dist/sync/durable-apply.test.js +0 -180
  864. package/dist/sync/durable-apply.test.js.map +0 -1
  865. package/dist/sync/event-sync.test.d.ts +0 -14
  866. package/dist/sync/event-sync.test.d.ts.map +0 -1
  867. package/dist/sync/event-sync.test.js +0 -1714
  868. package/dist/sync/event-sync.test.js.map +0 -1
  869. package/dist/sync/feature-flags.test.d.ts +0 -24
  870. package/dist/sync/feature-flags.test.d.ts.map +0 -1
  871. package/dist/sync/feature-flags.test.js +0 -594
  872. package/dist/sync/feature-flags.test.js.map +0 -1
  873. package/dist/sync/full-pass-cap-governor.bench.test.d.ts +0 -2
  874. package/dist/sync/full-pass-cap-governor.bench.test.d.ts.map +0 -1
  875. package/dist/sync/full-pass-cap-governor.bench.test.js +0 -179
  876. package/dist/sync/full-pass-cap-governor.bench.test.js.map +0 -1
  877. package/dist/sync/full-pass-caps.test.d.ts +0 -2
  878. package/dist/sync/full-pass-caps.test.d.ts.map +0 -1
  879. package/dist/sync/full-pass-caps.test.js +0 -550
  880. package/dist/sync/full-pass-caps.test.js.map +0 -1
  881. package/dist/sync/idle-full-reconcile.test.d.ts +0 -2
  882. package/dist/sync/idle-full-reconcile.test.d.ts.map +0 -1
  883. package/dist/sync/idle-full-reconcile.test.js +0 -62
  884. package/dist/sync/idle-full-reconcile.test.js.map +0 -1
  885. package/dist/sync/inbound-event-admission.test.d.ts +0 -2
  886. package/dist/sync/inbound-event-admission.test.d.ts.map +0 -1
  887. package/dist/sync/inbound-event-admission.test.js +0 -125
  888. package/dist/sync/inbound-event-admission.test.js.map +0 -1
  889. package/dist/sync/journal-ledger-stream.test.d.ts +0 -12
  890. package/dist/sync/journal-ledger-stream.test.d.ts.map +0 -1
  891. package/dist/sync/journal-ledger-stream.test.js +0 -134
  892. package/dist/sync/journal-ledger-stream.test.js.map +0 -1
  893. package/dist/sync/lease-client.test.d.ts +0 -2
  894. package/dist/sync/lease-client.test.d.ts.map +0 -1
  895. package/dist/sync/lease-client.test.js +0 -119
  896. package/dist/sync/lease-client.test.js.map +0 -1
  897. package/dist/sync/logger.test.d.ts +0 -19
  898. package/dist/sync/logger.test.d.ts.map +0 -1
  899. package/dist/sync/logger.test.js +0 -204
  900. package/dist/sync/logger.test.js.map +0 -1
  901. package/dist/sync/metrics.test.d.ts +0 -19
  902. package/dist/sync/metrics.test.d.ts.map +0 -1
  903. package/dist/sync/metrics.test.js +0 -357
  904. package/dist/sync/metrics.test.js.map +0 -1
  905. package/dist/sync/multipart-uploader.test.d.ts +0 -2
  906. package/dist/sync/multipart-uploader.test.d.ts.map +0 -1
  907. package/dist/sync/multipart-uploader.test.js +0 -135
  908. package/dist/sync/multipart-uploader.test.js.map +0 -1
  909. package/dist/sync/mutation-client.test.d.ts +0 -2
  910. package/dist/sync/mutation-client.test.d.ts.map +0 -1
  911. package/dist/sync/mutation-client.test.js +0 -100
  912. package/dist/sync/mutation-client.test.js.map +0 -1
  913. package/dist/sync/mutation-session.test.d.ts +0 -2
  914. package/dist/sync/mutation-session.test.d.ts.map +0 -1
  915. package/dist/sync/mutation-session.test.js +0 -190
  916. package/dist/sync/mutation-session.test.js.map +0 -1
  917. package/dist/sync/parallel-sync-coordinator.test.d.ts +0 -2
  918. package/dist/sync/parallel-sync-coordinator.test.d.ts.map +0 -1
  919. package/dist/sync/parallel-sync-coordinator.test.js +0 -564
  920. package/dist/sync/parallel-sync-coordinator.test.js.map +0 -1
  921. package/dist/sync/path-leases.test.d.ts +0 -2
  922. package/dist/sync/path-leases.test.d.ts.map +0 -1
  923. package/dist/sync/path-leases.test.js +0 -51
  924. package/dist/sync/path-leases.test.js.map +0 -1
  925. package/dist/sync/per-area-maintenance.test.d.ts +0 -2
  926. package/dist/sync/per-area-maintenance.test.d.ts.map +0 -1
  927. package/dist/sync/per-area-maintenance.test.js +0 -100
  928. package/dist/sync/per-area-maintenance.test.js.map +0 -1
  929. package/dist/sync/push-event.test.d.ts +0 -15
  930. package/dist/sync/push-event.test.d.ts.map +0 -1
  931. package/dist/sync/push-event.test.js +0 -282
  932. package/dist/sync/push-event.test.js.map +0 -1
  933. package/dist/sync/push-receiver.test.d.ts +0 -25
  934. package/dist/sync/push-receiver.test.d.ts.map +0 -1
  935. package/dist/sync/push-receiver.test.js +0 -2851
  936. package/dist/sync/push-receiver.test.js.map +0 -1
  937. package/dist/sync/push-transport.test.d.ts +0 -2
  938. package/dist/sync/push-transport.test.d.ts.map +0 -1
  939. package/dist/sync/push-transport.test.js +0 -70
  940. package/dist/sync/push-transport.test.js.map +0 -1
  941. package/dist/sync/push-walk-matchers.bench.test.d.ts +0 -2
  942. package/dist/sync/push-walk-matchers.bench.test.d.ts.map +0 -1
  943. package/dist/sync/push-walk-matchers.bench.test.js +0 -230
  944. package/dist/sync/push-walk-matchers.bench.test.js.map +0 -1
  945. package/dist/sync/realtime-network-integration.test.d.ts +0 -2
  946. package/dist/sync/realtime-network-integration.test.d.ts.map +0 -1
  947. package/dist/sync/realtime-network-integration.test.js +0 -83
  948. package/dist/sync/realtime-network-integration.test.js.map +0 -1
  949. package/dist/sync/realtime-rollout.test.d.ts +0 -2
  950. package/dist/sync/realtime-rollout.test.d.ts.map +0 -1
  951. package/dist/sync/realtime-rollout.test.js +0 -94
  952. package/dist/sync/realtime-rollout.test.js.map +0 -1
  953. package/dist/sync/realtime-telemetry.test.d.ts +0 -2
  954. package/dist/sync/realtime-telemetry.test.d.ts.map +0 -1
  955. package/dist/sync/realtime-telemetry.test.js +0 -300
  956. package/dist/sync/realtime-telemetry.test.js.map +0 -1
  957. package/dist/sync/receiver-origin-config.test.d.ts +0 -2
  958. package/dist/sync/receiver-origin-config.test.d.ts.map +0 -1
  959. package/dist/sync/receiver-origin-config.test.js +0 -39
  960. package/dist/sync/receiver-origin-config.test.js.map +0 -1
  961. package/dist/sync/reconcile-cursor.test.d.ts +0 -2
  962. package/dist/sync/reconcile-cursor.test.d.ts.map +0 -1
  963. package/dist/sync/reconcile-cursor.test.js +0 -139
  964. package/dist/sync/reconcile-cursor.test.js.map +0 -1
  965. package/dist/sync/remote-file-spool.test.d.ts +0 -2
  966. package/dist/sync/remote-file-spool.test.d.ts.map +0 -1
  967. package/dist/sync/remote-file-spool.test.js +0 -77
  968. package/dist/sync/remote-file-spool.test.js.map +0 -1
  969. package/dist/sync/scope-inventory-client.test.d.ts +0 -2
  970. package/dist/sync/scope-inventory-client.test.d.ts.map +0 -1
  971. package/dist/sync/scope-inventory-client.test.js +0 -103
  972. package/dist/sync/scope-inventory-client.test.js.map +0 -1
  973. package/dist/sync/secret-path-policy.test.d.ts +0 -2
  974. package/dist/sync/secret-path-policy.test.d.ts.map +0 -1
  975. package/dist/sync/secret-path-policy.test.js +0 -183
  976. package/dist/sync/secret-path-policy.test.js.map +0 -1
  977. package/dist/sync/snapshot-client.test.d.ts +0 -2
  978. package/dist/sync/snapshot-client.test.d.ts.map +0 -1
  979. package/dist/sync/snapshot-client.test.js +0 -169
  980. package/dist/sync/snapshot-client.test.js.map +0 -1
  981. package/dist/sync/state-store.test.d.ts +0 -2
  982. package/dist/sync/state-store.test.d.ts.map +0 -1
  983. package/dist/sync/state-store.test.js +0 -1556
  984. package/dist/sync/state-store.test.js.map +0 -1
  985. package/dist/sync/sync-contract.test.d.ts +0 -2
  986. package/dist/sync/sync-contract.test.d.ts.map +0 -1
  987. package/dist/sync/sync-contract.test.js +0 -141
  988. package/dist/sync/sync-contract.test.js.map +0 -1
  989. package/dist/sync/targeted-pull-prefixes.test.d.ts +0 -2
  990. package/dist/sync/targeted-pull-prefixes.test.d.ts.map +0 -1
  991. package/dist/sync/targeted-pull-prefixes.test.js +0 -33
  992. package/dist/sync/targeted-pull-prefixes.test.js.map +0 -1
  993. package/dist/sync/targeted-upsert-exact-list.test.d.ts +0 -2
  994. package/dist/sync/targeted-upsert-exact-list.test.d.ts.map +0 -1
  995. package/dist/sync/targeted-upsert-exact-list.test.js +0 -247
  996. package/dist/sync/targeted-upsert-exact-list.test.js.map +0 -1
  997. package/dist/sync/unchanged-push-events.test.d.ts +0 -2
  998. package/dist/sync/unchanged-push-events.test.d.ts.map +0 -1
  999. package/dist/sync/unchanged-push-events.test.js +0 -76
  1000. package/dist/sync/unchanged-push-events.test.js.map +0 -1
  1001. package/dist/sync/uploader-finalization.test.d.ts +0 -2
  1002. package/dist/sync/uploader-finalization.test.d.ts.map +0 -1
  1003. package/dist/sync/uploader-finalization.test.js +0 -107
  1004. package/dist/sync/uploader-finalization.test.js.map +0 -1
  1005. package/dist/sync-core.test.d.ts +0 -2
  1006. package/dist/sync-core.test.d.ts.map +0 -1
  1007. package/dist/sync-core.test.js +0 -189
  1008. package/dist/sync-core.test.js.map +0 -1
  1009. package/dist/sync-progress.test.d.ts +0 -2
  1010. package/dist/sync-progress.test.d.ts.map +0 -1
  1011. package/dist/sync-progress.test.js +0 -277
  1012. package/dist/sync-progress.test.js.map +0 -1
  1013. package/dist/telemetry-events.test.d.ts +0 -2
  1014. package/dist/telemetry-events.test.d.ts.map +0 -1
  1015. package/dist/telemetry-events.test.js +0 -113
  1016. package/dist/telemetry-events.test.js.map +0 -1
  1017. package/dist/telemetry.test.d.ts +0 -11
  1018. package/dist/telemetry.test.d.ts.map +0 -1
  1019. package/dist/telemetry.test.js +0 -1603
  1020. package/dist/telemetry.test.js.map +0 -1
  1021. package/dist/vault-client.test.d.ts +0 -7
  1022. package/dist/vault-client.test.d.ts.map +0 -1
  1023. package/dist/vault-client.test.js +0 -1334
  1024. package/dist/vault-client.test.js.map +0 -1
  1025. package/dist/watch-coverage.test.d.ts +0 -2
  1026. package/dist/watch-coverage.test.d.ts.map +0 -1
  1027. package/dist/watch-coverage.test.js +0 -56
  1028. package/dist/watch-coverage.test.js.map +0 -1
  1029. package/dist/watch-owner-lease.test.d.ts +0 -2
  1030. package/dist/watch-owner-lease.test.d.ts.map +0 -1
  1031. package/dist/watch-owner-lease.test.js +0 -353
  1032. package/dist/watch-owner-lease.test.js.map +0 -1
  1033. package/dist/watch-parent.test.d.ts +0 -2
  1034. package/dist/watch-parent.test.d.ts.map +0 -1
  1035. package/dist/watch-parent.test.js +0 -131
  1036. package/dist/watch-parent.test.js.map +0 -1
  1037. package/dist/watch-roots.test.d.ts +0 -18
  1038. package/dist/watch-roots.test.d.ts.map +0 -1
  1039. package/dist/watch-roots.test.js +0 -395
  1040. package/dist/watch-roots.test.js.map +0 -1
  1041. package/dist/watcher-continuity-hot-path.test.d.ts +0 -2
  1042. package/dist/watcher-continuity-hot-path.test.d.ts.map +0 -1
  1043. package/dist/watcher-continuity-hot-path.test.js +0 -40
  1044. package/dist/watcher-continuity-hot-path.test.js.map +0 -1
  1045. package/dist/watcher-event-gate.test.d.ts +0 -16
  1046. package/dist/watcher-event-gate.test.d.ts.map +0 -1
  1047. package/dist/watcher-event-gate.test.js +0 -191
  1048. package/dist/watcher-event-gate.test.js.map +0 -1
  1049. package/dist/watcher-replan-sweep.test.d.ts +0 -2
  1050. package/dist/watcher-replan-sweep.test.d.ts.map +0 -1
  1051. package/dist/watcher-replan-sweep.test.js +0 -245
  1052. package/dist/watcher-replan-sweep.test.js.map +0 -1
  1053. package/dist/watcher-stdout.test.d.ts +0 -2
  1054. package/dist/watcher-stdout.test.d.ts.map +0 -1
  1055. package/dist/watcher-stdout.test.js +0 -86
  1056. package/dist/watcher-stdout.test.js.map +0 -1
  1057. package/dist/watcher.test.d.ts +0 -2
  1058. package/dist/watcher.test.d.ts.map +0 -1
  1059. package/dist/watcher.test.js +0 -4301
  1060. package/dist/watcher.test.js.map +0 -1
  1061. package/dist/watcher.warmup-cancel.test.d.ts +0 -2
  1062. package/dist/watcher.warmup-cancel.test.d.ts.map +0 -1
  1063. package/dist/watcher.warmup-cancel.test.js +0 -59
  1064. package/dist/watcher.warmup-cancel.test.js.map +0 -1
  1065. package/dist/watcher.warmup-responsive.test.d.ts +0 -2
  1066. package/dist/watcher.warmup-responsive.test.d.ts.map +0 -1
  1067. package/dist/watcher.warmup-responsive.test.js +0 -62
  1068. package/dist/watcher.warmup-responsive.test.js.map +0 -1
@@ -1,1966 +0,0 @@
1
- import { describe, expect, it, vi } from "vitest";
2
- import { HeapCensus, RunnerHeapTelemetry, sampleRunnerHeap, heapSampleCloudProperties, heapPressureCloudProperties, heapRecycleCloudProperties, heapPressureStderrLine, heapRecycleStderrLine, performHeapHardExit, startRunnerHeapSampling, nodeMajorGcObserver, isFreshGcReading, MAX_FRESH_GC_READING_MS, resolveHeapPressureFraction, resolveHeapSampleIntervalMs, resolveHeapRecycleEnabled, resolveHeapRecycleLiveFraction, resolveHeapRecycleEmergencyFraction, resolveHeapRecycleSustainWindowMs, resolveHeapRecycleMinUptimeMs, resolveHeapCheckpointMs, resolveHeapPinnedFraction, resolveHeapPinnedSustainMs, resolveHeapHardExitFraction, resolveHeapRecycleLatchHardExitMs, resolveHeapFootprintRecycleEnabled, resolveHeapFootprintRecycleBytes, resolveHeapFootprintHardExitBytes, resolveDeclaredHeapCeilingBytes, DEFAULT_HEAP_RECYCLE_LIVE_FRACTION, DEFAULT_HEAP_RECYCLE_EMERGENCY_FRACTION, DEFAULT_HEAP_RECYCLE_SUSTAIN_WINDOW_MS, DEFAULT_HEAP_RECYCLE_MIN_UPTIME_MS, DEFAULT_HEAP_CHECKPOINT_MS, DEFAULT_HEAP_PINNED_FRACTION, DEFAULT_HEAP_PINNED_SUSTAIN_MS, DEFAULT_HEAP_HARD_EXIT_FRACTION, DEFAULT_HEAP_RECYCLE_LATCH_HARD_EXIT_MS, DEFAULT_HEAP_FOOTPRINT_RECYCLE_BYTES, DEFAULT_HEAP_FOOTPRINT_HARD_EXIT_BYTES, } from "./sync-runner-heap-telemetry.js";
3
- import { emitCloudTelemetry } from "../telemetry-events.js";
4
- function mutableReaders() {
5
- const state = {
6
- used: 0,
7
- total: 0,
8
- limit: 1000,
9
- externalV8: 0,
10
- rss: 0,
11
- external: 0,
12
- arrayBuffers: 0,
13
- now: 0,
14
- };
15
- const readers = {
16
- getHeapStatistics: () => ({
17
- used_heap_size: state.used,
18
- total_heap_size: state.total,
19
- heap_size_limit: state.limit,
20
- external_memory: state.externalV8,
21
- }),
22
- memoryUsage: () => ({
23
- rss: state.rss,
24
- heapTotal: state.total,
25
- heapUsed: state.used,
26
- external: state.external,
27
- arrayBuffers: state.arrayBuffers,
28
- }),
29
- monotonicNowMs: () => state.now,
30
- };
31
- return { state, readers };
32
- }
33
- function fakeScheduler() {
34
- let handler = null;
35
- let cleared = false;
36
- let unrefCalls = 0;
37
- const scheduler = {
38
- setInterval: (fn) => {
39
- handler = fn;
40
- return {
41
- unref: () => {
42
- unrefCalls += 1;
43
- },
44
- };
45
- },
46
- clearInterval: () => {
47
- cleared = true;
48
- handler = null;
49
- },
50
- };
51
- return {
52
- scheduler,
53
- tick: () => handler?.(),
54
- isCleared: () => cleared,
55
- unrefCalls: () => unrefCalls,
56
- };
57
- }
58
- /** A manual GC observer whose registered callback the test fires by hand. */
59
- function fakeGcObserver() {
60
- let cb = null;
61
- let started = false;
62
- let stopped = false;
63
- const observer = {
64
- start: (onMajorGc) => {
65
- cb = onMajorGc;
66
- started = true;
67
- },
68
- stop: () => {
69
- stopped = true;
70
- cb = null;
71
- },
72
- };
73
- return {
74
- observer,
75
- fire: () => cb?.(),
76
- started: () => started,
77
- stopped: () => stopped,
78
- };
79
- }
80
- describe("sampleRunnerHeap", () => {
81
- it("maps injected v8/process readings to a flat numeric record", () => {
82
- const census = new HeapCensus();
83
- census.register("mapA", () => 3);
84
- census.register("setB", () => 5);
85
- const { state, readers } = mutableReaders();
86
- Object.assign(state, {
87
- used: 111,
88
- total: 222,
89
- limit: 2048,
90
- externalV8: 33,
91
- rss: 444,
92
- external: 55,
93
- arrayBuffers: 66,
94
- now: 5000,
95
- });
96
- const sample = sampleRunnerHeap({ readers, census, sessionStartedAtMs: 1000 });
97
- expect(sample).toMatchObject({
98
- usedHeapBytes: 111,
99
- totalHeapBytes: 222,
100
- heapLimitBytes: 2048,
101
- externalV8Bytes: 33,
102
- rssBytes: 444,
103
- externalBytes: 55,
104
- arrayBuffersBytes: 66,
105
- uptimeMs: 4000,
106
- censusTotal: 8,
107
- });
108
- expect(sample.census).toEqual([
109
- { site: "mapA", count: 3 },
110
- { site: "setB", count: 5 },
111
- ]);
112
- });
113
- it("emits only numeric properties that survive the LOCAL telemetry sanitizer", async () => {
114
- // NOTE: this exercises hq-cloud's own emit-side sanitizer, which keys on the
115
- // VALUE type — a numeric value survives regardless of key. It is a DIFFERENT
116
- // and more permissive layer than hq-pro's ingest contract (the vault's
117
- // redactProperties, which drops any key not ending in _count/_bytes/_ms or
118
- // containing a denied substring). The regression this module fixes is that
119
- // the old `census_<token>` spelling passed HERE but was silently dropped at
120
- // ingest; the deny-safe `_count` spelling — pinned by the ingest-key-contract
121
- // test below — is what makes the attribution actually reach the store.
122
- const census = new HeapCensus();
123
- census.register("publishedDigestGenerations", () => 12345);
124
- census.register("knownKinds", () => 10);
125
- const { state, readers } = mutableReaders();
126
- Object.assign(state, {
127
- used: 1,
128
- total: 2,
129
- limit: 3,
130
- externalV8: 4,
131
- rss: 5,
132
- external: 6,
133
- arrayBuffers: 7,
134
- now: 10,
135
- });
136
- const props = heapSampleCloudProperties(sampleRunnerHeap({ readers, census, sessionStartedAtMs: 0 }));
137
- for (const value of Object.values(props)) {
138
- expect(typeof value).toBe("number");
139
- }
140
- const captured = [];
141
- const client = {
142
- postTelemetryEvents: async (batch) => {
143
- for (const event of batch.events)
144
- captured.push(event);
145
- return { accepted: batch.events.length };
146
- },
147
- };
148
- await emitCloudTelemetry(client, {
149
- eventName: "sync_runner_heap_sample",
150
- source: "sync-runner-heap",
151
- properties: props,
152
- });
153
- const survived = captured[0]?.properties ?? {};
154
- expect(survived.census_publishedDigestGenerations_count).toBe(12345);
155
- expect(survived.heap_used_bytes).toBe(1);
156
- // No property was dropped by the sanitizer.
157
- expect(Object.keys(survived).length).toBe(Object.keys(props).length);
158
- });
159
- });
160
- describe("HeapCensus", () => {
161
- it("rejects non-fixed census tokens and overwrites duplicates so the registry stays bounded", () => {
162
- const census = new HeapCensus();
163
- expect(() => census.register("has space", () => 1)).toThrow();
164
- expect(() => census.register("../path", () => 1)).toThrow();
165
- census.register("dupe", () => 1);
166
- census.register("dupe", () => 2);
167
- expect(census.siteCount).toBe(1);
168
- expect(census.snapshot()).toEqual([{ site: "dupe", count: 2 }]);
169
- });
170
- it("reports 0 for a faulty reader rather than throwing", () => {
171
- const census = new HeapCensus();
172
- census.register("ok", () => 4);
173
- census.register("boom", () => {
174
- throw new Error("reader exploded");
175
- });
176
- expect(census.snapshot()).toEqual([
177
- { site: "ok", count: 4 },
178
- { site: "boom", count: 0 },
179
- ]);
180
- });
181
- });
182
- describe("RunnerHeapTelemetry", () => {
183
- it("computes census growth against the session's first sample", () => {
184
- let a = 1;
185
- const b = 100;
186
- const census = new HeapCensus();
187
- census.register("aMap", () => a);
188
- census.register("bMap", () => b);
189
- const { state, readers } = mutableReaders();
190
- state.limit = 1000;
191
- state.used = 10;
192
- const controller = new RunnerHeapTelemetry({
193
- readers,
194
- census,
195
- sessionStartedAtMs: 0,
196
- pressureThresholdFraction: 0.75,
197
- });
198
- controller.sample(); // baseline a=1, b=100
199
- a = 5000;
200
- state.used = 800; // 0.8 of limit -> crosses 0.75
201
- const { pressure } = controller.sample();
202
- expect(pressure?.topSites[0]).toMatchObject({ site: "aMap", growth: 4999 });
203
- });
204
- it("keeps only baseline and latest across many samples (no unbounded history)", () => {
205
- let n = 0;
206
- const census = new HeapCensus();
207
- census.register("n", () => n);
208
- const { state, readers } = mutableReaders();
209
- state.limit = 1000;
210
- state.used = 1;
211
- const controller = new RunnerHeapTelemetry({
212
- readers,
213
- census,
214
- sessionStartedAtMs: 0,
215
- pressureThresholdFraction: 0.99,
216
- });
217
- for (n = 0; n < 100; n += 1) {
218
- state.now = n;
219
- controller.sample();
220
- }
221
- expect(controller.baselineSample?.census).toEqual([{ site: "n", count: 0 }]);
222
- expect(controller.latestSample?.census).toEqual([{ site: "n", count: 99 }]);
223
- });
224
- it("emits the pressure record exactly once per rising crossing, calibrated to the injected heap limit", () => {
225
- const census = new HeapCensus();
226
- census.register("x", () => 1);
227
- const { state, readers } = mutableReaders();
228
- state.limit = 2048 * 1024 * 1024; // desktop-injected 2048 MB ceiling
229
- const controller = new RunnerHeapTelemetry({
230
- readers,
231
- census,
232
- sessionStartedAtMs: 0,
233
- pressureThresholdFraction: 0.75,
234
- });
235
- state.used = state.limit * 0.5;
236
- expect(controller.sample().pressure).toBeNull(); // below threshold
237
- state.used = Math.round(state.limit * 0.76);
238
- const crossing = controller.sample().pressure; // rising crossing -> one record
239
- expect(crossing).not.toBeNull();
240
- expect(crossing?.thresholdFraction).toBe(0.75);
241
- expect(crossing?.usedFraction).toBeCloseTo(0.76, 2);
242
- state.used = Math.round(state.limit * 0.8);
243
- expect(controller.sample().pressure).toBeNull(); // still above -> no repeat
244
- state.used = Math.round(state.limit * 0.5);
245
- expect(controller.sample().pressure).toBeNull(); // dropped below -> re-arm
246
- state.used = Math.round(state.limit * 0.9);
247
- expect(controller.sample().pressure).not.toBeNull(); // second crossing -> record
248
- });
249
- });
250
- describe("startRunnerHeapSampling", () => {
251
- it("unrefs the timer, clears it on stop, and never lets a fault reach the caller", () => {
252
- const census = new HeapCensus();
253
- // A faulty reader must be swallowed to 0, never thrown out of the sampler.
254
- census.register("x", () => {
255
- throw new Error("reader boom");
256
- });
257
- const { state, readers } = mutableReaders();
258
- state.limit = 1000;
259
- state.used = 900; // 0.9 -> above the 0.75 threshold -> pressure fires
260
- const fake = fakeScheduler();
261
- const onSample = vi.fn(() => {
262
- throw new Error("sample emit boom");
263
- });
264
- const onPressure = vi.fn(() => {
265
- throw new Error("pressure emit boom");
266
- });
267
- const handle = startRunnerHeapSampling({
268
- readers,
269
- census,
270
- sessionStartedAtMs: 0,
271
- pressureThresholdFraction: 0.75,
272
- intervalMs: 60_000,
273
- scheduler: fake.scheduler,
274
- onSample,
275
- onPressure,
276
- log: () => { },
277
- });
278
- expect(fake.unrefCalls()).toBe(1);
279
- // A tick with a throwing reader AND throwing emit callbacks must not throw.
280
- expect(() => fake.tick()).not.toThrow();
281
- expect(onSample).toHaveBeenCalledTimes(1);
282
- expect(onPressure).toHaveBeenCalledTimes(1);
283
- handle.stop();
284
- expect(fake.isCleared()).toBe(true);
285
- // Ticks after stop are inert.
286
- fake.tick();
287
- expect(onSample).toHaveBeenCalledTimes(1);
288
- });
289
- it("drives repeated samples so at least two heap records reach the sink", () => {
290
- const census = new HeapCensus();
291
- census.register("x", () => 1);
292
- const { state, readers } = mutableReaders();
293
- state.limit = 1000;
294
- state.used = 1; // never crosses -> only heap samples, no pressure
295
- const fake = fakeScheduler();
296
- const samples = [];
297
- startRunnerHeapSampling({
298
- readers,
299
- census,
300
- sessionStartedAtMs: 0,
301
- pressureThresholdFraction: 0.75,
302
- intervalMs: 1,
303
- scheduler: fake.scheduler,
304
- onSample: (sample) => samples.push(sample.usedHeapBytes),
305
- onPressure: () => {
306
- throw new Error("no crossing expected");
307
- },
308
- });
309
- fake.tick();
310
- fake.tick();
311
- expect(samples).toHaveLength(2);
312
- });
313
- it("primes the growth baseline at start, so a first crossing already above the threshold still reports real growth", () => {
314
- let count = 100;
315
- const census = new HeapCensus();
316
- census.register("x", () => count);
317
- const { state, readers } = mutableReaders();
318
- state.limit = 1000;
319
- state.used = 900; // already above the 0.75 threshold at the very first tick
320
- const fake = fakeScheduler();
321
- const pressures = [];
322
- startRunnerHeapSampling({
323
- readers,
324
- census,
325
- sessionStartedAtMs: 0,
326
- pressureThresholdFraction: 0.75,
327
- intervalMs: 1000,
328
- scheduler: fake.scheduler,
329
- onSample: () => { },
330
- onPressure: (record) => pressures.push(record),
331
- });
332
- // Baseline was primed at count=100 before the first interval. Grow, then the
333
- // first scheduled sample crosses the threshold.
334
- count = 5000;
335
- fake.tick();
336
- expect(pressures).toHaveLength(1);
337
- // Without priming the baseline would equal the crossing sample and growth
338
- // would be reported as 0, losing the attribution.
339
- expect(pressures[0].topSites[0]).toMatchObject({ site: "x", growth: 4900 });
340
- });
341
- });
342
- describe("resolveHeapPressureFraction", () => {
343
- it("parses a valid fraction and falls back to the default on garbage or out-of-range input", () => {
344
- expect(resolveHeapPressureFraction("0.6")).toBe(0.6);
345
- expect(resolveHeapPressureFraction("1")).toBe(1);
346
- expect(resolveHeapPressureFraction("")).toBe(0.75);
347
- expect(resolveHeapPressureFraction("2")).toBe(0.75);
348
- expect(resolveHeapPressureFraction("-1")).toBe(0.75);
349
- expect(resolveHeapPressureFraction("0.5x")).toBe(0.75); // trailing junk rejected
350
- expect(resolveHeapPressureFraction(undefined)).toBe(0.75);
351
- });
352
- });
353
- describe("resolveHeapSampleIntervalMs", () => {
354
- it("parses whole milliseconds and rejects a malformed value like '60s' rather than accepting its prefix", () => {
355
- expect(resolveHeapSampleIntervalMs("60000")).toBe(60_000);
356
- expect(resolveHeapSampleIntervalMs("500")).toBe(500);
357
- // The natural-but-invalid "60s" must NOT become a 60 ms interval.
358
- expect(resolveHeapSampleIntervalMs("60s")).toBe(60_000);
359
- expect(resolveHeapSampleIntervalMs("1_000")).toBe(60_000);
360
- expect(resolveHeapSampleIntervalMs("")).toBe(60_000);
361
- expect(resolveHeapSampleIntervalMs("0")).toBe(60_000);
362
- expect(resolveHeapSampleIntervalMs(undefined)).toBe(60_000);
363
- });
364
- });
365
- describe("heapPressureStderrLine", () => {
366
- it("renders a compact numeric-only pressure line with fixed-token sites", () => {
367
- const line = heapPressureStderrLine({
368
- usedHeapBytes: 100,
369
- heapLimitBytes: 200,
370
- effectiveLimitBytes: 200,
371
- declaredCeilingBytes: 0,
372
- usedFraction: 0.5,
373
- thresholdFraction: 0.75,
374
- rssBytes: 300,
375
- externalBytes: 40,
376
- uptimeMs: 1000,
377
- topSites: [{ site: "knownKinds", count: 5, growth: 3 }],
378
- });
379
- expect(line).toContain("used=100");
380
- expect(line).toContain("limit=200");
381
- expect(line).toContain("uptime_ms=1000");
382
- expect(line).toContain("top=knownKinds:3");
383
- });
384
- });
385
- // --- Self-recycling governor (GC-anchored post-GC live floor) -----------------
386
- const MB = 1024 * 1024;
387
- // Comfortably past the 35-minute uptime floor, so the floor never gates a test
388
- // that is exercising a different property.
389
- const PAST_FLOOR_MS = DEFAULT_HEAP_RECYCLE_MIN_UPTIME_MS + 5 * 60_000;
390
- function governor(overrides = {}) {
391
- const census = overrides.census ?? new HeapCensus();
392
- if (!overrides.census)
393
- census.register("knownKinds", () => 1);
394
- const { state, readers } = mutableReaders();
395
- state.limit = overrides.limitBytes ?? 2048 * MB;
396
- const controller = new RunnerHeapTelemetry({
397
- readers,
398
- census,
399
- sessionStartedAtMs: 0,
400
- pressureThresholdFraction: 0.75,
401
- recycleLiveFraction: overrides.liveFraction ?? 0.6,
402
- recycleSustainWindowMs: overrides.windowMs ?? 120_000,
403
- recycleEmergencyFraction: overrides.emergencyFraction ?? 0.9,
404
- recycleMinUptimeMs: overrides.minUptimeMs ?? DEFAULT_HEAP_RECYCLE_MIN_UPTIME_MS,
405
- recycleEnabled: overrides.recycleEnabled ?? true,
406
- ...(overrides.declaredCeilingBytes !== undefined
407
- ? { declaredCeilingBytes: overrides.declaredCeilingBytes }
408
- : {}),
409
- ...(overrides.pinnedFraction !== undefined
410
- ? { recyclePinnedFraction: overrides.pinnedFraction }
411
- : {}),
412
- ...(overrides.pinnedSustainWindowMs !== undefined
413
- ? { recyclePinnedSustainWindowMs: overrides.pinnedSustainWindowMs }
414
- : {}),
415
- ...(overrides.hardExitFraction !== undefined
416
- ? { hardExitFraction: overrides.hardExitFraction }
417
- : {}),
418
- ...(overrides.latchHardExitMs !== undefined
419
- ? { latchHardExitMs: overrides.latchHardExitMs }
420
- : {}),
421
- ...(overrides.latchHardExitObservations !== undefined
422
- ? { latchHardExitObservations: overrides.latchHardExitObservations }
423
- : {}),
424
- ...(overrides.footprintRecycleEnabled !== undefined
425
- ? { footprintRecycleEnabled: overrides.footprintRecycleEnabled }
426
- : {}),
427
- ...(overrides.footprintRecycleBytes !== undefined
428
- ? { footprintRecycleBytes: overrides.footprintRecycleBytes }
429
- : {}),
430
- ...(overrides.footprintHardExitBytes !== undefined
431
- ? { footprintHardExitBytes: overrides.footprintHardExitBytes }
432
- : {}),
433
- });
434
- const setAt = (fraction, nowMs) => {
435
- state.used = Math.round(state.limit * fraction);
436
- state.now = nowMs;
437
- };
438
- // Footprint driver: a HIGH resident rss (absolute bytes) with a QUIET heap
439
- // (usedFraction default 0.30, below every heap floor), so only the footprint
440
- // tier can produce a verdict.
441
- const setFootprint = (rssBytes, nowMs, usedFraction = 0.3) => {
442
- state.rss = rssBytes;
443
- state.used = Math.round(state.limit * usedFraction);
444
- state.now = nowMs;
445
- };
446
- // The cooperative recycle channel (backward-compatible with the shipped tests).
447
- const observeAt = (fraction, nowMs) => {
448
- setAt(fraction, nowMs);
449
- return controller.observeMajorGc().recycle;
450
- };
451
- const sampleAt = (fraction, nowMs) => {
452
- setAt(fraction, nowMs);
453
- return controller.sample();
454
- };
455
- const evaluateAt = (fraction, nowMs) => {
456
- setAt(fraction, nowMs);
457
- return controller.evaluate().recycle;
458
- };
459
- // The full verdict channel (both cooperative recycle AND hard exit).
460
- const observeFullAt = (fraction, nowMs) => {
461
- setAt(fraction, nowMs);
462
- return controller.observeMajorGc();
463
- };
464
- const evaluateFullAt = (fraction, nowMs) => {
465
- setAt(fraction, nowMs);
466
- return controller.evaluate();
467
- };
468
- return {
469
- state,
470
- readers,
471
- census,
472
- controller,
473
- setAt,
474
- setFootprint,
475
- observeAt,
476
- sampleAt,
477
- evaluateAt,
478
- observeFullAt,
479
- evaluateFullAt,
480
- };
481
- }
482
- describe("RunnerHeapTelemetry — recycle governor (primary post-GC live path)", () => {
483
- it("recycles on a sustained post-GC live floor across the window, past the uptime floor", () => {
484
- const g = governor();
485
- // First qualifying post-GC observation at/above the live floor: anchors only.
486
- expect(g.observeAt(0.62, PAST_FLOOR_MS)).toBeNull();
487
- // Too soon (less than the 120 s window since the anchor): still no verdict.
488
- expect(g.observeAt(0.65, PAST_FLOOR_MS + 119_000)).toBeNull();
489
- // A window later, still at/above the floor: recycle, trigger "live".
490
- const recycle = g.observeAt(0.66, PAST_FLOOR_MS + 121_000);
491
- expect(recycle).not.toBeNull();
492
- expect(recycle?.trigger).toBe("live");
493
- expect(recycle?.liveFraction).toBeCloseTo(0.66, 2);
494
- expect(recycle?.observedSustainMs).toBe(121_000);
495
- expect(recycle?.recycleLiveFraction).toBe(0.6);
496
- });
497
- it("is immune to an instantaneous sawtooth: neither the sample path nor a below-floor live reading ever recycles", () => {
498
- // The exact defect: instantaneous used_heap_size oscillates high (0.60..0.89,
499
- // never at the 0.90 emergency line) while the POST-GC live floor stays low
500
- // (0.30). The old rule watched the instantaneous series and would have tripped;
501
- // the GC-anchored rule watches only the post-GC floor and never does.
502
- const g = governor();
503
- const inst = [0.62, 0.30, 0.88, 0.35, 0.89, 0.28, 0.87, 0.40];
504
- let t = PAST_FLOOR_MS;
505
- for (const f of inst) {
506
- // The interval sampler sees the instantaneous sawtooth — emergency only,
507
- // and 0.89 < 0.90, so it never fires.
508
- expect(g.sampleAt(f, t).recycle).toBeNull();
509
- // The post-GC live floor is flat at 0.30, well below the 0.60 floor.
510
- expect(g.observeAt(0.3, t)).toBeNull();
511
- t += 60_000;
512
- }
513
- });
514
- it("requires the window between the TWO qualifying observations, and resets the anchor on a dip", () => {
515
- const g = governor();
516
- // Two qualifying observations less than a window apart never recycle.
517
- expect(g.observeAt(0.7, PAST_FLOOR_MS)).toBeNull();
518
- expect(g.observeAt(0.7, PAST_FLOOR_MS + 60_000)).toBeNull(); // 60 s < 120 s
519
- // A dip below the floor resets the anchor: the clock since the FIRST
520
- // observation no longer counts.
521
- expect(g.observeAt(0.4, PAST_FLOOR_MS + 90_000)).toBeNull(); // dip -> anchor cleared
522
- expect(g.observeAt(0.7, PAST_FLOOR_MS + 100_000)).toBeNull(); // re-anchor here
523
- expect(g.observeAt(0.7, PAST_FLOOR_MS + 180_000)).toBeNull(); // only 80 s since re-anchor
524
- const recycle = g.observeAt(0.7, PAST_FLOOR_MS + 221_000); // 121 s since re-anchor
525
- expect(recycle).not.toBeNull();
526
- // The sustain span is measured from the RE-ANCHOR, not the first observation.
527
- expect(recycle?.observedSustainMs).toBe(121_000);
528
- });
529
- it("never recycles (live path) before the uptime floor, however high the live floor climbs", () => {
530
- const g = governor();
531
- // Live floor pinned at 0.80 for many observations, but every one is below the
532
- // 35-minute floor: no verdict, so the desktop's crash streak is never touched.
533
- let t = 60_000;
534
- for (let i = 0; i < 40; i += 1) {
535
- expect(g.observeAt(0.8, t)).toBeNull();
536
- t += 30_000; // stays under DEFAULT_HEAP_RECYCLE_MIN_UPTIME_MS (35 min)
537
- }
538
- // Cross the floor with the window already satisfied -> recycle.
539
- const recycle = g.observeAt(0.8, DEFAULT_HEAP_RECYCLE_MIN_UPTIME_MS + 1);
540
- expect(recycle).not.toBeNull();
541
- expect(recycle?.trigger).toBe("live");
542
- });
543
- it("keeps the uptime floor strictly above hq-desktop-app's 30-minute HEALTHY_RUN_WINDOW", () => {
544
- // A recycle must OUTLIVE the desktop's 30-minute window so should_reset_after_recovery
545
- // clears the crash streak instead of pacing respawn backoff. The literal is
546
- // quoted so a future change that would drop the floor to/under it fails here.
547
- const DESKTOP_HEALTHY_RUN_WINDOW_MS = 1_800_000;
548
- expect(DEFAULT_HEAP_RECYCLE_MIN_UPTIME_MS).toBe(2_100_000); // 35 min
549
- expect(DEFAULT_HEAP_RECYCLE_MIN_UPTIME_MS).toBeGreaterThan(DESKTOP_HEALTHY_RUN_WINDOW_MS);
550
- });
551
- it("scales the live floor with the reported heap limit, so a larger ceiling never recycles prematurely", () => {
552
- // 1700 MB is 0.83 of a 2048 MB ceiling (recycles) but only 0.415 of a 4096 MB
553
- // ceiling (below the 0.60 live floor -> never), because the floor is a
554
- // fraction of the injected heap_size_limit, not an absolute figure.
555
- const small = governor({ limitBytes: 2048 * MB });
556
- small.state.used = 1700 * MB;
557
- small.state.now = PAST_FLOOR_MS;
558
- expect(small.controller.observeMajorGc().recycle).toBeNull(); // anchor
559
- small.state.now = PAST_FLOOR_MS + 121_000;
560
- expect(small.controller.observeMajorGc().recycle).not.toBeNull();
561
- const large = governor({ limitBytes: 4096 * MB });
562
- let t = PAST_FLOOR_MS;
563
- for (let i = 0; i < 10; i += 1) {
564
- large.state.used = 1700 * MB; // 0.415 of 4096 MB
565
- large.state.now = t;
566
- expect(large.controller.observeMajorGc().recycle).toBeNull();
567
- t += 121_000;
568
- }
569
- });
570
- it("maintains the anchor on every major GC, so a close below-floor recovery resets the sustain run", () => {
571
- // The anchor is updated on EVERY observed major GC — there is no throttle
572
- // that could skip a below-floor recovery and leave a stale anchor faking a
573
- // continuous run (the reviewed defect).
574
- const g = governor();
575
- expect(g.observeAt(0.7, PAST_FLOOR_MS)).toBeNull(); // anchor
576
- expect(g.observeAt(0.4, PAST_FLOOR_MS + 1_000)).toBeNull(); // 1 s later, below floor -> reset
577
- expect(g.observeAt(0.7, PAST_FLOOR_MS + 2_000)).toBeNull(); // re-anchor here
578
- // 121 s past the FIRST anchor but only 119 s past the RE-anchor: no recycle.
579
- expect(g.observeAt(0.7, PAST_FLOOR_MS + 121_000)).toBeNull();
580
- // A window past the re-anchor -> recycle, sustain measured from the re-anchor.
581
- const recycle = g.observeAt(0.7, PAST_FLOOR_MS + 123_000);
582
- expect(recycle).not.toBeNull();
583
- expect(recycle?.observedSustainMs).toBe(121_000);
584
- });
585
- it("attaches census growth and rss/external/arrayBuffers deltas to the recycle record", () => {
586
- let entries = 100;
587
- const census = new HeapCensus();
588
- census.register("watcherJournalStores", () => entries);
589
- const g = governor({ census });
590
- // Prime the growth baseline at session start (entries=100, rss=0), exactly as
591
- // startRunnerHeapSampling does before the first interval.
592
- g.controller.primeBaseline();
593
- expect(g.observeAt(0.7, PAST_FLOOR_MS)).toBeNull(); // anchor
594
- entries = 900;
595
- g.state.rss = 1_500 * MB;
596
- g.state.external = 40 * MB;
597
- g.state.arrayBuffers = 12 * MB;
598
- const recycle = g.observeAt(0.7, PAST_FLOOR_MS + 121_000);
599
- expect(recycle).not.toBeNull();
600
- expect(recycle?.topSites[0]).toMatchObject({ site: "watcherJournalStores", growth: 800 });
601
- expect(recycle?.rssGrowthBytes).toBe(1_500 * MB);
602
- expect(recycle?.externalGrowthBytes).toBe(40 * MB);
603
- expect(recycle?.arrayBuffersGrowthBytes).toBe(12 * MB);
604
- expect(recycle?.censusTotal).toBe(900);
605
- });
606
- });
607
- describe("RunnerHeapTelemetry — emergency backstop", () => {
608
- it("recycles on a single instantaneous sample at/above the emergency fraction, even below the uptime floor", () => {
609
- const g = governor();
610
- // Well below the uptime floor, but a single instantaneous sample above the
611
- // 0.90 emergency line: at that reading V8 is minutes from aborting, recycle now.
612
- const { recycle } = g.sampleAt(0.92, 30_000);
613
- expect(recycle).not.toBeNull();
614
- expect(recycle?.trigger).toBe("emergency");
615
- expect(recycle?.observedSustainMs).toBe(0);
616
- });
617
- it("does not fire the emergency backstop below the emergency fraction", () => {
618
- const g = governor();
619
- // 0.89 instantaneous, sustained across many samples below the floor: the
620
- // emergency arm never fires (and the live path is off — no GC observations).
621
- let t = 30_000;
622
- for (let i = 0; i < 20; i += 1) {
623
- expect(g.sampleAt(0.89, t).recycle).toBeNull();
624
- t += 60_000;
625
- }
626
- });
627
- it("fires the emergency path even when a post-GC observation is already abort-adjacent (bypassing the window)", () => {
628
- const g = governor();
629
- // A post-GC live reading already at 0.95 recycles immediately, without the
630
- // sustain window and without a prior anchor.
631
- const recycle = g.observeAt(0.95, 20_000);
632
- expect(recycle).not.toBeNull();
633
- expect(recycle?.trigger).toBe("emergency");
634
- });
635
- it("evaluate() is a loop-top backstop that runs the emergency check off the timer path", () => {
636
- const g = governor();
637
- // The interval sampler never ticked, but a loop-top evaluate() catches an
638
- // abort-adjacent instantaneous reading — the starved-timer safety net.
639
- expect(g.evaluateAt(0.6, 30_000)).toBeNull(); // below emergency, no window seen
640
- const recycle = g.evaluateAt(0.92, 60_000);
641
- expect(recycle).not.toBeNull();
642
- expect(recycle?.trigger).toBe("emergency");
643
- });
644
- });
645
- describe("RunnerHeapTelemetry — recycle governor invariants", () => {
646
- it("emits at most one recycle verdict per session, across every path", () => {
647
- const g = governor();
648
- expect(g.observeAt(0.7, PAST_FLOOR_MS)).toBeNull();
649
- const first = g.observeAt(0.7, PAST_FLOOR_MS + 121_000);
650
- expect(first).not.toBeNull();
651
- // No second verdict from any path.
652
- expect(g.observeAt(0.95, PAST_FLOOR_MS + 200_000)).toBeNull();
653
- expect(g.sampleAt(0.99, PAST_FLOOR_MS + 260_000).recycle).toBeNull();
654
- expect(g.evaluateAt(0.99, PAST_FLOOR_MS + 320_000)).toBeNull();
655
- });
656
- it("the kill switch disables every recycle path; pressure still behaves as base", () => {
657
- const g = governor({ recycleEnabled: false });
658
- let pressures = 0;
659
- let recycles = 0;
660
- let t = PAST_FLOOR_MS;
661
- for (let i = 0; i < 20; i += 1) {
662
- const { pressure, recycle } = g.sampleAt(0.99, t); // far above any fraction
663
- if (pressure)
664
- pressures += 1;
665
- if (recycle)
666
- recycles += 1;
667
- if (g.observeAt(0.99, t))
668
- recycles += 1;
669
- if (g.evaluateAt(0.99, t))
670
- recycles += 1;
671
- t += 60_000;
672
- }
673
- expect(recycles).toBe(0); // governor off — never recycles on ANY path
674
- expect(pressures).toBe(1); // pressure record still fires once per crossing
675
- });
676
- it("a recycle record and stderr line carry only fixed tokens and integers — never a runner byte", () => {
677
- const SECRET_PATH = "/Users/hassaan/hq/companies/acme-corp/vault/report.md";
678
- const SLUG = "acme-corp";
679
- const FILENAME = "report.md";
680
- const backing = new Map();
681
- backing.set(SECRET_PATH, 1);
682
- backing.set(`companies/${SLUG}/notes`, 2);
683
- backing.set(FILENAME, 3);
684
- const census = new HeapCensus();
685
- census.register("watcherJournalStores", () => backing.size);
686
- census.register("publishedDigestGenerations", () => backing.size);
687
- const g = governor({ census });
688
- const recycle = g.sampleAt(0.95, PAST_FLOOR_MS).recycle; // emergency path
689
- expect(recycle).not.toBeNull();
690
- const line = heapRecycleStderrLine(recycle);
691
- const json = JSON.stringify(recycle);
692
- for (const secret of [SECRET_PATH, SLUG, FILENAME, "/Users/", "companies/"]) {
693
- expect(line).not.toContain(secret);
694
- expect(json).not.toContain(secret);
695
- }
696
- expect(json).toContain("watcherJournalStores");
697
- });
698
- it("the recycle stderr line matches NONE of hq-desktop-app's fatal stderr markers", () => {
699
- const DESKTOP_FATAL_MARKERS = [
700
- "javascript heap out of memory",
701
- "ineffective mark-compacts",
702
- "fatal error",
703
- "uncaught exception",
704
- "unhandledrejection",
705
- "panicked at",
706
- "assertion failed",
707
- "npm error ",
708
- "npm err! ",
709
- "enospc",
710
- "permission denied",
711
- "no such file or directory",
712
- "command not found",
713
- ];
714
- const census = new HeapCensus();
715
- for (const token of [
716
- "pendingAppliedUpserts",
717
- "watcherJournalStores",
718
- "publishedDigestGenerations",
719
- "knownKinds",
720
- "deleteSnapshotEpochs",
721
- ]) {
722
- census.register(token, () => 7);
723
- }
724
- const g = governor({ census });
725
- expect(g.observeAt(0.7, PAST_FLOOR_MS)).toBeNull();
726
- const recycle = g.observeAt(0.7, PAST_FLOOR_MS + 121_000);
727
- const line = heapRecycleStderrLine(recycle);
728
- const lowered = line.toLowerCase();
729
- for (const marker of DESKTOP_FATAL_MARKERS) {
730
- expect(lowered).not.toContain(marker);
731
- }
732
- expect(line.trimStart().startsWith("#")).toBe(false);
733
- expect(line).toContain("hq-sync-runner: heap-recycle");
734
- expect(line).toContain("trigger=live");
735
- expect(line).toContain("sustain_ms=");
736
- });
737
- });
738
- describe("RunnerHeapTelemetry — recorded production series replay (regression reopen)", () => {
739
- // The aborting generation's own recorded telemetry (person#prs_01KQ2TZQMA...,
740
- // 2026-09-01 18:57..19:48Z). heap_size_limit was 2348810240 B; the SIGABRT
741
- // landed at uptime 55m16s = 3_316_000 ms.
742
- const RECORDED_LIMIT_BYTES = 2_348_810_240;
743
- const ABORT_UPTIME_MS = 3_316_000;
744
- // The recorded per-sample INSTANTANEOUS used/limit fractions. Max is 0.741 —
745
- // it never reaches the old 0.78 rule and never two-in-a-row, and never the
746
- // 0.90 emergency line, so the instantaneous path is inert (the base failure).
747
- const INSTANTANEOUS = [
748
- 0.072, 0.106, 0.109, 0.458, 0.546, 0.251, 0.592, 0.564, 0.559, 0.427, 0.457,
749
- 0.564, 0.397, 0.584, 0.438, 0.523, 0.64, 0.548, 0.66, 0.664, 0.512, 0.513,
750
- 0.69, 0.703, 0.741,
751
- ];
752
- it("base instantaneous logic is inert: no sample-path recycle across the entire recorded series", () => {
753
- const g = governor({ limitBytes: RECORDED_LIMIT_BYTES });
754
- let recycles = 0;
755
- let t = 4.24 * 60_000;
756
- for (const f of INSTANTANEOUS) {
757
- if (g.sampleAt(f, t).recycle)
758
- recycles += 1;
759
- t += 2 * 60_000;
760
- }
761
- expect(recycles).toBe(0); // the exact inertness the regression exhibited
762
- });
763
- it("GC-anchored logic produces exactly one live recycle before the recorded 55m16s abort", () => {
764
- // The implied POST-GC live floor: monotonic, crossing 0.60 between ~36.7 and
765
- // ~39 min (the lower envelope of the instantaneous series). One major-GC
766
- // observation per minute.
767
- const LIVE_FLOOR = [
768
- { uptimeMin: 4, fraction: 0.07 },
769
- { uptimeMin: 12, fraction: 0.11 },
770
- { uptimeMin: 20, fraction: 0.25 },
771
- { uptimeMin: 28, fraction: 0.42 },
772
- { uptimeMin: 34, fraction: 0.51 },
773
- { uptimeMin: 37, fraction: 0.6 }, // crosses the floor here -> anchor
774
- { uptimeMin: 39, fraction: 0.63 }, // >= 120 s later -> recycle
775
- { uptimeMin: 46, fraction: 0.69 },
776
- { uptimeMin: 52, fraction: 0.74 },
777
- ];
778
- const g = governor({ limitBytes: RECORDED_LIMIT_BYTES });
779
- const verdicts = [];
780
- for (const point of LIVE_FLOOR) {
781
- const recycle = g.observeAt(point.fraction, point.uptimeMin * 60_000);
782
- if (recycle)
783
- verdicts.push(recycle);
784
- }
785
- expect(verdicts).toHaveLength(1);
786
- expect(verdicts[0].trigger).toBe("live");
787
- expect(verdicts[0].uptimeMs).toBeLessThan(ABORT_UPTIME_MS); // wins the race to V8
788
- expect(verdicts[0].uptimeMs).toBeGreaterThanOrEqual(DEFAULT_HEAP_RECYCLE_MIN_UPTIME_MS);
789
- // ~16 minutes of headroom before the recorded abort.
790
- expect(ABORT_UPTIME_MS - verdicts[0].uptimeMs).toBeGreaterThan(10 * 60_000);
791
- });
792
- });
793
- describe("ingest key contract — every emitted property key survives hq-pro redactProperties", () => {
794
- // hq-pro's raw-telemetry-envelope ingest keeps a numeric property ONLY when its
795
- // key matches this shape, ends in _count/_bytes/_ms, and contains none of these
796
- // denied substrings. Quoted here as literals: a future key that violates the
797
- // contract (the exact defect that dropped every census field to date) fails.
798
- const KEY_SHAPE = /^[A-Za-z][A-Za-z0-9_]{0,63}$/;
799
- const DENY_PARTS = [
800
- "authorization",
801
- "body",
802
- "content",
803
- "cookie",
804
- "email",
805
- "file",
806
- "message",
807
- "password",
808
- "path",
809
- "prompt",
810
- "query",
811
- "secret",
812
- "text",
813
- "token",
814
- "transcript",
815
- ];
816
- // Every FIXED census token the production runner registers (watch-loop ownMaps
817
- // + the decoupled emitter/watcher tokens). If a new token is added, add it here.
818
- const PRODUCTION_CENSUS_TOKENS = [
819
- "pendingAppliedUpserts",
820
- "pendingWatcherEntries",
821
- "pendingWatcherChanges",
822
- "pendingWatcherDroppedRouteHints",
823
- "quarantinedDeleteRoots",
824
- "watcherJournalStores",
825
- "watcherJournalRows",
826
- "targetedJournalSessions",
827
- "targetedJournalRows",
828
- "cachedAreaJournalMigrations",
829
- "pendingSlowPasses",
830
- "pendingFastPasses",
831
- "lastPublishedDigests",
832
- "publishedDigestGenerations",
833
- "deferredPublishes",
834
- "durablePublishedHashRetries",
835
- "initialPublishedDigests",
836
- "knownKinds",
837
- "deleteSnapshotEpochs",
838
- "ignoreFilterMemo",
839
- ];
840
- function assertIngestSafe(props) {
841
- for (const key of Object.keys(props)) {
842
- const lower = key.toLowerCase();
843
- expect(KEY_SHAPE.test(key), `key shape: ${key}`).toBe(true);
844
- expect(lower.endsWith("count") || lower.endsWith("bytes") || lower.endsWith("ms"), `key suffix: ${key}`).toBe(true);
845
- for (const part of DENY_PARTS) {
846
- expect(lower.includes(part), `deny part "${part}" in ${key}`).toBe(false);
847
- }
848
- }
849
- }
850
- function fullCensus() {
851
- const census = new HeapCensus();
852
- for (const token of PRODUCTION_CENSUS_TOKENS)
853
- census.register(token, () => 7);
854
- return census;
855
- }
856
- it("heapSampleCloudProperties keys are all ingest-safe", () => {
857
- const { readers } = mutableReaders();
858
- const sample = sampleRunnerHeap({ readers, census: fullCensus(), sessionStartedAtMs: 0 });
859
- assertIngestSafe(heapSampleCloudProperties(sample));
860
- });
861
- it("heapPressureCloudProperties keys are all ingest-safe", () => {
862
- const census = fullCensus();
863
- const { state, readers } = mutableReaders();
864
- state.limit = 2048 * MB;
865
- state.used = Math.round(2048 * MB * 0.8);
866
- const controller = new RunnerHeapTelemetry({
867
- readers,
868
- census,
869
- sessionStartedAtMs: 0,
870
- pressureThresholdFraction: 0.75,
871
- });
872
- const { pressure } = controller.sample();
873
- expect(pressure).not.toBeNull();
874
- assertIngestSafe(heapPressureCloudProperties(pressure));
875
- });
876
- it("heapRecycleCloudProperties keys are all ingest-safe (every trigger)", () => {
877
- const emergency = governor({ census: fullCensus() }).sampleAt(0.95, PAST_FLOOR_MS).recycle;
878
- expect(emergency).not.toBeNull();
879
- assertIngestSafe(heapRecycleCloudProperties(emergency));
880
- const g = governor({ census: fullCensus() });
881
- expect(g.observeAt(0.7, PAST_FLOOR_MS)).toBeNull();
882
- const live = g.observeAt(0.7, PAST_FLOOR_MS + 121_000);
883
- expect(live).not.toBeNull();
884
- assertIngestSafe(heapRecycleCloudProperties(live));
885
- // A footprint recycle carries the three NEW keys (trigger flag + two byte
886
- // floors); they must satisfy the same contract or ingest would drop them.
887
- const gFoot = governor({ census: fullCensus(), minUptimeMs: 0 });
888
- gFoot.setFootprint(4600 * MB, 30_000); // > 4096 recycle floor, < 4864 hard floor
889
- const footprint = gFoot.controller.evaluate().recycle;
890
- expect(footprint?.trigger).toBe("footprint");
891
- const footProps = heapRecycleCloudProperties(footprint);
892
- assertIngestSafe(footProps);
893
- expect(footProps.recycle_footprint_trigger_count).toBe(1);
894
- expect(footProps.recycle_footprint_recycle_floor_bytes).toBe(DEFAULT_HEAP_FOOTPRINT_RECYCLE_BYTES);
895
- expect(footProps.recycle_footprint_hard_exit_floor_bytes).toBe(DEFAULT_HEAP_FOOTPRINT_HARD_EXIT_BYTES);
896
- // A heap trigger reports 0 for the footprint trigger flag.
897
- expect(heapRecycleCloudProperties(live).recycle_footprint_trigger_count).toBe(0);
898
- });
899
- });
900
- describe("startRunnerHeapSampling — GC observer + recycle callback", () => {
901
- it("drives the governor to a LIVE recycle via the injected GC observer and swallows a throwing onRecycle", () => {
902
- const census = new HeapCensus();
903
- census.register("x", () => 1);
904
- const { state, readers } = mutableReaders();
905
- state.limit = 2048 * MB;
906
- const fake = fakeScheduler();
907
- const gc = fakeGcObserver();
908
- const recycles = [];
909
- const handle = startRunnerHeapSampling({
910
- readers,
911
- census,
912
- sessionStartedAtMs: 0,
913
- pressureThresholdFraction: 0.75,
914
- recycleLiveFraction: 0.6,
915
- recycleSustainWindowMs: 120_000,
916
- recycleEmergencyFraction: 0.9,
917
- recycleMinUptimeMs: DEFAULT_HEAP_RECYCLE_MIN_UPTIME_MS,
918
- intervalMs: 1,
919
- scheduler: fake.scheduler,
920
- gcObserver: gc.observer,
921
- onSample: () => { },
922
- onPressure: () => { },
923
- onRecycle: (record) => {
924
- recycles.push(record);
925
- throw new Error("recycle emit boom"); // must be swallowed
926
- },
927
- log: () => { },
928
- });
929
- expect(gc.started()).toBe(true);
930
- // First major GC at/above the live floor: anchors, no verdict.
931
- state.used = Math.round(state.limit * 0.7);
932
- state.now = PAST_FLOOR_MS;
933
- expect(() => gc.fire()).not.toThrow();
934
- expect(recycles).toHaveLength(0);
935
- // A window later: the second major GC produces the live recycle (throw swallowed).
936
- state.now = PAST_FLOOR_MS + 121_000;
937
- expect(() => gc.fire()).not.toThrow();
938
- expect(recycles).toHaveLength(1);
939
- expect(recycles[0].trigger).toBe("live");
940
- // At most once per session, even as GCs continue.
941
- state.now = PAST_FLOOR_MS + 300_000;
942
- expect(() => gc.fire()).not.toThrow();
943
- expect(recycles).toHaveLength(1);
944
- handle.stop();
945
- expect(gc.stopped()).toBe(true);
946
- });
947
- it("the loop-top evaluate() fires the emergency backstop when the interval timer never ticks", () => {
948
- const census = new HeapCensus();
949
- census.register("x", () => 1);
950
- const { state, readers } = mutableReaders();
951
- state.limit = 2048 * MB;
952
- const fake = fakeScheduler();
953
- const recycles = [];
954
- const handle = startRunnerHeapSampling({
955
- readers,
956
- census,
957
- sessionStartedAtMs: 0,
958
- pressureThresholdFraction: 0.75,
959
- recycleEmergencyFraction: 0.9,
960
- intervalMs: 60_000,
961
- scheduler: fake.scheduler,
962
- onSample: () => { },
963
- onPressure: () => { },
964
- onRecycle: (record) => recycles.push(record),
965
- log: () => { },
966
- });
967
- // The timer never ticked. An abort-adjacent instantaneous heap: the loop-top
968
- // evaluate() catches it anyway.
969
- state.used = Math.round(state.limit * 0.93);
970
- state.now = 30_000;
971
- handle.evaluate();
972
- expect(recycles).toHaveLength(1);
973
- expect(recycles[0].trigger).toBe("emergency");
974
- });
975
- it("produces no recycle when the governor is disabled by option", () => {
976
- const census = new HeapCensus();
977
- census.register("x", () => 1);
978
- const { state, readers } = mutableReaders();
979
- state.limit = 1000;
980
- state.used = 999;
981
- state.now = PAST_FLOOR_MS;
982
- const fake = fakeScheduler();
983
- const gc = fakeGcObserver();
984
- const recycles = [];
985
- const handle = startRunnerHeapSampling({
986
- readers,
987
- census,
988
- sessionStartedAtMs: 0,
989
- pressureThresholdFraction: 0.75,
990
- recycleEnabled: false,
991
- recycleMinUptimeMs: 0,
992
- intervalMs: 1,
993
- scheduler: fake.scheduler,
994
- gcObserver: gc.observer,
995
- onSample: () => { },
996
- onPressure: () => { },
997
- onRecycle: (record) => recycles.push(record),
998
- log: () => { },
999
- });
1000
- for (let i = 0; i < 10; i += 1) {
1001
- fake.tick();
1002
- gc.fire();
1003
- handle.evaluate();
1004
- }
1005
- expect(recycles).toHaveLength(0);
1006
- });
1007
- });
1008
- describe("isFreshGcReading", () => {
1009
- it("accepts a promptly-captured reading and rejects a stale (blocked-loop) one", () => {
1010
- expect(isFreshGcReading(1000, 1000)).toBe(true); // captured at the GC end
1011
- expect(isFreshGcReading(1000, 1000 + MAX_FRESH_GC_READING_MS)).toBe(true); // exactly at the bound
1012
- expect(isFreshGcReading(1000, 1000 + MAX_FRESH_GC_READING_MS + 1)).toBe(false); // just over
1013
- expect(isFreshGcReading(1000, 5000)).toBe(false); // blocked loop: 4 s stale reading
1014
- expect(isFreshGcReading(1000, 900)).toBe(true); // reading at/just before the GC end
1015
- // Missing entry timing degrades to "not fresh" (skip), never a false accept.
1016
- expect(isFreshGcReading(Number.NaN, 1000)).toBe(false);
1017
- expect(isFreshGcReading(1000, Number.NaN)).toBe(false);
1018
- expect(isFreshGcReading(1000, 1400, 500)).toBe(true); // custom threshold honored
1019
- });
1020
- });
1021
- describe("nodeMajorGcObserver", () => {
1022
- it("constructs, observes major GCs, and disconnects without throwing", () => {
1023
- const observer = nodeMajorGcObserver();
1024
- let fires = 0;
1025
- expect(() => observer.start(() => (fires += 1))).not.toThrow();
1026
- // Force a real major GC if the runtime exposes it; otherwise this is a no-op
1027
- // and the observer simply never fires — both are acceptable (degrade to
1028
- // silence). The contract under test is that neither start nor stop throws.
1029
- const globalGc = globalThis.gc;
1030
- if (typeof globalGc === "function") {
1031
- try {
1032
- globalGc({ type: "major" });
1033
- }
1034
- catch {
1035
- globalGc();
1036
- }
1037
- }
1038
- expect(() => observer.stop()).not.toThrow();
1039
- expect(fires).toBeGreaterThanOrEqual(0);
1040
- });
1041
- it("start() twice and stop() before start() never throw (degrade to silence)", () => {
1042
- const observer = nodeMajorGcObserver();
1043
- expect(() => observer.stop()).not.toThrow(); // stop before start
1044
- expect(() => observer.start(() => { })).not.toThrow();
1045
- expect(() => observer.start(() => { })).not.toThrow(); // re-start
1046
- expect(() => observer.stop()).not.toThrow();
1047
- expect(() => observer.stop()).not.toThrow(); // double stop
1048
- });
1049
- });
1050
- describe("resolveHeapRecycleEnabled", () => {
1051
- it("is ON by default and disabled only by an explicit whole-string off value", () => {
1052
- expect(resolveHeapRecycleEnabled(undefined)).toBe(true);
1053
- expect(resolveHeapRecycleEnabled("")).toBe(true);
1054
- expect(resolveHeapRecycleEnabled("1")).toBe(true);
1055
- expect(resolveHeapRecycleEnabled("true")).toBe(true);
1056
- expect(resolveHeapRecycleEnabled("0")).toBe(false);
1057
- expect(resolveHeapRecycleEnabled("false")).toBe(false);
1058
- expect(resolveHeapRecycleEnabled("NO")).toBe(false);
1059
- expect(resolveHeapRecycleEnabled(" off ")).toBe(false);
1060
- // A typo keeps the governor armed rather than silently disabling it.
1061
- expect(resolveHeapRecycleEnabled("disabled")).toBe(true);
1062
- });
1063
- });
1064
- describe("resolveHeapRecycleLiveFraction", () => {
1065
- it("parses a valid fraction and falls back to 0.60 on garbage or out-of-range input", () => {
1066
- expect(resolveHeapRecycleLiveFraction("0.5")).toBe(0.5);
1067
- expect(resolveHeapRecycleLiveFraction("1")).toBe(1);
1068
- expect(resolveHeapRecycleLiveFraction(undefined)).toBe(DEFAULT_HEAP_RECYCLE_LIVE_FRACTION);
1069
- expect(resolveHeapRecycleLiveFraction("")).toBe(DEFAULT_HEAP_RECYCLE_LIVE_FRACTION);
1070
- expect(resolveHeapRecycleLiveFraction("2")).toBe(DEFAULT_HEAP_RECYCLE_LIVE_FRACTION);
1071
- expect(resolveHeapRecycleLiveFraction("-1")).toBe(DEFAULT_HEAP_RECYCLE_LIVE_FRACTION);
1072
- expect(resolveHeapRecycleLiveFraction("0.6x")).toBe(DEFAULT_HEAP_RECYCLE_LIVE_FRACTION);
1073
- });
1074
- });
1075
- describe("resolveHeapRecycleEmergencyFraction", () => {
1076
- it("parses a valid fraction and falls back to 0.90 on garbage or out-of-range input", () => {
1077
- expect(resolveHeapRecycleEmergencyFraction("0.95")).toBe(0.95);
1078
- expect(resolveHeapRecycleEmergencyFraction("1")).toBe(1);
1079
- expect(resolveHeapRecycleEmergencyFraction(undefined)).toBe(DEFAULT_HEAP_RECYCLE_EMERGENCY_FRACTION);
1080
- expect(resolveHeapRecycleEmergencyFraction("")).toBe(DEFAULT_HEAP_RECYCLE_EMERGENCY_FRACTION);
1081
- expect(resolveHeapRecycleEmergencyFraction("2")).toBe(DEFAULT_HEAP_RECYCLE_EMERGENCY_FRACTION);
1082
- expect(resolveHeapRecycleEmergencyFraction("0.9x")).toBe(DEFAULT_HEAP_RECYCLE_EMERGENCY_FRACTION);
1083
- });
1084
- });
1085
- describe("resolveHeapRecycleSustainWindowMs", () => {
1086
- it("parses whole ms >= 0 (0 removes the window) and rejects '2m' rather than its prefix", () => {
1087
- expect(resolveHeapRecycleSustainWindowMs("120000")).toBe(120_000);
1088
- expect(resolveHeapRecycleSustainWindowMs("0")).toBe(0); // 0 is a valid window
1089
- expect(resolveHeapRecycleSustainWindowMs(undefined)).toBe(DEFAULT_HEAP_RECYCLE_SUSTAIN_WINDOW_MS);
1090
- expect(resolveHeapRecycleSustainWindowMs("2m")).toBe(DEFAULT_HEAP_RECYCLE_SUSTAIN_WINDOW_MS);
1091
- expect(resolveHeapRecycleSustainWindowMs("-1")).toBe(DEFAULT_HEAP_RECYCLE_SUSTAIN_WINDOW_MS);
1092
- expect(resolveHeapRecycleSustainWindowMs("")).toBe(DEFAULT_HEAP_RECYCLE_SUSTAIN_WINDOW_MS);
1093
- });
1094
- });
1095
- describe("resolveHeapRecycleMinUptimeMs", () => {
1096
- it("parses whole ms >= 0 (0 disables the floor) and rejects '35m' rather than its prefix", () => {
1097
- expect(resolveHeapRecycleMinUptimeMs("60000")).toBe(60_000);
1098
- expect(resolveHeapRecycleMinUptimeMs("0")).toBe(0); // 0 is a valid floor
1099
- expect(resolveHeapRecycleMinUptimeMs(undefined)).toBe(DEFAULT_HEAP_RECYCLE_MIN_UPTIME_MS);
1100
- expect(resolveHeapRecycleMinUptimeMs("35m")).toBe(DEFAULT_HEAP_RECYCLE_MIN_UPTIME_MS);
1101
- expect(resolveHeapRecycleMinUptimeMs("-1")).toBe(DEFAULT_HEAP_RECYCLE_MIN_UPTIME_MS);
1102
- expect(resolveHeapRecycleMinUptimeMs("")).toBe(DEFAULT_HEAP_RECYCLE_MIN_UPTIME_MS);
1103
- });
1104
- });
1105
- // --- v2-layered governor: effective limit, pinned + hard-exit tiers ----------
1106
- describe("RunnerHeapTelemetry — effective-limit re-denomination", () => {
1107
- it("divides every fraction by min(declared, reported) so a declared ceiling makes the trigger real", () => {
1108
- const declared = 2048 * MB;
1109
- const reported = 2233 * MB; // Node-25 reported limit sits above the declared ceiling
1110
- const withDeclared = governor({
1111
- declaredCeilingBytes: declared,
1112
- limitBytes: reported,
1113
- minUptimeMs: 0,
1114
- });
1115
- // 0.91 of the DECLARED ceiling: 1863 MB. Over effective (declared) that is
1116
- // 0.91 >= the 0.90 emergency line, so a single post-GC reading recycles.
1117
- withDeclared.state.used = Math.round(declared * 0.91);
1118
- withDeclared.state.now = 30_000;
1119
- const armed = withDeclared.controller.observeMajorGc().recycle;
1120
- expect(armed).not.toBeNull();
1121
- expect(armed?.trigger).toBe("emergency");
1122
- expect(armed?.effectiveLimitBytes).toBe(declared);
1123
- expect(armed?.declaredCeilingBytes).toBe(declared);
1124
- expect(armed?.heapLimitBytes).toBe(reported); // reported kept for provenance
1125
- expect(armed?.usedFraction).toBeCloseTo(0.91, 2);
1126
- });
1127
- it("the SAME bytes never reach emergency when the reported limit is the denominator (no declared)", () => {
1128
- const declared = 2048 * MB;
1129
- const reported = 2233 * MB;
1130
- const noDeclared = governor({ declaredCeilingBytes: null, limitBytes: reported, minUptimeMs: 0 });
1131
- // 1863 MB is 0.834 of the reported limit — below the 0.90 emergency line, so
1132
- // the post-GC path only anchors the live floor (no immediate recycle).
1133
- noDeclared.state.used = Math.round(declared * 0.91);
1134
- noDeclared.state.now = 30_000;
1135
- expect(noDeclared.controller.observeMajorGc().recycle).toBeNull();
1136
- });
1137
- it("falls back to the reported limit (bit-identical shipped semantics) when no ceiling is declared", () => {
1138
- const g = governor({ declaredCeilingBytes: null });
1139
- expect(g.observeAt(0.62, PAST_FLOOR_MS)).toBeNull();
1140
- const recycle = g.observeAt(0.66, PAST_FLOOR_MS + 121_000);
1141
- expect(recycle?.trigger).toBe("live");
1142
- expect(recycle?.effectiveLimitBytes).toBe(recycle?.heapLimitBytes);
1143
- expect(recycle?.declaredCeilingBytes).toBe(0);
1144
- });
1145
- });
1146
- describe("RunnerHeapTelemetry — pinned tier (T2, instantaneous sustained)", () => {
1147
- it("arms on an instantaneous fraction held at/above the floor across the window, past the uptime floor", () => {
1148
- const g = governor({ pinnedFraction: 0.84, pinnedSustainWindowMs: 20_000, minUptimeMs: 0 });
1149
- expect(g.sampleAt(0.85, 0).recycle).toBeNull(); // anchor (count 1)
1150
- expect(g.sampleAt(0.85, 10_000).recycle).toBeNull(); // 10 s < 20 s window
1151
- const { recycle } = g.sampleAt(0.85, 21_000); // 21 s >= window, count >= 2
1152
- expect(recycle).not.toBeNull();
1153
- expect(recycle?.trigger).toBe("pinned");
1154
- expect(recycle?.reason).toBe("cooperative");
1155
- expect(recycle?.pinnedFraction).toBe(0.84);
1156
- });
1157
- it("resets its anchor on any single below-floor observation (a healthy sawtooth never sustains)", () => {
1158
- const g = governor({ pinnedFraction: 0.84, pinnedSustainWindowMs: 20_000, minUptimeMs: 0 });
1159
- expect(g.sampleAt(0.85, 0).recycle).toBeNull(); // anchor
1160
- expect(g.sampleAt(0.80, 5_000).recycle).toBeNull(); // dip -> anchor reset
1161
- expect(g.sampleAt(0.85, 25_000).recycle).toBeNull(); // re-anchor here (count 1)
1162
- const { recycle } = g.sampleAt(0.85, 46_000); // 21 s past the re-anchor
1163
- expect(recycle?.trigger).toBe("pinned");
1164
- });
1165
- it("honours the 35-minute uptime floor (unlike the emergency tier)", () => {
1166
- const g = governor({ pinnedFraction: 0.84, pinnedSustainWindowMs: 0, minUptimeMs: 100_000 });
1167
- expect(g.sampleAt(0.85, 0).recycle).toBeNull(); // anchor
1168
- expect(g.sampleAt(0.85, 50_000).recycle).toBeNull(); // window satisfied but 50 s < 100 s floor
1169
- const { recycle } = g.sampleAt(0.85, 120_000); // past the floor
1170
- expect(recycle?.trigger).toBe("pinned");
1171
- });
1172
- it("never fires off the post-GC live path, and the live path never fires 'pinned'", () => {
1173
- // Instantaneous readings drive pinned; post-GC readings drive live. They keep
1174
- // separate anchors, so neither impersonates the other.
1175
- const gPinned = governor({ pinnedFraction: 0.84, pinnedSustainWindowMs: 0, minUptimeMs: 0 });
1176
- gPinned.sampleAt(0.85, 0); // instantaneous only
1177
- expect(gPinned.sampleAt(0.85, 1_000).recycle?.trigger).toBe("pinned");
1178
- const gLive = governor({ minUptimeMs: 0 });
1179
- gLive.observeAt(0.65, 0);
1180
- expect(gLive.observeAt(0.65, 121_000)?.trigger).toBe("live");
1181
- });
1182
- });
1183
- describe("RunnerHeapTelemetry — hard-exit tiers (T4)", () => {
1184
- it("hard_fraction: a single instantaneous observation at/above the hard line hard-exits with no prior latch", () => {
1185
- const g = governor({ minUptimeMs: DEFAULT_HEAP_RECYCLE_MIN_UPTIME_MS });
1186
- // 0.96 >= 0.955, well BELOW the uptime floor: the hard tier bypasses the floor
1187
- // exactly like a SIGABRT would, and preempts the cooperative recycle.
1188
- const { recycle, hardExit } = g.evaluateFullAt(0.96, 10_000);
1189
- expect(recycle).toBeNull();
1190
- expect(hardExit).not.toBeNull();
1191
- expect(hardExit?.reason).toBe("hard_fraction");
1192
- expect(hardExit?.trigger).toBe("emergency"); // no prior latch -> instantaneous family
1193
- expect(hardExit?.hardExitFraction).toBe(DEFAULT_HEAP_HARD_EXIT_FRACTION);
1194
- });
1195
- it("latch_timeout: an unhonoured cooperative latch ages out by TIME into a hard exit", () => {
1196
- const g = governor({ minUptimeMs: 0, latchHardExitMs: 60_000, latchHardExitObservations: 1_000_000 });
1197
- const armed = g.evaluateFullAt(0.92, 0); // cooperative emergency latch
1198
- expect(armed.recycle?.reason).toBe("cooperative");
1199
- expect(armed.recycle?.trigger).toBe("emergency");
1200
- expect(g.evaluateFullAt(0.92, 30_000).hardExit).toBeNull(); // 30 s < 60 s deadline
1201
- const late = g.evaluateFullAt(0.92, 61_000); // 61 s >= deadline
1202
- expect(late.recycle).toBeNull();
1203
- expect(late.hardExit?.reason).toBe("latch_timeout");
1204
- expect(late.hardExit?.trigger).toBe("emergency"); // inherits the latched tier
1205
- expect(late.hardExit?.postLatchObservations).toBeGreaterThanOrEqual(1);
1206
- });
1207
- it("latch_timeout: ages out by observation COUNT before the time deadline", () => {
1208
- const g = governor({ minUptimeMs: 0, latchHardExitMs: 10 * 60_000, latchHardExitObservations: 3 });
1209
- g.evaluateFullAt(0.92, 0); // cooperative emergency latch
1210
- expect(g.evaluateFullAt(0.7, 1_000).hardExit).toBeNull(); // post-latch obs 1 < 3
1211
- expect(g.evaluateFullAt(0.7, 2_000).hardExit).toBeNull(); // post-latch obs 2 < 3
1212
- const third = g.evaluateFullAt(0.7, 3_000); // post-latch obs 3 >= 3
1213
- expect(third.hardExit?.reason).toBe("latch_timeout");
1214
- });
1215
- it("the latch-age arm fires from EVERY observation path (interval sample, loop-top, post-GC)", () => {
1216
- const g = governor({ minUptimeMs: 0, latchHardExitMs: 0, latchHardExitObservations: 1_000_000 });
1217
- // latchHardExitMs=0: the first post-latch observation from any path hard-exits.
1218
- g.observeFullAt(0.92, 0); // post-GC emergency cooperative latch
1219
- const viaSample = g.sampleAt(0.7, 1);
1220
- expect(viaSample.hardExit?.reason).toBe("latch_timeout");
1221
- });
1222
- it("fires at most one hard exit per session and never a cooperative verdict afterwards", () => {
1223
- const g = governor({ minUptimeMs: 0, latchHardExitMs: 0, latchHardExitObservations: 1_000_000 });
1224
- g.evaluateFullAt(0.92, 0); // cooperative latch
1225
- expect(g.evaluateFullAt(0.7, 1).hardExit?.reason).toBe("latch_timeout"); // first hard exit
1226
- expect(g.evaluateFullAt(0.99, 2).hardExit).toBeNull(); // already hard-signalled
1227
- expect(g.evaluateFullAt(0.99, 3).recycle).toBeNull();
1228
- });
1229
- });
1230
- describe("RunnerHeapTelemetry — tier ordering and derivation pin (guard-constant policy)", () => {
1231
- it("pins 0.60 < 0.84 < 0.90 < 0.955 and each against the observed abort band", () => {
1232
- expect(DEFAULT_HEAP_RECYCLE_LIVE_FRACTION).toBe(0.6);
1233
- expect(DEFAULT_HEAP_PINNED_FRACTION).toBe(0.84);
1234
- expect(DEFAULT_HEAP_RECYCLE_EMERGENCY_FRACTION).toBe(0.9);
1235
- expect(DEFAULT_HEAP_HARD_EXIT_FRACTION).toBe(0.955);
1236
- const order = [
1237
- DEFAULT_HEAP_RECYCLE_LIVE_FRACTION,
1238
- DEFAULT_HEAP_PINNED_FRACTION,
1239
- DEFAULT_HEAP_RECYCLE_EMERGENCY_FRACTION,
1240
- DEFAULT_HEAP_HARD_EXIT_FRACTION,
1241
- ];
1242
- for (let i = 1; i < order.length; i += 1)
1243
- expect(order[i]).toBeGreaterThan(order[i - 1]);
1244
- // Pinned sits above the max healthy instantaneous evidence (~0.816 of declared)
1245
- // and below the legacy abort floor (1788/2048 = 0.873).
1246
- expect(DEFAULT_HEAP_PINNED_FRACTION).toBeGreaterThan(0.816);
1247
- expect(DEFAULT_HEAP_PINNED_FRACTION).toBeLessThan(1788 / 2048);
1248
- // Emergency and hard-exit both sit strictly below the minimum post-#471
1249
- // observed abort ratio (1995/2048 = 0.974), so both preempt the SIGABRT.
1250
- expect(DEFAULT_HEAP_RECYCLE_EMERGENCY_FRACTION).toBeLessThan(1995 / 2048);
1251
- expect(DEFAULT_HEAP_HARD_EXIT_FRACTION).toBeLessThan(1995 / 2048);
1252
- });
1253
- });
1254
- describe("RunnerHeapTelemetry — kill switch disables every tier (incl. hard)", () => {
1255
- it("disables live, pinned, emergency, hard_fraction, AND latch_timeout at once", () => {
1256
- const g = governor({ recycleEnabled: false, minUptimeMs: 0 });
1257
- let t = 0;
1258
- for (let i = 0; i < 20; i += 1) {
1259
- // 0.99 would fire hard_fraction; 0.85 sustained would fire pinned — none do.
1260
- const viaSample = g.sampleAt(0.99, t);
1261
- expect(viaSample.recycle).toBeNull();
1262
- expect(viaSample.hardExit).toBeNull();
1263
- const viaEval = g.evaluateFullAt(0.99, t + 1);
1264
- expect(viaEval.recycle).toBeNull();
1265
- expect(viaEval.hardExit).toBeNull();
1266
- const viaGc = g.observeFullAt(0.99, t + 2);
1267
- expect(viaGc.recycle).toBeNull();
1268
- expect(viaGc.hardExit).toBeNull();
1269
- t += 60_000;
1270
- }
1271
- });
1272
- });
1273
- // --- Resident-footprint tier (T5): the regression-reopen fix ------------------
1274
- //
1275
- // The four heap tiers denominate every fraction in min(declaredCeiling,
1276
- // heap_size_limit) — the V8 old-space cap. A non-heap (external/ArrayBuffer)
1277
- // burst outruns that cap while used_heap_size stays quiet, so NONE of them can
1278
- // see a 5,598 MB resident process with a calm heap; the desktop's whole-tree
1279
- // footprint backstop is left to pre-empt it, which IS this Sentry issue. The
1280
- // footprint tier adds an absolute rss BUDGET the heap tiers never had.
1281
- describe("RunnerHeapTelemetry — resident-footprint tier (T5)", () => {
1282
- // hq-desktop-app crates/hq-desktop-core: WATCHER_FOOTPRINT_HARD_CEILING_MB.
1283
- const DESKTOP_FOOTPRINT_HARD_CEILING_MB = 5120;
1284
- // Max npx launcher sibling across the 8 decomposed events (8-84 MB observed).
1285
- const LAUNCHER_HEADROOM_MB = 84;
1286
- // Highest healthy cold-ramp tree peak that must NOT recycle.
1287
- const HIGHEST_COLD_RAMP_MB = 3623;
1288
- // Drive ONE footprint reading (rss in bytes, quiet heap) through a chosen path
1289
- // on a fresh session, so the one-verdict-per-session latch never carries over.
1290
- function footprintVerdict(rssBytes, path) {
1291
- const g = governor({ minUptimeMs: 0 });
1292
- g.setFootprint(rssBytes, 30_000);
1293
- if (path === "sample") {
1294
- const r = g.controller.sample();
1295
- return { recycle: r.recycle, hardExit: r.hardExit };
1296
- }
1297
- if (path === "evaluate")
1298
- return g.controller.evaluate();
1299
- return g.controller.observeMajorGc();
1300
- }
1301
- it("pins the budgets from the production traces and hq-desktop-app's published constants", () => {
1302
- expect(DEFAULT_HEAP_FOOTPRINT_RECYCLE_BYTES).toBe(4096 * MB);
1303
- expect(DEFAULT_HEAP_FOOTPRINT_HARD_EXIT_BYTES).toBe(4864 * MB);
1304
- // Both budgets recycle the runner's OWN rss STRICTLY below the desktop's
1305
- // whole-tree pre-empt line (5120 MB) minus the launcher-sibling headroom.
1306
- const preemptLineBytes = (DESKTOP_FOOTPRINT_HARD_CEILING_MB - LAUNCHER_HEADROOM_MB) * MB;
1307
- expect(DEFAULT_HEAP_FOOTPRINT_RECYCLE_BYTES).toBeLessThan(preemptLineBytes);
1308
- expect(DEFAULT_HEAP_FOOTPRINT_HARD_EXIT_BYTES).toBeLessThan(preemptLineBytes);
1309
- // Cooperative < hard: a moderate climb recycles cooperatively; only an
1310
- // abort-adjacent reading hard-exits.
1311
- expect(DEFAULT_HEAP_FOOTPRINT_RECYCLE_BYTES).toBeLessThan(DEFAULT_HEAP_FOOTPRINT_HARD_EXIT_BYTES);
1312
- // The cooperative floor sits above the highest healthy cold ramp, so a large
1313
- // sync never trades this issue for respawn churn (the r1 failure mode).
1314
- expect(DEFAULT_HEAP_FOOTPRINT_RECYCLE_BYTES).toBeGreaterThan(HIGHEST_COLD_RAMP_MB * MB);
1315
- });
1316
- it("replays the evented production traces: runaways recycle/hard-exit, cold ramps never do", () => {
1317
- // The four cold ramps (healthy large syncs) must NEVER produce a verdict, on
1318
- // ANY path. On BASE the tier does not exist and these produce no verdict
1319
- // either — but neither do the runaways below, which is the base defect.
1320
- for (const treeMb of [2776, 3080, 3337, 3623]) {
1321
- for (const path of ["sample", "evaluate", "gc"]) {
1322
- const v = footprintVerdict(treeMb * MB, path);
1323
- expect(v.recycle, `cold ramp ${treeMb} via ${path}`).toBeNull();
1324
- expect(v.hardExit, `cold ramp ${treeMb} via ${path}`).toBeNull();
1325
- }
1326
- }
1327
- // 4493 MB (below the hard floor): a COOPERATIVE footprint recycle.
1328
- for (const path of ["sample", "evaluate", "gc"]) {
1329
- const v = footprintVerdict(4493 * MB, path);
1330
- expect(v.recycle?.trigger, `4493 via ${path}`).toBe("footprint");
1331
- expect(v.recycle?.reason).toBe("cooperative");
1332
- expect(v.recycle?.observedSustainMs).toBe(0); // single observation, no window
1333
- expect(v.hardExit).toBeNull();
1334
- }
1335
- // 5598 and 7949 MB (at/above the hard floor, already past the desktop line on
1336
- // the runner's own rss): a footprint HARD EXIT, no waiting for a pass boundary.
1337
- for (const rssMb of [5598, 7949]) {
1338
- for (const path of ["sample", "evaluate", "gc"]) {
1339
- const v = footprintVerdict(rssMb * MB, path);
1340
- expect(v.hardExit?.trigger, `${rssMb} via ${path}`).toBe("footprint");
1341
- expect(v.hardExit?.reason).toBe("hard_fraction");
1342
- expect(v.recycle).toBeNull();
1343
- }
1344
- }
1345
- });
1346
- it("arms on a SINGLE observation with no sustain window and below the uptime floor", () => {
1347
- // Default 35-minute uptime floor; a burst at 5 s uptime still recycles, so an
1348
- // 83-1142 MB/s climb can never outrun the tier the way a sustain window would.
1349
- const g = governor(); // default minUptimeMs = 35 min
1350
- g.setFootprint(4200 * MB, 5_000);
1351
- const { recycle } = g.controller.evaluate();
1352
- expect(recycle?.trigger).toBe("footprint");
1353
- expect(recycle?.reason).toBe("cooperative");
1354
- expect(recycle?.observedSustainMs).toBe(0);
1355
- expect(recycle?.uptimeMs).toBe(5_000);
1356
- });
1357
- it("carries rss/external/arrayBuffers, their growth deltas, and census attribution", () => {
1358
- let entries = 100;
1359
- const census = new HeapCensus();
1360
- census.register("watcherJournalStores", () => entries);
1361
- const g = governor({ census, minUptimeMs: 0 });
1362
- g.controller.primeBaseline(); // baseline at entries=100, rss=0
1363
- entries = 900;
1364
- g.state.external = 40 * MB;
1365
- g.state.arrayBuffers = 2000 * MB; // the non-heap growth that the heap cap misses
1366
- g.setFootprint(4600 * MB, 30_000);
1367
- const { recycle } = g.controller.evaluate();
1368
- expect(recycle?.trigger).toBe("footprint");
1369
- expect(recycle?.rssBytes).toBe(4600 * MB);
1370
- expect(recycle?.rssGrowthBytes).toBe(4600 * MB);
1371
- expect(recycle?.arrayBuffersGrowthBytes).toBe(2000 * MB);
1372
- expect(recycle?.externalGrowthBytes).toBe(40 * MB);
1373
- expect(recycle?.topSites[0]).toMatchObject({ site: "watcherJournalStores", growth: 800 });
1374
- });
1375
- it("adds a verdict only where the heap tiers are silent — a heap verdict always wins", () => {
1376
- // Quiet heap + high rss -> footprint fires (heap silent).
1377
- expect(footprintVerdict(4200 * MB, "evaluate").recycle?.trigger).toBe("footprint");
1378
- // A heap emergency with rss ALSO over the footprint budget keeps trigger
1379
- // "emergency": the heap tiers are evaluated first and their verdict is returned
1380
- // unchanged, so the footprint tier never suppresses or re-denominates it.
1381
- const g = governor({ minUptimeMs: 0 });
1382
- g.state.rss = 9000 * MB;
1383
- g.state.used = Math.round(g.state.limit * 0.95); // heap emergency line
1384
- g.state.now = 30_000;
1385
- expect(g.controller.evaluate().recycle?.trigger).toBe("emergency");
1386
- // A heap HARD-fraction with rss over the footprint budget stays a heap hard
1387
- // exit (trigger from the instantaneous family, not "footprint").
1388
- const gh = governor({ minUptimeMs: 0 });
1389
- gh.state.rss = 9000 * MB;
1390
- gh.state.used = Math.round(gh.state.limit * 0.96); // hard-exit fraction
1391
- gh.state.now = 30_000;
1392
- const hv = gh.controller.evaluate();
1393
- expect(hv.hardExit?.reason).toBe("hard_fraction");
1394
- expect(hv.hardExit?.trigger).toBe("emergency"); // NOT footprint
1395
- });
1396
- it("fires from evaluate() (loop-top) when the interval timer never ticks and no GC is observed", () => {
1397
- // The starved-sampler backstop: the module's own 11-minute-hole safety net now
1398
- // covers footprint too. Only evaluate() is ever called here.
1399
- const g = governor({ minUptimeMs: 0 });
1400
- g.setFootprint(4200 * MB, 30_000);
1401
- expect(g.controller.evaluate().recycle?.trigger).toBe("footprint");
1402
- });
1403
- it("hard-exits on a single reading at/above the footprint hard budget", () => {
1404
- const g = governor({ minUptimeMs: 0 });
1405
- g.setFootprint(DEFAULT_HEAP_FOOTPRINT_HARD_EXIT_BYTES, 30_000); // exactly the floor
1406
- const { recycle, hardExit } = g.controller.evaluate();
1407
- expect(recycle).toBeNull();
1408
- expect(hardExit?.trigger).toBe("footprint");
1409
- expect(hardExit?.reason).toBe("hard_fraction");
1410
- expect(hardExit?.rssBytes).toBe(DEFAULT_HEAP_FOOTPRINT_HARD_EXIT_BYTES);
1411
- });
1412
- it("ages an unhonoured footprint cooperative latch into a footprint latch_timeout hard exit", () => {
1413
- const g = governor({ minUptimeMs: 0, latchHardExitMs: 0, latchHardExitObservations: 1_000_000 });
1414
- g.setFootprint(4200 * MB, 0); // cooperative footprint latch (below the hard floor)
1415
- expect(g.controller.evaluate().recycle?.trigger).toBe("footprint");
1416
- // latchHardExitMs=0: the next observation ages the latch out. The hard exit
1417
- // inherits the footprint trigger from the latched tier.
1418
- g.setFootprint(4200 * MB, 1);
1419
- const late = g.controller.evaluate();
1420
- expect(late.recycle).toBeNull();
1421
- expect(late.hardExit?.reason).toBe("latch_timeout");
1422
- expect(late.hardExit?.trigger).toBe("footprint");
1423
- });
1424
- it("recycles at most once per session across every path, then never again", () => {
1425
- const g = governor({ minUptimeMs: 0 });
1426
- g.setFootprint(4200 * MB, 0);
1427
- expect(g.controller.evaluate().recycle?.trigger).toBe("footprint"); // the one recycle
1428
- g.setFootprint(4600 * MB, 60_000);
1429
- expect(g.controller.sample().recycle).toBeNull();
1430
- g.setFootprint(4600 * MB, 120_000);
1431
- expect(g.controller.observeMajorGc().recycle).toBeNull();
1432
- });
1433
- it("the footprint-specific disable silences ONLY the footprint tier; heap tiers still fire", () => {
1434
- const g = governor({ footprintRecycleEnabled: false, minUptimeMs: 0 });
1435
- g.setFootprint(9000 * MB, 30_000); // way over both budgets, quiet heap
1436
- const off = g.controller.evaluate();
1437
- expect(off.recycle).toBeNull();
1438
- expect(off.hardExit).toBeNull();
1439
- // A heap emergency on the same governor still fires — base behaviour intact.
1440
- g.state.used = Math.round(g.state.limit * 0.95);
1441
- g.state.now = 60_000;
1442
- expect(g.controller.evaluate().recycle?.trigger).toBe("emergency");
1443
- });
1444
- it("the global kill switch also disables the footprint tier", () => {
1445
- const g = governor({ recycleEnabled: false, minUptimeMs: 0 });
1446
- g.setFootprint(9000 * MB, 30_000);
1447
- const v = g.controller.evaluate();
1448
- expect(v.recycle).toBeNull();
1449
- expect(v.hardExit).toBeNull();
1450
- });
1451
- it("a disabled footprint tier reports 0 for both budget floors in the verdict record", () => {
1452
- // A reader must be able to tell an OFF tier (0) from a live one (the budget).
1453
- const g = governor({ footprintRecycleEnabled: false, minUptimeMs: 0 });
1454
- const emg = g.sampleAt(0.95, PAST_FLOOR_MS).recycle; // heap emergency still fires
1455
- expect(emg?.footprintRecycleBytes).toBe(0);
1456
- expect(emg?.footprintHardExitBytes).toBe(0);
1457
- // With the tier ON, a heap verdict still carries the configured budgets.
1458
- const g2 = governor({ minUptimeMs: 0 });
1459
- const emg2 = g2.sampleAt(0.95, PAST_FLOOR_MS).recycle;
1460
- expect(emg2?.footprintRecycleBytes).toBe(DEFAULT_HEAP_FOOTPRINT_RECYCLE_BYTES);
1461
- expect(emg2?.footprintHardExitBytes).toBe(DEFAULT_HEAP_FOOTPRINT_HARD_EXIT_BYTES);
1462
- });
1463
- it("honours a custom footprint budget and never fires just below it", () => {
1464
- const g = governor({ footprintRecycleBytes: 3000 * MB, footprintHardExitBytes: 4000 * MB, minUptimeMs: 0 });
1465
- g.setFootprint(2999 * MB, 10_000);
1466
- expect(g.controller.evaluate().recycle).toBeNull(); // 1 MB under the floor
1467
- g.setFootprint(3000 * MB, 20_000);
1468
- expect(g.controller.evaluate().recycle?.trigger).toBe("footprint"); // exactly the floor
1469
- });
1470
- it("a disabled footprint tier adds NO rss read, so a throwing memoryUsage never breaks a quiet-heap observation", () => {
1471
- // Regression: the kill switch must restore the exact prior observation path.
1472
- // With the tier off and a quiet heap (no verdict), evaluate()/observeMajorGc()
1473
- // must not touch memoryUsage() at all — so a throwing reader cannot swallow the
1474
- // observation before the heap tiers run.
1475
- const census = new HeapCensus();
1476
- census.register("x", () => 1);
1477
- let memReads = 0;
1478
- const readers = {
1479
- getHeapStatistics: () => ({
1480
- used_heap_size: Math.round(2048 * MB * 0.3), // quiet heap: no heap verdict
1481
- total_heap_size: 0,
1482
- heap_size_limit: 2048 * MB,
1483
- external_memory: 0,
1484
- }),
1485
- memoryUsage: () => {
1486
- memReads += 1;
1487
- throw new Error("memoryUsage boom");
1488
- },
1489
- monotonicNowMs: () => 30_000,
1490
- };
1491
- const controller = new RunnerHeapTelemetry({
1492
- readers,
1493
- census,
1494
- sessionStartedAtMs: 0,
1495
- pressureThresholdFraction: 0.75,
1496
- recycleMinUptimeMs: 0,
1497
- footprintRecycleEnabled: false,
1498
- });
1499
- expect(() => controller.evaluate()).not.toThrow();
1500
- expect(() => controller.observeMajorGc()).not.toThrow();
1501
- expect(controller.evaluate().recycle).toBeNull();
1502
- expect(controller.observeMajorGc().recycle).toBeNull();
1503
- expect(memReads).toBe(0); // the disabled tier read rss zero times
1504
- });
1505
- it("records the rss value that CROSSED the budget, not a later drifted re-read", () => {
1506
- // The decision reads rss once; the verdict sample re-reads memoryUsage a hair
1507
- // later. A reader whose rss drops between the two reads must not make the
1508
- // durable record claim an rss below the floor that triggered the hard exit.
1509
- const census = new HeapCensus();
1510
- census.register("x", () => 1);
1511
- const rssSequence = [5000 * MB, 100 * MB]; // decision sees 5000 (>= hard floor); re-read drifts to 100
1512
- let i = 0;
1513
- const readers = {
1514
- getHeapStatistics: () => ({
1515
- used_heap_size: Math.round(2048 * MB * 0.3), // quiet heap
1516
- total_heap_size: 0,
1517
- heap_size_limit: 2048 * MB,
1518
- external_memory: 0,
1519
- }),
1520
- memoryUsage: () => ({
1521
- rss: rssSequence[Math.min(i++, rssSequence.length - 1)],
1522
- heapTotal: 0,
1523
- heapUsed: 0,
1524
- external: 0,
1525
- arrayBuffers: 0,
1526
- }),
1527
- monotonicNowMs: () => 30_000,
1528
- };
1529
- const controller = new RunnerHeapTelemetry({
1530
- readers,
1531
- census,
1532
- sessionStartedAtMs: 0,
1533
- pressureThresholdFraction: 0.75,
1534
- recycleMinUptimeMs: 0,
1535
- });
1536
- const { hardExit } = controller.evaluate();
1537
- expect(hardExit?.trigger).toBe("footprint");
1538
- expect(hardExit?.reason).toBe("hard_fraction");
1539
- // Stamped with the checked 5000 MB, never the drifted 100 MB re-read.
1540
- expect(hardExit?.rssBytes).toBe(5000 * MB);
1541
- expect(hardExit?.rssBytes).toBeGreaterThanOrEqual(DEFAULT_HEAP_FOOTPRINT_HARD_EXIT_BYTES);
1542
- });
1543
- it("the footprint recycle stderr line matches NONE of hq-desktop-app's fatal markers", () => {
1544
- const DESKTOP_FATAL_MARKERS = [
1545
- "javascript heap out of memory",
1546
- "ineffective mark-compacts",
1547
- "fatal error",
1548
- "uncaught exception",
1549
- "unhandledrejection",
1550
- "panicked at",
1551
- "assertion failed",
1552
- "npm error ",
1553
- "npm err! ",
1554
- "enospc",
1555
- "permission denied",
1556
- "no such file or directory",
1557
- "command not found",
1558
- ];
1559
- const g = governor({ minUptimeMs: 0 });
1560
- g.setFootprint(4200 * MB, 30_000);
1561
- const line = heapRecycleStderrLine(g.controller.evaluate().recycle);
1562
- const lowered = line.toLowerCase();
1563
- for (const marker of DESKTOP_FATAL_MARKERS)
1564
- expect(lowered).not.toContain(marker);
1565
- expect(line.trimStart().startsWith("#")).toBe(false);
1566
- expect(line).toContain("trigger=footprint");
1567
- });
1568
- });
1569
- describe("startRunnerHeapSampling — footprint tier", () => {
1570
- it("drives a footprint cooperative recycle through the interval tick and swallows a throwing onRecycle", () => {
1571
- const census = new HeapCensus();
1572
- census.register("x", () => 1);
1573
- const { state, readers } = mutableReaders();
1574
- state.limit = 2048 * MB;
1575
- state.used = Math.round(state.limit * 0.3); // quiet heap
1576
- state.rss = 4300 * MB; // over the 4096 MB recycle floor, under the hard floor
1577
- const fake = fakeScheduler();
1578
- const recycles = [];
1579
- startRunnerHeapSampling({
1580
- readers,
1581
- census,
1582
- sessionStartedAtMs: 0,
1583
- pressureThresholdFraction: 0.99,
1584
- recycleMinUptimeMs: 0,
1585
- intervalMs: 60_000,
1586
- scheduler: fake.scheduler,
1587
- onSample: () => { },
1588
- onPressure: () => { },
1589
- onRecycle: (record) => {
1590
- recycles.push(record);
1591
- throw new Error("recycle emit boom"); // must be swallowed
1592
- },
1593
- log: () => { },
1594
- });
1595
- state.now = 30_000;
1596
- expect(() => fake.tick()).not.toThrow();
1597
- expect(recycles).toHaveLength(1);
1598
- expect(recycles[0].trigger).toBe("footprint");
1599
- });
1600
- it("delivers a footprint hard exit to onHardExit (never onRecycle)", () => {
1601
- const census = new HeapCensus();
1602
- census.register("x", () => 1);
1603
- const { state, readers } = mutableReaders();
1604
- state.limit = 2048 * MB;
1605
- state.used = Math.round(state.limit * 0.3); // quiet heap
1606
- state.rss = 5000 * MB; // over the 4864 MB hard floor
1607
- const fake = fakeScheduler();
1608
- const recycles = [];
1609
- const hardExits = [];
1610
- const handle = startRunnerHeapSampling({
1611
- readers,
1612
- census,
1613
- sessionStartedAtMs: 0,
1614
- pressureThresholdFraction: 0.99,
1615
- recycleMinUptimeMs: 0,
1616
- intervalMs: 60_000,
1617
- checkpointMs: 10,
1618
- scheduler: fake.scheduler,
1619
- onSample: () => { },
1620
- onPressure: () => { },
1621
- onRecycle: (record) => recycles.push(record),
1622
- onHardExit: (record) => hardExits.push(record),
1623
- log: () => { },
1624
- });
1625
- state.now = 0;
1626
- handle.maybeObserve();
1627
- expect(hardExits).toHaveLength(1);
1628
- expect(hardExits[0].trigger).toBe("footprint");
1629
- expect(hardExits[0].reason).toBe("hard_fraction");
1630
- expect(recycles).toHaveLength(0);
1631
- handle.stop();
1632
- });
1633
- it("the loop-top evaluate() fires the footprint tier when the interval timer never ticks", () => {
1634
- const census = new HeapCensus();
1635
- census.register("x", () => 1);
1636
- const { state, readers } = mutableReaders();
1637
- state.limit = 2048 * MB;
1638
- state.used = Math.round(state.limit * 0.3);
1639
- state.rss = 4300 * MB;
1640
- const fake = fakeScheduler();
1641
- const recycles = [];
1642
- const handle = startRunnerHeapSampling({
1643
- readers,
1644
- census,
1645
- sessionStartedAtMs: 0,
1646
- pressureThresholdFraction: 0.99,
1647
- recycleMinUptimeMs: 0,
1648
- intervalMs: 60_000,
1649
- scheduler: fake.scheduler,
1650
- onSample: () => { },
1651
- onPressure: () => { },
1652
- onRecycle: (record) => recycles.push(record),
1653
- log: () => { },
1654
- });
1655
- state.now = 30_000;
1656
- handle.evaluate(); // timer never ticked
1657
- expect(recycles).toHaveLength(1);
1658
- expect(recycles[0].trigger).toBe("footprint");
1659
- handle.stop();
1660
- });
1661
- it("a throwing memoryUsage reader degrades to silence on every path (never throws into a watch pass)", () => {
1662
- const census = new HeapCensus();
1663
- census.register("x", () => 1);
1664
- const readers = {
1665
- getHeapStatistics: () => ({
1666
- used_heap_size: 10,
1667
- total_heap_size: 20,
1668
- heap_size_limit: 2048 * MB,
1669
- external_memory: 0,
1670
- }),
1671
- memoryUsage: () => {
1672
- throw new Error("memoryUsage boom");
1673
- },
1674
- monotonicNowMs: () => 30_000,
1675
- };
1676
- const fake = fakeScheduler();
1677
- const gc = fakeGcObserver();
1678
- const handle = startRunnerHeapSampling({
1679
- readers,
1680
- census,
1681
- sessionStartedAtMs: 0,
1682
- pressureThresholdFraction: 0.99,
1683
- recycleMinUptimeMs: 0,
1684
- intervalMs: 60_000,
1685
- scheduler: fake.scheduler,
1686
- gcObserver: gc.observer,
1687
- onSample: () => { },
1688
- onPressure: () => { },
1689
- onRecycle: () => { },
1690
- onHardExit: () => { },
1691
- log: () => { },
1692
- });
1693
- expect(() => fake.tick()).not.toThrow();
1694
- expect(() => handle.evaluate()).not.toThrow();
1695
- expect(() => gc.fire()).not.toThrow();
1696
- handle.stop();
1697
- });
1698
- it("a footprint value in the record survives the LOCAL telemetry sanitizer as numbers only", async () => {
1699
- const g = governor({ minUptimeMs: 0 });
1700
- g.setFootprint(4300 * MB, 30_000);
1701
- const record = g.controller.evaluate().recycle;
1702
- const props = heapRecycleCloudProperties(record);
1703
- for (const value of Object.values(props))
1704
- expect(typeof value).toBe("number");
1705
- const captured = [];
1706
- const client = {
1707
- postTelemetryEvents: async (batch) => {
1708
- for (const event of batch.events)
1709
- captured.push(event);
1710
- return { accepted: batch.events.length };
1711
- },
1712
- };
1713
- await emitCloudTelemetry(client, {
1714
- eventName: "sync_runner_heap_recycle",
1715
- source: "sync-runner-heap",
1716
- properties: props,
1717
- });
1718
- const survived = captured[0]?.properties ?? {};
1719
- expect(survived.recycle_footprint_trigger_count).toBe(1);
1720
- expect(Object.keys(survived).length).toBe(Object.keys(props).length);
1721
- });
1722
- });
1723
- describe("resolve* parsers for the footprint knobs", () => {
1724
- it("resolveHeapFootprintRecycleEnabled: ON by default, disabled only by an explicit off value", () => {
1725
- expect(resolveHeapFootprintRecycleEnabled(undefined)).toBe(true);
1726
- expect(resolveHeapFootprintRecycleEnabled("")).toBe(true);
1727
- expect(resolveHeapFootprintRecycleEnabled("1")).toBe(true);
1728
- expect(resolveHeapFootprintRecycleEnabled("0")).toBe(false);
1729
- expect(resolveHeapFootprintRecycleEnabled("false")).toBe(false);
1730
- expect(resolveHeapFootprintRecycleEnabled(" OFF ")).toBe(false);
1731
- // A typo keeps the tier armed rather than silently disabling protection.
1732
- expect(resolveHeapFootprintRecycleEnabled("disabled")).toBe(true);
1733
- });
1734
- it("resolveHeapFootprintRecycleBytes: whole MB -> bytes, 4096 MB default, rejects a numeric prefix", () => {
1735
- expect(resolveHeapFootprintRecycleBytes("4096")).toBe(4096 * MB);
1736
- expect(resolveHeapFootprintRecycleBytes("1000")).toBe(1000 * MB);
1737
- expect(resolveHeapFootprintRecycleBytes(undefined)).toBe(DEFAULT_HEAP_FOOTPRINT_RECYCLE_BYTES);
1738
- expect(resolveHeapFootprintRecycleBytes("")).toBe(DEFAULT_HEAP_FOOTPRINT_RECYCLE_BYTES);
1739
- expect(resolveHeapFootprintRecycleBytes("0")).toBe(DEFAULT_HEAP_FOOTPRINT_RECYCLE_BYTES);
1740
- // A malformed value can NEVER silently lower the budget or disable the tier.
1741
- expect(resolveHeapFootprintRecycleBytes("4096x")).toBe(DEFAULT_HEAP_FOOTPRINT_RECYCLE_BYTES);
1742
- expect(resolveHeapFootprintRecycleBytes("4gb")).toBe(DEFAULT_HEAP_FOOTPRINT_RECYCLE_BYTES);
1743
- });
1744
- it("resolveHeapFootprintHardExitBytes: whole MB -> bytes, 4864 MB default, rejects garbage", () => {
1745
- expect(resolveHeapFootprintHardExitBytes("4864")).toBe(4864 * MB);
1746
- expect(resolveHeapFootprintHardExitBytes(undefined)).toBe(DEFAULT_HEAP_FOOTPRINT_HARD_EXIT_BYTES);
1747
- expect(resolveHeapFootprintHardExitBytes("0")).toBe(DEFAULT_HEAP_FOOTPRINT_HARD_EXIT_BYTES);
1748
- expect(resolveHeapFootprintHardExitBytes("4864x")).toBe(DEFAULT_HEAP_FOOTPRINT_HARD_EXIT_BYTES);
1749
- });
1750
- });
1751
- describe("startRunnerHeapSampling — work-driven checkpoint gate", () => {
1752
- function pinnedHandle(overrides) {
1753
- const census = new HeapCensus();
1754
- census.register("x", () => 1);
1755
- const { state, readers } = mutableReaders();
1756
- state.limit = 2048 * MB;
1757
- state.used = Math.round(state.limit * 0.85); // pinned range
1758
- const fake = fakeScheduler();
1759
- const recs = [];
1760
- const handle = startRunnerHeapSampling({
1761
- readers,
1762
- census,
1763
- sessionStartedAtMs: 0,
1764
- pressureThresholdFraction: 0.99,
1765
- recyclePinnedFraction: 0.84,
1766
- recyclePinnedSustainWindowMs: 0, // any two gated observations suffice
1767
- recycleMinUptimeMs: 0,
1768
- intervalMs: 60_000,
1769
- checkpointMs: overrides.checkpointMs,
1770
- scheduler: fake.scheduler,
1771
- onSample: () => { },
1772
- onPressure: () => { },
1773
- onRecycle: (record, counters) => recs.push({ record, counters }),
1774
- log: () => { },
1775
- });
1776
- return { state, handle, recs };
1777
- }
1778
- it("observes only when the gate is open (>= checkpointMs since the last observation)", () => {
1779
- const { state, handle, recs } = pinnedHandle({ checkpointMs: 100 });
1780
- state.now = 0;
1781
- handle.maybeObserve(); // first checkpoint: no prior observation -> observes (pinned count 1)
1782
- state.now = 50;
1783
- handle.maybeObserve(); // 50 < 100 -> below the gate, no observation
1784
- state.now = 150;
1785
- handle.maybeObserve(); // 150 >= 100 -> observes (pinned count 2 -> recycle)
1786
- expect(recs).toHaveLength(1);
1787
- expect(recs[0].record.trigger).toBe("pinned");
1788
- // Exactly two checkpoint observations (the 50 ms one was gated out); the 60 s
1789
- // interval timer never ticked, proving the feed was work-driven, not the timer.
1790
- expect(recs[0].counters.heapCheckpointObservationsCount).toBe(2);
1791
- expect(recs[0].counters.heapIntervalObservationsCount).toBe(0);
1792
- expect(recs[0].counters.msSincePreviousObservationMs).toBe(150);
1793
- });
1794
- it("checkpointMs=0 disables the work-driven checkpoint but keeps the loop-top evaluate()", () => {
1795
- const { state, handle, recs } = pinnedHandle({ checkpointMs: 0 });
1796
- state.now = 0;
1797
- handle.maybeObserve();
1798
- state.now = 100_000;
1799
- handle.maybeObserve(); // both disabled -> never observes
1800
- expect(recs).toHaveLength(0);
1801
- // The loop-top evaluate() is ungated and still works with checkpoints off.
1802
- state.used = Math.round(2048 * MB * 0.96); // hard-fraction range
1803
- // ... but this handle has no onHardExit, so route through a recycle instead:
1804
- state.used = Math.round(2048 * MB * 0.92); // emergency cooperative
1805
- state.now = 200_000;
1806
- handle.evaluate();
1807
- expect(recs).toHaveLength(1);
1808
- expect(recs[0].record.trigger).toBe("emergency");
1809
- });
1810
- it("delivers a hard exit to onHardExit (never onRecycle) and preempts the cooperative verdict", () => {
1811
- const census = new HeapCensus();
1812
- census.register("x", () => 1);
1813
- const { state, readers } = mutableReaders();
1814
- state.limit = 2048 * MB;
1815
- state.used = Math.round(state.limit * 0.96); // hard-fraction range
1816
- const fake = fakeScheduler();
1817
- const recycles = [];
1818
- const hardExits = [];
1819
- const handle = startRunnerHeapSampling({
1820
- readers,
1821
- census,
1822
- sessionStartedAtMs: 0,
1823
- pressureThresholdFraction: 0.99,
1824
- recycleMinUptimeMs: 0,
1825
- intervalMs: 60_000,
1826
- checkpointMs: 10,
1827
- scheduler: fake.scheduler,
1828
- onSample: () => { },
1829
- onPressure: () => { },
1830
- onRecycle: (record) => recycles.push(record),
1831
- onHardExit: (record) => hardExits.push(record),
1832
- log: () => { },
1833
- });
1834
- state.now = 0;
1835
- handle.maybeObserve();
1836
- expect(hardExits).toHaveLength(1);
1837
- expect(hardExits[0].reason).toBe("hard_fraction");
1838
- expect(recycles).toHaveLength(0);
1839
- handle.stop();
1840
- });
1841
- });
1842
- describe("performHeapHardExit", () => {
1843
- function hardFractionRecord() {
1844
- const record = governor({ minUptimeMs: 0 }).sampleAt(0.96, 10_000).hardExit;
1845
- expect(record).not.toBeNull();
1846
- return record;
1847
- }
1848
- it("writes the NDJSON record to stdout, then the marker to stderr, then exits — in that order", () => {
1849
- const calls = [];
1850
- performHeapHardExit(hardFractionRecord(), {
1851
- writeStdout: (line) => calls.push(`out:${line}`),
1852
- writeStderr: (line) => calls.push(`err:${line}`),
1853
- exit: (code) => calls.push(`exit:${code}`),
1854
- }, 1);
1855
- expect(calls).toHaveLength(3);
1856
- expect(calls[0]).toContain("out:");
1857
- expect(calls[0]).toContain('"type":"heap-recycle"');
1858
- expect(calls[0]).toContain('"reason":"hard_fraction"');
1859
- expect(calls[1]).toContain("err:");
1860
- expect(calls[1]).toContain("hq-sync-runner: heap-recycle");
1861
- expect(calls[2]).toBe("exit:1");
1862
- });
1863
- it("still exits even if BOTH stream writes throw (a closed/blocked pipe)", () => {
1864
- let exited = -1;
1865
- performHeapHardExit(hardFractionRecord(), {
1866
- writeStdout: () => {
1867
- throw new Error("EPIPE");
1868
- },
1869
- writeStderr: () => {
1870
- throw new Error("EPIPE");
1871
- },
1872
- exit: (code) => {
1873
- exited = code;
1874
- },
1875
- }, 1);
1876
- expect(exited).toBe(1);
1877
- });
1878
- it("the hard-exit stderr marker matches NONE of hq-desktop-app's fatal classifiers (both hard reasons)", () => {
1879
- const DESKTOP_FATAL_MARKERS = [
1880
- "javascript heap out of memory",
1881
- "ineffective mark-compacts",
1882
- "fatal error",
1883
- "uncaught exception",
1884
- "unhandledrejection",
1885
- "panicked at",
1886
- "assertion failed",
1887
- "npm error ",
1888
- "npm err! ",
1889
- "enospc",
1890
- "permission denied",
1891
- "no such file or directory",
1892
- "command not found",
1893
- ];
1894
- const hardFraction = hardFractionRecord();
1895
- const latch = (() => {
1896
- const g = governor({ minUptimeMs: 0, latchHardExitMs: 0, latchHardExitObservations: 1_000_000 });
1897
- g.evaluateFullAt(0.92, 0);
1898
- return g.evaluateFullAt(0.7, 1).hardExit;
1899
- })();
1900
- for (const record of [hardFraction, latch]) {
1901
- const line = heapRecycleStderrLine(record).toLowerCase();
1902
- for (const marker of DESKTOP_FATAL_MARKERS) {
1903
- expect(line, `reason ${record.reason} must not contain "${marker}"`).not.toContain(marker);
1904
- }
1905
- expect(line.trimStart().startsWith("#")).toBe(false);
1906
- expect(line).toContain("hq-sync-runner: heap-recycle");
1907
- }
1908
- expect(heapRecycleStderrLine(hardFraction)).toContain("reason=hard_fraction");
1909
- expect(heapRecycleStderrLine(latch)).toContain("reason=latch_timeout");
1910
- });
1911
- });
1912
- describe("resolveDeclaredHeapCeilingBytes", () => {
1913
- const MBb = 1024 * 1024;
1914
- it("parses --max-old-space-size from execArgv in both forms, last occurrence wins", () => {
1915
- expect(resolveDeclaredHeapCeilingBytes(["--max-old-space-size=2048"], undefined)).toBe(2048 * MBb);
1916
- expect(resolveDeclaredHeapCeilingBytes(["--max-old-space-size", "2048"], undefined)).toBe(2048 * MBb);
1917
- expect(resolveDeclaredHeapCeilingBytes(["--max-old-space-size=1024", "--max-old-space-size=2048"], undefined)).toBe(2048 * MBb);
1918
- expect(resolveDeclaredHeapCeilingBytes(["--max_old_space_size=2048"], undefined)).toBe(2048 * MBb);
1919
- });
1920
- it("falls back to NODE_OPTIONS only when execArgv has none, honours one pair of quotes, execArgv wins", () => {
1921
- expect(resolveDeclaredHeapCeilingBytes([], "--max-old-space-size=2048")).toBe(2048 * MBb);
1922
- expect(resolveDeclaredHeapCeilingBytes([], '--max-old-space-size="2048"')).toBe(2048 * MBb);
1923
- expect(resolveDeclaredHeapCeilingBytes(["--max-old-space-size=4096"], "--max-old-space-size=2048")).toBe(4096 * MBb);
1924
- });
1925
- it("returns null on absent/garbage/zero so the governor falls back to the reported limit", () => {
1926
- expect(resolveDeclaredHeapCeilingBytes([], undefined)).toBeNull();
1927
- expect(resolveDeclaredHeapCeilingBytes(["--max-old-space-size=abc"], undefined)).toBeNull();
1928
- expect(resolveDeclaredHeapCeilingBytes(["--max-old-space-size=0"], undefined)).toBeNull();
1929
- expect(resolveDeclaredHeapCeilingBytes(["--other=5"], " ")).toBeNull();
1930
- });
1931
- });
1932
- describe("resolve* parsers for the new governor knobs", () => {
1933
- it("resolveHeapCheckpointMs: 250 default, 0 valid (disables), rejects '250x'", () => {
1934
- expect(resolveHeapCheckpointMs("250")).toBe(250);
1935
- expect(resolveHeapCheckpointMs("0")).toBe(0);
1936
- expect(resolveHeapCheckpointMs(undefined)).toBe(DEFAULT_HEAP_CHECKPOINT_MS);
1937
- expect(resolveHeapCheckpointMs("250x")).toBe(DEFAULT_HEAP_CHECKPOINT_MS);
1938
- expect(resolveHeapCheckpointMs("-1")).toBe(DEFAULT_HEAP_CHECKPOINT_MS);
1939
- });
1940
- it("resolveHeapPinnedFraction: 0.84 default, out-of-range/garbage falls back", () => {
1941
- expect(resolveHeapPinnedFraction("0.84")).toBe(0.84);
1942
- expect(resolveHeapPinnedFraction("1")).toBe(1);
1943
- expect(resolveHeapPinnedFraction(undefined)).toBe(DEFAULT_HEAP_PINNED_FRACTION);
1944
- expect(resolveHeapPinnedFraction("2")).toBe(DEFAULT_HEAP_PINNED_FRACTION);
1945
- expect(resolveHeapPinnedFraction("0.84x")).toBe(DEFAULT_HEAP_PINNED_FRACTION);
1946
- });
1947
- it("resolveHeapPinnedSustainMs: 20000 default, 0 valid, rejects '20s'", () => {
1948
- expect(resolveHeapPinnedSustainMs("20000")).toBe(20_000);
1949
- expect(resolveHeapPinnedSustainMs("0")).toBe(0);
1950
- expect(resolveHeapPinnedSustainMs(undefined)).toBe(DEFAULT_HEAP_PINNED_SUSTAIN_MS);
1951
- expect(resolveHeapPinnedSustainMs("20s")).toBe(DEFAULT_HEAP_PINNED_SUSTAIN_MS);
1952
- });
1953
- it("resolveHeapHardExitFraction: 0.955 default, out-of-range/garbage falls back", () => {
1954
- expect(resolveHeapHardExitFraction("0.955")).toBe(0.955);
1955
- expect(resolveHeapHardExitFraction(undefined)).toBe(DEFAULT_HEAP_HARD_EXIT_FRACTION);
1956
- expect(resolveHeapHardExitFraction("2")).toBe(DEFAULT_HEAP_HARD_EXIT_FRACTION);
1957
- expect(resolveHeapHardExitFraction("0.955x")).toBe(DEFAULT_HEAP_HARD_EXIT_FRACTION);
1958
- });
1959
- it("resolveHeapRecycleLatchHardExitMs: 60000 default, 0 valid, rejects '60s'", () => {
1960
- expect(resolveHeapRecycleLatchHardExitMs("60000")).toBe(60_000);
1961
- expect(resolveHeapRecycleLatchHardExitMs("0")).toBe(0);
1962
- expect(resolveHeapRecycleLatchHardExitMs(undefined)).toBe(DEFAULT_HEAP_RECYCLE_LATCH_HARD_EXIT_MS);
1963
- expect(resolveHeapRecycleLatchHardExitMs("60s")).toBe(DEFAULT_HEAP_RECYCLE_LATCH_HARD_EXIT_MS);
1964
- });
1965
- });
1966
- //# sourceMappingURL=sync-runner-heap-telemetry.test.js.map