@quickchatai/quickreview 0.0.0-stage → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (1443) hide show
  1. package/LICENSE +23 -0
  2. package/README.md +385 -2
  3. package/THIRD-PARTY-NOTICES.md +134 -0
  4. package/agents/pass-abstraction.md +64 -0
  5. package/agents/pass-ask-human.md +134 -0
  6. package/agents/pass-backcompat.md +67 -0
  7. package/agents/pass-baseline.md +61 -0
  8. package/agents/pass-behaviour-delta.md +64 -0
  9. package/agents/pass-bounds.md +36 -0
  10. package/agents/pass-claims.md +31 -0
  11. package/agents/pass-concurrency.md +168 -0
  12. package/agents/pass-consistency.md +57 -0
  13. package/agents/pass-contracts.md +30 -0
  14. package/agents/pass-data-safety.md +54 -0
  15. package/agents/pass-deferred.md +35 -0
  16. package/agents/pass-delivery.md +37 -0
  17. package/agents/pass-duplication.md +60 -0
  18. package/agents/pass-intent.md +63 -0
  19. package/agents/pass-lint-conformance.md +46 -0
  20. package/agents/pass-maintainability.md +67 -0
  21. package/agents/pass-placement.md +68 -0
  22. package/agents/pass-prod-risk.md +24 -0
  23. package/agents/pass-rollout.md +32 -0
  24. package/agents/pass-roundtrip.md +46 -0
  25. package/agents/pass-security.md +31 -0
  26. package/agents/pass-simplicity.md +68 -0
  27. package/agents/pass-statelessness.md +27 -0
  28. package/agents/pass-style.md +37 -0
  29. package/agents/pass-sweep.md +57 -0
  30. package/agents/pass-tests.md +58 -0
  31. package/agents/pass-ui.md +23 -0
  32. package/agents/pass-validate.md +50 -0
  33. package/agents/pass-widened.md +46 -0
  34. package/agents/scan/pass-scan.md +86 -0
  35. package/bin/qcr.js +11 -0
  36. package/config.example.toml +1067 -0
  37. package/deploy/ansible/README.md +356 -0
  38. package/deploy/ansible/group_vars/all.yml +212 -0
  39. package/deploy/ansible/inventory.example.ini +25 -0
  40. package/deploy/ansible/playbook.yml +360 -0
  41. package/deploy/collect-secrets.sh +289 -0
  42. package/deploy/collect-slack-secrets.mjs +1190 -0
  43. package/deploy/github-app-manifest.json +31 -0
  44. package/deploy/manifest.schema.json +75 -0
  45. package/deploy/qcr-update.sh +803 -0
  46. package/deploy/reviewer/AGENTS.override.md +12 -0
  47. package/dist/extensions/cli/bash-guard-ambient.js +42 -0
  48. package/dist/extensions/cli/bash-guard-ambient.js.map +1 -0
  49. package/dist/extensions/cli/bash-guard.js +5 -0
  50. package/dist/extensions/cli/bash-guard.js.map +1 -0
  51. package/dist/extensions/cli/companion-guard.js +5 -0
  52. package/dist/extensions/cli/companion-guard.js.map +1 -0
  53. package/dist/extensions/cli/debug-round.js +8 -0
  54. package/dist/extensions/cli/debug-round.js.map +1 -0
  55. package/dist/extensions/cli/inject-bridge.js +5 -0
  56. package/dist/extensions/cli/inject-bridge.js.map +1 -0
  57. package/dist/extensions/cli/ledger-pin.js +5 -0
  58. package/dist/extensions/cli/ledger-pin.js.map +1 -0
  59. package/dist/extensions/cli/lens.js +13 -0
  60. package/dist/extensions/cli/lens.js.map +1 -0
  61. package/dist/extensions/cli/muted-theme.js +5 -0
  62. package/dist/extensions/cli/muted-theme.js.map +1 -0
  63. package/dist/extensions/cli/onboarding.js +5 -0
  64. package/dist/extensions/cli/onboarding.js.map +1 -0
  65. package/dist/extensions/cli/setup.js +5 -0
  66. package/dist/extensions/cli/setup.js.map +1 -0
  67. package/dist/extensions/cli/tui-view.js +5 -0
  68. package/dist/extensions/cli/tui-view.js.map +1 -0
  69. package/dist/extensions/companion-guard.js +361 -0
  70. package/dist/extensions/companion-guard.js.map +1 -0
  71. package/dist/extensions/debug-round.js +204 -0
  72. package/dist/extensions/debug-round.js.map +1 -0
  73. package/dist/extensions/inject-bridge.js +603 -0
  74. package/dist/extensions/inject-bridge.js.map +1 -0
  75. package/dist/extensions/muted-theme.js +12 -0
  76. package/dist/extensions/muted-theme.js.map +1 -0
  77. package/dist/extensions/onboarding.js +175 -0
  78. package/dist/extensions/onboarding.js.map +1 -0
  79. package/dist/extensions/setup-replay.js +269 -0
  80. package/dist/extensions/setup-replay.js.map +1 -0
  81. package/dist/extensions/setup-scan.js +998 -0
  82. package/dist/extensions/setup-scan.js.map +1 -0
  83. package/dist/extensions/setup-triage.js +175 -0
  84. package/dist/extensions/setup-triage.js.map +1 -0
  85. package/dist/extensions/setup.js +1160 -0
  86. package/dist/extensions/setup.js.map +1 -0
  87. package/dist/extensions/tui-view.js +389 -0
  88. package/dist/extensions/tui-view.js.map +1 -0
  89. package/dist/extensions/vendor/openviking-pi/client.js +376 -0
  90. package/dist/extensions/vendor/openviking-pi/client.js.map +1 -0
  91. package/dist/extensions/vendor/openviking-pi/config.js +189 -0
  92. package/dist/extensions/vendor/openviking-pi/config.js.map +1 -0
  93. package/dist/extensions/vendor/openviking-pi/index.js +421 -0
  94. package/dist/extensions/vendor/openviking-pi/index.js.map +1 -0
  95. package/dist/extensions/vendor/openviking-pi/lib/capture-adapter.mjs +86 -0
  96. package/dist/extensions/vendor/openviking-pi/lib/capture-adapter.mjs.map +1 -0
  97. package/dist/extensions/vendor/openviking-pi/lib/takeover-core.mjs +408 -0
  98. package/dist/extensions/vendor/openviking-pi/lib/takeover-core.mjs.map +1 -0
  99. package/dist/extensions/vendor/openviking-pi/lib/uri-guard-adapter.mjs +41 -0
  100. package/dist/extensions/vendor/openviking-pi/lib/uri-guard-adapter.mjs.map +1 -0
  101. package/dist/extensions/vendor/openviking-pi/qcr-hint.js +290 -0
  102. package/dist/extensions/vendor/openviking-pi/qcr-hint.js.map +1 -0
  103. package/dist/extensions/vendor/openviking-pi/qcr-honest.js +148 -0
  104. package/dist/extensions/vendor/openviking-pi/qcr-honest.js.map +1 -0
  105. package/dist/extensions/vendor/openviking-pi/qcr-hooks.js +68 -0
  106. package/dist/extensions/vendor/openviking-pi/qcr-hooks.js.map +1 -0
  107. package/dist/extensions/vendor/openviking-pi/qcr-leaf.js +77 -0
  108. package/dist/extensions/vendor/openviking-pi/qcr-leaf.js.map +1 -0
  109. package/dist/extensions/vendor/openviking-pi/qcr-lesson.js +216 -0
  110. package/dist/extensions/vendor/openviking-pi/qcr-lesson.js.map +1 -0
  111. package/dist/extensions/vendor/openviking-pi/qcr-namespaces.js +154 -0
  112. package/dist/extensions/vendor/openviking-pi/qcr-namespaces.js.map +1 -0
  113. package/dist/extensions/vendor/openviking-pi/qcr-recall.js +254 -0
  114. package/dist/extensions/vendor/openviking-pi/qcr-recall.js.map +1 -0
  115. package/dist/extensions/vendor/openviking-pi/qcr-shim.js +94 -0
  116. package/dist/extensions/vendor/openviking-pi/qcr-shim.js.map +1 -0
  117. package/dist/extensions/vendor/openviking-pi/qcr-write.js +333 -0
  118. package/dist/extensions/vendor/openviking-pi/qcr-write.js.map +1 -0
  119. package/dist/extensions/vendor/openviking-pi/recall.js +108 -0
  120. package/dist/extensions/vendor/openviking-pi/recall.js.map +1 -0
  121. package/dist/extensions/vendor/openviking-pi/shared/capture-utils.mjs +529 -0
  122. package/dist/extensions/vendor/openviking-pi/shared/capture-utils.mjs.map +1 -0
  123. package/dist/extensions/vendor/openviking-pi/shared/credentials.mjs +205 -0
  124. package/dist/extensions/vendor/openviking-pi/shared/credentials.mjs.map +1 -0
  125. package/dist/extensions/vendor/openviking-pi/shared/pending-queue.mjs +442 -0
  126. package/dist/extensions/vendor/openviking-pi/shared/pending-queue.mjs.map +1 -0
  127. package/dist/extensions/vendor/openviking-pi/shared/profile-inject.mjs +286 -0
  128. package/dist/extensions/vendor/openviking-pi/shared/profile-inject.mjs.map +1 -0
  129. package/dist/extensions/vendor/openviking-pi/shared/recall-compress-core.mjs +189 -0
  130. package/dist/extensions/vendor/openviking-pi/shared/recall-compress-core.mjs.map +1 -0
  131. package/dist/extensions/vendor/openviking-pi/shared/recall-core.mjs +580 -0
  132. package/dist/extensions/vendor/openviking-pi/shared/recall-core.mjs.map +1 -0
  133. package/dist/extensions/vendor/openviking-pi/shared/retryable.mjs +11 -0
  134. package/dist/extensions/vendor/openviking-pi/shared/retryable.mjs.map +1 -0
  135. package/dist/extensions/vendor/openviking-pi/shared/session-model.mjs +63 -0
  136. package/dist/extensions/vendor/openviking-pi/shared/session-model.mjs.map +1 -0
  137. package/dist/extensions/vendor/openviking-pi/shared/uri-guard.mjs +58 -0
  138. package/dist/extensions/vendor/openviking-pi/shared/uri-guard.mjs.map +1 -0
  139. package/dist/extensions/vendor/openviking-pi/shared/workspace-peer.mjs +16 -0
  140. package/dist/extensions/vendor/openviking-pi/shared/workspace-peer.mjs.map +1 -0
  141. package/dist/extensions/vendor/openviking-pi/sync.js +127 -0
  142. package/dist/extensions/vendor/openviking-pi/sync.js.map +1 -0
  143. package/dist/extensions/vendor/openviking-pi/takeover.js +25 -0
  144. package/dist/extensions/vendor/openviking-pi/takeover.js.map +1 -0
  145. package/dist/extensions/vendor/openviking-pi/tools.js +417 -0
  146. package/dist/extensions/vendor/openviking-pi/tools.js.map +1 -0
  147. package/dist/src/anomalies.js +483 -0
  148. package/dist/src/anomalies.js.map +1 -0
  149. package/dist/src/answerworker.js +180 -0
  150. package/dist/src/answerworker.js.map +1 -0
  151. package/dist/src/appstamp.js +68 -0
  152. package/dist/src/appstamp.js.map +1 -0
  153. package/dist/src/archive/admission.js +3 -0
  154. package/dist/src/archive/admission.js.map +1 -0
  155. package/dist/src/archive/archivedb.js +474 -0
  156. package/dist/src/archive/archivedb.js.map +1 -0
  157. package/dist/src/archive/archiver.js +1770 -0
  158. package/dist/src/archive/archiver.js.map +1 -0
  159. package/dist/src/archive/archivewrite.js +198 -0
  160. package/dist/src/archive/archivewrite.js.map +1 -0
  161. package/dist/src/archive/bundle.js +266 -0
  162. package/dist/src/archive/bundle.js.map +1 -0
  163. package/dist/src/archive/dbmove.js +638 -0
  164. package/dist/src/archive/dbmove.js.map +1 -0
  165. package/dist/src/archive/duplicatecounts.js +80 -0
  166. package/dist/src/archive/duplicatecounts.js.map +1 -0
  167. package/dist/src/archive/eligibility.js +113 -0
  168. package/dist/src/archive/eligibility.js.map +1 -0
  169. package/dist/src/archive/extract.js +288 -0
  170. package/dist/src/archive/extract.js.map +1 -0
  171. package/dist/src/archive/fsutil.js +330 -0
  172. package/dist/src/archive/fsutil.js.map +1 -0
  173. package/dist/src/archive/gzfile.js +277 -0
  174. package/dist/src/archive/gzfile.js.map +1 -0
  175. package/dist/src/archive/kinds.js +22 -0
  176. package/dist/src/archive/kinds.js.map +1 -0
  177. package/dist/src/archive/livecheckpoint.js +178 -0
  178. package/dist/src/archive/livecheckpoint.js.map +1 -0
  179. package/dist/src/archive/liveretention.js +145 -0
  180. package/dist/src/archive/liveretention.js.map +1 -0
  181. package/dist/src/archive/manifest.js +284 -0
  182. package/dist/src/archive/manifest.js.map +1 -0
  183. package/dist/src/archive/overseer.js +283 -0
  184. package/dist/src/archive/overseer.js.map +1 -0
  185. package/dist/src/archive/piglobal.js +129 -0
  186. package/dist/src/archive/piglobal.js.map +1 -0
  187. package/dist/src/archive/plan.js +398 -0
  188. package/dist/src/archive/plan.js.map +1 -0
  189. package/dist/src/archive/prarchive.js +831 -0
  190. package/dist/src/archive/prarchive.js.map +1 -0
  191. package/dist/src/archive/prfiles.js +303 -0
  192. package/dist/src/archive/prfiles.js.map +1 -0
  193. package/dist/src/archive/report.js +169 -0
  194. package/dist/src/archive/report.js.map +1 -0
  195. package/dist/src/archive/restore.js +276 -0
  196. package/dist/src/archive/restore.js.map +1 -0
  197. package/dist/src/archive/rows.js +106 -0
  198. package/dist/src/archive/rows.js.map +1 -0
  199. package/dist/src/archive/seal.js +480 -0
  200. package/dist/src/archive/seal.js.map +1 -0
  201. package/dist/src/archive/status.js +528 -0
  202. package/dist/src/archive/status.js.map +1 -0
  203. package/dist/src/archive/storepass.js +409 -0
  204. package/dist/src/archive/storepass.js.map +1 -0
  205. package/dist/src/backfill.js +217 -0
  206. package/dist/src/backfill.js.map +1 -0
  207. package/dist/src/bench/cost.js +87 -0
  208. package/dist/src/bench/exec.js +76 -0
  209. package/dist/src/bench/values.js +14 -0
  210. package/dist/src/botcontrol.js +127 -0
  211. package/dist/src/botcontrol.js.map +1 -0
  212. package/dist/src/botworker.js +805 -0
  213. package/dist/src/botworker.js.map +1 -0
  214. package/dist/src/capture.js +234 -0
  215. package/dist/src/capture.js.map +1 -0
  216. package/dist/src/cases.js +1491 -0
  217. package/dist/src/cases.js.map +1 -0
  218. package/dist/src/channelfs.js +27 -0
  219. package/dist/src/channelfs.js.map +1 -0
  220. package/dist/src/checklist.js +312 -0
  221. package/dist/src/checklist.js.map +1 -0
  222. package/dist/src/ciretry.js +91 -0
  223. package/dist/src/ciretry.js.map +1 -0
  224. package/dist/src/cli.js +1916 -0
  225. package/dist/src/cli.js.map +1 -0
  226. package/dist/src/cliops.js +333 -0
  227. package/dist/src/cliops.js.map +1 -0
  228. package/dist/src/clonedir.js +15 -0
  229. package/dist/src/clonedir.js.map +1 -0
  230. package/dist/src/commandeffects.js +43 -0
  231. package/dist/src/commandeffects.js.map +1 -0
  232. package/dist/src/commands.js +1312 -0
  233. package/dist/src/commands.js.map +1 -0
  234. package/dist/src/companioninbox.js +203 -0
  235. package/dist/src/companioninbox.js.map +1 -0
  236. package/dist/src/compare.js +673 -0
  237. package/dist/src/compare.js.map +1 -0
  238. package/dist/src/config.js +1027 -0
  239. package/dist/src/config.js.map +1 -0
  240. package/dist/src/configcheck.js +111 -0
  241. package/dist/src/configcheck.js.map +1 -0
  242. package/dist/src/coreext.js +43 -0
  243. package/dist/src/coreext.js.map +1 -0
  244. package/dist/src/daemon.js +929 -0
  245. package/dist/src/daemon.js.map +1 -0
  246. package/dist/src/debuground.js +731 -0
  247. package/dist/src/debuground.js.map +1 -0
  248. package/dist/src/debugroundpi.js +219 -0
  249. package/dist/src/debugroundpi.js.map +1 -0
  250. package/dist/src/diagnostics.js +14 -0
  251. package/dist/src/diagnostics.js.map +1 -0
  252. package/dist/src/digest.js +139 -0
  253. package/dist/src/digest.js.map +1 -0
  254. package/dist/src/dispatch.js +1726 -0
  255. package/dist/src/dispatch.js.map +1 -0
  256. package/dist/src/engine/answerguard.js +18 -0
  257. package/dist/src/engine/answerguard.js.map +1 -0
  258. package/dist/src/engine/botsdk.js +262 -0
  259. package/dist/src/engine/botsdk.js.map +1 -0
  260. package/dist/src/engine/caserunner-sdk.js +332 -0
  261. package/dist/src/engine/caserunner-sdk.js.map +1 -0
  262. package/dist/src/engine/debugpi.js +194 -0
  263. package/dist/src/engine/debugpi.js.map +1 -0
  264. package/dist/src/eod.js +473 -0
  265. package/dist/src/eod.js.map +1 -0
  266. package/dist/src/eodpinwatch.js +391 -0
  267. package/dist/src/eodpinwatch.js.map +1 -0
  268. package/dist/src/escalation.js +1009 -0
  269. package/dist/src/escalation.js.map +1 -0
  270. package/dist/src/eventloop.js +779 -0
  271. package/dist/src/eventloop.js.map +1 -0
  272. package/dist/src/execboundary.js +430 -0
  273. package/dist/src/execboundary.js.map +1 -0
  274. package/dist/src/feedback.js +915 -0
  275. package/dist/src/feedback.js.map +1 -0
  276. package/dist/src/findingscheck.js +200 -0
  277. package/dist/src/findingscheck.js.map +1 -0
  278. package/dist/src/fsdenied.js +26 -0
  279. package/dist/src/fsdenied.js.map +1 -0
  280. package/dist/src/ghread.js +181 -0
  281. package/dist/src/ghread.js.map +1 -0
  282. package/dist/src/github.js +1063 -0
  283. package/dist/src/github.js.map +1 -0
  284. package/dist/src/homes.js +103 -0
  285. package/dist/src/homes.js.map +1 -0
  286. package/dist/src/hostroute.js +24 -0
  287. package/dist/src/hostroute.js.map +1 -0
  288. package/dist/src/improvements.js +625 -0
  289. package/dist/src/improvements.js.map +1 -0
  290. package/dist/src/install.js +946 -0
  291. package/dist/src/install.js.map +1 -0
  292. package/dist/src/installkind.js +40 -0
  293. package/dist/src/installkind.js.map +1 -0
  294. package/dist/src/ipc/capability.js +286 -0
  295. package/dist/src/ipc/capability.js.map +1 -0
  296. package/dist/src/ipc/client.js +226 -0
  297. package/dist/src/ipc/client.js.map +1 -0
  298. package/dist/src/ipc/control.js +70 -0
  299. package/dist/src/ipc/control.js.map +1 -0
  300. package/dist/src/ipc/ghreadshim.js +77 -0
  301. package/dist/src/ipc/ghreadshim.js.map +1 -0
  302. package/dist/src/ipc/launcher.js +65 -0
  303. package/dist/src/ipc/launcher.js.map +1 -0
  304. package/dist/src/ipc/permits.js +293 -0
  305. package/dist/src/ipc/permits.js.map +1 -0
  306. package/dist/src/ipc/postshim.js +137 -0
  307. package/dist/src/ipc/postshim.js.map +1 -0
  308. package/dist/src/ipc/protocol.js +239 -0
  309. package/dist/src/ipc/protocol.js.map +1 -0
  310. package/dist/src/ipc/server.js +312 -0
  311. package/dist/src/ipc/server.js.map +1 -0
  312. package/dist/src/ipc/workerspec.js +148 -0
  313. package/dist/src/ipc/workerspec.js.map +1 -0
  314. package/dist/src/learner/learner.js +1272 -0
  315. package/dist/src/learner/learner.js.map +1 -0
  316. package/dist/src/learner/miner.js +948 -0
  317. package/dist/src/learner/miner.js.map +1 -0
  318. package/dist/src/learner/packet.js +216 -0
  319. package/dist/src/learner/packet.js.map +1 -0
  320. package/dist/src/learner/receipt.js +135 -0
  321. package/dist/src/learner/receipt.js.map +1 -0
  322. package/dist/src/learner/status.js +38 -0
  323. package/dist/src/learner/status.js.map +1 -0
  324. package/dist/src/ledgercheck.js +120 -0
  325. package/dist/src/ledgercheck.js.map +1 -0
  326. package/dist/src/lessonledger.js +451 -0
  327. package/dist/src/lessonledger.js.map +1 -0
  328. package/dist/src/lessonselect.js +639 -0
  329. package/dist/src/lessonselect.js.map +1 -0
  330. package/dist/src/lessonshadow.js +540 -0
  331. package/dist/src/lessonshadow.js.map +1 -0
  332. package/dist/src/levers.js +302 -0
  333. package/dist/src/levers.js.map +1 -0
  334. package/dist/src/live/projection.js +450 -0
  335. package/dist/src/live/projection.js.map +1 -0
  336. package/dist/src/live/publish.js +83 -0
  337. package/dist/src/live/publish.js.map +1 -0
  338. package/dist/src/live/read.js +60 -0
  339. package/dist/src/live/read.js.map +1 -0
  340. package/dist/src/livecli.js +288 -0
  341. package/dist/src/livecli.js.map +1 -0
  342. package/dist/src/loginhint.js +42 -0
  343. package/dist/src/loginhint.js.map +1 -0
  344. package/dist/src/loginrefresh/atomic.js +66 -0
  345. package/dist/src/loginrefresh/atomic.js.map +1 -0
  346. package/dist/src/loginrefresh/lock.js +93 -0
  347. package/dist/src/loginrefresh/lock.js.map +1 -0
  348. package/dist/src/loginrefresh/main.js +58 -0
  349. package/dist/src/loginrefresh/main.js.map +1 -0
  350. package/dist/src/loginrefresh/pirefresh.js +49 -0
  351. package/dist/src/loginrefresh/pirefresh.js.map +1 -0
  352. package/dist/src/loginrefresh/refresher.js +286 -0
  353. package/dist/src/loginrefresh/refresher.js.map +1 -0
  354. package/dist/src/loginrefresh/supervisor.js +253 -0
  355. package/dist/src/loginrefresh/supervisor.js.map +1 -0
  356. package/dist/src/loginrefresh/types.js +4 -0
  357. package/dist/src/loginrefresh/types.js.map +1 -0
  358. package/dist/src/memory/context.js +251 -0
  359. package/dist/src/memory/context.js.map +1 -0
  360. package/dist/src/memory/datafence.js +5 -0
  361. package/dist/src/memory/datafence.js.map +1 -0
  362. package/dist/src/memory/delivery.js +131 -0
  363. package/dist/src/memory/delivery.js.map +1 -0
  364. package/dist/src/memory/eventtags.js +81 -0
  365. package/dist/src/memory/eventtags.js.map +1 -0
  366. package/dist/src/memory/health.js +713 -0
  367. package/dist/src/memory/health.js.map +1 -0
  368. package/dist/src/memory/import.js +504 -0
  369. package/dist/src/memory/import.js.map +1 -0
  370. package/dist/src/memory/layout.js +252 -0
  371. package/dist/src/memory/layout.js.map +1 -0
  372. package/dist/src/memory/legacy-file.js +100 -0
  373. package/dist/src/memory/legacy-file.js.map +1 -0
  374. package/dist/src/memory/lessons.js +370 -0
  375. package/dist/src/memory/lessons.js.map +1 -0
  376. package/dist/src/memory/ovsession.js +449 -0
  377. package/dist/src/memory/ovsession.js.map +1 -0
  378. package/dist/src/memory/relayout.js +259 -0
  379. package/dist/src/memory/relayout.js.map +1 -0
  380. package/dist/src/memory/roundactivity.js +180 -0
  381. package/dist/src/memory/roundactivity.js.map +1 -0
  382. package/dist/src/memory/selection.js +690 -0
  383. package/dist/src/memory/selection.js.map +1 -0
  384. package/dist/src/memory/shadowstatus.js +69 -0
  385. package/dist/src/memory/shadowstatus.js.map +1 -0
  386. package/dist/src/memory/store.js +83 -0
  387. package/dist/src/memory/store.js.map +1 -0
  388. package/dist/src/memory/textidentity.js +8 -0
  389. package/dist/src/memory/textidentity.js.map +1 -0
  390. package/dist/src/metrics.js +773 -0
  391. package/dist/src/metrics.js.map +1 -0
  392. package/dist/src/missingconfig.js +8 -0
  393. package/dist/src/missingconfig.js.map +1 -0
  394. package/dist/src/npmverbs.js +226 -0
  395. package/dist/src/npmverbs.js.map +1 -0
  396. package/dist/src/onboard/choices.js +191 -0
  397. package/dist/src/onboard/choices.js.map +1 -0
  398. package/dist/src/onboard/engine.js +344 -0
  399. package/dist/src/onboard/engine.js.map +1 -0
  400. package/dist/src/onboard/launch.js +83 -0
  401. package/dist/src/onboard/launch.js.map +1 -0
  402. package/dist/src/onboard/steps/appslug.js +211 -0
  403. package/dist/src/onboard/steps/appslug.js.map +1 -0
  404. package/dist/src/onboard/steps/bringup.js +408 -0
  405. package/dist/src/onboard/steps/bringup.js.map +1 -0
  406. package/dist/src/onboard/steps/compose.js +343 -0
  407. package/dist/src/onboard/steps/compose.js.map +1 -0
  408. package/dist/src/onboard/steps/configdelivery.js +50 -0
  409. package/dist/src/onboard/steps/configdelivery.js.map +1 -0
  410. package/dist/src/onboard/steps/configfill.js +1148 -0
  411. package/dist/src/onboard/steps/configfill.js.map +1 -0
  412. package/dist/src/onboard/steps/deploysh.js +80 -0
  413. package/dist/src/onboard/steps/deploysh.js.map +1 -0
  414. package/dist/src/onboard/steps/embeddings.js +472 -0
  415. package/dist/src/onboard/steps/embeddings.js.map +1 -0
  416. package/dist/src/onboard/steps/escalation.js +571 -0
  417. package/dist/src/onboard/steps/escalation.js.map +1 -0
  418. package/dist/src/onboard/steps/githubapp.js +1092 -0
  419. package/dist/src/onboard/steps/githubapp.js.map +1 -0
  420. package/dist/src/onboard/steps/golive.js +506 -0
  421. package/dist/src/onboard/steps/golive.js.map +1 -0
  422. package/dist/src/onboard/steps/index.js +67 -0
  423. package/dist/src/onboard/steps/index.js.map +1 -0
  424. package/dist/src/onboard/steps/ingress.js +762 -0
  425. package/dist/src/onboard/steps/ingress.js.map +1 -0
  426. package/dist/src/onboard/steps/inventory.js +420 -0
  427. package/dist/src/onboard/steps/inventory.js.map +1 -0
  428. package/dist/src/onboard/steps/llmauth.js +893 -0
  429. package/dist/src/onboard/steps/llmauth.js.map +1 -0
  430. package/dist/src/onboard/steps/memory.js +1060 -0
  431. package/dist/src/onboard/steps/memory.js.map +1 -0
  432. package/dist/src/onboard/steps/memorykeys.js +43 -0
  433. package/dist/src/onboard/steps/memorykeys.js.map +1 -0
  434. package/dist/src/onboard/steps/preflight.js +172 -0
  435. package/dist/src/onboard/steps/preflight.js.map +1 -0
  436. package/dist/src/onboard/steps/proof.js +502 -0
  437. package/dist/src/onboard/steps/proof.js.map +1 -0
  438. package/dist/src/onboard/steps/ssh.js +300 -0
  439. package/dist/src/onboard/steps/ssh.js.map +1 -0
  440. package/dist/src/onboard/steps/topology.js +291 -0
  441. package/dist/src/onboard/steps/topology.js.map +1 -0
  442. package/dist/src/onboard/steps/transport.js +511 -0
  443. package/dist/src/onboard/steps/transport.js.map +1 -0
  444. package/dist/src/onboard/steps/verifyup.js +362 -0
  445. package/dist/src/onboard/steps/verifyup.js.map +1 -0
  446. package/dist/src/onboard/steps/vmdeploy.js +368 -0
  447. package/dist/src/onboard/steps/vmdeploy.js.map +1 -0
  448. package/dist/src/onboard/toml.js +53 -0
  449. package/dist/src/onboard/toml.js.map +1 -0
  450. package/dist/src/opencli.js +508 -0
  451. package/dist/src/opencli.js.map +1 -0
  452. package/dist/src/openpr.js +457 -0
  453. package/dist/src/openpr.js.map +1 -0
  454. package/dist/src/openviking/client.js +821 -0
  455. package/dist/src/openviking/client.js.map +1 -0
  456. package/dist/src/openviking/context.js +218 -0
  457. package/dist/src/openviking/context.js.map +1 -0
  458. package/dist/src/openviking/embedder.js +457 -0
  459. package/dist/src/openviking/embedder.js.map +1 -0
  460. package/dist/src/openviking/gapsink.js +38 -0
  461. package/dist/src/openviking/gapsink.js.map +1 -0
  462. package/dist/src/openviking/health.js +69 -0
  463. package/dist/src/openviking/health.js.map +1 -0
  464. package/dist/src/openviking/index.js +24 -0
  465. package/dist/src/openviking/index.js.map +1 -0
  466. package/dist/src/openviking/lessonfind.js +54 -0
  467. package/dist/src/openviking/lessonfind.js.map +1 -0
  468. package/dist/src/openviking/probe.js +89 -0
  469. package/dist/src/openviking/probe.js.map +1 -0
  470. package/dist/src/openviking/proc.js +95 -0
  471. package/dist/src/openviking/proc.js.map +1 -0
  472. package/dist/src/openviking/provisionreport.js +144 -0
  473. package/dist/src/openviking/provisionreport.js.map +1 -0
  474. package/dist/src/openviking/reembed.js +317 -0
  475. package/dist/src/openviking/reembed.js.map +1 -0
  476. package/dist/src/openviking/relayout.js +153 -0
  477. package/dist/src/openviking/relayout.js.map +1 -0
  478. package/dist/src/openviking/sidecar-main.js +39 -0
  479. package/dist/src/openviking/sidecar-main.js.map +1 -0
  480. package/dist/src/openviking/sidecar.js +79 -0
  481. package/dist/src/openviking/sidecar.js.map +1 -0
  482. package/dist/src/openviking/store.js +1758 -0
  483. package/dist/src/openviking/store.js.map +1 -0
  484. package/dist/src/openviking/supervisor.js +422 -0
  485. package/dist/src/openviking/supervisor.js.map +1 -0
  486. package/dist/src/openviking/types.js +5 -0
  487. package/dist/src/openviking/types.js.map +1 -0
  488. package/dist/src/operator-recovery.js +172 -0
  489. package/dist/src/operator-recovery.js.map +1 -0
  490. package/dist/src/operatormessage.js +44 -0
  491. package/dist/src/operatormessage.js.map +1 -0
  492. package/dist/src/outcomes.js +1361 -0
  493. package/dist/src/outcomes.js.map +1 -0
  494. package/dist/src/piauthcopy.js +5 -0
  495. package/dist/src/piauthcopy.js.map +1 -0
  496. package/dist/src/picli.js +45 -0
  497. package/dist/src/picli.js.map +1 -0
  498. package/dist/src/picwd.js +25 -0
  499. package/dist/src/picwd.js.map +1 -0
  500. package/dist/src/pilogin.js +35 -0
  501. package/dist/src/pilogin.js.map +1 -0
  502. package/dist/src/pingpong.js +1028 -0
  503. package/dist/src/pingpong.js.map +1 -0
  504. package/dist/src/posting-journal.js +441 -0
  505. package/dist/src/posting-journal.js.map +1 -0
  506. package/dist/src/posting-outbox.js +662 -0
  507. package/dist/src/posting-outbox.js.map +1 -0
  508. package/dist/src/posting-receipt.js +203 -0
  509. package/dist/src/posting-receipt.js.map +1 -0
  510. package/dist/src/posting.js +348 -0
  511. package/dist/src/posting.js.map +1 -0
  512. package/dist/src/postops.js +637 -0
  513. package/dist/src/postops.js.map +1 -0
  514. package/dist/src/pr-activity.js +11 -0
  515. package/dist/src/pr-activity.js.map +1 -0
  516. package/dist/src/pr-author.js +5 -0
  517. package/dist/src/pr-author.js.map +1 -0
  518. package/dist/src/pr-conversation.js +355 -0
  519. package/dist/src/pr-conversation.js.map +1 -0
  520. package/dist/src/pr-session-lifecycle.js +542 -0
  521. package/dist/src/pr-session-lifecycle.js.map +1 -0
  522. package/dist/src/preflight.js +341 -0
  523. package/dist/src/preflight.js.map +1 -0
  524. package/dist/src/priorresolve.js +275 -0
  525. package/dist/src/priorresolve.js.map +1 -0
  526. package/dist/src/qcrbin.js +180 -0
  527. package/dist/src/qcrbin.js.map +1 -0
  528. package/dist/src/recheck.js +1398 -0
  529. package/dist/src/recheck.js.map +1 -0
  530. package/dist/src/reconcile.js +820 -0
  531. package/dist/src/reconcile.js.map +1 -0
  532. package/dist/src/recordedfindings.js +15 -0
  533. package/dist/src/recordedfindings.js.map +1 -0
  534. package/dist/src/regression.js +546 -0
  535. package/dist/src/regression.js.map +1 -0
  536. package/dist/src/replay.js +598 -0
  537. package/dist/src/replay.js.map +1 -0
  538. package/dist/src/requiredpasses.js +113 -0
  539. package/dist/src/requiredpasses.js.map +1 -0
  540. package/dist/src/resumecheck.js +168 -0
  541. package/dist/src/resumecheck.js.map +1 -0
  542. package/dist/src/reviewcli.js +671 -0
  543. package/dist/src/reviewcli.js.map +1 -0
  544. package/dist/src/reviewcontext.js +22 -0
  545. package/dist/src/reviewcontext.js.map +1 -0
  546. package/dist/src/reviewdetach.js +574 -0
  547. package/dist/src/reviewdetach.js.map +1 -0
  548. package/dist/src/reviewhistory.js +284 -0
  549. package/dist/src/reviewhistory.js.map +1 -0
  550. package/dist/src/reviewhome.js +26 -0
  551. package/dist/src/reviewhome.js.map +1 -0
  552. package/dist/src/reviewmemory.js +110 -0
  553. package/dist/src/reviewmemory.js.map +1 -0
  554. package/dist/src/reviewrendercli.js +104 -0
  555. package/dist/src/reviewrendercli.js.map +1 -0
  556. package/dist/src/round-work.js +20 -0
  557. package/dist/src/round-work.js.map +1 -0
  558. package/dist/src/runhost.js +72 -0
  559. package/dist/src/runhost.js.map +1 -0
  560. package/dist/src/scanauth.js +25 -0
  561. package/dist/src/scanauth.js.map +1 -0
  562. package/dist/src/scanbox.js +846 -0
  563. package/dist/src/scanbox.js.map +1 -0
  564. package/dist/src/scancli.js +1074 -0
  565. package/dist/src/scancli.js.map +1 -0
  566. package/dist/src/scandriverlog.js +30 -0
  567. package/dist/src/scandriverlog.js.map +1 -0
  568. package/dist/src/session-bridge.js +75 -0
  569. package/dist/src/session-bridge.js.map +1 -0
  570. package/dist/src/session-command-payload.js +29 -0
  571. package/dist/src/session-command-payload.js.map +1 -0
  572. package/dist/src/session-command-supervisor.js +939 -0
  573. package/dist/src/session-command-supervisor.js.map +1 -0
  574. package/dist/src/sessionjsonl.js +85 -0
  575. package/dist/src/sessionjsonl.js.map +1 -0
  576. package/dist/src/sessions.js +541 -0
  577. package/dist/src/sessions.js.map +1 -0
  578. package/dist/src/setup/adapters.js +330 -0
  579. package/dist/src/setup/adapters.js.map +1 -0
  580. package/dist/src/setup/baselines.js +64 -0
  581. package/dist/src/setup/baselines.js.map +1 -0
  582. package/dist/src/setup/caserunner.js +554 -0
  583. package/dist/src/setup/caserunner.js.map +1 -0
  584. package/dist/src/setup/configcommit.js +358 -0
  585. package/dist/src/setup/configcommit.js.map +1 -0
  586. package/dist/src/setup/engine.js +672 -0
  587. package/dist/src/setup/engine.js.map +1 -0
  588. package/dist/src/setup/facts.js +593 -0
  589. package/dist/src/setup/facts.js.map +1 -0
  590. package/dist/src/setup/findings.js +948 -0
  591. package/dist/src/setup/findings.js.map +1 -0
  592. package/dist/src/setup/history.js +338 -0
  593. package/dist/src/setup/history.js.map +1 -0
  594. package/dist/src/setup/interview.js +185 -0
  595. package/dist/src/setup/interview.js.map +1 -0
  596. package/dist/src/setup/ledger.js +207 -0
  597. package/dist/src/setup/ledger.js.map +1 -0
  598. package/dist/src/setup/pins.js +43 -0
  599. package/dist/src/setup/pins.js.map +1 -0
  600. package/dist/src/setup/portrait.js +432 -0
  601. package/dist/src/setup/portrait.js.map +1 -0
  602. package/dist/src/setup/presentation.js +9 -0
  603. package/dist/src/setup/presentation.js.map +1 -0
  604. package/dist/src/setup/profile.js +417 -0
  605. package/dist/src/setup/profile.js.map +1 -0
  606. package/dist/src/setup/replay.js +240 -0
  607. package/dist/src/setup/replay.js.map +1 -0
  608. package/dist/src/setup/replaybuild.js +311 -0
  609. package/dist/src/setup/replaybuild.js.map +1 -0
  610. package/dist/src/setup/replayrun.js +806 -0
  611. package/dist/src/setup/replayrun.js.map +1 -0
  612. package/dist/src/setup/replaysource.js +169 -0
  613. package/dist/src/setup/replaysource.js.map +1 -0
  614. package/dist/src/setup/retune.js +333 -0
  615. package/dist/src/setup/retune.js.map +1 -0
  616. package/dist/src/setup/retunelog.js +51 -0
  617. package/dist/src/setup/retunelog.js.map +1 -0
  618. package/dist/src/setup/scan.js +725 -0
  619. package/dist/src/setup/scan.js.map +1 -0
  620. package/dist/src/setup/scanbuild.js +133 -0
  621. package/dist/src/setup/scanbuild.js.map +1 -0
  622. package/dist/src/setup/scanfacts.js +96 -0
  623. package/dist/src/setup/scanfacts.js.map +1 -0
  624. package/dist/src/setup/scanlease.js +251 -0
  625. package/dist/src/setup/scanlease.js.map +1 -0
  626. package/dist/src/setup/scanreport.js +289 -0
  627. package/dist/src/setup/scanreport.js.map +1 -0
  628. package/dist/src/setup/scanrun.js +1733 -0
  629. package/dist/src/setup/scanrun.js.map +1 -0
  630. package/dist/src/setup/scantree.js +257 -0
  631. package/dist/src/setup/scantree.js.map +1 -0
  632. package/dist/src/setup/stage2.js +617 -0
  633. package/dist/src/setup/stage2.js.map +1 -0
  634. package/dist/src/setup/stage2request.js +259 -0
  635. package/dist/src/setup/stage2request.js.map +1 -0
  636. package/dist/src/setup/survey.js +307 -0
  637. package/dist/src/setup/survey.js.map +1 -0
  638. package/dist/src/setup/surveyrun.js +549 -0
  639. package/dist/src/setup/surveyrun.js.map +1 -0
  640. package/dist/src/setup/textsniff.js +89 -0
  641. package/dist/src/setup/textsniff.js.map +1 -0
  642. package/dist/src/setup/trackersink.js +395 -0
  643. package/dist/src/setup/trackersink.js.map +1 -0
  644. package/dist/src/setup/triage.js +636 -0
  645. package/dist/src/setup/triage.js.map +1 -0
  646. package/dist/src/setup/tuning.js +585 -0
  647. package/dist/src/setup/tuning.js.map +1 -0
  648. package/dist/src/setup/unitcut.js +437 -0
  649. package/dist/src/setup/unitcut.js.map +1 -0
  650. package/dist/src/singleflight.js +72 -0
  651. package/dist/src/singleflight.js.map +1 -0
  652. package/dist/src/slack/announce.js +725 -0
  653. package/dist/src/slack/announce.js.map +1 -0
  654. package/dist/src/slack/api.js +227 -0
  655. package/dist/src/slack/api.js.map +1 -0
  656. package/dist/src/slack/messages.js +158 -0
  657. package/dist/src/slack/messages.js.map +1 -0
  658. package/dist/src/slack/origin.js +550 -0
  659. package/dist/src/slack/origin.js.map +1 -0
  660. package/dist/src/slack/policy.js +225 -0
  661. package/dist/src/slack/policy.js.map +1 -0
  662. package/dist/src/slack/reply.js +153 -0
  663. package/dist/src/slack/reply.js.map +1 -0
  664. package/dist/src/slack/router.js +189 -0
  665. package/dist/src/slack/router.js.map +1 -0
  666. package/dist/src/slack/socket.js +323 -0
  667. package/dist/src/slack/socket.js.map +1 -0
  668. package/dist/src/slack/types.js +11 -0
  669. package/dist/src/slack/types.js.map +1 -0
  670. package/dist/src/sqlitehint.js +30 -0
  671. package/dist/src/sqlitehint.js.map +1 -0
  672. package/dist/src/ssh-observation.js +25 -0
  673. package/dist/src/ssh-observation.js.map +1 -0
  674. package/dist/src/state.js +5869 -0
  675. package/dist/src/state.js.map +1 -0
  676. package/dist/src/statemachine.js +220 -0
  677. package/dist/src/statemachine.js.map +1 -0
  678. package/dist/src/stubs.js +52 -0
  679. package/dist/src/stubs.js.map +1 -0
  680. package/dist/src/takeover.js +506 -0
  681. package/dist/src/takeover.js.map +1 -0
  682. package/dist/src/takeoverpi.js +249 -0
  683. package/dist/src/takeoverpi.js.map +1 -0
  684. package/dist/src/terminal-failure.js +26 -0
  685. package/dist/src/terminal-failure.js.map +1 -0
  686. package/dist/src/thread-resolution-refusal.js +4 -0
  687. package/dist/src/thread-resolution-refusal.js.map +1 -0
  688. package/dist/src/tmux.js +126 -0
  689. package/dist/src/tmux.js.map +1 -0
  690. package/dist/src/trackerid.js +43 -0
  691. package/dist/src/trackerid.js.map +1 -0
  692. package/dist/src/transcriptindex.js +512 -0
  693. package/dist/src/transcriptindex.js.map +1 -0
  694. package/dist/src/tui/actions.js +404 -0
  695. package/dist/src/tui/actions.js.map +1 -0
  696. package/dist/src/tui/alerts.js +523 -0
  697. package/dist/src/tui/alerts.js.map +1 -0
  698. package/dist/src/tui/app.js +1835 -0
  699. package/dist/src/tui/app.js.map +1 -0
  700. package/dist/src/tui/archiveops.js +164 -0
  701. package/dist/src/tui/archiveops.js.map +1 -0
  702. package/dist/src/tui/autofile.js +191 -0
  703. package/dist/src/tui/autofile.js.map +1 -0
  704. package/dist/src/tui/board.js +1143 -0
  705. package/dist/src/tui/board.js.map +1 -0
  706. package/dist/src/tui/candidates.js +699 -0
  707. package/dist/src/tui/candidates.js.map +1 -0
  708. package/dist/src/tui/cellwidth.js +151 -0
  709. package/dist/src/tui/cellwidth.js.map +1 -0
  710. package/dist/src/tui/changelog-store.js +404 -0
  711. package/dist/src/tui/changelog-store.js.map +1 -0
  712. package/dist/src/tui/chord.js +26 -0
  713. package/dist/src/tui/chord.js.map +1 -0
  714. package/dist/src/tui/clipboard.js +81 -0
  715. package/dist/src/tui/clipboard.js.map +1 -0
  716. package/dist/src/tui/cmdbar.js +253 -0
  717. package/dist/src/tui/cmdbar.js.map +1 -0
  718. package/dist/src/tui/companion.js +1275 -0
  719. package/dist/src/tui/companion.js.map +1 -0
  720. package/dist/src/tui/companionplan.js +200 -0
  721. package/dist/src/tui/companionplan.js.map +1 -0
  722. package/dist/src/tui/companiontab.js +61 -0
  723. package/dist/src/tui/companiontab.js.map +1 -0
  724. package/dist/src/tui/confighome.js +105 -0
  725. package/dist/src/tui/confighome.js.map +1 -0
  726. package/dist/src/tui/connect.js +44 -0
  727. package/dist/src/tui/connect.js.map +1 -0
  728. package/dist/src/tui/deploy-ceremony.js +75 -0
  729. package/dist/src/tui/deploy-ceremony.js.map +1 -0
  730. package/dist/src/tui/deploy-drain.js +93 -0
  731. package/dist/src/tui/deploy-drain.js.map +1 -0
  732. package/dist/src/tui/deploy-process.js +234 -0
  733. package/dist/src/tui/deploy-process.js.map +1 -0
  734. package/dist/src/tui/deploytab.js +1263 -0
  735. package/dist/src/tui/deploytab.js.map +1 -0
  736. package/dist/src/tui/design.js +111 -0
  737. package/dist/src/tui/design.js.map +1 -0
  738. package/dist/src/tui/digesttab.js +148 -0
  739. package/dist/src/tui/digesttab.js.map +1 -0
  740. package/dist/src/tui/emptystate.js +32 -0
  741. package/dist/src/tui/emptystate.js.map +1 -0
  742. package/dist/src/tui/evidence.js +790 -0
  743. package/dist/src/tui/evidence.js.map +1 -0
  744. package/dist/src/tui/feed.js +415 -0
  745. package/dist/src/tui/feed.js.map +1 -0
  746. package/dist/src/tui/feedbacktab.js +907 -0
  747. package/dist/src/tui/feedbacktab.js.map +1 -0
  748. package/dist/src/tui/filters.js +72 -0
  749. package/dist/src/tui/filters.js.map +1 -0
  750. package/dist/src/tui/ghread.js +272 -0
  751. package/dist/src/tui/ghread.js.map +1 -0
  752. package/dist/src/tui/historypull.js +61 -0
  753. package/dist/src/tui/historypull.js.map +1 -0
  754. package/dist/src/tui/inboxpull.js +197 -0
  755. package/dist/src/tui/inboxpull.js.map +1 -0
  756. package/dist/src/tui/index.js +1425 -0
  757. package/dist/src/tui/index.js.map +1 -0
  758. package/dist/src/tui/issuesink.js +206 -0
  759. package/dist/src/tui/issuesink.js.map +1 -0
  760. package/dist/src/tui/jsonfile.js +32 -0
  761. package/dist/src/tui/jsonfile.js.map +1 -0
  762. package/dist/src/tui/keys.js +97 -0
  763. package/dist/src/tui/keys.js.map +1 -0
  764. package/dist/src/tui/layout.js +70 -0
  765. package/dist/src/tui/layout.js.map +1 -0
  766. package/dist/src/tui/learning.js +469 -0
  767. package/dist/src/tui/learning.js.map +1 -0
  768. package/dist/src/tui/lessonswitch.js +103 -0
  769. package/dist/src/tui/lessonswitch.js.map +1 -0
  770. package/dist/src/tui/livecontrol.js +167 -0
  771. package/dist/src/tui/livecontrol.js.map +1 -0
  772. package/dist/src/tui/memforward.js +310 -0
  773. package/dist/src/tui/memforward.js.map +1 -0
  774. package/dist/src/tui/memincident.js +287 -0
  775. package/dist/src/tui/memincident.js.map +1 -0
  776. package/dist/src/tui/memory.js +485 -0
  777. package/dist/src/tui/memory.js.map +1 -0
  778. package/dist/src/tui/memtab.js +513 -0
  779. package/dist/src/tui/memtab.js.map +1 -0
  780. package/dist/src/tui/metricstab.js +979 -0
  781. package/dist/src/tui/metricstab.js.map +1 -0
  782. package/dist/src/tui/model.js +104 -0
  783. package/dist/src/tui/model.js.map +1 -0
  784. package/dist/src/tui/mouse.js +83 -0
  785. package/dist/src/tui/mouse.js.map +1 -0
  786. package/dist/src/tui/msg.js +196 -0
  787. package/dist/src/tui/msg.js.map +1 -0
  788. package/dist/src/tui/nativecompanion.js +321 -0
  789. package/dist/src/tui/nativecompanion.js.map +1 -0
  790. package/dist/src/tui/openurl.js +17 -0
  791. package/dist/src/tui/openurl.js.map +1 -0
  792. package/dist/src/tui/paint.js +501 -0
  793. package/dist/src/tui/paint.js.map +1 -0
  794. package/dist/src/tui/panes.js +74 -0
  795. package/dist/src/tui/panes.js.map +1 -0
  796. package/dist/src/tui/pipane.js +166 -0
  797. package/dist/src/tui/pipane.js.map +1 -0
  798. package/dist/src/tui/poll-hooks.js +11 -0
  799. package/dist/src/tui/poll-hooks.js.map +1 -0
  800. package/dist/src/tui/poll.js +113 -0
  801. package/dist/src/tui/poll.js.map +1 -0
  802. package/dist/src/tui/proposals.js +715 -0
  803. package/dist/src/tui/proposals.js.map +1 -0
  804. package/dist/src/tui/prpause.js +132 -0
  805. package/dist/src/tui/prpause.js.map +1 -0
  806. package/dist/src/tui/reload.js +351 -0
  807. package/dist/src/tui/reload.js.map +1 -0
  808. package/dist/src/tui/remote.js +312 -0
  809. package/dist/src/tui/remote.js.map +1 -0
  810. package/dist/src/tui/rollover.js +767 -0
  811. package/dist/src/tui/rollover.js.map +1 -0
  812. package/dist/src/tui/scantab.js +1053 -0
  813. package/dist/src/tui/scantab.js.map +1 -0
  814. package/dist/src/tui/setupentry.js +81 -0
  815. package/dist/src/tui/setupentry.js.map +1 -0
  816. package/dist/src/tui/sidebar.js +602 -0
  817. package/dist/src/tui/sidebar.js.map +1 -0
  818. package/dist/src/tui/sshtriage.js +393 -0
  819. package/dist/src/tui/sshtriage.js.map +1 -0
  820. package/dist/src/tui/startup.js +172 -0
  821. package/dist/src/tui/startup.js.map +1 -0
  822. package/dist/src/tui/tabs.js +41 -0
  823. package/dist/src/tui/tabs.js.map +1 -0
  824. package/dist/src/tui/termmirror.js +217 -0
  825. package/dist/src/tui/termmirror.js.map +1 -0
  826. package/dist/src/tui/theme.js +95 -0
  827. package/dist/src/tui/theme.js.map +1 -0
  828. package/dist/src/tui/ticketstab.js +224 -0
  829. package/dist/src/tui/ticketstab.js.map +1 -0
  830. package/dist/src/tui/tmuxsocket.js +101 -0
  831. package/dist/src/tui/tmuxsocket.js.map +1 -0
  832. package/dist/src/tui/trackertickets.js +77 -0
  833. package/dist/src/tui/trackertickets.js.map +1 -0
  834. package/dist/src/tui/unwedge.js +245 -0
  835. package/dist/src/tui/unwedge.js.map +1 -0
  836. package/dist/src/tui/viewer.js +479 -0
  837. package/dist/src/tui/viewer.js.map +1 -0
  838. package/dist/src/tui/viewerinput.js +125 -0
  839. package/dist/src/tui/viewerinput.js.map +1 -0
  840. package/dist/src/updatenotice.js +143 -0
  841. package/dist/src/updatenotice.js.map +1 -0
  842. package/dist/src/usage.js +1007 -0
  843. package/dist/src/usage.js.map +1 -0
  844. package/dist/src/verdicts.js +3848 -0
  845. package/dist/src/verdicts.js.map +1 -0
  846. package/dist/src/version.js +58 -0
  847. package/dist/src/version.js.map +1 -0
  848. package/dist/src/wakes.js +411 -0
  849. package/dist/src/wakes.js.map +1 -0
  850. package/dist/src/webhook.js +725 -0
  851. package/dist/src/webhook.js.map +1 -0
  852. package/dist/src/webhookheal.js +238 -0
  853. package/dist/src/webhookheal.js.map +1 -0
  854. package/dist/src/wire.js +1801 -0
  855. package/dist/src/wire.js.map +1 -0
  856. package/dist/src/worker-session-host.js +531 -0
  857. package/dist/src/worker-session-host.js.map +1 -0
  858. package/dist/src/workerbreaker.js +112 -0
  859. package/dist/src/workerbreaker.js.map +1 -0
  860. package/dist/src/workercontrol.js +49 -0
  861. package/dist/src/workercontrol.js.map +1 -0
  862. package/dist/src/workerlease.js +351 -0
  863. package/dist/src/workerlease.js.map +1 -0
  864. package/dist/src/workerliveness.js +84 -0
  865. package/dist/src/workerliveness.js.map +1 -0
  866. package/dist/src/workerlog.js +65 -0
  867. package/dist/src/workerlog.js.map +1 -0
  868. package/dist/src/workerruntime.js +10 -0
  869. package/dist/src/workerruntime.js.map +1 -0
  870. package/dist/src/workersupervisor.js +1206 -0
  871. package/dist/src/workersupervisor.js.map +1 -0
  872. package/dist/src/workerusage.js +23 -0
  873. package/dist/src/workerusage.js.map +1 -0
  874. package/dist/src/workerworld.js +332 -0
  875. package/dist/src/workerworld.js.map +1 -0
  876. package/dist/src/worktrees.js +984 -0
  877. package/dist/src/worktrees.js.map +1 -0
  878. package/docker/Dockerfile +284 -0
  879. package/docker/Dockerfile.dockerignore +35 -0
  880. package/docker/README.md +221 -0
  881. package/docker/companion/Dockerfile +139 -0
  882. package/docker/companion/agents/evidence.md +34 -0
  883. package/docker/companion/agents/explore.md +26 -0
  884. package/docker/companion/agents/pass-survey.md +49 -0
  885. package/docker/companion/agents/study.md +26 -0
  886. package/docker/companion/entrypoint.sh +343 -0
  887. package/docker/companion/memory-health.mjs +269 -0
  888. package/docker/entrypoint.sh +782 -0
  889. package/docker/memory/Dockerfile +191 -0
  890. package/docker/memory/Dockerfile.dockerignore +20 -0
  891. package/docker/memory/README.md +60 -0
  892. package/docker/memory/entrypoint.sh +163 -0
  893. package/docker/setid/qcr-setid.c +109 -0
  894. package/docker/tunnel/Dockerfile.cloudflared +51 -0
  895. package/docker/tunnel/Dockerfile.ngrok +40 -0
  896. package/docker/tunnel/sidecar.mjs +411 -0
  897. package/docker/vm/tmux.conf +26 -0
  898. package/docker-compose.yml +348 -0
  899. package/extensions/cli/bash-guard-ambient.ts +71 -0
  900. package/extensions/cli/bash-guard.ts +12 -0
  901. package/extensions/cli/companion-guard.ts +8 -0
  902. package/extensions/cli/debug-round.ts +9 -0
  903. package/extensions/cli/inject-bridge.ts +8 -0
  904. package/extensions/cli/ledger-pin.ts +13 -0
  905. package/extensions/cli/lens.ts +22 -0
  906. package/extensions/cli/muted-theme.ts +9 -0
  907. package/extensions/cli/onboarding.ts +8 -0
  908. package/extensions/cli/setup.ts +8 -0
  909. package/extensions/cli/tui-view.ts +8 -0
  910. package/extensions/companion-guard.ts +411 -0
  911. package/extensions/debug-round.ts +281 -0
  912. package/extensions/inject-bridge.ts +630 -0
  913. package/extensions/inline-bash.ts +102 -0
  914. package/extensions/muted-theme.json +68 -0
  915. package/extensions/muted-theme.ts +23 -0
  916. package/extensions/onboarding.ts +233 -0
  917. package/extensions/setup-replay.ts +336 -0
  918. package/extensions/setup-scan.ts +1236 -0
  919. package/extensions/setup-triage.ts +190 -0
  920. package/extensions/setup.ts +1428 -0
  921. package/extensions/tui-view.ts +489 -0
  922. package/extensions/vendor/openviking-pi/LICENSE +201 -0
  923. package/extensions/vendor/openviking-pi/NOTICE +68 -0
  924. package/extensions/vendor/openviking-pi/README.md +550 -0
  925. package/extensions/vendor/openviking-pi/client.ts +588 -0
  926. package/extensions/vendor/openviking-pi/config.json +28 -0
  927. package/extensions/vendor/openviking-pi/config.ts +271 -0
  928. package/extensions/vendor/openviking-pi/index.ts +523 -0
  929. package/extensions/vendor/openviking-pi/lib/capture-adapter.d.mts +10 -0
  930. package/extensions/vendor/openviking-pi/lib/capture-adapter.mjs +88 -0
  931. package/extensions/vendor/openviking-pi/lib/takeover-core.d.mts +80 -0
  932. package/extensions/vendor/openviking-pi/lib/takeover-core.mjs +406 -0
  933. package/extensions/vendor/openviking-pi/lib/uri-guard-adapter.d.mts +1 -0
  934. package/extensions/vendor/openviking-pi/lib/uri-guard-adapter.mjs +42 -0
  935. package/extensions/vendor/openviking-pi/patches/0000-vendoring-and-build-conformance.patch +726 -0
  936. package/extensions/vendor/openviking-pi/patches/0001-remove-session-before-compact-handler.patch +101 -0
  937. package/extensions/vendor/openviking-pi/patches/0002-no-ambient-work-in-subagent-leaves.patch +202 -0
  938. package/extensions/vendor/openviking-pi/patches/0003-never-auto-create-openviking-sessions.patch +120 -0
  939. package/extensions/vendor/openviking-pi/patches/0004-viking-write-durable-batch-write.patch +521 -0
  940. package/extensions/vendor/openviking-pi/patches/0005-second-memory-namespace.patch +786 -0
  941. package/extensions/vendor/openviking-pi/patches/0006-writes-that-stick-and-honest-errors.patch +996 -0
  942. package/extensions/vendor/openviking-pi/patches/0007-bounded-recall-no-commit.patch +794 -0
  943. package/extensions/vendor/openviking-pi/patches/0008-pr-derived-recall.patch +379 -0
  944. package/extensions/vendor/openviking-pi/patches/0009-pr-session-tools-in-round-areas.patch +375 -0
  945. package/extensions/vendor/openviking-pi/patches/0010-typed-lessons.patch +448 -0
  946. package/extensions/vendor/openviking-pi/patches/0011-review-session-memory-boundary.patch +382 -0
  947. package/extensions/vendor/openviking-pi/patches/0012-typecheck-against-the-real-pi.patch +129 -0
  948. package/extensions/vendor/openviking-pi/patches/0013-createopenviking-factory.patch +1168 -0
  949. package/extensions/vendor/openviking-pi/qcr-hint.ts +313 -0
  950. package/extensions/vendor/openviking-pi/qcr-honest.ts +183 -0
  951. package/extensions/vendor/openviking-pi/qcr-hooks.ts +87 -0
  952. package/extensions/vendor/openviking-pi/qcr-leaf.ts +78 -0
  953. package/extensions/vendor/openviking-pi/qcr-lesson.ts +231 -0
  954. package/extensions/vendor/openviking-pi/qcr-namespaces.ts +198 -0
  955. package/extensions/vendor/openviking-pi/qcr-recall.ts +288 -0
  956. package/extensions/vendor/openviking-pi/qcr-shim.ts +142 -0
  957. package/extensions/vendor/openviking-pi/qcr-write.ts +427 -0
  958. package/extensions/vendor/openviking-pi/recall.ts +149 -0
  959. package/extensions/vendor/openviking-pi/shared/capture-utils.d.mts +9 -0
  960. package/extensions/vendor/openviking-pi/shared/capture-utils.mjs +515 -0
  961. package/extensions/vendor/openviking-pi/shared/credentials.d.mts +14 -0
  962. package/extensions/vendor/openviking-pi/shared/credentials.mjs +228 -0
  963. package/extensions/vendor/openviking-pi/shared/pending-queue.d.mts +19 -0
  964. package/extensions/vendor/openviking-pi/shared/pending-queue.mjs +458 -0
  965. package/extensions/vendor/openviking-pi/shared/profile-inject.d.mts +17 -0
  966. package/extensions/vendor/openviking-pi/shared/profile-inject.mjs +294 -0
  967. package/extensions/vendor/openviking-pi/shared/recall-compress-core.mjs +195 -0
  968. package/extensions/vendor/openviking-pi/shared/recall-core.d.mts +13 -0
  969. package/extensions/vendor/openviking-pi/shared/recall-core.mjs +609 -0
  970. package/extensions/vendor/openviking-pi/shared/retryable.mjs +9 -0
  971. package/extensions/vendor/openviking-pi/shared/session-model.d.mts +3 -0
  972. package/extensions/vendor/openviking-pi/shared/session-model.mjs +57 -0
  973. package/extensions/vendor/openviking-pi/shared/uri-guard.mjs +56 -0
  974. package/extensions/vendor/openviking-pi/shared/workspace-peer.d.mts +5 -0
  975. package/extensions/vendor/openviking-pi/shared/workspace-peer.mjs +16 -0
  976. package/extensions/vendor/openviking-pi/sync.ts +163 -0
  977. package/extensions/vendor/openviking-pi/takeover.ts +36 -0
  978. package/extensions/vendor/openviking-pi/tools.ts +479 -0
  979. package/extensions/vendor/openviking-pi/upstream.json +48 -0
  980. package/package.json +138 -4
  981. package/profiles/default/README.md +21 -0
  982. package/profiles/default/addenda/.gitkeep +0 -0
  983. package/profiles/default/profile.toml +17 -0
  984. package/profiles/example-django/README.md +21 -0
  985. package/profiles/example-django/addenda/10-migration-discipline.md +13 -0
  986. package/profiles/example-django/addenda/20-new-column-nullability.md +12 -0
  987. package/profiles/example-django/addenda/30-test-doctrine.md +12 -0
  988. package/profiles/example-django/addenda/40-orm-usage.md +19 -0
  989. package/profiles/example-django/addenda/50-declared-shape.md +10 -0
  990. package/profiles/example-django/addenda/60-config-placement.md +14 -0
  991. package/profiles/example-django/heuristics.toml +24 -0
  992. package/profiles/example-django/profile.toml +9 -0
  993. package/profiles/fast/README.md +24 -0
  994. package/profiles/fast/profile.toml +59 -0
  995. package/profiles/minimal/README.md +17 -0
  996. package/profiles/minimal/addenda/.gitkeep +0 -0
  997. package/profiles/minimal/profile.toml +8 -0
  998. package/profiles/snappy/README.md +24 -0
  999. package/profiles/snappy/addenda/10-race-as-question.md +6 -0
  1000. package/profiles/snappy/profile.toml +46 -0
  1001. package/prompts/companion-day-open.md +46 -0
  1002. package/prompts/companion-first-run.md +104 -0
  1003. package/prompts/companion.md +821 -0
  1004. package/prompts/conversation-system.md +117 -0
  1005. package/prompts/eod-sweep.md +120 -0
  1006. package/prompts/onboarding.md +74 -0
  1007. package/prompts/pass-common.md +52 -0
  1008. package/prompts/pass-quality-common.md +22 -0
  1009. package/prompts/round-first.md +874 -0
  1010. package/prompts/round-follow-up.md +991 -0
  1011. package/prompts/round-re-review.md +889 -0
  1012. package/prompts/round-recheck.md +196 -0
  1013. package/prompts/round-staleness.md +856 -0
  1014. package/schemas/review-result.v1.json +391 -0
  1015. package/schemas/scan-result.v1.json +421 -0
  1016. package/schemas/version.v1.json +57 -0
  1017. package/scripts/approve-pr.sh +16 -0
  1018. package/scripts/build-stamp.mjs +67 -0
  1019. package/scripts/commit-verdict.sh +155 -0
  1020. package/scripts/companion-e2e.sh +250 -0
  1021. package/scripts/companion-memory-forward.mjs +1966 -0
  1022. package/scripts/config-fingerprint.sh +28 -0
  1023. package/scripts/deploy-manifest.mjs +141 -0
  1024. package/scripts/deploy.sh +1435 -0
  1025. package/scripts/directory-lock.mjs +193 -0
  1026. package/scripts/heartbeat-fresh.mjs +54 -0
  1027. package/scripts/install-locator.sh +328 -0
  1028. package/scripts/install-wrapper.sh +76 -0
  1029. package/scripts/memory-search-check.mjs +98 -0
  1030. package/scripts/mint-token.sh +212 -0
  1031. package/scripts/openviking-embedder.py +392 -0
  1032. package/scripts/openviking-ov-conf.mjs +161 -0
  1033. package/scripts/openviking-provision.mjs +1122 -0
  1034. package/scripts/openviking-reembed.mjs +1154 -0
  1035. package/scripts/post-review.sh +16 -0
  1036. package/scripts/pr-checks.sh +256 -0
  1037. package/scripts/pr-context.py +174 -0
  1038. package/scripts/pr-context.sh +63 -0
  1039. package/scripts/pr-self.sh +144 -0
  1040. package/scripts/pr-threads.sh +145 -0
  1041. package/scripts/qcr +15 -0
  1042. package/scripts/qcr-host.sh +769 -0
  1043. package/scripts/render-review.sh +24 -0
  1044. package/scripts/reply-thread.sh +16 -0
  1045. package/scripts/required-passes.py +112 -0
  1046. package/scripts/smoke-companion.sh +211 -0
  1047. package/scripts/tui-deploy-runner.mjs +61 -0
  1048. package/scripts/verify-dist.mjs +201 -0
  1049. package/scripts/vm-ghcr-login.sh +188 -0
  1050. package/seeds/agents/pass-baseline.md +61 -0
  1051. package/seeds/agents/pass-contracts.md +30 -0
  1052. package/seeds/agents/pass-data-safety.md +54 -0
  1053. package/seeds/agents/pass-delivery.md +37 -0
  1054. package/seeds/agents/pass-prod-risk.md +24 -0
  1055. package/seeds/agents/pass-security.md +31 -0
  1056. package/seeds/agents/pass-statelessness.md +27 -0
  1057. package/seeds/agents/pass-ui.md +23 -0
  1058. package/seeds/agents/pass-validate.md +50 -0
  1059. package/seeds/prompts/conversation-system.md +117 -0
  1060. package/seeds/prompts/eod-sweep.md +120 -0
  1061. package/seeds/prompts/pass-common.md +52 -0
  1062. package/skills/companion/adjudicate/SKILL.md +247 -0
  1063. package/skills/companion/evidence/SKILL.md +150 -0
  1064. package/skills/companion/land/SKILL.md +200 -0
  1065. package/skills/companion/replay/SKILL.md +138 -0
  1066. package/skills/companion/setup/SKILL.md +167 -0
  1067. package/skills/companion/survey/SKILL.md +160 -0
  1068. package/skills/selfimprove/README.md +34 -0
  1069. package/skills/selfimprove/SKILL.md +127 -0
  1070. package/skills/selfimprove/agents/openai.yaml +2 -0
  1071. package/skills/selfimprove/commands/selfimprove.md +6 -0
  1072. package/skills/selfimprove/references/fix-loop.md +49 -0
  1073. package/skills/selfimprove/references/ledger.md +20 -0
  1074. package/skills/selfimprove/references/setup.md +40 -0
  1075. package/src/anomalies.ts +566 -0
  1076. package/src/answerworker.ts +251 -0
  1077. package/src/appstamp.ts +65 -0
  1078. package/src/archive/admission.ts +3 -0
  1079. package/src/archive/archivedb.ts +548 -0
  1080. package/src/archive/archiver.ts +1963 -0
  1081. package/src/archive/archivewrite.ts +279 -0
  1082. package/src/archive/bundle.ts +333 -0
  1083. package/src/archive/dbmove.ts +911 -0
  1084. package/src/archive/duplicatecounts.ts +98 -0
  1085. package/src/archive/eligibility.ts +181 -0
  1086. package/src/archive/extract.ts +342 -0
  1087. package/src/archive/fsutil.ts +415 -0
  1088. package/src/archive/gzfile.ts +370 -0
  1089. package/src/archive/kinds.ts +21 -0
  1090. package/src/archive/livecheckpoint.ts +217 -0
  1091. package/src/archive/liveretention.ts +180 -0
  1092. package/src/archive/manifest.ts +519 -0
  1093. package/src/archive/overseer.ts +336 -0
  1094. package/src/archive/piglobal.ts +174 -0
  1095. package/src/archive/plan.ts +612 -0
  1096. package/src/archive/prarchive.ts +984 -0
  1097. package/src/archive/prfiles.ts +406 -0
  1098. package/src/archive/report.ts +252 -0
  1099. package/src/archive/restore.ts +330 -0
  1100. package/src/archive/rows.ts +187 -0
  1101. package/src/archive/seal.ts +630 -0
  1102. package/src/archive/status.ts +719 -0
  1103. package/src/archive/storepass.ts +581 -0
  1104. package/src/backfill.ts +362 -0
  1105. package/src/bench/cost.ts +113 -0
  1106. package/src/bench/exec.ts +90 -0
  1107. package/src/bench/values.ts +13 -0
  1108. package/src/botcontrol.ts +176 -0
  1109. package/src/botworker.ts +953 -0
  1110. package/src/capture.ts +321 -0
  1111. package/src/cases.ts +1789 -0
  1112. package/src/channelfs.ts +26 -0
  1113. package/src/checklist.ts +506 -0
  1114. package/src/ciretry.ts +141 -0
  1115. package/src/cli.ts +2271 -0
  1116. package/src/cliops.ts +384 -0
  1117. package/src/clonedir.ts +15 -0
  1118. package/src/commandeffects.ts +57 -0
  1119. package/src/commands.ts +1678 -0
  1120. package/src/companioninbox.ts +239 -0
  1121. package/src/compare.ts +957 -0
  1122. package/src/config.ts +2050 -0
  1123. package/src/configcheck.ts +133 -0
  1124. package/src/coreext.ts +47 -0
  1125. package/src/daemon.ts +1302 -0
  1126. package/src/debuground.ts +927 -0
  1127. package/src/debugroundpi.ts +262 -0
  1128. package/src/diagnostics.ts +14 -0
  1129. package/src/digest.ts +183 -0
  1130. package/src/dispatch.ts +2250 -0
  1131. package/src/engine/answerguard.ts +27 -0
  1132. package/src/engine/botsdk.ts +336 -0
  1133. package/src/engine/caserunner-sdk.ts +423 -0
  1134. package/src/engine/debugpi.ts +235 -0
  1135. package/src/eod.ts +669 -0
  1136. package/src/eodpinwatch.ts +556 -0
  1137. package/src/escalation.ts +1253 -0
  1138. package/src/eventloop.ts +1045 -0
  1139. package/src/execboundary.ts +633 -0
  1140. package/src/feedback.ts +1162 -0
  1141. package/src/findingscheck.ts +298 -0
  1142. package/src/fsdenied.ts +24 -0
  1143. package/src/ghread.ts +242 -0
  1144. package/src/github.ts +1497 -0
  1145. package/src/homes.ts +175 -0
  1146. package/src/hostroute.ts +53 -0
  1147. package/src/improvements.ts +787 -0
  1148. package/src/install.ts +1103 -0
  1149. package/src/installkind.ts +50 -0
  1150. package/src/ipc/capability.ts +333 -0
  1151. package/src/ipc/client.ts +269 -0
  1152. package/src/ipc/control.ts +90 -0
  1153. package/src/ipc/ghreadshim.ts +94 -0
  1154. package/src/ipc/launcher.ts +65 -0
  1155. package/src/ipc/permits.ts +362 -0
  1156. package/src/ipc/postshim.ts +164 -0
  1157. package/src/ipc/protocol.ts +342 -0
  1158. package/src/ipc/server.ts +371 -0
  1159. package/src/ipc/workerspec.ts +218 -0
  1160. package/src/learner/learner.ts +1655 -0
  1161. package/src/learner/miner.ts +1290 -0
  1162. package/src/learner/packet.ts +340 -0
  1163. package/src/learner/receipt.ts +168 -0
  1164. package/src/learner/status.ts +107 -0
  1165. package/src/ledgercheck.ts +157 -0
  1166. package/src/lessonledger.ts +703 -0
  1167. package/src/lessonselect.ts +888 -0
  1168. package/src/lessonshadow.ts +810 -0
  1169. package/src/levers.ts +393 -0
  1170. package/src/live/projection.ts +491 -0
  1171. package/src/live/publish.ts +92 -0
  1172. package/src/live/read.ts +86 -0
  1173. package/src/livecli.ts +336 -0
  1174. package/src/loginhint.ts +56 -0
  1175. package/src/loginrefresh/atomic.ts +76 -0
  1176. package/src/loginrefresh/lock.ts +104 -0
  1177. package/src/loginrefresh/main.ts +59 -0
  1178. package/src/loginrefresh/pirefresh.ts +57 -0
  1179. package/src/loginrefresh/refresher.ts +326 -0
  1180. package/src/loginrefresh/supervisor.ts +273 -0
  1181. package/src/loginrefresh/types.ts +35 -0
  1182. package/src/memory/context.ts +385 -0
  1183. package/src/memory/datafence.ts +9 -0
  1184. package/src/memory/delivery.ts +171 -0
  1185. package/src/memory/eventtags.ts +80 -0
  1186. package/src/memory/health.ts +953 -0
  1187. package/src/memory/import.ts +664 -0
  1188. package/src/memory/layout.ts +261 -0
  1189. package/src/memory/legacy-file.ts +104 -0
  1190. package/src/memory/lessons.ts +447 -0
  1191. package/src/memory/ovsession.ts +601 -0
  1192. package/src/memory/relayout.ts +335 -0
  1193. package/src/memory/roundactivity.ts +209 -0
  1194. package/src/memory/selection.ts +989 -0
  1195. package/src/memory/shadowstatus.ts +125 -0
  1196. package/src/memory/store.ts +275 -0
  1197. package/src/memory/textidentity.ts +8 -0
  1198. package/src/metrics.ts +1056 -0
  1199. package/src/missingconfig.ts +7 -0
  1200. package/src/npmverbs.ts +264 -0
  1201. package/src/onboard/choices.ts +222 -0
  1202. package/src/onboard/engine.ts +518 -0
  1203. package/src/onboard/launch.ts +115 -0
  1204. package/src/onboard/steps/appslug.ts +265 -0
  1205. package/src/onboard/steps/bringup.ts +482 -0
  1206. package/src/onboard/steps/compose.ts +459 -0
  1207. package/src/onboard/steps/configdelivery.ts +58 -0
  1208. package/src/onboard/steps/configfill.ts +1352 -0
  1209. package/src/onboard/steps/deploysh.ts +105 -0
  1210. package/src/onboard/steps/embeddings.ts +550 -0
  1211. package/src/onboard/steps/escalation.ts +640 -0
  1212. package/src/onboard/steps/githubapp.ts +1414 -0
  1213. package/src/onboard/steps/golive.ts +577 -0
  1214. package/src/onboard/steps/index.ts +71 -0
  1215. package/src/onboard/steps/ingress.ts +907 -0
  1216. package/src/onboard/steps/inventory.ts +526 -0
  1217. package/src/onboard/steps/llmauth.ts +1095 -0
  1218. package/src/onboard/steps/memory.ts +1290 -0
  1219. package/src/onboard/steps/memorykeys.ts +85 -0
  1220. package/src/onboard/steps/preflight.ts +191 -0
  1221. package/src/onboard/steps/proof.ts +624 -0
  1222. package/src/onboard/steps/ssh.ts +377 -0
  1223. package/src/onboard/steps/topology.ts +337 -0
  1224. package/src/onboard/steps/transport.ts +665 -0
  1225. package/src/onboard/steps/verifyup.ts +448 -0
  1226. package/src/onboard/steps/vmdeploy.ts +442 -0
  1227. package/src/onboard/toml.ts +50 -0
  1228. package/src/opencli.ts +591 -0
  1229. package/src/openpr.ts +568 -0
  1230. package/src/openviking/client.ts +1131 -0
  1231. package/src/openviking/context.ts +263 -0
  1232. package/src/openviking/embedder.ts +516 -0
  1233. package/src/openviking/gapsink.ts +63 -0
  1234. package/src/openviking/health.ts +83 -0
  1235. package/src/openviking/index.ts +119 -0
  1236. package/src/openviking/lessonfind.ts +92 -0
  1237. package/src/openviking/probe.ts +129 -0
  1238. package/src/openviking/proc.ts +110 -0
  1239. package/src/openviking/provisionreport.ts +160 -0
  1240. package/src/openviking/reembed.ts +412 -0
  1241. package/src/openviking/relayout.ts +177 -0
  1242. package/src/openviking/sidecar-main.ts +38 -0
  1243. package/src/openviking/sidecar.ts +106 -0
  1244. package/src/openviking/store.ts +2025 -0
  1245. package/src/openviking/supervisor.ts +474 -0
  1246. package/src/openviking/types.ts +174 -0
  1247. package/src/operator-recovery.ts +237 -0
  1248. package/src/operatormessage.ts +52 -0
  1249. package/src/outcomes.ts +1670 -0
  1250. package/src/piauthcopy.ts +12 -0
  1251. package/src/picli.ts +49 -0
  1252. package/src/picwd.ts +25 -0
  1253. package/src/pilogin.ts +37 -0
  1254. package/src/pingpong.ts +1339 -0
  1255. package/src/posting-journal.ts +549 -0
  1256. package/src/posting-outbox.ts +802 -0
  1257. package/src/posting-receipt.ts +324 -0
  1258. package/src/posting.ts +603 -0
  1259. package/src/postops.ts +832 -0
  1260. package/src/pr-activity.ts +20 -0
  1261. package/src/pr-author.ts +6 -0
  1262. package/src/pr-conversation.ts +432 -0
  1263. package/src/pr-session-lifecycle.ts +631 -0
  1264. package/src/preflight.ts +391 -0
  1265. package/src/priorresolve.ts +343 -0
  1266. package/src/qcrbin.ts +186 -0
  1267. package/src/recheck.ts +1775 -0
  1268. package/src/reconcile.ts +1030 -0
  1269. package/src/recordedfindings.ts +27 -0
  1270. package/src/regression.ts +833 -0
  1271. package/src/replay.ts +816 -0
  1272. package/src/requiredpasses.ts +148 -0
  1273. package/src/resumecheck.ts +246 -0
  1274. package/src/reviewcli.ts +787 -0
  1275. package/src/reviewcontext.ts +35 -0
  1276. package/src/reviewdetach.ts +734 -0
  1277. package/src/reviewhistory.ts +427 -0
  1278. package/src/reviewhome.ts +36 -0
  1279. package/src/reviewmemory.ts +133 -0
  1280. package/src/reviewrendercli.ts +139 -0
  1281. package/src/round-work.ts +42 -0
  1282. package/src/runhost.ts +108 -0
  1283. package/src/scanauth.ts +36 -0
  1284. package/src/scanbox.ts +1081 -0
  1285. package/src/scancli.ts +1296 -0
  1286. package/src/scandriverlog.ts +32 -0
  1287. package/src/session-bridge.ts +139 -0
  1288. package/src/session-command-payload.ts +35 -0
  1289. package/src/session-command-supervisor.ts +1142 -0
  1290. package/src/sessionjsonl.ts +88 -0
  1291. package/src/sessions.ts +659 -0
  1292. package/src/setup/adapters.ts +335 -0
  1293. package/src/setup/baselines.ts +110 -0
  1294. package/src/setup/caserunner.ts +611 -0
  1295. package/src/setup/configcommit.ts +443 -0
  1296. package/src/setup/engine.ts +1001 -0
  1297. package/src/setup/facts.ts +627 -0
  1298. package/src/setup/findings.ts +1264 -0
  1299. package/src/setup/history.ts +443 -0
  1300. package/src/setup/interview.ts +243 -0
  1301. package/src/setup/ledger.ts +324 -0
  1302. package/src/setup/pins.ts +66 -0
  1303. package/src/setup/portrait.ts +635 -0
  1304. package/src/setup/presentation.ts +18 -0
  1305. package/src/setup/profile.ts +508 -0
  1306. package/src/setup/replay.ts +370 -0
  1307. package/src/setup/replaybuild.ts +392 -0
  1308. package/src/setup/replayrun.ts +1096 -0
  1309. package/src/setup/replaysource.ts +198 -0
  1310. package/src/setup/retune.ts +415 -0
  1311. package/src/setup/retunelog.ts +95 -0
  1312. package/src/setup/scan.ts +1033 -0
  1313. package/src/setup/scanbuild.ts +168 -0
  1314. package/src/setup/scanfacts.ts +107 -0
  1315. package/src/setup/scanlease.ts +297 -0
  1316. package/src/setup/scanreport.ts +373 -0
  1317. package/src/setup/scanrun.ts +2268 -0
  1318. package/src/setup/scantree.ts +259 -0
  1319. package/src/setup/stage2.ts +926 -0
  1320. package/src/setup/stage2request.ts +347 -0
  1321. package/src/setup/survey.ts +458 -0
  1322. package/src/setup/surveyrun.ts +758 -0
  1323. package/src/setup/textsniff.ts +95 -0
  1324. package/src/setup/trackersink.ts +433 -0
  1325. package/src/setup/triage.ts +768 -0
  1326. package/src/setup/tuning.ts +766 -0
  1327. package/src/setup/unitcut.ts +523 -0
  1328. package/src/singleflight.ts +86 -0
  1329. package/src/slack/announce.ts +911 -0
  1330. package/src/slack/api.ts +303 -0
  1331. package/src/slack/messages.ts +288 -0
  1332. package/src/slack/origin.ts +599 -0
  1333. package/src/slack/policy.ts +354 -0
  1334. package/src/slack/reply.ts +201 -0
  1335. package/src/slack/router.ts +285 -0
  1336. package/src/slack/socket.ts +384 -0
  1337. package/src/slack/types.ts +108 -0
  1338. package/src/sqlitehint.ts +32 -0
  1339. package/src/ssh-observation.ts +30 -0
  1340. package/src/state.ts +8243 -0
  1341. package/src/statemachine.ts +369 -0
  1342. package/src/stubs.ts +68 -0
  1343. package/src/takeover.ts +634 -0
  1344. package/src/takeoverpi.ts +293 -0
  1345. package/src/terminal-failure.ts +41 -0
  1346. package/src/thread-resolution-refusal.ts +2 -0
  1347. package/src/tmux.ts +153 -0
  1348. package/src/trackerid.ts +41 -0
  1349. package/src/transcriptindex.ts +665 -0
  1350. package/src/tui/actions.ts +484 -0
  1351. package/src/tui/alerts.ts +666 -0
  1352. package/src/tui/app.ts +1979 -0
  1353. package/src/tui/archiveops.ts +192 -0
  1354. package/src/tui/autofile.ts +233 -0
  1355. package/src/tui/board.ts +1432 -0
  1356. package/src/tui/candidates.ts +889 -0
  1357. package/src/tui/cellwidth.ts +148 -0
  1358. package/src/tui/changelog-store.ts +503 -0
  1359. package/src/tui/chord.ts +25 -0
  1360. package/src/tui/clipboard.ts +92 -0
  1361. package/src/tui/cmdbar.ts +296 -0
  1362. package/src/tui/companion.ts +1427 -0
  1363. package/src/tui/companionplan.ts +247 -0
  1364. package/src/tui/companiontab.ts +83 -0
  1365. package/src/tui/confighome.ts +155 -0
  1366. package/src/tui/connect.ts +68 -0
  1367. package/src/tui/deploy-ceremony.ts +104 -0
  1368. package/src/tui/deploy-drain.ts +129 -0
  1369. package/src/tui/deploy-process.ts +265 -0
  1370. package/src/tui/deploytab.ts +1523 -0
  1371. package/src/tui/design.ts +125 -0
  1372. package/src/tui/digesttab.ts +214 -0
  1373. package/src/tui/emptystate.ts +39 -0
  1374. package/src/tui/evidence.ts +999 -0
  1375. package/src/tui/feed.ts +604 -0
  1376. package/src/tui/feedbacktab.ts +1077 -0
  1377. package/src/tui/filters.ts +90 -0
  1378. package/src/tui/ghread.ts +321 -0
  1379. package/src/tui/historypull.ts +81 -0
  1380. package/src/tui/inboxpull.ts +236 -0
  1381. package/src/tui/index.ts +1565 -0
  1382. package/src/tui/issuesink.ts +238 -0
  1383. package/src/tui/jsonfile.ts +42 -0
  1384. package/src/tui/keys.ts +109 -0
  1385. package/src/tui/layout.ts +108 -0
  1386. package/src/tui/learning.ts +627 -0
  1387. package/src/tui/lessonswitch.ts +118 -0
  1388. package/src/tui/livecontrol.ts +228 -0
  1389. package/src/tui/memforward.ts +443 -0
  1390. package/src/tui/memincident.ts +363 -0
  1391. package/src/tui/memory.ts +620 -0
  1392. package/src/tui/memtab.ts +606 -0
  1393. package/src/tui/metricstab.ts +1177 -0
  1394. package/src/tui/model.ts +131 -0
  1395. package/src/tui/mouse.ts +98 -0
  1396. package/src/tui/msg.ts +268 -0
  1397. package/src/tui/nativecompanion.ts +417 -0
  1398. package/src/tui/openurl.ts +21 -0
  1399. package/src/tui/paint.ts +511 -0
  1400. package/src/tui/panes.ts +98 -0
  1401. package/src/tui/pipane.ts +219 -0
  1402. package/src/tui/poll-hooks.ts +12 -0
  1403. package/src/tui/poll.ts +147 -0
  1404. package/src/tui/proposals.ts +838 -0
  1405. package/src/tui/prpause.ts +150 -0
  1406. package/src/tui/reload.ts +436 -0
  1407. package/src/tui/remote.ts +413 -0
  1408. package/src/tui/rollover.ts +969 -0
  1409. package/src/tui/scantab.ts +1290 -0
  1410. package/src/tui/setupentry.ts +93 -0
  1411. package/src/tui/sidebar.ts +749 -0
  1412. package/src/tui/sshtriage.ts +510 -0
  1413. package/src/tui/startup.ts +231 -0
  1414. package/src/tui/tabs.ts +45 -0
  1415. package/src/tui/termmirror.ts +224 -0
  1416. package/src/tui/theme.ts +95 -0
  1417. package/src/tui/ticketstab.ts +310 -0
  1418. package/src/tui/tmuxsocket.ts +129 -0
  1419. package/src/tui/trackertickets.ts +84 -0
  1420. package/src/tui/unwedge.ts +286 -0
  1421. package/src/tui/viewer.ts +575 -0
  1422. package/src/tui/viewerinput.ts +173 -0
  1423. package/src/updatenotice.ts +178 -0
  1424. package/src/usage.ts +1154 -0
  1425. package/src/verdicts.ts +4689 -0
  1426. package/src/version.ts +80 -0
  1427. package/src/wakes.ts +476 -0
  1428. package/src/webhook.ts +942 -0
  1429. package/src/webhookheal.ts +276 -0
  1430. package/src/wire.ts +2153 -0
  1431. package/src/worker-session-host.ts +602 -0
  1432. package/src/workerbreaker.ts +156 -0
  1433. package/src/workercontrol.ts +104 -0
  1434. package/src/workerlease.ts +441 -0
  1435. package/src/workerliveness.ts +103 -0
  1436. package/src/workerlog.ts +79 -0
  1437. package/src/workerruntime.ts +30 -0
  1438. package/src/workersupervisor.ts +1538 -0
  1439. package/src/workerusage.ts +42 -0
  1440. package/src/workerworld.ts +427 -0
  1441. package/src/worktrees.ts +1138 -0
  1442. package/tests/fixtures/regression-cases.json +795 -0
  1443. package/tests/fixtures/seed-manifest.json +19 -0
