@aitne/daemon 0.1.9 → 0.1.11

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 (333) hide show
  1. package/dist/adapters/adapter-watchdog.d.ts +70 -0
  2. package/dist/adapters/adapter-watchdog.js +115 -0
  3. package/dist/adapters/discord.d.ts +17 -1
  4. package/dist/adapters/discord.js +33 -0
  5. package/dist/adapters/notification-manager.d.ts +27 -1
  6. package/dist/adapters/notification-manager.js +54 -39
  7. package/dist/adapters/slack-adapter.d.ts +26 -1
  8. package/dist/adapters/slack-adapter.js +41 -0
  9. package/dist/adapters/telegram-adapter.d.ts +18 -1
  10. package/dist/adapters/telegram-adapter.js +41 -2
  11. package/dist/adapters/types.d.ts +20 -0
  12. package/dist/adapters/whatsapp-adapter.d.ts +26 -7
  13. package/dist/adapters/whatsapp-adapter.js +74 -21
  14. package/dist/api/env-writer.d.ts +1 -0
  15. package/dist/api/env-writer.js +17 -7
  16. package/dist/api/helpers/agent-errors-registry.d.ts +5 -5
  17. package/dist/api/helpers/agent-errors-registry.js +5 -5
  18. package/dist/api/routes/agent-schedule.js +5 -1
  19. package/dist/api/routes/agent.js +33 -12
  20. package/dist/api/routes/agents/index.js +75 -16
  21. package/dist/api/routes/agents/views.d.ts +37 -2
  22. package/dist/api/routes/agents/views.js +64 -2
  23. package/dist/api/routes/apple-calendar.js +4 -1
  24. package/dist/api/routes/background-task.d.ts +22 -0
  25. package/dist/api/routes/background-task.js +338 -0
  26. package/dist/api/routes/browser-history.js +9 -1
  27. package/dist/api/routes/calendar.js +12 -2
  28. package/dist/api/routes/context/path-resolve.js +6 -1
  29. package/dist/api/routes/context/permissions.js +12 -2
  30. package/dist/api/routes/context/snapshots.js +0 -3
  31. package/dist/api/routes/context/write.js +3 -17
  32. package/dist/api/routes/dashboard/config.js +58 -12
  33. package/dist/api/routes/dashboard/cost-approvals.js +66 -0
  34. package/dist/api/routes/dashboard/notifications.js +9 -9
  35. package/dist/api/routes/dashboard/oauth-google.js +5 -3
  36. package/dist/api/routes/feedback.d.ts +3 -0
  37. package/dist/api/routes/feedback.js +349 -0
  38. package/dist/api/routes/git.js +10 -3
  39. package/dist/api/routes/github.js +5 -1
  40. package/dist/api/routes/integrations/crud-patch.js +5 -1
  41. package/dist/api/routes/integrations-reconcile.js +2 -2
  42. package/dist/api/routes/mcp.js +65 -13
  43. package/dist/api/routes/notion.d.ts +1 -1
  44. package/dist/api/routes/observations.js +7 -7
  45. package/dist/api/routes/obsidian.d.ts +1 -1
  46. package/dist/api/routes/receipts.js +5 -1
  47. package/dist/api/routes/setup-migrate.js +1 -1
  48. package/dist/api/routes/setup.js +1 -1
  49. package/dist/api/routes/task-flows.d.ts +1 -1
  50. package/dist/api/routes/task-flows.js +1 -1
  51. package/dist/api/routes/tuning.d.ts +29 -0
  52. package/dist/api/routes/tuning.js +304 -0
  53. package/dist/api/server.d.ts +44 -16
  54. package/dist/api/server.js +12 -0
  55. package/dist/bootstrap/adapters.d.ts +19 -0
  56. package/dist/bootstrap/adapters.js +61 -0
  57. package/dist/bootstrap/api.d.ts +5 -3
  58. package/dist/bootstrap/api.js +45 -13
  59. package/dist/bootstrap/catchup.d.ts +1 -1
  60. package/dist/bootstrap/catchup.js +11 -11
  61. package/dist/bootstrap/event-pipeline.d.ts +11 -0
  62. package/dist/bootstrap/event-pipeline.js +246 -8
  63. package/dist/bootstrap/observers.js +9 -6
  64. package/dist/bootstrap/schedule-helpers.d.ts +104 -6
  65. package/dist/bootstrap/schedule-helpers.js +172 -19
  66. package/dist/config.js +32 -12
  67. package/dist/core/agent-core.d.ts +33 -1
  68. package/dist/core/agent-core.js +36 -1
  69. package/dist/core/agents/activity-scan-cadence.d.ts +103 -0
  70. package/dist/core/agents/activity-scan-cadence.js +127 -0
  71. package/dist/core/agents/agent-route-override.d.ts +53 -0
  72. package/dist/core/agents/agent-route-override.js +69 -0
  73. package/dist/core/agents/builtin-registry.d.ts +51 -14
  74. package/dist/core/agents/builtin-registry.js +92 -15
  75. package/dist/core/agents/config-gate-reconcile.d.ts +38 -0
  76. package/dist/core/agents/config-gate-reconcile.js +51 -0
  77. package/dist/core/agents/cron-substitute.d.ts +1 -1
  78. package/dist/core/agents/cron-substitute.js +1 -1
  79. package/dist/core/agents/custom-routine-migration.d.ts +60 -0
  80. package/dist/core/agents/custom-routine-migration.js +149 -0
  81. package/dist/core/agents/firing-blocked.d.ts +1 -1
  82. package/dist/core/agents/hourly-cadence.d.ts +102 -0
  83. package/dist/core/agents/hourly-cadence.js +126 -0
  84. package/dist/core/agents/loader-boot.js +23 -0
  85. package/dist/core/agents/loader.d.ts +19 -0
  86. package/dist/core/agents/loader.js +34 -2
  87. package/dist/core/agents/override-merge.d.ts +1 -1
  88. package/dist/core/agents/override-merge.js +9 -1
  89. package/dist/core/agents/recurrence-convert.d.ts +1 -1
  90. package/dist/core/agents/recurrence-convert.js +1 -1
  91. package/dist/core/agents/recurring-schedule-adapter.js +8 -0
  92. package/dist/core/alerts.js +6 -6
  93. package/dist/core/backends/auth-health-monitor.d.ts +2 -2
  94. package/dist/core/backends/auth-health-monitor.js +1 -1
  95. package/dist/core/backends/backend-router.d.ts +27 -1
  96. package/dist/core/backends/backend-router.js +165 -1
  97. package/dist/core/backends/claude-code-core.d.ts +71 -31
  98. package/dist/core/backends/claude-code-core.js +282 -54
  99. package/dist/core/backends/cli-quota-guards.d.ts +29 -1
  100. package/dist/core/backends/cli-quota-guards.js +40 -5
  101. package/dist/core/backends/codex-core.d.ts +6 -0
  102. package/dist/core/backends/codex-core.js +22 -6
  103. package/dist/core/backends/failure-spend.d.ts +58 -0
  104. package/dist/core/backends/failure-spend.js +137 -0
  105. package/dist/core/backends/gemini-cli-core.d.ts +6 -0
  106. package/dist/core/backends/gemini-cli-core.js +38 -6
  107. package/dist/core/backends/model-registry.d.ts +1 -1
  108. package/dist/core/backends/model-registry.js +4 -4
  109. package/dist/core/backends/opencode-core.d.ts +1 -1
  110. package/dist/core/backends/opencode-core.js +5 -5
  111. package/dist/core/backends/plan-presets.js +47 -18
  112. package/dist/core/bang-commands/commands-cost.js +3 -1
  113. package/dist/core/bang-commands/commands-report.js +4 -3
  114. package/dist/core/bang-commands/commands-research.js +4 -1
  115. package/dist/core/bang-commands/commands-revert-tuning.d.ts +18 -0
  116. package/dist/core/bang-commands/commands-revert-tuning.js +63 -0
  117. package/dist/core/bang-commands/commands-stop-start.js +3 -3
  118. package/dist/core/bang-commands/commands-task-control.d.ts +19 -0
  119. package/dist/core/bang-commands/commands-task-control.js +147 -0
  120. package/dist/core/bang-commands/commands-wiki.js +5 -5
  121. package/dist/core/bang-commands/index.d.ts +2 -0
  122. package/dist/core/bang-commands/index.js +12 -0
  123. package/dist/core/bang-commands/registry.d.ts +12 -0
  124. package/dist/core/browser-history/research-cluster-fanout.d.ts +28 -14
  125. package/dist/core/browser-history/research-cluster-fanout.js +39 -16
  126. package/dist/core/channel-timeline.d.ts +5 -1
  127. package/dist/core/channel-timeline.js +13 -0
  128. package/dist/core/context/index-reconciler.js +5 -2
  129. package/dist/core/context/policy-index-reconciler.d.ts +6 -4
  130. package/dist/core/context/policy-index-runner.js +25 -6
  131. package/dist/core/context-builder-calendar.js +10 -2
  132. package/dist/core/context-builder-conversation.d.ts +8 -1
  133. package/dist/core/context-builder-conversation.js +41 -7
  134. package/dist/core/context-builder-yesterday.js +4 -3
  135. package/dist/core/context-builder.d.ts +7 -2
  136. package/dist/core/context-builder.js +193 -5
  137. package/dist/core/context-file-serializer.d.ts +1 -1
  138. package/dist/core/context-file-serializer.js +1 -1
  139. package/dist/core/context-health.js +2 -2
  140. package/dist/core/context-paths.d.ts +11 -1
  141. package/dist/core/context-paths.js +17 -1
  142. package/dist/core/context-validation/prepare-write.js +1 -1
  143. package/dist/core/context-validation/routine-rulebook.d.ts +1 -1
  144. package/dist/core/context-vault-aliases.d.ts +0 -13
  145. package/dist/core/context-vault-aliases.js +37 -0
  146. package/dist/core/custom-routines.d.ts +99 -0
  147. package/dist/core/custom-routines.js +187 -0
  148. package/dist/core/daemon-api-cli.js +50 -1
  149. package/dist/core/day-boundary.d.ts +46 -0
  150. package/dist/core/day-boundary.js +40 -0
  151. package/dist/core/dispatcher-activity-scan.d.ts +221 -0
  152. package/dist/core/dispatcher-activity-scan.js +775 -0
  153. package/dist/core/dispatcher-error-handling.d.ts +6 -11
  154. package/dist/core/dispatcher-error-handling.js +38 -62
  155. package/dist/core/dispatcher-hourly-check.js +6 -1
  156. package/dist/core/dispatcher-message-handler.d.ts +10 -0
  157. package/dist/core/dispatcher-message-handler.js +24 -0
  158. package/dist/core/dispatcher-morning-routine.d.ts +6 -6
  159. package/dist/core/dispatcher-morning-routine.js +13 -13
  160. package/dist/core/dispatcher-result-processor.d.ts +33 -0
  161. package/dist/core/dispatcher-result-processor.js +167 -11
  162. package/dist/core/dispatcher-scheduled-background-task.d.ts +42 -0
  163. package/dist/core/dispatcher-scheduled-background-task.js +89 -0
  164. package/dist/core/dispatcher-scheduled-tasks.d.ts +104 -1
  165. package/dist/core/dispatcher-scheduled-tasks.js +480 -8
  166. package/dist/core/dispatcher-task-delivery.d.ts +105 -0
  167. package/dist/core/dispatcher-task-delivery.js +555 -0
  168. package/dist/core/dispatcher-types.d.ts +48 -9
  169. package/dist/core/dispatcher-types.js +3 -3
  170. package/dist/core/dispatcher.d.ts +112 -31
  171. package/dist/core/dispatcher.js +297 -60
  172. package/dist/core/dm-freshness-metrics.d.ts +1 -1
  173. package/dist/core/drift-effects.js +2 -2
  174. package/dist/core/feedback/consolidation-prep.d.ts +94 -0
  175. package/dist/core/feedback/consolidation-prep.js +254 -0
  176. package/dist/core/feedback/eviction-scorer.d.ts +81 -0
  177. package/dist/core/feedback/eviction-scorer.js +136 -0
  178. package/dist/core/feedback/lesson-format.d.ts +79 -0
  179. package/dist/core/feedback/lesson-format.js +199 -0
  180. package/dist/core/feedback/lesson-injection.d.ts +98 -0
  181. package/dist/core/feedback/lesson-injection.js +174 -0
  182. package/dist/core/feedback/lesson-merge.d.ts +51 -0
  183. package/dist/core/feedback/lesson-merge.js +88 -0
  184. package/dist/core/feedback/lesson-store-overview.d.ts +46 -0
  185. package/dist/core/feedback/lesson-store-overview.js +42 -0
  186. package/dist/core/feedback/promotion-gate.d.ts +69 -0
  187. package/dist/core/feedback/promotion-gate.js +117 -0
  188. package/dist/core/feedback/regeneralization-prep.d.ts +87 -0
  189. package/dist/core/feedback/regeneralization-prep.js +152 -0
  190. package/dist/core/feedback/scope-parser.d.ts +86 -0
  191. package/dist/core/feedback/scope-parser.js +141 -0
  192. package/dist/core/feedback/self-performance-prep.d.ts +186 -0
  193. package/dist/core/feedback/self-performance-prep.js +541 -0
  194. package/dist/core/feedback/tuning-actuator.d.ts +198 -0
  195. package/dist/core/feedback/tuning-actuator.js +432 -0
  196. package/dist/core/feedback/tuning-recommender.d.ts +247 -0
  197. package/dist/core/feedback/tuning-recommender.js +580 -0
  198. package/dist/core/feedback/tuning-revert-monitor.d.ts +90 -0
  199. package/dist/core/feedback/tuning-revert-monitor.js +213 -0
  200. package/dist/core/health-monitor.d.ts +6 -0
  201. package/dist/core/health-monitor.js +1 -1
  202. package/dist/core/injection-policy.d.ts +83 -1
  203. package/dist/core/injection-policy.js +61 -3
  204. package/dist/core/integration-main-backend.js +4 -0
  205. package/dist/core/management-md.d.ts +2 -2
  206. package/dist/core/management-md.js +51 -13
  207. package/dist/core/morning/orchestrator.d.ts +2 -2
  208. package/dist/core/morning/orchestrator.js +2 -2
  209. package/dist/core/notification-gate.d.ts +64 -0
  210. package/dist/core/notification-gate.js +51 -0
  211. package/dist/core/notification-rate-limit.d.ts +40 -0
  212. package/dist/core/notification-rate-limit.js +50 -0
  213. package/dist/core/policy-files.d.ts +1 -1
  214. package/dist/core/policy-files.js +2 -2
  215. package/dist/core/pre-pass-freshness.d.ts +4 -4
  216. package/dist/core/retention.d.ts +5 -0
  217. package/dist/core/retention.js +20 -4
  218. package/dist/core/review-context.d.ts +1 -1
  219. package/dist/core/review-context.js +10 -5
  220. package/dist/core/roadmap-write-lock.d.ts +2 -1
  221. package/dist/core/roadmap-write-lock.js +15 -10
  222. package/dist/core/routine-acquisition-plan.d.ts +47 -1
  223. package/dist/core/routine-acquisition-plan.js +78 -20
  224. package/dist/core/routine-fetch-window-retry.js +7 -4
  225. package/dist/core/routine-fetch-window-runner.d.ts +39 -3
  226. package/dist/core/routine-fetch-window-runner.js +264 -13
  227. package/dist/core/routine-windows.d.ts +2 -2
  228. package/dist/core/routine-windows.js +8 -5
  229. package/dist/core/scheduler.d.ts +175 -16
  230. package/dist/core/scheduler.js +559 -102
  231. package/dist/core/signal-detector.d.ts +51 -1
  232. package/dist/core/signal-detector.js +321 -24
  233. package/dist/core/skills-compiler-denied-tools.js +2 -2
  234. package/dist/core/skills-compiler-skill-index.d.ts +2 -2
  235. package/dist/core/skills-compiler-skill-index.js +2 -2
  236. package/dist/core/skills-compiler-variants.d.ts +1 -1
  237. package/dist/core/skills-compiler-variants.js +8 -0
  238. package/dist/core/skills-compiler.d.ts +29 -26
  239. package/dist/core/skills-compiler.js +117 -81
  240. package/dist/core/skills-manifest.d.ts +37 -0
  241. package/dist/core/skills-manifest.js +73 -2
  242. package/dist/core/sleep-inhibitor.d.ts +79 -0
  243. package/dist/core/sleep-inhibitor.js +132 -0
  244. package/dist/core/slim-system-prompt-loader.d.ts +77 -0
  245. package/dist/core/slim-system-prompt-loader.js +141 -0
  246. package/dist/core/spawn-gates.d.ts +126 -0
  247. package/dist/core/spawn-gates.js +180 -0
  248. package/dist/core/today-direct-writer.d.ts +60 -14
  249. package/dist/core/today-direct-writer.js +90 -13
  250. package/dist/core/today-write-lock.d.ts +4 -2
  251. package/dist/core/today-write-lock.js +30 -20
  252. package/dist/core/wake-detector.d.ts +55 -0
  253. package/dist/core/wake-detector.js +80 -0
  254. package/dist/core/wiki/compile-lock.d.ts +1 -1
  255. package/dist/core/wiki/compile-lock.js +1 -1
  256. package/dist/core/wiki/wiki-fts.js +13 -6
  257. package/dist/core/workdir.js +15 -6
  258. package/dist/db/activity-scan-signals.d.ts +77 -0
  259. package/dist/db/activity-scan-signals.js +378 -0
  260. package/dist/db/agents-store.d.ts +28 -0
  261. package/dist/db/agents-store.js +62 -0
  262. package/dist/db/background-task-clarifications-store.d.ts +81 -0
  263. package/dist/db/background-task-clarifications-store.js +152 -0
  264. package/dist/db/background-task-store.d.ts +207 -0
  265. package/dist/db/background-task-store.js +380 -0
  266. package/dist/db/browser-history-store.d.ts +39 -6
  267. package/dist/db/browser-history-store.js +51 -7
  268. package/dist/db/browser-task-clarifications-store.d.ts +12 -0
  269. package/dist/db/browser-task-clarifications-store.js +35 -5
  270. package/dist/db/browser-task-store.d.ts +3 -0
  271. package/dist/db/browser-task-store.js +29 -4
  272. package/dist/db/deferred-dm.d.ts +86 -0
  273. package/dist/db/deferred-dm.js +199 -0
  274. package/dist/db/feedback-signals-store.d.ts +77 -0
  275. package/dist/db/feedback-signals-store.js +144 -0
  276. package/dist/db/migrations.js +380 -0
  277. package/dist/db/observations.d.ts +2 -2
  278. package/dist/db/observations.js +3 -3
  279. package/dist/db/schema.js +260 -22
  280. package/dist/db/voice-transcripts-store.d.ts +1 -1
  281. package/dist/index.js +86 -29
  282. package/dist/messaging/browser-task-mcp-notifier.d.ts +12 -70
  283. package/dist/messaging/browser-task-mcp-notifier.js +30 -151
  284. package/dist/messaging/browser-task-screenshot-attachment.d.ts +15 -0
  285. package/dist/messaging/browser-task-screenshot-attachment.js +63 -0
  286. package/dist/observers/delegated-sync-worker.d.ts +6 -6
  287. package/dist/observers/delegated-sync-worker.js +10 -10
  288. package/dist/observers/git-delegated-cron.d.ts +1 -1
  289. package/dist/observers/git-delegated-cron.js +2 -2
  290. package/dist/observers/github-poller-classifier.d.ts +3 -3
  291. package/dist/observers/github-poller-classifier.js +3 -3
  292. package/dist/observers/imminent-event-scheduler.d.ts +1 -1
  293. package/dist/observers/imminent-event-scheduler.js +1 -1
  294. package/dist/observers/mail-poller.d.ts +1 -0
  295. package/dist/observers/mail-poller.js +42 -3
  296. package/dist/observers/observation-summarizer/summarizer-client.d.ts +2 -2
  297. package/dist/observers/observation-summarizer/summarizer-client.js +2 -2
  298. package/dist/observers/observation-summarizer/worker.d.ts +2 -2
  299. package/dist/observers/observation-summarizer/worker.js +4 -4
  300. package/dist/observers/obsidian-watcher.d.ts +1 -1
  301. package/dist/observers/obsidian-watcher.js +1 -1
  302. package/dist/safety/agent-write-tracker.d.ts +4 -4
  303. package/dist/safety/agent-write-tracker.js +4 -4
  304. package/dist/safety/always-disallowed.d.ts +1 -1
  305. package/dist/safety/always-disallowed.js +39 -0
  306. package/dist/safety/audit.d.ts +43 -5
  307. package/dist/safety/audit.js +86 -18
  308. package/dist/safety/risk-classifier.d.ts +6 -0
  309. package/dist/safety/risk-classifier.js +97 -18
  310. package/dist/scheduler/activity-scan-gate.d.ts +86 -0
  311. package/dist/scheduler/activity-scan-gate.js +132 -0
  312. package/dist/services/background-task/background-task-budget.d.ts +80 -0
  313. package/dist/services/background-task/background-task-budget.js +91 -0
  314. package/dist/services/background-task/background-task-driver.d.ts +105 -0
  315. package/dist/services/background-task/background-task-driver.js +416 -0
  316. package/dist/services/background-task/background-task-runner.d.ts +96 -0
  317. package/dist/services/background-task/background-task-runner.js +673 -0
  318. package/dist/services/background-task/background-task-tools.d.ts +84 -0
  319. package/dist/services/background-task/background-task-tools.js +247 -0
  320. package/dist/services/background-task/background-task-transition-events.d.ts +43 -0
  321. package/dist/services/background-task/background-task-transition-events.js +54 -0
  322. package/dist/services/browser-history/automation/egress-denylist.d.ts +1 -1
  323. package/dist/services/browser-history/automation/egress-denylist.js +34 -8
  324. package/dist/services/browser-history/lifecycle/platform.js +44 -2
  325. package/dist/services/browser-history/managed-chromium/sandbox-launcher.js +0 -1
  326. package/dist/services/browser-task/browser-task-runner.js +53 -8
  327. package/dist/services/mcp/probe.js +30 -8
  328. package/dist/services/observations-batch.d.ts +1 -1
  329. package/dist/services/observations-batch.js +2 -2
  330. package/dist/settings/runtime-settings.d.ts +45 -12
  331. package/dist/settings/runtime-settings.js +215 -40
  332. package/dist/settings/settings-store.js +11 -3
  333. package/package.json +4 -4
@@ -111,7 +111,7 @@ function integrationsForWindow(symbol) {
111
111
  */
112
112
  function resolveFetchMode(integration, state, sessionBackend) {
113
113
  if (!state)
114
- return null;
114
+ return "no_state";
115
115
  switch (state.mode) {
116
116
  case "direct":
117
117
  return "direct";
@@ -131,21 +131,31 @@ function resolveFetchMode(integration, state, sessionBackend) {
131
131
  }
132
132
  return "delegated-cross";
133
133
  }
134
- return null;
134
+ return "no_binding";
135
135
  case "native":
136
136
  // Native binding must match the session backend. Otherwise the
137
137
  // partial's `mode:native:<key>` block would be filtered out by
138
138
  // `applyIntegrationModeFilter` anyway — skip the row to avoid
139
- // emitting a `<fetch>` that no branch can handle.
139
+ // emitting a `<fetch>` that no branch can handle. With
140
+ // per-integration backend routing (`resolveIntegrationBackend`)
141
+ // the caller passes the integration's own `nativeBackend` here, so
142
+ // in practice this branch only drops rows whose binding is null.
140
143
  if (state.nativeBackend === sessionBackend)
141
144
  return "native";
142
- return null;
145
+ return "no_binding";
143
146
  case "disabled":
144
- return null;
147
+ return "disabled";
145
148
  default:
146
- return null;
149
+ return "unknown_mode";
147
150
  }
148
151
  }