@@ -0,0 +1,1272 @@
1
+ // The learner: candidates in, curated lessons out, and a person told when the
2
+ // curation did not happen.
3
+ //
4
+ // The loop, daemon-side and deterministic up to the curator's own judgement:
5
+ //
6
+ // 1. MINE (src/learner/miner.ts) — at EOD − `lessons_mine_lead_min`, and on
7
+ // the operator's word (`qcr lessons mine`): every human outcome becomes a
8
+ // row of `lesson_candidates`, deduplicated by a deterministic ref, with a
9
+ // class. The first mine also turns the digests' lost "Learnings" into
10
+ // candidates (`source = digest-backfill`), and a post-approval recheck's
11
+ // APPROVE → REQUEST_CHANGES reversal is one too (`source = recheck`): the
12
+ // reviewer's own conclusion, labelled so, offered after every other
13
+ // source.
14
+ // 2. PACKET (src/learner/packet.ts) — at the day's EOD fire: candidates
15
+ // first offered more than `lessons_expiry_ops_days` ago are expired
16
+ // (recorded on the row, in an event, and in the packet's own list — never
17
+ // silent); up to `lessons_packet_new_max` queued ones are offered for the first
18
+ // time; every undecided offered candidate is carried forward. Clustered
19
+ // by class with the 90-day recurrence, the fixed / left-open counterweight
20
+ // and the lessons already covering the class. Written to
21
+ // `state/eod/<day>/outcomes.{json,md}`; the sweep prompt points at it
22
+ // (`prepareEod` → wire.ts's `dayContext`).
23
+ // 3. RECEIPT — the curator answers with the whitelisted command
24
+ // `eod-curation-receipt` (src/learner/receipt.ts): per candidate,
25
+ // adopted / declined with a reason / refused (the write failed).
26
+ // 4. VERIFY — an adoption counts only when a lesson in `experiences/`
27
+ // carries a typed header whose evidence cites the candidate
28
+ // (`cand:c<id>`, src/memory/lessons.ts). Checked against memory while it
29
+ // reads healthy; a claimed lesson memory does not hold, or a refused
30
+ // write, wakes `eod_lessons_not_persisted` and puts the candidate back
31
+ // in the packet. No receipt `lessons_receipt_wait_min` after the sweep
32
+ // was delivered wakes `eod_curation_missing`. Both are wake kinds and
33
+ // ride status.json `memory.curation` — the board banner, the desktop
34
+ // notification and `qcr status`.
35
+ //
36
+ // Also measured: the look-for : don't-raise balance of the lessons in force
37
+ // (`lessonBalance`), the learner's health metric.
38
+ //
39
+ // Nothing here writes memory or GitHub, and nothing here is on the round
40
+ // path. Its tables live on the state database beside the outcome capture's.
41
+ import { withinBudget } from "@quickchatai/pi-quickreview/src/budget.js";
42
+ import { mkdirSync, renameSync, writeFileSync } from "node:fs";
43
+ import { join } from "node:path";
44
+ import { MEMORY_DEFAULTS } from "../config.js";
45
+ import { localWallClockToInstant, zoneDateString, zonedParts, parseHHMM } from "../eod.js";
46
+ import { jsonColumn } from "../lessonledger.js";
47
+ import { EXPERIENCES_AREA, areaOfId } from "../memory/layout.js";
48
+ import { coveringLessons, lessonBalance, parseLesson, } from "../memory/lessons.js";
49
+ import { chainRoots, outcomeRows, findingClass, lensIdsOf, mineDigestBackfill, mineFates, mineFeedback, mineHumanRecall, minePostMerge, mineRecheckFlips, mineTaggedComments, RECALL_SCAN_LIMITS, reviewFateCandidates, tableExists, } from "./miner.js";
50
+ import { addDays, dayDiff, majorityPolarity, packetPointer, packetMarkdownRel, packetRelDir, renderCurationSection, renderPacketMarkdown, } from "./packet.js";
51
+ import { candidateLabel } from "./receipt.js";
52
+ export { curationPhrase } from "./status.js";
53
+ export const LEARNER_WAKE = Object.freeze({
54
+ missing: "eod_curation_missing",
55
+ notPersisted: "eod_lessons_not_persisted",
56
+ });
57
+ /** The learner's knobs at their shipped values — the `[memory]` defaults
58
+ * (src/config.ts MEMORY_DEFAULTS), which hold each value once. */
59
+ export const LEARNER_DEFAULTS = Object.freeze({
60
+ lessons_mine_lead_min: MEMORY_DEFAULTS.lessons_mine_lead_min,
61
+ lessons_mine_days: MEMORY_DEFAULTS.lessons_mine_days,
62
+ lessons_receipt_wait_min: MEMORY_DEFAULTS.lessons_receipt_wait_min,
63
+ lessons_expiry_ops_days: MEMORY_DEFAULTS.lessons_expiry_ops_days,
64
+ lessons_packet_new_max: MEMORY_DEFAULTS.lessons_packet_new_max,
65
+ lessons_recall_window_days: MEMORY_DEFAULTS.lessons_recall_window_days,
66
+ lessons_recurrence_days: MEMORY_DEFAULTS.lessons_recurrence_days,
67
+ lessons_digest_backfill_from: MEMORY_DEFAULTS.lessons_digest_backfill_from,
68
+ lessons_digest_backfill_to: MEMORY_DEFAULTS.lessons_digest_backfill_to,
69
+ });
70
+ /** The `[memory] lessons_*` knobs (src/config.ts) as the learner takes them,
71
+ * with floors — a mistyped 0 must not expire every candidate at once or wake
72
+ * the moment the sweep is delivered. One mapping, for wire.ts and the CLI. */
73
+ export function learnerKnobsOf(m) {
74
+ return {
75
+ lessons_mine_lead_min: Math.max(0, m.lessons_mine_lead_min),
76
+ lessons_mine_days: Math.max(1, m.lessons_mine_days),
77
+ lessons_receipt_wait_min: Math.max(1, m.lessons_receipt_wait_min),
78
+ lessons_expiry_ops_days: Math.max(1, m.lessons_expiry_ops_days),
79
+ lessons_packet_new_max: Math.max(0, m.lessons_packet_new_max),
80
+ lessons_recall_window_days: Math.max(1, m.lessons_recall_window_days),
81
+ lessons_recurrence_days: Math.max(1, m.lessons_recurrence_days),
82
+ lessons_digest_backfill_from: m.lessons_digest_backfill_from,
83
+ lessons_digest_backfill_to: m.lessons_digest_backfill_to,
84
+ };
85
+ }
86
+ const SCHEMA = `
87
+ CREATE TABLE IF NOT EXISTS lesson_candidates (
88
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
89
+ -- the dedup key: one human outcome is one candidate, whichever mine saw it
90
+ ref TEXT NOT NULL UNIQUE,
91
+ source TEXT NOT NULL,
92
+ kind TEXT NOT NULL,
93
+ polarity TEXT NOT NULL,
94
+ class TEXT NOT NULL,
95
+ lens_ids TEXT NOT NULL DEFAULT '[]',
96
+ pr INTEGER,
97
+ round_no INTEGER,
98
+ finding_key TEXT,
99
+ path TEXT,
100
+ line INTEGER,
101
+ summary TEXT NOT NULL,
102
+ quote TEXT,
103
+ evidence TEXT NOT NULL DEFAULT '[]',
104
+ occurred_at TEXT NOT NULL,
105
+ mined_at TEXT NOT NULL,
106
+ -- the ops day it first rode a packet; NULL = queued, never offered
107
+ offered_day TEXT,
108
+ last_offered_day TEXT,
109
+ offers INTEGER NOT NULL DEFAULT 0,
110
+ -- the ops day a refused write or an unfound adoption re-opened it: its
111
+ -- expiry clock restarts there (NULL = it runs from offered_day)
112
+ reopened_day TEXT,
113
+ -- open | adopting (the receipt said adopted; memory not checked yet) |
114
+ -- adopted (a lesson header cites it) | declined | expired |
115
+ -- withdrawn (its human outcome changed since it was mined — never deleted)
116
+ status TEXT NOT NULL DEFAULT 'open',
117
+ decided_at TEXT,
118
+ decided_day TEXT,
119
+ reason TEXT,
120
+ lesson_ids TEXT,
121
+ claimed_lesson TEXT,
122
+ receipt_day TEXT,
123
+ receipt_at TEXT,
124
+ updated_at TEXT NOT NULL
125
+ );
126
+ CREATE INDEX IF NOT EXISTS lesson_candidates_status ON lesson_candidates (status, offered_day);
127
+ CREATE INDEX IF NOT EXISTS lesson_candidates_class ON lesson_candidates (class, occurred_at);
128
+ CREATE TABLE IF NOT EXISTS eod_curations (
129
+ day TEXT PRIMARY KEY,
130
+ packet_at TEXT,
131
+ offered TEXT NOT NULL DEFAULT '[]',
132
+ new_today TEXT NOT NULL DEFAULT '[]',
133
+ expired TEXT NOT NULL DEFAULT '[]',
134
+ fired_at TEXT,
135
+ receipt_at TEXT,
136
+ receipt TEXT,
137
+ missing_woken_at TEXT,
138
+ -- [{id, why}] adoptions memory does not hold and refused writes
139
+ not_persisted TEXT NOT NULL DEFAULT '[]',
140
+ -- when the list last went from empty to non-empty (the incident's start)
141
+ not_persisted_since TEXT,
142
+ -- the not_persisted items (id + why) a wake has already named
143
+ not_persisted_woken TEXT NOT NULL DEFAULT '[]',
144
+ updated_at TEXT NOT NULL
145
+ );
146
+ CREATE TABLE IF NOT EXISTS learner_marks (
147
+ key TEXT PRIMARY KEY,
148
+ value TEXT,
149
+ at TEXT NOT NULL
150
+ );
151
+ CREATE TABLE IF NOT EXISTS learner_recall_scans (
152
+ pr INTEGER PRIMARY KEY,
153
+ merged_at TEXT NOT NULL,
154
+ base_ref TEXT,
155
+ attempts INTEGER NOT NULL DEFAULT 0,
156
+ last_scan_at TEXT,
157
+ merge_commit TEXT,
158
+ touches INTEGER,
159
+ done INTEGER NOT NULL DEFAULT 0,
160
+ outcome TEXT
161
+ );
162
+ `;
163
+ /** A candidate in one of these is decided: it leaves the not-persisted lists,
164
+ * and a refused write re-opens only an expired one (`applyReceipt`). */
165
+ const SETTLED_STATUSES = ["adopted", "declined", "expired", "withdrawn"];
166
+ const SETTLED_SQL = SETTLED_STATUSES.map((s) => `'${s}'`).join(", ");
167
+ const DAY_MS = 86_400_000;
168
+ /** A lesson written moments before its receipt may not be listed yet. */
169
+ const VERIFY_GRACE_MS = 10 * 60_000;
170
+ /** How long `prepareEod` waits for a mine it had to start itself. */
171
+ const PREPARE_MINE_BUDGET_MS = 60_000;
172
+ /** How long a lesson read for the packet may take. */
173
+ const LESSON_READ_BUDGET_MS = 20_000;
174
+ /** With no adoption waiting, the lessons in force are re-read this often. */
175
+ const LESSON_REFRESH_MS = 30 * 60_000;
176
+ /** How many curation days back the status looks for an unresolved failure. */
177
+ const UNRESOLVED_SCAN_DAYS = 30;
178
+ /** `p`, or "timeout" once `ms` passed. A rejection reads as "timeout" too —
179
+ * the caller's fallback is the same — but its cause goes to `onReject`, so a
180
+ * failure is never mistaken for a slow answer in the log. */
181
+ async function withTimeout(p, ms, onReject) {
182
+ const result = await withinBudget(p.catch((error) => {
183
+ onReject(error);
184
+ return "timeout";
185
+ }), ms);
186
+ return result.kind === "done" ? result.value : "timeout";
187
+ }
188
+ /** The ops day a candidate's expiry clock runs from: the day it was
189
+ * re-opened, else its first offer. */
190
+ function clockDay(c) {
191
+ return c.reopened_day ?? c.offered_day ?? "";
192
+ }
193
+ function writeAtomic(path, body) {
194
+ const tmp = `${path}.tmp-${process.pid}`;
195
+ writeFileSync(tmp, body);
196
+ renameSync(tmp, path);
197
+ }
198
+ /** Shared admission for the status incident and the durable wake. */
199
+ function missingCuration(row, laterReceipt, now, waitMs) {
200
+ const fired = Date.parse(row.fired_at ?? "");
201
+ return (!laterReceipt &&
202
+ row.receipt_at === null &&
203
+ jsonColumn(row.offered, []).length > 0 &&
204
+ Number.isFinite(fired) &&
205
+ (row.missing_woken_at !== null || now - fired >= waitMs));
206
+ }
207
+ export class Learner {
208
+ deps;
209
+ store;
210
+ cfg;
211
+ now;
212
+ log;
213
+ mining = null;
214
+ timer = null;
215
+ ticking = false;
216
+ /** The last complete read of the lessons in force. */
217
+ lessonsRead = null;
218
+ constructor(deps) {
219
+ this.deps = deps;
220
+ this.store = deps.store;
221
+ this.cfg = { ...LEARNER_DEFAULTS, ...(deps.config ?? {}) };
222
+ this.now = deps.now ?? (() => new Date());
223
+ this.log = deps.log ?? (() => { });
224
+ this.store.db.exec(SCHEMA);
225
+ }
226
+ ts() {
227
+ return this.now().toISOString();
228
+ }
229
+ /** The EOD date `now` falls on, in the EOD timezone. */
230
+ today() {
231
+ return zoneDateString(this.now(), this.deps.timeZone);
232
+ }
233
+ mark(key) {
234
+ const row = this.store.db.prepare("SELECT value FROM learner_marks WHERE key = ?").get(key);
235
+ return row ? (row.value ?? "") : null;
236
+ }
237
+ setMark(key, value) {
238
+ this.store.db
239
+ .prepare("INSERT INTO learner_marks (key, value, at) VALUES (?, ?, ?) ON CONFLICT(key) DO UPDATE SET value = excluded.value, at = excluded.at")
240
+ .run(key, value, this.ts());
241
+ }
242
+ // ---- 1. mine ---------------------------------------------------------------
243
+ /** Insert drafts; returns how many were new per source. */
244
+ insert(drafts) {
245
+ const at = this.ts();
246
+ const stmt = this.store.db.prepare(`INSERT OR IGNORE INTO lesson_candidates
247
+ (ref, source, kind, polarity, class, lens_ids, pr, round_no, finding_key, path, line,
248
+ summary, quote, evidence, occurred_at, mined_at, updated_at)
249
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`);
250
+ const added = {};
251
+ this.store.db.transaction(() => {
252
+ for (const d of drafts) {
253
+ const r = stmt.run(d.ref, d.source, d.kind, d.polarity, d.class, JSON.stringify(d.lens_ids), d.pr, d.round_no, d.finding_key, d.path, d.line, d.summary, d.quote, JSON.stringify(d.evidence), d.occurred_at, at, at);
254
+ if (r.changes > 0)
255
+ added[d.source] = (added[d.source] ?? 0) + 1;
256
+ }
257
+ })();
258
+ return added;
259
+ }
260
+ /**
261
+ * Mine every source once (single-flight: a mine already running is joined,
262
+ * never doubled). A source that throws is reported in `errors`; the others
263
+ * still land.
264
+ */
265
+ mine() {
266
+ if (this.mining)
267
+ return this.mining;
268
+ this.mining = this.mineOnce().finally(() => {
269
+ this.mining = null;
270
+ });
271
+ return this.mining;
272
+ }
273
+ async mineOnce() {
274
+ const now = this.now();
275
+ const since = this.mineSince(now);
276
+ const report = {
277
+ added: 0,
278
+ seen: {},
279
+ added_by_source: {},
280
+ recall: null,
281
+ digest: null,
282
+ fates: { revised: 0, withdrawn: 0, reinstated: 0 },
283
+ relinked: 0,
284
+ errors: [],
285
+ };
286
+ const drafts = [];
287
+ const run = (name, fn) => {
288
+ try {
289
+ drafts.push(...fn());
290
+ }
291
+ catch (err) {
292
+ report.errors.push(`${name}: ${err instanceof Error ? err.message : String(err)}`);
293
+ }
294
+ };
295
+ run("fates", () => mineFates(this.store, since));
296
+ // The ledger before the tagged comments: a [feedback] comment the ledger
297
+ // holds is a `feedback_comment`; only a drained one is a `tagged_comment`.
298
+ run("feedback", () => mineFeedback(this.store, since));
299
+ run("tagged comments", () => mineTaggedComments(this.store, since));
300
+ run("human recall", () => mineHumanRecall(this.store, since, this.deps.botLogin));
301
+ // The recheck's own APPROVE → REQUEST_CHANGES reversals — the reviewer's
302
+ // conclusion, so a candidate only, gated on a standing APPROVE and one per
303
+ // (PR, head) (miner.ts header).
304
+ run("recheck reversals", () => mineRecheckFlips(this.store, since));
305
+ // Post-merge recall stores its candidates as it records each read.
306
+ let recallAdded = 0;
307
+ if (this.deps.git) {
308
+ try {
309
+ const r = await minePostMerge(this.store, {
310
+ ...this.recallScope(now, this.deps.git),
311
+ maxPrs: RECALL_SCAN_LIMITS.prsPerMine,
312
+ persist: (d) => {
313
+ recallAdded += this.insert(d).recall ?? 0;
314
+ },
315
+ });
316
+ drafts.push(...r.drafts);
317
+ report.recall = { scanned: r.scanned, unknown: r.unknown };
318
+ }
319
+ catch (err) {
320
+ report.errors.push(`post-merge: ${err instanceof Error ? err.message : String(err)}`);
321
+ }
322
+ }
323
+ for (const d of drafts)
324
+ report.seen[d.source] = (report.seen[d.source] ?? 0) + 1;
325
+ report.added_by_source = this.insert(drafts);
326
+ if (recallAdded > 0)
327
+ report.added_by_source.recall = (report.added_by_source.recall ?? 0) + recallAdded;
328
+ try {
329
+ const oldest = this.store.db
330
+ .prepare("SELECT MIN(occurred_at) AS at FROM lesson_candidates WHERE status='open' AND source IN ('feedback','tagged-comment')")
331
+ .get();
332
+ const relinkDrafts = oldest.at !== null && oldest.at < since
333
+ ? [...mineFeedback(this.store, oldest.at), ...mineTaggedComments(this.store, oldest.at)]
334
+ : drafts;
335
+ report.relinked = this.relink(relinkDrafts);
336
+ }
337
+ catch (err) {
338
+ report.errors.push(`relink: ${err instanceof Error ? err.message : String(err)}`);
339
+ }
340
+ try {
341
+ report.fates = this.reviseFates(since);
342
+ }
343
+ catch (err) {
344
+ report.errors.push(`fate revision: ${err instanceof Error ? err.message : String(err)}`);
345
+ }
346
+ // The lost digest learnings — once, until every digest of the range was
347
+ // read (a file that could not be read keeps it owed).
348
+ const digestKey = `digest-backfill:${this.cfg.lessons_digest_backfill_from}..${this.cfg.lessons_digest_backfill_to}`;
349
+ if (this.mark(digestKey) === null) {
350
+ try {
351
+ const d = mineDigestBackfill({
352
+ dir: join(this.deps.root, "digest"),
353
+ from: this.cfg.lessons_digest_backfill_from,
354
+ to: this.cfg.lessons_digest_backfill_to,
355
+ });
356
+ const added = this.insert(d.drafts)["digest-backfill"] ?? 0;
357
+ report.digest = { files: d.files, absent: d.absent, unreadable: d.unreadable, added };
358
+ report.added_by_source["digest-backfill"] = added;
359
+ report.seen["digest-backfill"] = d.drafts.length;
360
+ if (d.unreadable === 0)
361
+ this.setMark(digestKey, JSON.stringify(report.digest));
362
+ }
363
+ catch (err) {
364
+ report.errors.push(`digest backfill: ${err instanceof Error ? err.message : String(err)}`);
365
+ }
366
+ }
367
+ report.added = Object.values(report.added_by_source).reduce((n, v) => n + (v ?? 0), 0);
368
+ this.store.logEvent("lessons_mined", null, report);
369
+ return report;
370
+ }
371
+ /**
372
+ * An undecided `[feedback]` reply, tagged comment or deleted bot comment
373
+ * takes its class, lens and anchor from the outcome capture's link of the
374
+ * bot comment it answered — a link the reconcile sweep or the case backfill
375
+ * may make only after the candidate was mined, and `INSERT OR IGNORE` never
376
+ * revisits a row, so it would stay `feedback.general` with no lens for good.
377
+ * Every mine re-derives them from today's drafts, as `reviseFates` does for
378
+ * fates. Decided candidates are history. A ref two routes both drafted
379
+ * takes its FIRST draft, as the insert does: the ledger's before the
380
+ * tagged comment's.
381
+ */
382
+ relink(drafts) {
383
+ const stmt = this.store.db.prepare(`UPDATE lesson_candidates SET class = ?, lens_ids = ?, round_no = ?, finding_key = ?, path = ?,
384
+ line = ?, summary = ?, evidence = ?, updated_at = ?
385
+ WHERE ref = ? AND status = 'open' AND source IN ('feedback', 'tagged-comment')
386
+ AND (class IS NOT ? OR lens_ids IS NOT ? OR round_no IS NOT ? OR finding_key IS NOT ?
387
+ OR path IS NOT ? OR line IS NOT ? OR summary IS NOT ?)`);
388
+ const at = this.ts();
389
+ let n = 0;
390
+ const seen = new Set();
391
+ this.store.db.transaction(() => {
392
+ for (const d of drafts) {
393
+ if (d.source !== "feedback" && d.source !== "tagged-comment")
394
+ continue;
395
+ if (seen.has(d.ref))
396
+ continue;
397
+ seen.add(d.ref);
398
+ const lens = JSON.stringify(d.lens_ids);
399
+ n += stmt.run(d.class, lens, d.round_no, d.finding_key, d.path, d.line, d.summary, JSON.stringify(d.evidence), at, d.ref, d.class, lens, d.round_no, d.finding_key, d.path, d.line, d.summary).changes;
400
+ }
401
+ })();
402
+ return n;
403
+ }
404
+ /** The oldest event a mine reads: `lessons_mine_days` before `now`. */
405
+ mineSince(now) {
406
+ return new Date(now.getTime() - this.cfg.lessons_mine_days * DAY_MS).toISOString();
407
+ }
408
+ /** The start of the recurrence window a cluster counts over. */
409
+ recurrenceSince() {
410
+ return new Date(this.now().getTime() - this.cfg.lessons_recurrence_days * DAY_MS).toISOString();
411
+ }
412
+ /** What post-merge recall reads — the same for the day's mine and the
413
+ * ticks between mines, which differ only in their budgets. */
414
+ recallScope(now, git) {
415
+ return {
416
+ sinceIso: this.mineSince(now),
417
+ now,
418
+ windowDays: this.cfg.lessons_recall_window_days,
419
+ baseBranch: this.deps.baseBranch,
420
+ git,
421
+ log: this.log,
422
+ };
423
+ }
424
+ /**
425
+ * Post-merge recall between mines (`RECALL_SCAN_LIMITS.prsPerTick` PRs and
426
+ * `budgetMs` a tick): the day's mine alone reads too few merged PRs to keep
427
+ * up with the merge rate or drain a backlog. Git only, read-only; what it
428
+ * finds is inserted at once and offered by the next packet. Never throws.
429
+ */
430
+ async recallStep() {
431
+ const git = this.deps.git;
432
+ if (!git)
433
+ return;
434
+ let added = 0;
435
+ try {
436
+ const r = await minePostMerge(this.store, {
437
+ ...this.recallScope(this.now(), git),
438
+ maxPrs: RECALL_SCAN_LIMITS.prsPerTick,
439
+ budgetMs: RECALL_SCAN_LIMITS.budgetMs,
440
+ persist: (d) => {
441
+ added += this.insert(d).recall ?? 0;
442
+ },
443
+ });
444
+ if (r.scanned > 0 || added > 0)
445
+ this.log(`learner: post-merge recall read ${r.scanned} merged PR(s), ${added} new candidate(s)${r.unknown ? `, ${r.unknown} unknown` : ""}`);
446
+ }
447
+ catch (err) {
448
+ this.log("learner: post-merge recall failed", err);
449
+ }
450
+ }
451
+ /**
452
+ * Re-read the undecided fate candidates against the outcome capture's
453
+ * outcomes as they stand (`reviewFateCandidates`): the capture re-decides a
454
+ * fate on every pass and may join a posting to an earlier chain later, so a
455
+ * candidate minted once is never trusted as written. One whose chain still
456
+ * holds a candidate fate is revised in place (its kind, polarity and summary
457
+ * follow the fate); one that no longer does is withdrawn — recorded on the
458
+ * row, in an event and in the mine's report, never deleted; and a withdrawn
459
+ * one whose chain holds a candidate fate again is reinstated (its ref is
460
+ * the same, so the mine's insert could not bring it back). Queued and
461
+ * offered candidates alike; a
462
+ * decided one is history and is left as it is.
463
+ */
464
+ reviseFates(sinceIso) {
465
+ const db = this.store.db;
466
+ const hasOutcomes = tableExists(this.store, "finding_outcomes");
467
+ const freshOutcome = hasOutcomes
468
+ ? "OR pr IN (SELECT pr FROM finding_outcomes WHERE COALESCE(decided_at,fate_changed_at)>=?)"
469
+ : "";
470
+ const rows = this.candidates(`source = 'fate' AND (status='open' OR (status='withdrawn' AND (decided_at>=? ${freshOutcome}))) ORDER BY id`, sinceIso, ...(hasOutcomes ? [sinceIso] : []));
471
+ const out = { revised: 0, withdrawn: 0, reinstated: 0 };
472
+ if (rows.length === 0)
473
+ return out;
474
+ const reviews = reviewFateCandidates(this.store, rows);
475
+ const at = this.ts();
476
+ const day = this.today();
477
+ const changes = [];
478
+ const refresh = (c, d) => [
479
+ d.kind,
480
+ d.polarity,
481
+ d.class,
482
+ JSON.stringify(d.lens_ids),
483
+ d.summary,
484
+ d.quote,
485
+ JSON.stringify(d.evidence),
486
+ d.path,
487
+ d.line,
488
+ // The event's time moves only with its fate: a recurrence window
489
+ // counts the human outcome, not the capture's re-reading of it.
490
+ d.kind !== c.kind ? d.occurred_at : c.occurred_at,
491
+ ];
492
+ db.transaction(() => {
493
+ for (const c of rows) {
494
+ const r = reviews.get(c.id);
495
+ if (!r)
496
+ continue;
497
+ if (r.kind === "gone") {
498
+ if (c.status !== "open")
499
+ continue;
500
+ db.prepare(`UPDATE lesson_candidates SET status = 'withdrawn', decided_at = ?, decided_day = ?, reason = ?, updated_at = ?
501
+ WHERE id = ? AND status = 'open'`).run(at, day, `withdrawn: ${r.why}`, at, c.id);
502
+ out.withdrawn += 1;
503
+ changes.push({ id: c.id, change: "withdrawn", why: r.why });
504
+ continue;
505
+ }
506
+ const d = r.draft;
507
+ if (c.status === "withdrawn") {
508
+ db.prepare(`UPDATE lesson_candidates SET status = 'open', decided_at = NULL, decided_day = NULL, reason = ?,
509
+ reopened_day = CASE WHEN offered_day IS NULL THEN NULL ELSE ? END,
510
+ kind = ?, polarity = ?, class = ?, lens_ids = ?, summary = ?, quote = ?, evidence = ?,
511
+ path = ?, line = ?, occurred_at = ?, updated_at = ?
512
+ WHERE id = ? AND status = 'withdrawn'`).run(`reinstated: its fate is ${d.kind} again`, day, ...refresh(c, d), at, c.id);
513
+ out.reinstated += 1;
514
+ changes.push({ id: c.id, change: "reinstated" });
515
+ continue;
516
+ }
517
+ if (d.kind === c.kind &&
518
+ d.polarity === c.polarity &&
519
+ d.class === c.class &&
520
+ JSON.stringify(d.lens_ids) === c.lens_ids &&
521
+ d.summary === c.summary &&
522
+ d.quote === c.quote &&
523
+ d.path === c.path &&
524
+ d.line === c.line)
525
+ continue;
526
+ db.prepare(`UPDATE lesson_candidates SET kind = ?, polarity = ?, class = ?, lens_ids = ?, summary = ?, quote = ?,
527
+ evidence = ?, path = ?, line = ?, occurred_at = ?, updated_at = ?
528
+ WHERE id = ? AND status = 'open'`).run(...refresh(c, d), at, c.id);
529
+ out.revised += 1;
530
+ changes.push({ id: c.id, change: d.kind !== c.kind ? `${c.kind} → ${d.kind}` : "revised" });
531
+ }
532
+ })();
533
+ if (changes.length > 0)
534
+ this.store.logEvent("lesson_candidates_revised", null, { changes });
535
+ return out;
536
+ }
537
+ // ---- 2. the packet ---------------------------------------------------------
538
+ candidates(where, ...args) {
539
+ return this.store.db
540
+ .prepare(`SELECT * FROM lesson_candidates WHERE ${where}`)
541
+ .all(...args);
542
+ }
543
+ /** Read the lessons in force (experiences/), bounded; null when memory is
544
+ * off, unhealthy or does not answer in time. Remembers a complete read. */
545
+ async readLessons() {
546
+ if (!this.deps.lessons)
547
+ return null;
548
+ if (this.deps.healthy && !this.deps.healthy())
549
+ return null;
550
+ const res = await withTimeout(this.deps.lessons.sweep(), LESSON_READ_BUDGET_MS, (err) => this.log("learner: the lessons read failed", err));
551
+ if (res === "timeout")
552
+ return null;
553
+ const lessons = [];
554
+ for (const e of res.entries) {
555
+ if (areaOfId(e.id) !== EXPERIENCES_AREA)
556
+ continue;
557
+ const p = parseLesson(e.text);
558
+ if (p)
559
+ lessons.push({ ...p, id: e.id });
560
+ }
561
+ // Newest first (ids carry their stamp), so a coverage list leads with the
562
+ // freshest lesson.
563
+ lessons.sort((a, b) => (a.id < b.id ? 1 : a.id > b.id ? -1 : 0));
564
+ const complete = res.unread.length === 0;
565
+ if (complete)
566
+ this.lessonsRead = { lessons, complete, at: this.ts() };
567
+ return { lessons, complete };
568
+ }
569
+ /** Per class, the candidates whose event fell in the window, whatever
570
+ * became of them — offered, queued, decided or expired — except the
571
+ * withdrawn (minted from an outcome that has since changed). */
572
+ recurrence(sinceIso) {
573
+ return new Map(this.store.db
574
+ .prepare("SELECT class, COUNT(*) AS n FROM lesson_candidates WHERE occurred_at >= ? AND status <> 'withdrawn' GROUP BY class")
575
+ .all(sinceIso).map((r) => [r.class, r.n]));
576
+ }
577
+ /** Per class, the posted findings humans fixed and left open in the
578
+ * window — the counterweight a cluster shows. */
579
+ counterweights(sinceIso) {
580
+ const out = new Map();
581
+ if (!tableExists(this.store, "finding_outcomes"))
582
+ return out;
583
+ const prs = this.store.db
584
+ .prepare("SELECT DISTINCT pr FROM finding_outcomes WHERE fate IN ('fixed','open_at_close') AND COALESCE(decided_at,fate_changed_at)>=?")
585
+ .all(sinceIso);
586
+ const finding = this.store.db.prepare("SELECT lens_ids,lens,kind FROM round_findings WHERE pr=? AND round_no=? AND finding_key=?");
587
+ for (const { pr } of prs)
588
+ for (const { root, end } of chainRoots(outcomeRows(this.store, pr))) {
589
+ if (!["fixed", "open_at_close"].includes(end.fate) ||
590
+ (end.decided_at ?? end.fate_changed_at) < sinceIso)
591
+ continue;
592
+ const f = finding.get(pr, root.round_no, root.finding_key);
593
+ if (!f)
594
+ continue;
595
+ const cls = findingClass(lensIdsOf(f.lens_ids, f.lens), f.kind);
596
+ const count = out.get(cls) ?? { fixed: 0, ignored: 0 };
597
+ if (end.fate === "fixed")
598
+ count.fixed++;
599
+ else
600
+ count.ignored++;
601
+ out.set(cls, count);
602
+ }
603
+ return out;
604
+ }
605
+ /**
606
+ * Build and write the packet for EOD day `day`: expire, offer, carry,
607
+ * cluster. Idempotent per day — a second build (a retried fire) offers no
608
+ * more than the day's cap and expires nothing twice.
609
+ */
610
+ async buildPacket(day) {
611
+ const at = this.ts();
612
+ const db = this.store.db;
613
+ // Expire: offered, undecided, past the window — counted from its first
614
+ // offer, or from the day a refused write or an unfound adoption re-opened
615
+ // it (that candidate was promised the next packet, and gets a full window).
616
+ const expired = [];
617
+ db.transaction(() => {
618
+ for (const c of this.candidates("status = 'open' AND offered_day IS NOT NULL")) {
619
+ if (dayDiff(clockDay(c), day) < this.cfg.lessons_expiry_ops_days)
620
+ continue;
621
+ db.prepare(`UPDATE lesson_candidates SET status = 'expired', decided_at = ?, decided_day = ?, reason = ?, updated_at = ?
622
+ WHERE id = ? AND status = 'open'`).run(at, day, c.reopened_day
623
+ ? `undecided ${this.cfg.lessons_expiry_ops_days} ops days after it was re-opened (${c.reopened_day}; first offered ${c.offered_day})`
624
+ : `undecided ${this.cfg.lessons_expiry_ops_days} ops days after it was first offered (${c.offered_day})`, at, c.id);
625
+ expired.push({
626
+ id: c.id,
627
+ label: candidateLabel(c.id),
628
+ class: c.class,
629
+ summary: c.summary,
630
+ offered_day: c.offered_day,
631
+ });
632
+ }
633
+ if (expired.length > 0)
634
+ this.store.logEvent("lesson_candidates_expired", null, {
635
+ day,
636
+ ids: expired.map((e) => e.id),
637
+ after_ops_days: this.cfg.lessons_expiry_ops_days,
638
+ });
639
+ })();
640
+ // Candidates expired by an earlier build of the same day stay listed —
641
+ // the ones its record lists, and the ones its expiry committed before
642
+ // that build was cut short (the rows say so: expired on this day).
643
+ const prior = this.curation(day);
644
+ const priorExpired = prior ? jsonColumn(prior.expired, []) : [];
645
+ const expiredOnDay = this.candidates("status = 'expired' AND decided_day = ? ORDER BY id", day);
646
+ for (const id of [...priorExpired, ...expiredOnDay.map((c) => c.id)]) {
647
+ if (expired.some((e) => e.id === id))
648
+ continue;
649
+ const c = this.candidates("id = ?", id)[0];
650
+ if (c)
651
+ expired.push({
652
+ id: c.id,
653
+ label: candidateLabel(c.id),
654
+ class: c.class,
655
+ summary: c.summary,
656
+ offered_day: c.offered_day ?? day,
657
+ });
658
+ }
659
+ // Offer: queued candidates, look-for first, up to the day's cap — the
660
+ // reviewer's own recheck reversals after every other source, so its own
661
+ // conclusions never crowd a person's outcome out of the packet.
662
+ const offeredToday = db.prepare("SELECT COUNT(*) AS n FROM lesson_candidates WHERE offered_day = ?").get(day).n;
663
+ const slots = Math.max(0, this.cfg.lessons_packet_new_max - offeredToday);
664
+ if (slots > 0) {
665
+ const fresh = db
666
+ .prepare(`SELECT id FROM lesson_candidates WHERE status = 'open' AND offered_day IS NULL
667
+ ORDER BY CASE source WHEN 'recheck' THEN 1 ELSE 0 END,
668
+ CASE polarity WHEN 'look-for' THEN 0 ELSE 1 END,
669
+ CASE source WHEN 'recall' THEN 0 WHEN 'fate' THEN 1 WHEN 'feedback' THEN 2
670
+ WHEN 'tagged-comment' THEN 2 ELSE 3 END,
671
+ occurred_at DESC, id
672
+ LIMIT ?`)
673
+ .all(slots);
674
+ const offer = db.prepare("UPDATE lesson_candidates SET offered_day = ?, updated_at = ? WHERE id = ? AND offered_day IS NULL");
675
+ db.transaction(() => {
676
+ for (const f of fresh)
677
+ offer.run(day, at, f.id);
678
+ })();
679
+ }
680
+ // Carry: every offered candidate still undecided rides today's packet.
681
+ db.prepare(`UPDATE lesson_candidates SET offers = offers + 1, last_offered_day = ?, updated_at = ?
682
+ WHERE status = 'open' AND offered_day IS NOT NULL AND (last_offered_day IS NULL OR last_offered_day <> ?)`).run(day, at, day);
683
+ const offered = this.candidates("status = 'open' AND offered_day IS NOT NULL ORDER BY class, occurred_at DESC, id");
684
+ const queued = db
685
+ .prepare("SELECT COUNT(*) AS n FROM lesson_candidates WHERE status = 'open' AND offered_day IS NULL")
686
+ .get().n;
687
+ // Cluster, with recurrence, the counterweight and coverage.
688
+ const since = this.recurrenceSince();
689
+ const recurrence = this.recurrence(since);
690
+ const weights = this.counterweights(since);
691
+ const read = await this.readLessons();
692
+ const byClass = new Map();
693
+ for (const c of offered)
694
+ byClass.set(c.class, [...(byClass.get(c.class) ?? []), c]);
695
+ const toPacket = (c) => ({
696
+ id: c.id,
697
+ label: candidateLabel(c.id),
698
+ kind: c.kind,
699
+ source: c.source,
700
+ polarity: c.polarity,
701
+ class: c.class,
702
+ lens_ids: jsonColumn(c.lens_ids, []),
703
+ pr: c.pr,
704
+ path: c.path,
705
+ line: c.line,
706
+ summary: c.summary,
707
+ quote: c.quote,
708
+ evidence: jsonColumn(c.evidence, []),
709
+ occurred_at: c.occurred_at,
710
+ offered_day: c.offered_day,
711
+ expires_after: addDays(clockDay(c), this.cfg.lessons_expiry_ops_days - 1),
712
+ new: c.offered_day === day,
713
+ });
714
+ // A partial read proves nothing absent: the lessons it found do cover the
715
+ // class, but "none found" is unknown, and a balance over part of memory
716
+ // is no balance at all.
717
+ const coverage = (cls, lensIds) => {
718
+ if (!read)
719
+ return null;
720
+ const found = coveringLessons(read.lessons, cls, lensIds);
721
+ return read.complete || found.length > 0 ? found : null;
722
+ };
723
+ const clusters = [...byClass.entries()].map(([cls, rows]) => {
724
+ const lensIds = [...new Set(rows.flatMap((r) => jsonColumn(r.lens_ids, [])))];
725
+ const w = weights.get(cls) ?? { fixed: 0, ignored: 0 };
726
+ return {
727
+ class: cls,
728
+ polarity: majorityPolarity(rows),
729
+ recurrence: recurrence.get(cls) ?? 0,
730
+ fixed: w.fixed,
731
+ ignored: w.ignored,
732
+ covering: coverage(cls, lensIds),
733
+ candidates: rows.map(toPacket),
734
+ };
735
+ });
736
+ // The reviewer's own recheck reversals after every other cluster —
737
+ // the same demotion as the first offer, because a busy reversal class
738
+ // would otherwise lead the packet on recurrence alone; then misses first,
739
+ // then the busiest classes.
740
+ const reviewerOnly = (c) => c.candidates.every((x) => x.source === "recheck");
741
+ clusters.sort((a, b) => Number(reviewerOnly(a)) - Number(reviewerOnly(b)) ||
742
+ Number(b.polarity === "look-for") - Number(a.polarity === "look-for") ||
743
+ b.recurrence - a.recurrence ||
744
+ a.class.localeCompare(b.class));
745
+ const fresh = offered.filter((c) => c.offered_day === day).length;
746
+ const packet = {
747
+ day,
748
+ generated_at: at,
749
+ expiry_ops_days: this.cfg.lessons_expiry_ops_days,
750
+ recurrence_days: this.cfg.lessons_recurrence_days,
751
+ offered: offered.length,
752
+ new: fresh,
753
+ carried: offered.length - fresh,
754
+ queued,
755
+ expired,
756
+ balance: read?.complete ? lessonBalance(read.lessons) : null,
757
+ lessons_read: !this.deps.lessons
758
+ ? "off"
759
+ : read === null
760
+ ? "unreadable"
761
+ : read.complete
762
+ ? "ok"
763
+ : "partial",
764
+ clusters,
765
+ };
766
+ const dir = join(this.deps.root, packetRelDir(day));
767
+ mkdirSync(dir, { recursive: true });
768
+ writeAtomic(join(dir, "outcomes.json"), `${JSON.stringify(packet, null, 2)}\n`);
769
+ writeAtomic(join(this.deps.root, packetMarkdownRel(day)), renderPacketMarkdown(packet));
770
+ db.prepare(`INSERT INTO eod_curations (day, packet_at, offered, new_today, expired, updated_at)
771
+ VALUES (?, ?, ?, ?, ?, ?)
772
+ ON CONFLICT(day) DO UPDATE SET packet_at = excluded.packet_at, offered = excluded.offered,
773
+ new_today = excluded.new_today, expired = excluded.expired, updated_at = excluded.updated_at`).run(day, at, JSON.stringify(offered.map((c) => c.id)), JSON.stringify(offered.filter((c) => c.offered_day === day).map((c) => c.id)), JSON.stringify(expired.map((e) => e.id)), at);
774
+ this.store.logEvent("eod_packet_written", null, {
775
+ day,
776
+ offered: packet.offered,
777
+ new: packet.new,
778
+ carried: packet.carried,
779
+ queued,
780
+ expired: expired.length,
781
+ lessons_read: packet.lessons_read,
782
+ });
783
+ return packet;
784
+ }
785
+ /**
786
+ * The EOD sweep's day context (wire.ts → `dayContext`): mine first when the
787
+ * day's mine has not run (bounded — a slow git read never holds the sweep),
788
+ * then build the packet. `lines` is the pointer the digest carries;
789
+ * `curation` the instructions the prompt renders after the seed.
790
+ */
791
+ async prepareEod(day) {
792
+ if (this.mark(`mined:${day}`) === null) {
793
+ const r = await withTimeout(this.mine(), PREPARE_MINE_BUDGET_MS, (err) => this.log("learner: the EOD mine failed", err));
794
+ if (r !== "timeout")
795
+ this.setMark(`mined:${day}`, this.ts());
796
+ }
797
+ const packet = await this.buildPacket(day);
798
+ return { lines: packetPointer(packet), curation: renderCurationSection(packet), packet };
799
+ }
800
+ /** The sweep for `day` reached the overseer (`EodTimerDeps.onFire`): the
801
+ * receipt is owed from now. */
802
+ eodFired(day) {
803
+ const at = this.ts();
804
+ this.store.db
805
+ .prepare(`INSERT INTO eod_curations (day, fired_at, updated_at) VALUES (?, ?, ?)
806
+ ON CONFLICT(day) DO UPDATE SET fired_at = excluded.fired_at, updated_at = excluded.updated_at`)
807
+ .run(day, at, at);
808
+ }
809
+ curation(day) {
810
+ return this.store.db.prepare("SELECT * FROM eod_curations WHERE day = ?").get(day);
811
+ }
812
+ // ---- 3. the receipt -----------------------------------------------------------
813
+ /**
814
+ * Apply a validated `eod-curation-receipt`. All or nothing: a day with no
815
+ * packet, a candidate id the learner never minted, or one that day's packet
816
+ * did not offer, refuses the whole receipt (the curator fixes it and writes
817
+ * it again) — a receipt decides what its packet put in front of the
818
+ * curator, never a queued candidate nobody showed it. `adopted` waits for
819
+ * memory to show the lesson (`adopting`);
820
+ * `declined` is final; `refused` keeps the candidate open and wakes
821
+ * `eod_lessons_not_persisted` at once. A candidate already settled since
822
+ * the packet — adopted (memory showed its lesson), withdrawn or expired —
823
+ * keeps its status whatever the receipt says: memory's evidence and the
824
+ * learner's own record outrank a later claim (only `refused` re-opens an
825
+ * expired one, with a fresh clock).
826
+ */
827
+ applyReceipt(receipt) {
828
+ const row = this.curation(receipt.day);
829
+ if (!row?.packet_at)
830
+ return { ok: false, reason: `no outcomes packet was written for ${receipt.day}` };
831
+ const ids = receipt.decisions.flatMap((d) => d.candidates);
832
+ const offered = new Set(jsonColumn(row.offered, []));
833
+ const known = new Set(ids.length === 0
834
+ ? []
835
+ : this.store.db
836
+ .prepare(`SELECT id FROM lesson_candidates WHERE id IN (${ids.map(() => "?").join(",")})`)
837
+ .all(...ids).map((r) => r.id));
838
+ const unknown = ids.filter((id) => !known.has(id));
839
+ if (unknown.length > 0)
840
+ return {
841
+ ok: false,
842
+ reason: `unknown candidate id(s): ${unknown.map(candidateLabel).join(", ")} — nothing was recorded; send the receipt again without them`,
843
+ };
844
+ const notOffered = ids.filter((id) => !offered.has(id));
845
+ if (notOffered.length > 0)
846
+ return {
847
+ ok: false,
848
+ reason: `candidate id(s) the ${receipt.day} packet did not offer: ${notOffered.map(candidateLabel).join(", ")} — nothing was recorded; decide only what that packet offered`,
849
+ };
850
+ const at = this.ts();
851
+ const today = this.today();
852
+ const db = this.store.db;
853
+ const counts = { adopted: 0, declined: 0, refused: 0 };
854
+ const refused = [];
855
+ db.transaction(() => {
856
+ for (const d of receipt.decisions) {
857
+ for (const id of d.candidates) {
858
+ if (d.decision === "adopted") {
859
+ // An adoption memory already showed stands; an undecided one
860
+ // waits for the lesson to be found; a settled one keeps its
861
+ // decision and the reason for it — only the receipt is recorded.
862
+ db.prepare(`UPDATE lesson_candidates SET status = CASE WHEN status IN ('open', 'adopting') THEN 'adopting' ELSE status END,
863
+ claimed_lesson = CASE WHEN status IN ('open', 'adopting') THEN ? ELSE claimed_lesson END,
864
+ reason = CASE WHEN status IN ('open', 'adopting') THEN COALESCE(?, reason) ELSE reason END,
865
+ receipt_day = ?, receipt_at = ?, updated_at = ?
866
+ WHERE id = ?`).run(d.lesson ?? null, d.reason ?? null, receipt.day, at, at, id);
867
+ counts.adopted += 1;
868
+ }
869
+ else if (d.decision === "declined") {
870
+ // Only an undecided candidate is declined: a declination never
871
+ // overwrites a memory-verified adoption, a withdrawal or an expiry.
872
+ db.prepare(`UPDATE lesson_candidates SET status = 'declined', decided_at = ?, decided_day = ?, reason = ?,
873
+ receipt_day = ?, receipt_at = ?, updated_at = ? WHERE id = ? AND status IN ('open', 'adopting')`).run(at, receipt.day, d.reason ?? null, receipt.day, at, at, id);
874
+ db.prepare("UPDATE lesson_candidates SET receipt_day = ?, receipt_at = ?, updated_at = ? WHERE id = ? AND status NOT IN ('open', 'adopting')").run(receipt.day, at, at, id);
875
+ counts.declined += 1;
876
+ }
877
+ else {
878
+ // A refused write puts the candidate back in the packet with a
879
+ // fresh expiry clock (it was promised the next packet); one
880
+ // already adopted, declined or withdrawn stays as it is.
881
+ const before = db.prepare("SELECT status FROM lesson_candidates WHERE id = ?").get(id).status;
882
+ const keep = SETTLED_STATUSES.includes(before) && before !== "expired";
883
+ if (keep)
884
+ db.prepare("UPDATE lesson_candidates SET receipt_day = ?, receipt_at = ?, updated_at = ? WHERE id = ?").run(receipt.day, at, at, id);
885
+ else
886
+ db.prepare(`UPDATE lesson_candidates SET status = 'open', reopened_day = ?, decided_at = NULL, decided_day = NULL,
887
+ reason = ?, receipt_day = ?, receipt_at = ?, updated_at = ? WHERE id = ?`).run(today, `write refused: ${d.reason ?? ""}`, receipt.day, at, at, id);
888
+ counts.refused += 1;
889
+ if (!keep)
890
+ refused.push({
891
+ id,
892
+ why: `the curator reported the write refused: ${d.reason ?? "no reason"}`,
893
+ });
894
+ }
895
+ }
896
+ }
897
+ db.prepare("UPDATE eod_curations SET receipt_at = ?, receipt = ?, updated_at = ? WHERE day = ?").run(at, JSON.stringify({ ...counts, decisions: receipt.decisions.length }), at, receipt.day);
898
+ this.store.logEvent("eod_curation_receipt", null, { day: receipt.day, ...counts });
899
+ if (refused.length > 0)
900
+ this.notPersisted(receipt.day, refused);
901
+ })();
902
+ return { ok: true, day: receipt.day, ...counts };
903
+ }
904
+ /** Record adoptions memory does not hold / writes refused, and wake when
905
+ * the list names something no earlier wake named. */
906
+ notPersisted(day, items) {
907
+ this.store.db.transaction(() => {
908
+ const row = this.curation(day);
909
+ const prev = jsonColumn(row?.not_persisted, []);
910
+ const merged = [...prev];
911
+ for (const i of items)
912
+ if (!merged.some((m) => m.id === i.id && m.why === i.why))
913
+ merged.push(i);
914
+ const woken = new Set(jsonColumn(row?.not_persisted_woken, []));
915
+ const key = (m) => `${m.id}:${m.why}`;
916
+ const fresh = merged.filter((m) => !woken.has(key(m)));
917
+ const at = this.ts();
918
+ // The incident starts when the day's list goes from empty to non-empty.
919
+ const since = prev.length > 0 && row?.not_persisted_since ? row.not_persisted_since : at;
920
+ this.store.db
921
+ .prepare(`INSERT INTO eod_curations (day, not_persisted, not_persisted_since, not_persisted_woken, updated_at)
922
+ VALUES (?, ?, ?, ?, ?)
923
+ ON CONFLICT(day) DO UPDATE SET not_persisted = excluded.not_persisted,
924
+ not_persisted_since = excluded.not_persisted_since,
925
+ not_persisted_woken = excluded.not_persisted_woken, updated_at = excluded.updated_at`)
926
+ .run(day, JSON.stringify(merged), since, JSON.stringify([...woken, ...fresh.map(key)]), at);
927
+ if (fresh.length === 0)
928
+ return;
929
+ const labels = merged.map((m) => candidateLabel(m.id)).join(", ");
930
+ this.deps.wake?.(LEARNER_WAKE.notPersisted, `EOD ${day}: ${merged.length} lesson(s) not persisted (${labels})`, [
931
+ `EOD LESSONS NOT PERSISTED — the curation of ${day} did not land ${merged.length} lesson(s) in reviewer memory: ${labels}.`,
932
+ ...merged.slice(0, 8).map((m) => `- ${candidateLabel(m.id)}: ${m.why.slice(0, 200)}`),
933
+ "The candidates are open again and ride the next outcomes packet. Check memory health (`qcr status`) and the overseer's viking_write answers; a lesson counts only once its typed header cites the candidate (`cand:c<id>`).",
934
+ ].join("\n"));
935
+ })();
936
+ }
937
+ // ---- 4. the tick: mine on time, verify, and wake when the receipt is late ----
938
+ /** When today's mine is due: `lessons_mine_lead_min` before the EOD time. */
939
+ mineDueAt() {
940
+ const p = zonedParts(this.now(), this.deps.timeZone);
941
+ const { hour, minute } = parseHHMM(this.deps.eodTime);
942
+ const fire = localWallClockToInstant(p.year, p.month, p.day, hour, minute, this.deps.timeZone);
943
+ return fire.getTime() - this.cfg.lessons_mine_lead_min * 60_000;
944
+ }
945
+ /** One pass: the day's mine when due, the missing-receipt check, and the
946
+ * verification of adoptions against memory. Never throws. */
947
+ async tick() {
948
+ if (this.ticking)
949
+ return;
950
+ this.ticking = true;
951
+ try {
952
+ const day = this.today();
953
+ if (this.now().getTime() >= this.mineDueAt() && this.mark(`mined:${day}`) === null) {
954
+ try {
955
+ const r = await this.mine();
956
+ this.setMark(`mined:${day}`, this.ts());
957
+ this.log(`learner: mined ${r.added} new lesson candidate(s) for ${day}${r.errors.length ? ` (${r.errors.length} source error(s))` : ""}`);
958
+ }
959
+ catch (err) {
960
+ this.log("learner: mine failed", err);
961
+ }
962
+ }
963
+ await this.recallStep();
964
+ try {
965
+ this.checkMissing();
966
+ }
967
+ catch (err) {
968
+ this.log("learner: receipt check failed", err);
969
+ }
970
+ try {
971
+ await this.verify();
972
+ }
973
+ catch (err) {
974
+ this.log("learner: verification failed", err);
975
+ }
976
+ }
977
+ finally {
978
+ this.ticking = false;
979
+ }
980
+ }
981
+ /** Wake `eod_curation_missing` once per day whose delivered sweep offered
982
+ * candidates and drew no receipt within the wait — never for a day a later
983
+ * day's receipt already made good (`unresolved`'s rule: its candidates rode
984
+ * that later packet), and an empty packet, which owes no receipt, never
985
+ * takes one of the checked days' places. */
986
+ checkMissing() {
987
+ const now = this.now().getTime();
988
+ const waitMs = this.cfg.lessons_receipt_wait_min * 60_000;
989
+ const rows = this.store.db
990
+ .prepare(`SELECT * FROM eod_curations WHERE fired_at IS NOT NULL AND receipt_at IS NULL
991
+ AND missing_woken_at IS NULL AND offered <> '[]'
992
+ AND day > COALESCE((SELECT MAX(day) FROM eod_curations WHERE receipt_at IS NOT NULL), '')
993
+ ORDER BY day DESC LIMIT 7`)
994
+ .all();
995
+ for (const r of rows) {
996
+ const offered = jsonColumn(r.offered, []);
997
+ if (offered.length === 0)
998
+ continue;
999
+ if (!missingCuration(r, false, now, waitMs))
1000
+ continue;
1001
+ this.store.db.transaction(() => {
1002
+ const at = this.ts();
1003
+ this.store.db
1004
+ .prepare("UPDATE eod_curations SET missing_woken_at = ?, updated_at = ? WHERE day = ?")
1005
+ .run(at, at, r.day);
1006
+ this.deps.wake?.(LEARNER_WAKE.missing, `EOD ${r.day}: no curation receipt ${this.cfg.lessons_receipt_wait_min} min after the sweep`, [
1007
+ `EOD CURATION MISSING — the EOD sweep for ${r.day} was delivered at ${r.fired_at}, its outcomes packet offered ${offered.length} candidate(s) (\`${packetMarkdownRel(r.day)}\`), and no \`eod-curation-receipt\` arrived within ${this.cfg.lessons_receipt_wait_min} minutes.`,
1008
+ "Nothing says the day's outcomes were curated. The candidates stay open and ride the next packet; undecided, they expire (recorded). Check the overseer session, then curate the packet and write the receipt.",
1009
+ ].join("\n"));
1010
+ })();
1011
+ }
1012
+ }
1013
+ /**
1014
+ * Check adoptions against memory (only while it reads healthy): a lesson
1015
+ * in `experiences/` whose typed header cites a candidate adopts it — with or
1016
+ * without a receipt. An `adopting` candidate whose receipt is older than the
1017
+ * grace, with memory read in full and no lesson citing it, was not
1018
+ * persisted: it goes back to open and wakes. A partial read proves nothing
1019
+ * absent.
1020
+ */
1021
+ async verify() {
1022
+ try {
1023
+ await this.verifyAgainstMemory();
1024
+ }
1025
+ finally {
1026
+ // State.db only: a decided candidate leaves the lists even while memory
1027
+ // cannot be read.
1028
+ this.pruneNotPersisted();
1029
+ }
1030
+ }
1031
+ async verifyAgainstMemory() {
1032
+ const waiting = this.store.db
1033
+ .prepare("SELECT COUNT(*) AS n FROM lesson_candidates WHERE status = 'adopting' OR (status = 'open' AND offered_day IS NOT NULL)")
1034
+ .get().n;
1035
+ // Memory is read every tick while an adoption waits to be checked or an
1036
+ // offered candidate may be adopted by a lesson written without a receipt
1037
+ // (the store's sweep is incremental: an unchanged file is not re-read),
1038
+ // and otherwise every `LESSON_REFRESH_MS`, for the balance metric.
1039
+ const last = this.lessonsRead ? Date.parse(this.lessonsRead.at) : NaN;
1040
+ if (waiting === 0 && Number.isFinite(last) && this.now().getTime() - last < LESSON_REFRESH_MS)
1041
+ return;
1042
+ const pending = this.candidates("status IN ('open', 'adopting')");
1043
+ const read = await this.readLessons();
1044
+ if (!read)
1045
+ return;
1046
+ const cited = new Map();
1047
+ for (const l of read.lessons)
1048
+ for (const id of l.candidates)
1049
+ cited.set(id, [...(cited.get(id) ?? []), l.id]);
1050
+ const at = this.ts();
1051
+ const db = this.store.db;
1052
+ const missingByDay = new Map();
1053
+ // `pending` was read before the memory read awaited: a receipt applied
1054
+ // meanwhile may have settled a candidate or re-dated its adoption, so
1055
+ // every write below holds only against the state it was decided from.
1056
+ db.transaction(() => {
1057
+ for (const c of pending) {
1058
+ const lessons = cited.get(c.id);
1059
+ if (lessons) {
1060
+ db.prepare(`UPDATE lesson_candidates SET status = 'adopted', lesson_ids = ?, decided_at = COALESCE(decided_at, ?),
1061
+ decided_day = COALESCE(decided_day, receipt_day, ?), updated_at = ?
1062
+ WHERE id = ? AND status IN ('open', 'adopting')`).run(JSON.stringify(lessons), at, this.today(), at, c.id);
1063
+ continue;
1064
+ }
1065
+ if (c.status !== "adopting" || !read.complete)
1066
+ continue;
1067
+ const receiptAt = Date.parse(c.receipt_at ?? "");
1068
+ if (!Number.isFinite(receiptAt) || this.now().getTime() - receiptAt < VERIFY_GRACE_MS)
1069
+ continue;
1070
+ // Back to the packet, with a fresh expiry clock: the wake promised the
1071
+ // next packet, and a candidate first offered days ago must not expire
1072
+ // at it.
1073
+ const reopened = db
1074
+ .prepare(`UPDATE lesson_candidates SET status = 'open', reopened_day = ?, reason = ?, updated_at = ?
1075
+ WHERE id = ? AND status = 'adopting' AND receipt_at IS ?`)
1076
+ .run(this.today(), `the receipt of ${c.receipt_day} said adopted, but no lesson in experiences/ cites cand:${candidateLabel(c.id)}`, at, c.id, c.receipt_at);
1077
+ if (reopened.changes === 0)
1078
+ continue;
1079
+ const day = c.receipt_day ?? this.today();
1080
+ missingByDay.set(day, [
1081
+ ...(missingByDay.get(day) ?? []),
1082
+ {
1083
+ id: c.id,
1084
+ why: `adopted${c.claimed_lesson ? ` as ${c.claimed_lesson}` : ""}, but no lesson in experiences/ cites cand:${candidateLabel(c.id)}`,
1085
+ },
1086
+ ]);
1087
+ }
1088
+ for (const [day, items] of missingByDay)
1089
+ this.notPersisted(day, items);
1090
+ })();
1091
+ }
1092
+ /** A candidate decided since leaves the not-persisted lists it was on: the
1093
+ * lesson landed after all (adopted — a retry, the next day's curation), or
1094
+ * the curator declined it, or it expired (recorded) or was withdrawn. What
1095
+ * stays on a list is still a lesson nobody has made good. */
1096
+ pruneNotPersisted() {
1097
+ const db = this.store.db;
1098
+ const settled = new Set(db
1099
+ .prepare(`SELECT id FROM lesson_candidates WHERE status IN (${SETTLED_SQL})`)
1100
+ .all().map((r) => r.id));
1101
+ const at = this.ts();
1102
+ for (const row of db
1103
+ .prepare("SELECT day, not_persisted FROM eod_curations WHERE not_persisted <> '[]'")
1104
+ .all()) {
1105
+ const list = jsonColumn(row.not_persisted, []);
1106
+ const kept = list.filter((m) => !settled.has(m.id));
1107
+ if (kept.length !== list.length)
1108
+ db.prepare(`UPDATE eod_curations SET not_persisted = ?,
1109
+ not_persisted_since = CASE WHEN ? = 0 THEN NULL ELSE not_persisted_since END, updated_at = ?
1110
+ WHERE day = ?`).run(JSON.stringify(kept), kept.length, at, row.day);
1111
+ }
1112
+ }
1113
+ start(intervalMs = 300_000) {
1114
+ if (this.timer)
1115
+ return;
1116
+ void this.tick();
1117
+ this.timer = setInterval(() => void this.tick(), Math.max(10_000, intervalMs));
1118
+ this.timer.unref?.();
1119
+ }
1120
+ stop() {
1121
+ if (this.timer)
1122
+ clearInterval(this.timer);
1123
+ this.timer = null;
1124
+ }
1125
+ // ---- reading back ------------------------------------------------------------
1126
+ /**
1127
+ * Every curation failure not made good since, newest first, over the last
1128
+ * `UNRESOLVED_SCAN_DAYS` curation days: a `missing` day (the sweep
1129
+ * delivered, candidates offered, no receipt within the wait) until it or a
1130
+ * later day is receipted — its candidates rode the later packet, so that
1131
+ * receipt decided them or carried them on — and a `not_persisted` day until
1132
+ * every candidate on its list is decided (`pruneNotPersisted`). The next
1133
+ * day's packet does not resolve either: a failure stays in front of a
1134
+ * person until something made it good.
1135
+ */
1136
+ unresolved() {
1137
+ const db = this.store.db;
1138
+ const rows = db
1139
+ .prepare("SELECT * FROM eod_curations ORDER BY day DESC LIMIT ?")
1140
+ .all(UNRESOLVED_SCAN_DAYS);
1141
+ const lists = new Map(rows.map((r) => [r.day, jsonColumn(r.not_persisted, [])]));
1142
+ const ids = [...new Set([...lists.values()].flatMap((l) => l.map((m) => m.id)))];
1143
+ const settled = new Set(ids.length === 0
1144
+ ? []
1145
+ : db
1146
+ .prepare(`SELECT id FROM lesson_candidates WHERE status IN (${SETTLED_SQL}) AND id IN (${ids.map(() => "?").join(",")})`)
1147
+ .all(...ids).map((r) => r.id));
1148
+ const now = this.now().getTime();
1149
+ const waitMs = this.cfg.lessons_receipt_wait_min * 60_000;
1150
+ const out = [];
1151
+ let laterReceipt = false;
1152
+ for (const r of rows) {
1153
+ const open = new Set((lists.get(r.day) ?? []).filter((m) => !settled.has(m.id)).map((m) => m.id));
1154
+ if (open.size > 0)
1155
+ out.push({
1156
+ day: r.day,
1157
+ state: "not_persisted",
1158
+ count: open.size,
1159
+ since: r.not_persisted_since ?? r.updated_at,
1160
+ });
1161
+ const offered = jsonColumn(r.offered, []);
1162
+ const fired = Date.parse(r.fired_at ?? "");
1163
+ if (missingCuration(r, laterReceipt, now, waitMs))
1164
+ out.push({
1165
+ day: r.day,
1166
+ state: "missing",
1167
+ count: offered.length,
1168
+ since: r.missing_woken_at ?? new Date(fired + waitMs).toISOString(),
1169
+ });
1170
+ if (r.receipt_at !== null)
1171
+ laterReceipt = true;
1172
+ }
1173
+ return out;
1174
+ }
1175
+ /** The curation for status.json: the newest unresolved failure when there
1176
+ * is one (a missed day stays reported after the next packet is written),
1177
+ * else the latest day's. */
1178
+ status() {
1179
+ const db = this.store.db;
1180
+ const count = (where, ...args) => db.prepare(`SELECT COUNT(*) AS n FROM lesson_candidates WHERE ${where}`).get(...args).n;
1181
+ const open = count("status = 'open' AND offered_day IS NOT NULL");
1182
+ const queued = count("status = 'open' AND offered_day IS NULL");
1183
+ const balance = this.lessonsRead
1184
+ ? { ...lessonBalance(this.lessonsRead.lessons), as_of: this.lessonsRead.at }
1185
+ : null;
1186
+ const unresolved = this.unresolved();
1187
+ const head = unresolved[0];
1188
+ const incident = unresolved[unresolved.length - 1] ?? null;
1189
+ const row = head
1190
+ ? this.curation(head.day)
1191
+ : db
1192
+ .prepare("SELECT * FROM eod_curations WHERE packet_at IS NOT NULL ORDER BY day DESC LIMIT 1")
1193
+ .get();
1194
+ if (!row)
1195
+ return {
1196
+ day: null,
1197
+ state: "no_packet",
1198
+ offered: 0,
1199
+ adopted: 0,
1200
+ declined: 0,
1201
+ verifying: 0,
1202
+ not_persisted: 0,
1203
+ expired_today: 0,
1204
+ open,
1205
+ queued,
1206
+ receipt_at: null,
1207
+ balance,
1208
+ unresolved,
1209
+ incident,
1210
+ };
1211
+ const offered = jsonColumn(row.offered, []);
1212
+ let state;
1213
+ if (head)
1214
+ state = head.state;
1215
+ else if (row.receipt_at !== null)
1216
+ state = "received";
1217
+ else if (row.fired_at === null)
1218
+ state = "packet_ready";
1219
+ else if (offered.length === 0)
1220
+ state = "nothing";
1221
+ else
1222
+ state = "awaiting";
1223
+ return {
1224
+ day: row.day,
1225
+ state,
1226
+ offered: offered.length,
1227
+ adopted: count("receipt_day = ? AND status = 'adopted'", row.day),
1228
+ declined: count("receipt_day = ? AND status = 'declined'", row.day),
1229
+ verifying: count("receipt_day = ? AND status = 'adopting'", row.day),
1230
+ not_persisted: unresolved.find((u) => u.day === row.day && u.state === "not_persisted")?.count ?? 0,
1231
+ expired_today: jsonColumn(row.expired, []).length,
1232
+ open,
1233
+ queued,
1234
+ receipt_at: row.receipt_at,
1235
+ balance,
1236
+ unresolved,
1237
+ incident,
1238
+ };
1239
+ }
1240
+ /** Undecided candidates per class, busiest first — `qcr lessons`. */
1241
+ clusters() {
1242
+ const since = this.recurrenceSince();
1243
+ const rows = this.candidates("status = 'open' ORDER BY class, id");
1244
+ const out = new Map();
1245
+ for (const r of rows) {
1246
+ const e = out.get(r.class) ?? { rows: [], queued: 0 };
1247
+ e.rows.push(r);
1248
+ if (r.offered_day === null)
1249
+ e.queued += 1;
1250
+ out.set(r.class, e);
1251
+ }
1252
+ const recurrence = this.recurrence(since);
1253
+ return [...out.entries()]
1254
+ .map(([cls, e]) => ({
1255
+ class: cls,
1256
+ polarity: majorityPolarity(e.rows),
1257
+ open: e.rows.length - e.queued,
1258
+ queued: e.queued,
1259
+ recurrence: recurrence.get(cls) ?? 0,
1260
+ }))
1261
+ .sort((a, b) => b.open + b.queued - (a.open + a.queued) || a.class.localeCompare(b.class));
1262
+ }
1263
+ /** One candidate row (tests, `qcr lessons`). */
1264
+ candidate(id) {
1265
+ return this.candidates("id = ?", id)[0];
1266
+ }
1267
+ /** Every candidate row, oldest first (tests). */
1268
+ allCandidates() {
1269
+ return this.candidates("1 = 1 ORDER BY id");
1270
+ }
1271
+ }
1272
+ //# sourceMappingURL=learner.js.map