152
+ /** Narrow a `resolveFetchMode` result to the fetch-mode side of the union. */
153
+ function isFetchMode(value) {
154
+ return (value === "direct"
155
+ || value === "delegated-same"
156
+ || value === "delegated-cross"
157
+ || value === "native");
158
+ }
149
159
  /**
150
160
  * Resolve the backend the sub-session for this integration MUST run on
151
161
  * so that the partial body's resolved `mode:` block has a working wire
@@ -170,9 +180,9 @@ function resolveFetchMode(integration, state, sessionBackend) {
170
180
  * backend keeps the pre-pass tier predictable.
171
181
  * - `direct`: REST via curl to the daemon — sub-session stays on
172
182
  * `defaultBackend`.
173
- * - `disabled` / no state: irrelevant (`resolveFetchMode` returns
174
- * `null` and the row is dropped before backend matters); returning
175
- * `defaultBackend` is a no-op safety default.
183
+ * - `disabled` / no state: irrelevant (`resolveFetchMode` returns a
184
+ * drop reason and the row is dropped before backend matters);
185
+ * returning `defaultBackend` is a no-op safety default.
176
186
  *
177
187
  * The function is intentionally `null`-free — every call site benefits
178
188
  * from a guaranteed backend so the per-integration spawn path never has
@@ -277,6 +287,11 @@ function renderFetchRow(row) {
277
287
  if (row.label !== undefined) {
278
288
  parts.push(`label="${xmlAttr(row.label)}"`);
279
289
  }
290
+ // `collectFetchRows` only attaches a non-empty allowlist (empty drops
291
+ // the row with `no_fetch_targets`), so defined ⇒ renderable.
292
+ if (row.fetchTargets !== undefined) {
293
+ parts.push(`targets='${xmlQueryAttr(JSON.stringify(row.fetchTargets))}'`);
294
+ }
280
295
  // Single-quote delimiter on `query=` — see `xmlQueryAttr` rationale.
281
296
  parts.push(`query='${xmlQueryAttr(row.query)}'`);
282
297
  return ` <fetch ${parts.join(" ")} />`;
@@ -291,31 +306,65 @@ function renderFetchRow(row) {
291
306
  * monolithic block and the union of per-integration sub-plan blocks
292
307
  * carry bit-identical row sequences.
293
308
  */
294
- function collectFetchRows(input) {
309
+ function collectFetchRows(input,
310
+ /**
311
+ * N3 observability hook — invoked once per dropped (window ×
312
+ * integration) cell with the drop reason. Optional so the render-only
313
+ * consumers (`buildAcquisitionPlan`, `rebuildSubPlanForBackend`) pay
314
+ * nothing.
315
+ */
316
+ onDrop) {
295
317
  const rows = [];
296
318
  const specs = ROUTINE_WINDOWS[input.routine];
297
319
  for (const spec of specs) {
298
320
  const integrations = integrationsForWindow(spec.window);
299
321
  for (const integration of integrations) {
300
322
  const state = input.integrations[integration];
323
+ // Notion rows carry the user's fetch-target allowlist (undefined
324
+ // for every other integration). Resolved up here — before the mode
325
+ // guards — but the empty-allowlist drop stays AFTER them, so a
326
+ // disabled / unbound Notion row keeps its mode-derived drop reason
327
+ // and `no_fetch_targets` means exactly "active but unconfigured".
328
+ const fetchTargets = integration === "notion" ? (state?.fetchTargets ?? []) : undefined;
301
329
  // Per-integration backend resolution. Was: `input.sessionBackend`
302
330
  // (single backend for the whole plan), which caused `resolveFetchMode`
303
- // to return `null` for native bindings on a different backend
304
- // silently dropping the row. With `resolveIntegrationBackend` the
305
- // sub-session is routed to the integration's actual bound backend
306
- // (`nativeBackend`, or `delegatedBackend` for userManagedConnector),
307
- // and `resolveFetchMode` then matches on the correct backend so the
331
+ // to drop rows for native bindings on a different backend. With
332
+ // `resolveIntegrationBackend` the sub-session is routed to the
333
+ // integration's actual bound backend (`nativeBackend`, or
334
+ // `delegatedBackend` for userManagedConnector), and
335
+ // `resolveFetchMode` then matches on the correct backend so the
308
336
  // row survives. The runner uses `requiredBackend` (bubbled up via
309
337
  // `FetchRow`) to spawn each sub-session on the right backend via
310
338
  // `BackendRouter.resolveBinding({ requestedBackendId })`.
311
339
  const requiredBackend = resolveIntegrationBackend(integration, state, input.sessionBackend);
312
340
  const fetchMode = resolveFetchMode(integration, state, requiredBackend);
313
- if (fetchMode === null)
341
+ if (!isFetchMode(fetchMode)) {
342
+ onDrop?.({ integration, window: spec.window, reason: fetchMode });
314
343
  continue;
344
+ }
315
345
  const queryTemplate = lookupQuery(spec.window, integration, fetchMode);
316
- if (queryTemplate === undefined)
346
+ if (queryTemplate === undefined) {
347
+ // `integrationsForWindow` only yields integrations present in
348
+ // the catalog for this window, so an undefined template means
349
+ // the MODE cell is missing. For `direct` that is the documented
350
+ // intentional pattern (cf. `cal_morning_7d` in
351
+ // routine-windows.ts): the daemon serves the data inline, so the
352
+ // pre-pass must not double-fetch. Any other mode is a genuine
353
+ // catalog hole.
354
+ onDrop?.({
355
+ integration,
356
+ window: spec.window,
357
+ reason: fetchMode === "direct"
358
+ ? "direct_inline_prefetch"
359
+ : "no_window_query",
360
+ });
317
361
  continue;
362
+ }
318
363
  const query = substituteAcquisitionTokens(queryTemplate, input.timestamps);
364
+ if (fetchTargets !== undefined && fetchTargets.length === 0) {
365
+ onDrop?.({ integration, window: spec.window, reason: "no_fetch_targets" });
366
+ continue;
367
+ }
319
368
  // perAccount fan-out is meaningful only in `direct` mode, where the
320
369
  // daemon stores per-account OAuth tokens and polls each. In
321
370
  // `delegated-same` / `delegated-cross` / `native` the integration's
@@ -332,6 +381,9 @@ function collectFetchRows(input) {
332
381
  // surface so the partials never need to defend against them.
333
382
  if (spec.perAccount && fetchMode === "direct") {
334
383
  const accountRows = input.accounts.filter((a) => a.integration === integration);
384
+ if (accountRows.length === 0) {
385
+ onDrop?.({ integration, window: spec.window, reason: "no_accounts" });
386
+ }
335
387
  for (const account of accountRows) {
336
388
  rows.push({
337
389
  integration,
@@ -340,6 +392,7 @@ function collectFetchRows(input) {
340
392
  accountId: account.accountId,
341
393
  label: account.label,
342
394
  query,
395
+ fetchTargets,
343
396
  requiredBackend,
344
397
  });
345
398
  }
@@ -350,6 +403,7 @@ function collectFetchRows(input) {
350
403
  mode: fetchMode,
351
404
  window: spec.window,
352
405
  query,
406
+ fetchTargets,
353
407
  requiredBackend,
354
408
  });
355
409
  }
@@ -418,9 +472,13 @@ export function buildAcquisitionPlan(input) {
418
472
  * `scoped="<key>"` attribute and the partition itself.
419
473
  */
420
474
  export function splitAcquisitionPlanByIntegration(input) {
421
- const rows = collectFetchRows(input);
475
+ return buildAcquisitionPlanAssembly(input).subPlans;
476
+ }
477
+ export function buildAcquisitionPlanAssembly(input) {
478
+ const drops = [];
479
+ const rows = collectFetchRows(input, (drop) => drops.push(drop));
422
480
  if (rows.length === 0)
423
- return [];
481
+ return { subPlans: [], drops };
424
482
  // Group rows by integration while keeping insertion order inside each
425
483
  // group (the `ROUTINE_WINDOWS` walk order from `collectFetchRows`).
426
484
  const groups = new Map();
@@ -453,5 +511,5 @@ export function splitAcquisitionPlanByIntegration(input) {
453
511
  requiredBackend,
454
512
  });
455
513
  }
456
- return out;
514
+ return { subPlans: out, drops };
457
515
  }
@@ -84,10 +84,13 @@ function isFetchFailedWithStatus(err, predicate) {
84
84
  /**
85
85
  * Sentinel error-status strings the runner classifies as deterministic
86
86
  * (no point retrying — the next attempt re-emits the same bytes and
87
- * re-trips the same gate). Centralised so the partial author (who emits
88
- * these strings into `errors[*].status`), the runner (which interprets
89
- * them here), and any future telemetry that filters on them all reference
90
- * the same vocabulary.
87
+ * re-trips the same gate). The emitting side of the contract is the
88
+ * agent profile's `fetch-failed` bullet
89
+ * (`agent-assets/agent-profiles/routine-fetch-window.md`), which
90
+ * instructs the agent to set `status:"permission-denied"` when its own
91
+ * permission layer blocked a tool call; the runner interprets the
92
+ * strings here, and any future telemetry that filters on them
93
+ * references the same vocabulary.
91
94
  *
92
95
  * See `RETRY_REASONS.DETERMINISTIC_FAILURE` for the rationale and the
93
96
  * specific gates these sentinels are paired with — and for why
@@ -3,7 +3,7 @@
3
3
  *
4
4
  * docs/design/appendices/routine-data-acquisition.md §6.1.1 + docs/design/appendices/pre-pass-fan-out.md
5
5
  * — every routine dispatcher (morning_routine, today_refresh,
6
- * hourly_check, evening / weekly / monthly review) calls this runner
6
+ * activity_scan, evening / weekly / monthly review) calls this runner
7
7
  * immediately before dispatching the parent session. The runner:
8
8
  *
9
9
  * 1. Reads the per-routine plan from `ROUTINE_WINDOWS` and the current
@@ -27,7 +27,7 @@
27
27
  * 4. The caller grafts the block into the **parent** routine event's
28
28
  * `event.data.fetchReportBlock`. ContextBuilder injects it verbatim
29
29
  * into the parent session's prompt (mirrors the `<gate_decision>`
30
- * pattern used by hourly_check Stage 3).
30
+ * pattern used by activity_scan Stage 3).
31
31
  *
32
32
  * Failure-mode contract (docs/design/appendices/pre-pass-fan-out.md §5):
33
33
  *
@@ -57,6 +57,7 @@ import type { IAgentRouter } from "./backends/backend-router.js";
57
57
  import type { IAuditLogger, IContextBuilder } from "./dispatcher-types.js";
58
58
  import type { PromptAssembler } from "./dispatcher-prompt.js";
59
59
  import { type RoutineWindowKey } from "./routine-windows.js";
60
+ import type { AutonomousSpawnGate } from "./spawn-gates.js";
60
61
  /**
61
62
  * Structured form of the agent's single-line JSON output. Matches the
62
63
  * contract in `agent-profiles/routine-fetch-window.md`:
@@ -142,7 +143,7 @@ export interface RoutineFetchWindowResult {
142
143
  /**
143
144
  * HOURLY_CHECK_GATE_REDESIGN_PLAN.md §3.4 — caller options for `run()`.
144
145
  *
145
- * The hourly_check coordinator passes `integrationKeyFilter` to restrict
146
+ * The activity_scan coordinator passes `integrationKeyFilter` to restrict
146
147
  * the fan-out to the subset of integrations whose freshness window has
147
148
  * elapsed. Morning_routine / evening_review / weekly_review call
148
149
  * `run()` without options so they fetch every integration the routine
@@ -194,6 +195,14 @@ export interface RoutineFetchWindowRunnerDeps {
194
195
  getEventBroadcaster?: () => {
195
196
  broadcastEvent: (data: unknown) => void;
196
197
  } | null;
198
+ /**
199
+ * PREPASS_COST_REDUCTION_PLAN.md N2 — offline/auth spawn gate shared
200
+ * with the dispatcher. Evaluated per integration sub-session (the
201
+ * hourly `harvestForGate` path spawns the runner directly, bypassing
202
+ * the dispatcher's own gate). Optional: when undefined the runner
203
+ * spawns unconditionally, exactly as pre-N2.
204
+ */
205
+ spawnGate?: AutonomousSpawnGate;
197
206
  }
198
207
  /**
199
208
  * Compose the per-execute `allowedToolsOverride` for the pre-pass. The
@@ -340,6 +349,7 @@ export declare class RoutineFetchWindowRunner {
340
349
  private readonly prompt;
341
350
  private readonly getActiveMailAccounts;
342
351
  private readonly getEventBroadcaster;
352
+ private readonly spawnGate;
343
353
  constructor(deps: RoutineFetchWindowRunnerDeps);
344
354
  /**
345
355
  * Broadcast a single pre-pass progress event to the dashboard SSE
@@ -426,6 +436,32 @@ export declare class RoutineFetchWindowRunner {
426
436
  private budgetCapAttemptRecord;
427
437
  private didExhaustRetries;
428
438
  private backoffForAttempt;
439
+ /**
440
+ * PREPASS_COST_REDUCTION_PLAN.md N2 — evaluate the offline/auth spawn
441
+ * gate for one integration's sub-session. Candidates are the
442
+ * pre-resolved binding's main + fallback backends; when pre-resolve
443
+ * failed, the sub-plan's `requiredBackend` is the only candidate the
444
+ * attempt loop could use. Fail-open on every error path (returns null).
445
+ */
446
+ private evaluateSpawnGate;
447
+ /**
448
+ * Build the `skipped` SubReport for a spawn-gate skip and write its
449
+ * audit row. Mirrors the empty-attempts synthetic record (attempt 0,
450
+ * no SSE sub-session emits — no session was spawned). The audit row is
451
+ * `result='skipped'` with `detail.prePass.skipReason` carrying N2's
452
+ * `offline` / `auth_unhealthy`, matching the N3 plan-drop row shape so
453
+ * all pre-pass skip telemetry is queryable through one path.
454
+ */
455
+ private spawnGateSkippedSubReport;
456
+ /**
457
+ * PREPASS_COST_REDUCTION_PLAN.md N3 — one `skipped` audit row per
458
+ * (integration × reason) group of plan-assembly drops, with the
459
+ * dropped windows listed in `detail.prePass.windows`. Grouped at
460
+ * integration granularity because that is the unit a session would
461
+ * have been spawned for (and the unit the deferred R5 streak skip
462
+ * will key on). Observability only — no skip behavior changes here.
463
+ */
464
+ private logPlanAssemblyDrops;
429
465
  /**
430
466
  * Unified audit-row companion for every fan-out failure mode —
431
467
  * binding-resolve-failed, global-budget-cap, budget-cap (per-integration),