@zaip-ai/cli 1.0.8 → 1.3.1

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 (360) hide show
  1. package/README.md +1 -1
  2. package/dist/services/adapters.d.ts +1 -1
  3. package/dist/services/adapters.js +1 -1
  4. package/dist/services/agent-adapters.js +3 -3
  5. package/dist/services/agent-adapters.js.map +1 -1
  6. package/dist/services/agent-adapters.test.js +7 -1
  7. package/dist/services/agent-adapters.test.js.map +1 -1
  8. package/dist/services/codex-pre-tool-hook-template.d.ts.map +1 -1
  9. package/dist/services/codex-pre-tool-hook-template.js +89 -7
  10. package/dist/services/codex-pre-tool-hook-template.js.map +1 -1
  11. package/dist/services/codex-rules.d.ts +1 -1
  12. package/dist/services/codex-rules.d.ts.map +1 -1
  13. package/dist/services/codex-rules.js +7 -0
  14. package/dist/services/codex-rules.js.map +1 -1
  15. package/dist/services/install-agents-template.d.ts.map +1 -1
  16. package/dist/services/install-agents-template.js +1 -0
  17. package/dist/services/install-agents-template.js.map +1 -1
  18. package/dist/services/logger.test.js +2 -2
  19. package/dist/services/runtime-template.test.js +31 -7
  20. package/dist/services/runtime-template.test.js.map +1 -1
  21. package/dist/services/template-manifest.d.ts.map +1 -1
  22. package/dist/services/template-manifest.js +12 -3
  23. package/dist/services/template-manifest.js.map +1 -1
  24. package/package.json +1 -1
  25. package/templates/.agents/architecture/software-architecture.md +131 -0
  26. package/templates/.agents/branding/brandbook.docx +0 -0
  27. package/templates/.agents/branding/brandbook.md +60 -0
  28. package/templates/.agents/config/agents/catalog.yaml +7 -7
  29. package/templates/.agents/config/clients/codex/agents/zaip-agent-backend.toml +2 -2
  30. package/templates/.agents/config/clients/codex/agents/zaip-agent-designer.toml +2 -2
  31. package/templates/.agents/config/clients/codex/agents/zaip-agent-finalizer.toml +1 -1
  32. package/templates/.agents/config/clients/codex/agents/zaip-agent-frontend.toml +8 -8
  33. package/templates/.agents/config/clients/codex/agents/zaip-agent-orchestrator.toml +1 -1
  34. package/templates/.agents/dashboard/.tmp-run-list.json +254 -0
  35. package/templates/.agents/dashboard/.zaip-managed.json +457 -173
  36. package/templates/.agents/dashboard/apps/frontend/dist/assets/{CostCalculationGuidePage-Z60df2r-.js → CostCalculationGuidePage-ovxurkIk.js} +1 -1
  37. package/templates/.agents/dashboard/apps/frontend/dist/assets/DashboardHelpDialog-BgVgrfhQ.js +2310 -0
  38. package/templates/.agents/dashboard/apps/frontend/dist/assets/{PricingSettingsDialog-Coc6pA-1.js → PricingSettingsDialog-vSvvOHQp.js} +1 -1
  39. package/templates/.agents/dashboard/apps/frontend/dist/assets/ProjectSettingsPage-BomxqCBU.css +1 -0
  40. package/templates/.agents/dashboard/apps/frontend/dist/assets/ProjectSettingsPage-zH758vfs.js +3 -0
  41. package/templates/.agents/dashboard/apps/frontend/dist/assets/TraceabilityWorkspace-DLn-Mz2M.js +1 -0
  42. package/templates/.agents/dashboard/apps/frontend/dist/assets/{TraceabilityWorkspace-CaKwQP43.css → TraceabilityWorkspace-DvvavDLY.css} +1 -1
  43. package/templates/.agents/dashboard/apps/frontend/dist/assets/cost-monitor-DKwP1stV.js +68 -0
  44. package/templates/.agents/dashboard/apps/frontend/dist/assets/cost-monitor-PoJA2PI1.css +1 -0
  45. package/templates/.agents/dashboard/apps/frontend/dist/assets/{icons-vendor-DFBuc_qp.js → icons-vendor-B_lDDHn1.js} +1 -1
  46. package/templates/.agents/dashboard/apps/frontend/dist/assets/index-B31GMG5O.css +1 -0
  47. package/templates/.agents/dashboard/apps/frontend/dist/assets/index-CZQlsLV9.js +2 -0
  48. package/templates/.agents/dashboard/apps/frontend/dist/assets/{react-vendor-CCQOHdVI.js → react-vendor-B3TJrD4O.js} +1 -1
  49. package/templates/.agents/dashboard/apps/frontend/dist/assets/{traceability-pC2_0J8x.js → traceability-7f1j5wx3.js} +1 -1
  50. package/templates/.agents/dashboard/apps/frontend/dist/index.html +7 -7
  51. package/templates/.agents/dashboard/apps/frontend/package.json +1 -1
  52. package/templates/.agents/dashboard/apps/frontend/playwright.dom.config.ts +32 -0
  53. package/templates/.agents/dashboard/apps/frontend/src/App.tsx +199 -140
  54. package/templates/.agents/dashboard/apps/frontend/src/AppOverlays.tsx +0 -21
  55. package/templates/.agents/dashboard/apps/frontend/src/DashboardAlternateContent.tsx +20 -11
  56. package/templates/.agents/dashboard/apps/frontend/src/ProjectSettingsPage.tsx +14 -7
  57. package/templates/.agents/dashboard/apps/frontend/src/ProjectStackEditor.tsx +4 -2
  58. package/templates/.agents/dashboard/apps/frontend/src/TraceabilityWorkspace.dom.e2e.ts +56 -0
  59. package/templates/.agents/dashboard/apps/frontend/src/TraceabilityWorkspace.test.ts +21 -2
  60. package/templates/.agents/dashboard/apps/frontend/src/TraceabilityWorkspace.tsx +89 -19
  61. package/templates/.agents/dashboard/apps/frontend/src/cost-period-refresh.test.ts +19 -4
  62. package/templates/.agents/dashboard/apps/frontend/src/dashboard-api.test.ts +49 -3
  63. package/templates/.agents/dashboard/apps/frontend/src/dashboard-api.ts +29 -10
  64. package/templates/.agents/dashboard/apps/frontend/src/operations-period-render.test.ts +4 -4
  65. package/templates/.agents/dashboard/apps/frontend/src/overview-status-page.test.ts +4 -2
  66. package/templates/.agents/dashboard/apps/frontend/src/project-settings-page.css +36 -26
  67. package/templates/.agents/dashboard/apps/frontend/src/project-settings.test.ts +2 -2
  68. package/templates/.agents/dashboard/apps/frontend/src/snapshot-banner-semantics.test.ts +47 -6
  69. package/templates/.agents/dashboard/apps/frontend/src/snapshot-coherence.test.ts +59 -9
  70. package/templates/.agents/dashboard/apps/frontend/src/sqlite-page-export.test.ts +32 -0
  71. package/templates/.agents/dashboard/apps/frontend/src/sqlite-page-export.ts +21 -0
  72. package/templates/.agents/dashboard/apps/frontend/src/styles.css +19 -0
  73. package/templates/.agents/dashboard/apps/frontend/src/traceability-task-pagination.test.ts +32 -0
  74. package/templates/.agents/dashboard/apps/frontend/src/traceability-task-pagination.ts +36 -0
  75. package/templates/.agents/dashboard/apps/frontend/src/traceability-workspace.css +6 -2
  76. package/templates/.agents/dashboard/apps/frontend/src/use-app-cost-loaders.test.ts +137 -23
  77. package/templates/.agents/dashboard/apps/frontend/src/use-app-cost-loaders.ts +229 -35
  78. package/templates/.agents/dashboard/apps/frontend/src/use-app-effects.ts +61 -7
  79. package/templates/.agents/dashboard/apps/frontend/src/use-app-operations-pages.ts +3 -6
  80. package/templates/.agents/dashboard/apps/frontend/src/use-app-trace-documents.ts +7 -1
  81. package/templates/.agents/dashboard/apps/frontend/src/use-app-work-list-page.test.ts +163 -0
  82. package/templates/.agents/dashboard/apps/frontend/src/use-app-work-list-page.ts +136 -0
  83. package/templates/.agents/dashboard/apps/frontend/src/use-operations-detail-export.ts +76 -0
  84. package/templates/.agents/dashboard/apps/frontend/src/work-list-load-dedup.test.ts +23 -0
  85. package/templates/.agents/dashboard/apps/frontend/src/work-list-load-dedup.ts +27 -0
  86. package/templates/.agents/dashboard/apps/frontend/src/work-list-pagination.test.ts +39 -15
  87. package/templates/.agents/dashboard/apps/frontend/src/work-list-pagination.ts +3 -4
  88. package/templates/.agents/dashboard/apps/frontend/vite.config.ts +4 -1
  89. package/templates/.agents/dashboard/modules/cost-monitor/package.json +1 -1
  90. package/templates/.agents/dashboard/modules/cost-monitor/src/react/CompactLifecycleCostTable.test.ts +89 -19
  91. package/templates/.agents/dashboard/modules/cost-monitor/src/react/CompactLifecycleCostTable.tsx +31 -16
  92. package/templates/.agents/dashboard/modules/cost-monitor/src/react/CostCharts.test.ts +43 -14
  93. package/templates/.agents/dashboard/modules/cost-monitor/src/react/CostCharts.tsx +5 -5
  94. package/templates/.agents/dashboard/modules/cost-monitor/src/react/CostDeveloperAttributionPanel.tsx +60 -0
  95. package/templates/.agents/dashboard/modules/cost-monitor/src/react/CostDeveloperAttributionTable.tsx +191 -0
  96. package/templates/.agents/dashboard/modules/cost-monitor/src/react/CostFilters.loading.test.ts +14 -0
  97. package/templates/.agents/dashboard/modules/cost-monitor/src/react/CostFilters.run-page.test.ts +18 -0
  98. package/templates/.agents/dashboard/modules/cost-monitor/src/react/CostFilters.tsx +18 -3
  99. package/templates/.agents/dashboard/modules/cost-monitor/src/react/CostModelsAuditTable.tsx +1 -1
  100. package/templates/.agents/dashboard/modules/cost-monitor/src/react/CostMonitorContent.tsx +75 -44
  101. package/templates/.agents/dashboard/modules/cost-monitor/src/react/CostMonitorLoadErrors.tsx +35 -0
  102. package/templates/.agents/dashboard/modules/cost-monitor/src/react/CostMonitorPage.test.ts +162 -40
  103. package/templates/.agents/dashboard/modules/cost-monitor/src/react/CostMonitorPage.tsx +221 -79
  104. package/templates/.agents/dashboard/modules/cost-monitor/src/react/CostTableLoading.test.ts +132 -0
  105. package/templates/.agents/dashboard/modules/cost-monitor/src/react/CostTableLoading.tsx +70 -0
  106. package/templates/.agents/dashboard/modules/cost-monitor/src/react/CostTables.test.ts +203 -155
  107. package/templates/.agents/dashboard/modules/cost-monitor/src/react/CostTables.tsx +164 -125
  108. package/templates/.agents/dashboard/modules/cost-monitor/src/react/cost-monitor-copy.ts +2 -0
  109. package/templates/.agents/dashboard/modules/cost-monitor/src/react/cost-monitor-views.ts +3 -1
  110. package/templates/.agents/dashboard/modules/cost-monitor/src/react/cost-monitor.css +5 -2
  111. package/templates/.agents/dashboard/modules/cost-monitor/src/react/cost-page-range.ts +35 -0
  112. package/templates/.agents/dashboard/modules/cost-monitor/src/react/index.ts +2 -2
  113. package/templates/.agents/dashboard/modules/cost-monitor/src/react/period-cost-groups.ts +2 -1
  114. package/templates/.agents/dashboard/modules/cost-monitor/src/react/use-compact-cost-page.ts +32 -9
  115. package/templates/.agents/dashboard/modules/cost-monitor/src/react/use-cost-group-page.test.ts +37 -2
  116. package/templates/.agents/dashboard/modules/cost-monitor/src/react/use-cost-group-page.ts +131 -9
  117. package/templates/.agents/dashboard/modules/cost-monitor/src/react/use-cost-run-page.ts +34 -17
  118. package/templates/.agents/dashboard/modules/cost-monitor/src/server/build-cost-monitor-projection.test.ts +0 -24
  119. package/templates/.agents/dashboard/modules/cost-monitor/src/server/build-cost-summary-projection.test.ts +225 -424
  120. package/templates/.agents/dashboard/modules/cost-monitor/src/server/build-cost-summary-projection.ts +24 -15
  121. package/templates/.agents/dashboard/modules/cost-monitor/src/server/build-cost-summary-terminal-day.test.ts +6 -1
  122. package/templates/.agents/dashboard/modules/cost-monitor/src/server/source-size-cost-server/build-cost-monitor-projection-agents.test.ts +31 -0
  123. package/templates/.agents/dashboard/modules/cost-monitor/src/server/source-size-cost-server/build-cost-summary-projection-duration.test.ts +414 -0
  124. package/templates/.agents/dashboard/modules/operations/package.json +1 -1
  125. package/templates/.agents/dashboard/modules/operations/src/contracts.ts +46 -26
  126. package/templates/.agents/dashboard/modules/operations/src/react/DeveloperAttributionPanel.test.ts +54 -0
  127. package/templates/.agents/dashboard/modules/operations/src/react/DeveloperAttributionPanel.tsx +247 -0
  128. package/templates/.agents/dashboard/modules/operations/src/react/EntityTables.tsx +31 -11
  129. package/templates/.agents/dashboard/modules/operations/src/react/OperationsMainContent.tsx +39 -13
  130. package/templates/.agents/dashboard/modules/operations/src/react/OperationsOverview.helpers.tsx +107 -2
  131. package/templates/.agents/dashboard/modules/operations/src/react/OperationsOverview.macro-metrics.test.ts +55 -0
  132. package/templates/.agents/dashboard/modules/operations/src/react/OperationsOverview.test.ts +23 -29
  133. package/templates/.agents/dashboard/modules/operations/src/react/OperationsOverview.tsx +211 -184
  134. package/templates/.agents/dashboard/modules/operations/src/react/OperationsOverviewTopPanel.tsx +127 -0
  135. package/templates/.agents/dashboard/modules/operations/src/react/OperationsPage.tsx +60 -51
  136. package/templates/.agents/dashboard/modules/operations/src/react/OperationsPageNavigation.tsx +1 -4
  137. package/templates/.agents/dashboard/modules/operations/src/react/OperationsPageOverview.tsx +3 -0
  138. package/templates/.agents/dashboard/modules/operations/src/react/PagedWorkList.test.tsx +43 -0
  139. package/templates/.agents/dashboard/modules/operations/src/react/PagedWorkList.tsx +181 -0
  140. package/templates/.agents/dashboard/modules/operations/src/react/PeriodSummaryTable.tsx +32 -10
  141. package/templates/.agents/dashboard/modules/operations/src/react/TaskDetailsDialog.tsx +9 -3
  142. package/templates/.agents/dashboard/modules/operations/src/react/UnifiedWorkBoard.tsx +13 -5
  143. package/templates/.agents/dashboard/modules/operations/src/react/UnifiedWorkList.test.ts +16 -6
  144. package/templates/.agents/dashboard/modules/operations/src/react/UnifiedWorkList.tsx +14 -4
  145. package/templates/.agents/dashboard/modules/operations/src/react/conversation-rows.ts +1 -2
  146. package/templates/.agents/dashboard/modules/operations/src/react/developer-identities.test.ts +18 -0
  147. package/templates/.agents/dashboard/modules/operations/src/react/developer-identities.ts +30 -0
  148. package/templates/.agents/dashboard/modules/operations/src/react/execution-metrics.ts +1 -0
  149. package/templates/.agents/dashboard/modules/operations/src/react/export/ExcelExportAction.test.ts +393 -4
  150. package/templates/.agents/dashboard/modules/operations/src/react/export/ExcelExportAction.tsx +484 -61
  151. package/templates/.agents/dashboard/modules/operations/src/react/export/export-layout.test.ts +23 -1
  152. package/templates/.agents/dashboard/modules/operations/src/react/export/xlsx-runtime-e2e.test.ts +248 -0
  153. package/templates/.agents/dashboard/modules/operations/src/react/index.ts +1 -0
  154. package/templates/.agents/dashboard/modules/operations/src/react/operation-duration.test.ts +4 -4
  155. package/templates/.agents/dashboard/modules/operations/src/react/operation-duration.ts +6 -4
  156. package/templates/.agents/dashboard/modules/operations/src/react/operations-coverage-toast.test.ts +4 -3
  157. package/templates/.agents/dashboard/modules/operations/src/react/operations-date-filters.css +1 -1
  158. package/templates/.agents/dashboard/modules/operations/src/react/operations-global-filters.test.ts +4 -1
  159. package/templates/.agents/dashboard/modules/operations/src/react/operations-overview-period-filter.test.ts +22 -12
  160. package/templates/.agents/dashboard/modules/operations/src/react/operations-overview.css +4 -0
  161. package/templates/.agents/dashboard/modules/operations/src/react/operations-overview.status-cards.test.ts +1 -1
  162. package/templates/.agents/dashboard/modules/operations/src/react/operations-page-contract.ts +53 -6
  163. package/templates/.agents/dashboard/modules/operations/src/react/operations-view-order.test.ts +2 -4
  164. package/templates/.agents/dashboard/modules/operations/src/react/period-summary.test.ts +82 -6
  165. package/templates/.agents/dashboard/modules/operations/src/react/period-summary.ts +1 -0
  166. package/templates/.agents/dashboard/modules/operations/src/react/work-board-model.test.ts +2 -1
  167. package/templates/.agents/dashboard/modules/operations/src/react/work-board-model.ts +1 -1
  168. package/templates/.agents/dashboard/modules/operations/src/server/execution-relationship-counts.test.ts +19 -7
  169. package/templates/.agents/dashboard/modules/operations/src/server/execution-relationship-counts.ts +4 -1
  170. package/templates/.agents/dashboard/modules/operations/src/server/metric-coverage.ts +1 -0
  171. package/templates/.agents/dashboard/modules/operations/src/server/quick-daily-operations-projection.ts +11 -5
  172. package/templates/.agents/dashboard/modules/traceability/package.json +1 -1
  173. package/templates/.agents/dashboard/packages/branding/package.json +1 -1
  174. package/templates/.agents/dashboard/packages/branding/src/index.ts +1 -1
  175. package/templates/.agents/dashboard/packages/contracts/package.json +1 -1
  176. package/templates/.agents/dashboard/packages/contracts/src/index.ts +1 -0
  177. package/templates/.agents/dashboard/packages/data-export/package.json +1 -1
  178. package/templates/.agents/dashboard/packages/local-runtime/dist/server.cjs +533 -338
  179. package/templates/.agents/dashboard/packages/local-runtime/dist/sqlite-read-model.cjs +506 -311
  180. package/templates/.agents/dashboard/packages/local-runtime/gitignore.template +2 -0
  181. package/templates/.agents/dashboard/packages/local-runtime/package.json +1 -1
  182. package/templates/.agents/dashboard/packages/local-runtime/scripts/build-sqlite-dashboard.mjs +15 -7
  183. package/templates/.agents/dashboard/packages/local-runtime/scripts/build-sqlite-runtime.mjs +44 -13
  184. package/templates/.agents/dashboard/packages/local-runtime/scripts/rebuild-sqlite-read-model.mjs +8 -3
  185. package/templates/.agents/dashboard/packages/local-runtime/scripts/source-size-runtime-scripts/sqlite-read-model-fixture.mjs +397 -0
  186. package/templates/.agents/dashboard/packages/local-runtime/scripts/test-sqlite-read-model.mjs +472 -145
  187. package/templates/.agents/dashboard/packages/local-runtime/scripts/test-unix-launchers.mjs +15 -3
  188. package/templates/.agents/dashboard/packages/local-runtime/scripts/validate-sqlite-read-model.mjs +141 -33
  189. package/templates/.agents/dashboard/packages/local-runtime/server.mjs +533 -338
  190. package/templates/.agents/dashboard/packages/local-runtime/src/project-settings.test.ts +6 -2
  191. package/templates/.agents/dashboard/packages/local-runtime/src/project-settings.ts +3 -3
  192. package/templates/.agents/dashboard/packages/local-runtime/src/server-board.test.ts +89 -16
  193. package/templates/.agents/dashboard/packages/local-runtime/src/server-board.ts +33 -16
  194. package/templates/.agents/dashboard/packages/local-runtime/src/server-classification-page.test.ts +87 -0
  195. package/templates/.agents/dashboard/packages/local-runtime/src/server-period-macro-metric.test.ts +44 -0
  196. package/templates/.agents/dashboard/packages/local-runtime/src/server-period-macro-metric.ts +125 -0
  197. package/templates/.agents/dashboard/packages/local-runtime/src/server-reconciliation-refresh.test.ts +66 -0
  198. package/templates/.agents/dashboard/packages/local-runtime/src/server-request-authority.test.ts +61 -0
  199. package/templates/.agents/dashboard/packages/local-runtime/src/server-request-authority.ts +18 -0
  200. package/templates/.agents/dashboard/packages/local-runtime/src/server-run-projections.test.ts +42 -0
  201. package/templates/.agents/dashboard/packages/local-runtime/src/server-snapshot-refresh.ts +97 -0
  202. package/templates/.agents/dashboard/packages/local-runtime/src/server-snapshot.test.ts +22 -5
  203. package/templates/.agents/dashboard/packages/local-runtime/src/server-sqlite-task-trace.ts +91 -0
  204. package/templates/.agents/dashboard/packages/local-runtime/src/server-workspace.ts +7 -3
  205. package/templates/.agents/dashboard/packages/local-runtime/src/server.test-fixtures.ts +36 -0
  206. package/templates/.agents/dashboard/packages/local-runtime/src/server.test.ts +230 -132
  207. package/templates/.agents/dashboard/packages/local-runtime/src/server.ts +224 -182
  208. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-artifact-counts.ts +28 -0
  209. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-cost-agent-page.test.ts +63 -0
  210. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-cost-agent-page.ts +109 -0
  211. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-cost-aggregates.ts +497 -0
  212. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-cost-fast-page-parity.test-support.ts +65 -0
  213. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-cost-group-page.test.ts +176 -0
  214. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-cost-group-page.ts +119 -0
  215. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-cost-group-projection.ts +41 -0
  216. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-cost-invocation-page.test.ts +16 -0
  217. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-cost-invocation-page.ts +29 -0
  218. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-first-fold-cache.ts +355 -0
  219. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-first-fold-persistence.ts +121 -0
  220. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-first-fold-timing.ts +27 -0
  221. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-metric-contract.ts +16 -2
  222. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-operations-projection.ts +15 -0
  223. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-operations-work-list.test.ts +223 -0
  224. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-operations-work-list.ts +304 -0
  225. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-read-model-cache.test-support.ts +23 -0
  226. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-read-model-first-fold-types.ts +89 -0
  227. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-read-model-multi-provider-fixture.ts +227 -0
  228. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-read-model-multi-provider.test.ts +691 -0
  229. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-read-model-source-fingerprint.ts +81 -0
  230. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-read-model.test.ts +1655 -567
  231. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-read-model.ts +2168 -1268
  232. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-snapshot-cache.ts +129 -0
  233. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-snapshot-install.test.ts +26 -0
  234. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-snapshot-install.ts +28 -0
  235. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-snapshot-seed.test.ts +116 -0
  236. package/templates/.agents/dashboard/packages/local-runtime/start-dashboard-launch-page.mjs +146 -0
  237. package/templates/.agents/dashboard/packages/local-runtime/start-dashboard-launch-page.test.mjs +165 -0
  238. package/templates/.agents/dashboard/packages/local-runtime/start-dashboard-refresh.mjs +140 -0
  239. package/templates/.agents/dashboard/packages/local-runtime/start-dashboard.mjs +255 -289
  240. package/templates/.agents/dashboard/packages/local-runtime/start-dashboard.test.mjs +94 -88
  241. package/templates/.agents/dashboard/packages/ui/package.json +1 -1
  242. package/templates/.agents/dashboard/packages/windows-launcher/Program.cs +5 -2
  243. package/templates/.agents/dashboard/tests/e2e/package.json +1 -1
  244. package/templates/.agents/dashboard/tests/e2e/playwright.config.ts +4 -1
  245. package/templates/.agents/dashboard/tests/e2e/specs/cost-monitor-loading.spec.ts +142 -0
  246. package/templates/.agents/dashboard/tests/e2e/specs/cost-monitor-pagination.spec.ts +232 -0
  247. package/templates/.agents/dashboard/tests/e2e/specs/dashboard-performance-matrix.spec.ts +743 -0
  248. package/templates/.agents/dashboard/tests/e2e/specs/dashboard.spec.ts +189 -214
  249. package/templates/.agents/dashboard/zaip-dashboard-windows.exe +0 -0
  250. package/templates/.agents/design/.zaip-managed.json +3 -3
  251. package/templates/.agents/design/apps/catalog/package.json +1 -1
  252. package/templates/.agents/design/packages/local-runtime/package.json +1 -1
  253. package/templates/.agents/growth/estrategia-bootstrap-90-dias.md +169 -0
  254. package/templates/.agents/growth/strategy.md +27 -0
  255. package/templates/.agents/marketing/estrategia-marketing-zaip-90-dias.md +197 -0
  256. package/templates/.agents/marketing/strategy.md +29 -0
  257. package/templates/.agents/requirements/autonomous-assurance.md +6 -6
  258. package/templates/.agents/requirements/comparative-audit.md +1 -1
  259. package/templates/.agents/requirements/context-engine.md +1 -1
  260. package/templates/.agents/requirements/cost-observability.md +1 -1
  261. package/templates/.agents/requirements/dashboard-launch.md +1 -1
  262. package/templates/.agents/requirements/data-export.md +1 -1
  263. package/templates/.agents/requirements/design-system.md +1 -1
  264. package/templates/.agents/requirements/execution-engine.md +3 -3
  265. package/templates/.agents/requirements/kanban-dashboard.md +10 -2
  266. package/templates/.agents/requirements/model-orchestration.md +1 -1
  267. package/templates/.agents/requirements/public-distribution.md +1 -1
  268. package/templates/.agents/requirements/software-architecture.md +1 -1
  269. package/templates/.agents/requirements/strategic-improvements.md +1 -1
  270. package/templates/.agents/requirements/work-lifecycle.md +4 -4
  271. package/templates/.agents/requirements/zaip-strategic-95.md +1 -1
  272. package/templates/.agents/rules/dashboard-ui-consistency.md +14 -0
  273. package/templates/.agents/rules/frontend-lite.md +4 -4
  274. package/templates/.agents/rules/run-lifecycle-closure.md +4 -4
  275. package/templates/.agents/runtime/VERSION +1 -1
  276. package/templates/.agents/runtime/bin/zaip.mjs +1142 -1041
  277. package/templates/.agents/runtime/checksums.sha256 +6 -6
  278. package/templates/.agents/runtime/manifest.json +1 -1
  279. package/templates/.agents/runtime/pnpm-lock.sha256 +1 -1
  280. package/templates/.agents/runtime/provenance.json +5 -5
  281. package/templates/.agents/runtime/sbom.cdx.json +3 -3
  282. package/templates/.agents/sales/playbook.md +32 -0
  283. package/templates/.agents/sales/roteiro-comercial-zaip.md +252 -0
  284. package/templates/.agents/skills/criar-pasta-obsidian/scripts/generate-obsidian-vault.test.mjs +20 -16
  285. package/templates/.agents/skills/zaip-aios/SKILL.md +1 -1
  286. package/templates/.agents/skills/zaip-skill-agent-catalog/SKILL.md +22 -0
  287. package/templates/.agents/skills/zaip-skill-agent-catalog/agents/openai.yaml +4 -0
  288. package/templates/.agents/skills/zaip-skill-author-skills/SKILL.md +3 -2
  289. package/templates/.agents/skills/zaip-skill-author-skills/scripts/audit-skill-catalog.mjs +49 -0
  290. package/templates/.agents/skills/zaip-skill-author-skills/scripts/author-skill-scripts.test.mjs +27 -0
  291. package/templates/.agents/skills/zaip-skill-author-skills/scripts/run-skill-tests.mjs +37 -0
  292. package/templates/.agents/skills/zaip-skill-backend/SKILL.md +1 -0
  293. package/templates/.agents/skills/zaip-skill-brand-governance/SKILL.md +9 -2
  294. package/templates/.agents/skills/zaip-skill-brand-governance/references/brandbook-framework.md +39 -0
  295. package/templates/.agents/skills/zaip-skill-brand-governance/references/brandbook-standards.md +1 -1
  296. package/templates/.agents/skills/zaip-skill-change/SKILL.md +1 -1
  297. package/templates/.agents/skills/zaip-skill-change/references/observable-evidence.md +83 -0
  298. package/templates/.agents/skills/zaip-skill-dashboard-diagnostics/SKILL.md +22 -0
  299. package/templates/.agents/skills/zaip-skill-dashboard-diagnostics/agents/openai.yaml +4 -0
  300. package/templates/.agents/skills/zaip-skill-enforce-architecture/SKILL.md +2 -0
  301. package/templates/.agents/skills/zaip-skill-execution/SKILL.md +1 -1
  302. package/templates/.agents/skills/zaip-skill-frontend/SKILL.md +4 -3
  303. package/templates/.agents/skills/zaip-skill-frontend/agents/openai.yaml +2 -2
  304. package/templates/.agents/skills/zaip-skill-github-deploy/SKILL.md +10 -10
  305. package/templates/.agents/skills/zaip-skill-growth-strategy-revops/SKILL.md +6 -0
  306. package/templates/.agents/skills/zaip-skill-lifecycle-closure/SKILL.md +27 -0
  307. package/templates/.agents/skills/zaip-skill-lifecycle-closure/agents/openai.yaml +4 -0
  308. package/templates/.agents/skills/zaip-skill-marketing/SKILL.md +6 -0
  309. package/templates/.agents/skills/zaip-skill-prd/SKILL.md +4 -0
  310. package/templates/.agents/skills/zaip-skill-reconcile-telemetry/scripts/reconcile-local-telemetry.mjs +111 -104
  311. package/templates/.agents/skills/zaip-skill-reconcile-telemetry/scripts/reconcile-telemetry-explicit-recovery.mjs +223 -0
  312. package/templates/.agents/skills/zaip-skill-reconcile-telemetry/scripts/reconcile-telemetry-lib.mjs +55 -9
  313. package/templates/.agents/skills/zaip-skill-reconcile-telemetry/scripts/reconcile-telemetry-lib.test.mjs +145 -14
  314. package/templates/.agents/skills/zaip-skill-reconcile-telemetry/scripts/reconcile-telemetry-remeasurement.mjs +19 -9
  315. package/templates/.agents/skills/zaip-skill-reconcile-telemetry/scripts/reconcile-telemetry-remeasurement.test.mjs +82 -5
  316. package/templates/.agents/skills/zaip-skill-reconcile-telemetry/scripts/source-size-telemetry/model-identity-reconciliation.mjs +77 -0
  317. package/templates/.agents/skills/zaip-skill-release-qualification/SKILL.md +20 -0
  318. package/templates/.agents/skills/zaip-skill-release-qualification/agents/openai.yaml +4 -0
  319. package/templates/.agents/skills/zaip-skill-review/SKILL.md +5 -0
  320. package/templates/.agents/skills/zaip-skill-rules/SKILL.md +1 -1
  321. package/templates/.agents/skills/zaip-skill-sales-methodology/SKILL.md +6 -0
  322. package/templates/.agents/skills/zaip-skill-spec/SKILL.md +4 -0
  323. package/templates/.agents/skills/zaip-skill-sqlite-read-model/SKILL.md +22 -90
  324. package/templates/.agents/skills/zaip-skill-sqlite-read-model/scripts/ensure-node.mjs +28 -5
  325. package/templates/.agents/zaip-aios/INDEX.md +57 -22
  326. package/templates/.agents/zaip-aios/README.md +24 -13
  327. package/templates/.agents/zaip-aios/VERSION +1 -1
  328. package/templates/.agents/zaip-aios/guides/02-requirements.md +5 -0
  329. package/templates/.agents/zaip-aios/guides/06-execucao.md +13 -4
  330. package/templates/.agents/zaip-aios/guides/07-revisao-e-validacao.md +7 -0
  331. package/templates/.agents/zaip-aios/guides/10-seguranca.md +23 -0
  332. package/templates/.agents/zaip-aios/guides/11-observabilidade-e-custos.md +6 -6
  333. package/templates/.agents/zaip-aios/guides/13-boas-praticas.md +3 -0
  334. package/templates/.agents/zaip-aios/guides/16-lifecycle-e-reconciliacao.md +12 -3
  335. package/templates/.agents/zaip-aios/guides/17-como-o-custo-e-calculado.md +5 -5
  336. package/templates/.agents/zaip-aios/guides/18-catalogo-de-agentes.md +76 -0
  337. package/templates/.agents/zaip-aios/guides/19-assurance-e-autonomia.md +95 -0
  338. package/templates/.agents/zaip-aios/guides/20-instalacao-detalhada.md +366 -0
  339. package/templates/.agents/zaip-aios/guides/21-telemetria-monitor-custos.md +46 -0
  340. package/templates/.agents/zaip-aios/guides/22-fluxos-e-roteamento.md +74 -0
  341. package/templates/.agents/zaip-aios/guides/23-orquestracao-de-modelos.md +483 -0
  342. package/templates/.agents/zaip-aios/guides/24-calculo-de-custos-openai.md +85 -0
  343. package/templates/.agents/zaip-aios/guides/25-fontes-de-precos-openai.md +19 -0
  344. package/templates/.agents/zaip-aios/guides/26-qualidade-e-release.md +111 -0
  345. package/templates/.agents/zaip-aios/guides/27-telemetria-git-native.md +172 -0
  346. package/templates/.agents/zaip-aios/guides/28-lifecycle-completo.md +149 -0
  347. package/templates/.agents/zaip-aios/guides/assets/diagrams/lifecycles-task-spec-prd.png +0 -0
  348. package/templates/.agents/zaip-aios/guides/assets/diagrams/prd-lifecycle.png +0 -0
  349. package/templates/.agents/zaip-aios/guides/assets/diagrams/spec-lifecycle.png +0 -0
  350. package/templates/.agents/zaip-aios/guides/assets/diagrams/task-lifecycle.png +0 -0
  351. package/templates/template-manifest.json +756 -235
  352. package/templates/.agents/dashboard/apps/frontend/dist/assets/DashboardHelpDialog-Cs6dzDmW.js +0 -1505
  353. package/templates/.agents/dashboard/apps/frontend/dist/assets/ProjectSettingsPage-QE1k9yZB.css +0 -1
  354. package/templates/.agents/dashboard/apps/frontend/dist/assets/ProjectSettingsPage-_Pf5DA_A.js +0 -3
  355. package/templates/.agents/dashboard/apps/frontend/dist/assets/TraceabilityWorkspace-BVlz3DLZ.js +0 -1
  356. package/templates/.agents/dashboard/apps/frontend/dist/assets/cost-monitor-BZ5WdaMN.css +0 -1
  357. package/templates/.agents/dashboard/apps/frontend/dist/assets/cost-monitor-Cf9ctPVt.js +0 -68
  358. package/templates/.agents/dashboard/apps/frontend/dist/assets/index-8A4DcNXM.js +0 -2
  359. package/templates/.agents/dashboard/apps/frontend/dist/assets/index-DK_enB5Z.css +0 -1
  360. package/templates/.agents/dashboard/apps/frontend/src/use-idle-cost-prefetch.ts +0 -45
@@ -1,15 +1,24 @@
1
- import { mkdir, mkdtemp, readFile, readdir, rename, utimes, writeFile } from "node:fs/promises";
1
+ import { createHash } from "node:crypto";
2
+ import { mkdir, mkdtemp, readdir, readFile, rename, utimes, writeFile } from "node:fs/promises";
2
3
  import { join, resolve } from "node:path";
3
4
  import { DatabaseSync } from "node:sqlite";
4
5
  import { afterEach, describe, expect, it } from "vitest";
5
6
  import { createDashboardApp, projectAllTimeTopTasks } from "./server.js";
6
- import { allocateAttributedTokenActiveMs, rebuildSqliteReadModel, sourceFingerprint, SqliteReadModelFileSystem } from "./sqlite-read-model.js";
7
+ import { expectFastCostPagesMatchCanonical } from "./sqlite-cost-fast-page-parity.test-support.js";
8
+ import {
9
+ allocateAttributedTokenActiveMs,
10
+ rebuildSqliteReadModel,
11
+ SqliteReadModelFileSystem,
12
+ sourceFingerprint,
13
+ } from "./sqlite-read-model.js";
14
+ import { expectPersistedFirstFoldCaches } from "./sqlite-read-model-cache.test-support.js";
7
15
 
8
16
  const roots: string[] = [];
9
- // Windows can deny SQLite's sidecar files below the system TEMP directory.
10
- // Keep disposable fixtures in the workspace-local test area instead; each
11
- // test still receives its own root and never touches the live read model.
12
- const sqliteTestTempRoot = join(resolve(import.meta.dirname, "../../../../../.."), ".tmp", "sqlite-read-model-tests");
17
+ const sqliteTestTempRoot = join(
18
+ resolve(import.meta.dirname, "../../../../../.."),
19
+ ".tmp",
20
+ "sqlite-read-model-tests",
21
+ );
13
22
  async function createSqliteTestRoot(): Promise<string> {
14
23
  await mkdir(sqliteTestTempRoot, { recursive: true });
15
24
  return mkdtemp(join(sqliteTestTempRoot, "fixture-"));
@@ -23,7 +32,6 @@ afterEach(async () => {
23
32
  ),
24
33
  );
25
34
  });
26
-
27
35
  describe("SQLite dashboard read model", () => {
28
36
  it("snapshots sorted eligible canonical sources once for fingerprinting and ingestion", async () => {
29
37
  const root = await createSqliteTestRoot();
@@ -33,7 +41,11 @@ describe("SQLite dashboard read model", () => {
33
41
  await mkdir(join(root, ".agents", "records", "tasks", "nested"), { recursive: true });
34
42
  await mkdir(join(root, ".agents", "records", "telemetry"), { recursive: true });
35
43
  await mkdir(join(root, ".agents", "config"), { recursive: true });
36
- await writeFile(join(root, ".agents", "config", "project.yaml"), "zaip:\n enabled: true\n", "utf8");
44
+ await writeFile(
45
+ join(root, ".agents", "config", "project.yaml"),
46
+ "zaip:\n enabled: true\n",
47
+ "utf8",
48
+ );
37
49
  await writeFile(included, "# included\n", "utf8");
38
50
  await writeFile(excluded, "ignored\n", "utf8");
39
51
 
@@ -50,13 +62,42 @@ describe("SQLite dashboard read model", () => {
50
62
  await expect(rebuildSqliteReadModel(root)).resolves.toMatchObject({ files: 2 });
51
63
  });
52
64
 
65
+ it("accepts only the canonical C3D4 historical assignment among lifecycle files", async () => {
66
+ const root = await createSqliteTestRoot();
67
+ roots.push(root);
68
+ const attributionRoot = join(
69
+ root,
70
+ ".agents",
71
+ "records",
72
+ "lifecycle",
73
+ "historical-developer-attribution",
74
+ );
75
+ await mkdir(attributionRoot, { recursive: true });
76
+ await mkdir(join(root, ".agents", "records", "lifecycle", "views"), { recursive: true });
77
+ await mkdir(join(root, ".agents", "config"), { recursive: true });
78
+ await writeFile(join(root, ".agents", "config", "project.yaml"), "zaip:\n enabled: true\n");
79
+ await writeFile(join(attributionRoot, "HDA-2026-08-29-ZAIP-AI-C3D4.json"), "{}\n");
80
+ await writeFile(join(root, ".agents", "records", "lifecycle", "views", "foreign.json"), "{}\n");
81
+
82
+ const snapshot = await sourceFingerprint(root);
83
+ expect(snapshot.candidates.map((candidate) => candidate.source)).toContain(
84
+ ".agents/records/lifecycle/historical-developer-attribution/HDA-2026-08-29-ZAIP-AI-C3D4.json",
85
+ );
86
+ expect(snapshot.candidates.map((candidate) => candidate.source)).not.toContain(
87
+ ".agents/records/lifecycle/views/foreign.json",
88
+ );
89
+ });
53
90
  it("uses a current-schema seed after a canonical change", async () => {
54
91
  const root = await createSqliteTestRoot();
55
92
  roots.push(root);
56
93
  const task = join(root, ".agents", "records", "tasks", "task.md");
57
94
  await mkdir(join(root, ".agents", "records", "tasks"), { recursive: true });
58
95
  await mkdir(join(root, ".agents", "config"), { recursive: true });
59
- await writeFile(join(root, ".agents", "config", "project.yaml"), "zaip:\n enabled: true\n", "utf8");
96
+ await writeFile(
97
+ join(root, ".agents", "config", "project.yaml"),
98
+ "zaip:\n enabled: true\n",
99
+ "utf8",
100
+ );
60
101
  await writeFile(task, "# original\n", "utf8");
61
102
  await expect(rebuildSqliteReadModel(root)).resolves.toMatchObject({ cache: "rebuilt" });
62
103
  await writeFile(task, "# changed canonically\n", "utf8");
@@ -65,7 +106,14 @@ describe("SQLite dashboard read model", () => {
65
106
  try {
66
107
  process.env.ZAIP_SQLITE_DB_PATH = join(root, ".local", "dashboard-sqlite", "next.sqlite");
67
108
  process.env.ZAIP_SQLITE_PREFER_LAST_VALID_SEED = "1";
68
- await expect(rebuildSqliteReadModel(root)).resolves.toMatchObject({ cache: "stale_seed", files: 2 });
109
+ await expect(rebuildSqliteReadModel(root)).resolves.toMatchObject({
110
+ cache: "stale_seed",
111
+ files: 2,
112
+ });
113
+ await expect(rebuildSqliteReadModel(root, { forceCanonical: true })).resolves.toMatchObject({
114
+ cache: "rebuilt",
115
+ files: 2,
116
+ });
69
117
  } finally {
70
118
  if (previousPath === undefined) delete process.env.ZAIP_SQLITE_DB_PATH;
71
119
  else process.env.ZAIP_SQLITE_DB_PATH = previousPath;
@@ -79,55 +127,103 @@ describe("SQLite dashboard read model", () => {
79
127
  roots.push(root);
80
128
  await mkdir(join(root, ".agents", "records", "tasks"), { recursive: true });
81
129
  await mkdir(join(root, ".agents", "config"), { recursive: true });
82
- await writeFile(join(root, ".agents", "config", "project.yaml"), "zaip:\n enabled: true\n", "utf8");
130
+ await writeFile(
131
+ join(root, ".agents", "config", "project.yaml"),
132
+ "zaip:\n enabled: true\n",
133
+ "utf8",
134
+ );
83
135
  await expect(rebuildSqliteReadModel(root)).resolves.toMatchObject({ cache: "rebuilt" });
84
136
  const path = join(root, ".local", "dashboard-sqlite", "read-model.sqlite");
85
137
  const database = new DatabaseSync(path);
86
- database.prepare("UPDATE zaip_aios_activities SET payload_json=? WHERE payload_type='first_fold_monthly_quick_cache'").run(JSON.stringify({
87
- from_day: "2026-08-01", to_day: "2026-08-18", source_latest_day: "2026-08-30",
88
- aggregate: { days: 0, total_run_count: 0, agent_invocation_count: 0, llm_call_count: null, duration_ms: null, total_tokens: null, cost_brl: null, execution_day_count: 0 },
89
- pages: { task: [], spec: [], prd: [] }, top_tasks: [],
90
- }));
138
+ database
139
+ .prepare(
140
+ "UPDATE zaip_aios_activities SET payload_json=? WHERE payload_type='first_fold_monthly_quick_cache'",
141
+ )
142
+ .run(
143
+ JSON.stringify({
144
+ from_day: "2026-08-01",
145
+ to_day: "2026-08-18",
146
+ source_latest_day: "2026-08-30",
147
+ aggregate: {
148
+ days: 0,
149
+ total_run_count: 0,
150
+ agent_invocation_count: 0,
151
+ llm_call_count: null,
152
+ duration_ms: null,
153
+ total_tokens: null,
154
+ cost_brl: null,
155
+ execution_day_count: 0,
156
+ },
157
+ pages: { task: [], spec: [], prd: [] },
158
+ top_tasks: [],
159
+ }),
160
+ );
91
161
  database.close();
92
162
  const filesystem = new SqliteReadModelFileSystem(root);
93
163
  try {
94
- expect(filesystem.firstFoldMonthlyQuick({ from: "2026-08-01", to: "2026-08-18" })).not.toBeNull();
164
+ expect(
165
+ filesystem.firstFoldMonthlyQuick({ from: "2026-08-01", to: "2026-08-18" }),
166
+ ).not.toBeNull();
95
167
  expect(filesystem.firstFoldMonthlyQuick({ from: "2026-08-01", to: "2026-08-19" })).toBeNull();
96
- expect(filesystem.firstFoldMonthlyQuick({ from: "2026-09-01", to: "2026-09-01" })).toMatchObject({
97
- aggregate: { total_run_count: 0 }, pages: { task: [], spec: [], prd: [] },
168
+ expect(
169
+ filesystem.firstFoldMonthlyQuick({ from: "2026-09-01", to: "2026-09-01" }),
170
+ ).toMatchObject({
171
+ aggregate: { total_run_count: 0 },
172
+ pages: { task: [], spec: [], prd: [] },
98
173
  });
99
- } finally { filesystem.close(); }
174
+ } finally {
175
+ filesystem.close();
176
+ }
100
177
  });
101
178
 
102
179
  it("treats an empty snapshot as an exact empty later-month projection", async () => {
103
180
  const root = await createSqliteTestRoot();
104
181
  roots.push(root);
105
182
  await mkdir(join(root, ".agents", "config"), { recursive: true });
106
- await writeFile(join(root, ".agents", "config", "project.yaml"), "zaip:\n enabled: true\n", "utf8");
183
+ await writeFile(
184
+ join(root, ".agents", "config", "project.yaml"),
185
+ "zaip:\n enabled: true\n",
186
+ "utf8",
187
+ );
107
188
  await expect(rebuildSqliteReadModel(root)).resolves.toMatchObject({ cache: "rebuilt" });
108
189
  const filesystem = new SqliteReadModelFileSystem(root);
109
190
  try {
110
- expect(filesystem.firstFoldMonthlyQuick({ from: "2099-01-01", to: "2099-01-01" })).toMatchObject({
111
- aggregate: { total_run_count: 0 }, pages: { task: [], spec: [], prd: [] },
191
+ expect(
192
+ filesystem.firstFoldMonthlyQuick({ from: "2099-01-01", to: "2099-01-01" }),
193
+ ).toMatchObject({
194
+ aggregate: { total_run_count: 0 },
195
+ pages: { task: [], spec: [], prd: [] },
112
196
  });
113
- } finally { filesystem.close(); }
197
+ } finally {
198
+ filesystem.close();
199
+ }
114
200
  });
115
201
 
116
- it("does not serve a schema 59 seed during the one-time SQLite cache migration", async () => {
202
+ it("does not serve a prior-schema seed during the one-time SQLite cache migration", async () => {
117
203
  const root = await createSqliteTestRoot();
118
204
  roots.push(root);
119
205
  await mkdir(join(root, ".agents", "records", "tasks"), { recursive: true });
120
206
  await mkdir(join(root, ".agents", "config"), { recursive: true });
121
- await writeFile(join(root, ".agents", "config", "project.yaml"), "zaip:\n enabled: true\n", "utf8");
207
+ await writeFile(
208
+ join(root, ".agents", "config", "project.yaml"),
209
+ "zaip:\n enabled: true\n",
210
+ "utf8",
211
+ );
122
212
  await writeFile(join(root, ".agents", "records", "tasks", "task.md"), "# task\n", "utf8");
123
213
  await expect(rebuildSqliteReadModel(root)).resolves.toMatchObject({ cache: "rebuilt" });
124
214
  const cacheDirectory = join(root, ".local", "dashboard-sqlite", "cache");
125
- const current = (await readdir(cacheDirectory)).find((entry) => entry.startsWith("v60-") && entry.endsWith(".sqlite"));
215
+ const current = (await readdir(cacheDirectory)).find(
216
+ (entry) => /^v\d+-/.test(entry) && entry.endsWith(".sqlite"),
217
+ );
126
218
  expect(current).toBeDefined();
127
- const legacy = join(cacheDirectory, current!.replace("v60-", ""));
219
+ const legacy = join(cacheDirectory, current!.replace(/^v\d+-/, ""));
128
220
  await rename(join(cacheDirectory, current!), legacy);
129
221
  const oldSeed = new DatabaseSync(legacy);
130
- oldSeed.prepare("UPDATE zaip_aios_activities SET payload_json=json_set(payload_json, '$.value', '59') WHERE payload_type='metadata' AND json_extract(payload_json, '$.key')='schema_version'").run();
222
+ oldSeed
223
+ .prepare(
224
+ "UPDATE zaip_aios_activities SET payload_json=json_set(payload_json, '$.value', '65') WHERE payload_type='metadata' AND json_extract(payload_json, '$.key')='schema_version'",
225
+ )
226
+ .run();
131
227
  oldSeed.close();
132
228
  const priorPath = process.env.ZAIP_SQLITE_DB_PATH;
133
229
  const priorSeed = process.env.ZAIP_SQLITE_PREFER_LAST_VALID_SEED;
@@ -145,19 +241,41 @@ describe("SQLite dashboard read model", () => {
145
241
 
146
242
  it("rateia sobreposição e virada de dia na fato temporal aditiva", () => {
147
243
  const overlap = allocateAttributedTokenActiveMs([
148
- { activityRowId: "A", startMs: Date.parse("2026-08-10T12:00:00.000Z"), endMs: Date.parse("2026-08-10T13:00:00.000Z") },
149
- { activityRowId: "B", startMs: Date.parse("2026-08-10T12:30:00.000Z"), endMs: Date.parse("2026-08-10T13:30:00.000Z") },
244
+ {
245
+ activityRowId: "A",
246
+ startMs: Date.parse("2026-08-10T12:00:00.000Z"),
247
+ endMs: Date.parse("2026-08-10T13:00:00.000Z"),
248
+ },
249
+ {
250
+ activityRowId: "B",
251
+ startMs: Date.parse("2026-08-10T12:30:00.000Z"),
252
+ endMs: Date.parse("2026-08-10T13:30:00.000Z"),
253
+ },
150
254
  ]);
151
255
  expect(overlap.reduce((sum, fact) => sum + fact.value, 0)).toBe(5_400_000);
152
- expect(overlap.filter((fact) => fact.activityRowId === "A").reduce((sum, fact) => sum + fact.value, 0)).toBe(2_700_000);
153
- expect(overlap.filter((fact) => fact.activityRowId === "B").reduce((sum, fact) => sum + fact.value, 0)).toBe(2_700_000);
256
+ expect(
257
+ overlap
258
+ .filter((fact) => fact.activityRowId === "A")
259
+ .reduce((sum, fact) => sum + fact.value, 0),
260
+ ).toBe(2_700_000);
261
+ expect(
262
+ overlap
263
+ .filter((fact) => fact.activityRowId === "B")
264
+ .reduce((sum, fact) => sum + fact.value, 0),
265
+ ).toBe(2_700_000);
154
266
  const midnight = allocateAttributedTokenActiveMs([
155
- { activityRowId: "MID", startMs: Date.parse("2026-08-11T02:30:00.000Z"), endMs: Date.parse("2026-08-11T03:30:00.000Z") },
267
+ {
268
+ activityRowId: "MID",
269
+ startMs: Date.parse("2026-08-11T02:30:00.000Z"),
270
+ endMs: Date.parse("2026-08-11T03:30:00.000Z"),
271
+ },
156
272
  ]);
157
- expect(midnight).toEqual(expect.arrayContaining([
158
- expect.objectContaining({ day: "2026-08-10", value: 1_800_000 }),
159
- expect.objectContaining({ day: "2026-08-11", value: 1_800_000 }),
160
- ]));
273
+ expect(midnight).toEqual(
274
+ expect.arrayContaining([
275
+ expect.objectContaining({ day: "2026-08-10", value: 1_800_000 }),
276
+ expect.objectContaining({ day: "2026-08-11", value: 1_800_000 }),
277
+ ]),
278
+ );
161
279
  });
162
280
  it("projects canonical executions, conversations, changes and decisions without lifecycle aggregates", async () => {
163
281
  const root = await createSqliteTestRoot();
@@ -166,10 +284,9 @@ describe("SQLite dashboard read model", () => {
166
284
  await mkdir(join(root, ".agents", "records", "executions", "2026", "08", "EXEC-1"), {
167
285
  recursive: true,
168
286
  });
169
- await mkdir(
170
- join(root, ".agents", "records", "changes", "2026", "08", "CHG-1", "decisions"),
171
- { recursive: true },
172
- );
287
+ await mkdir(join(root, ".agents", "records", "changes", "2026", "08", "CHG-1", "decisions"), {
288
+ recursive: true,
289
+ });
173
290
  await writeFile(join(root, ".agents", "config", "project.yaml"), "zaip:\n enabled: true\n");
174
291
  await writeFile(
175
292
  join(root, ".agents", "records", "executions", "2026", "08", "EXEC-1", "execution.md"),
@@ -210,17 +327,7 @@ created_at: 2026-08-10T11:00:00.000Z
210
327
  `,
211
328
  );
212
329
  await writeFile(
213
- join(
214
- root,
215
- ".agents",
216
- "records",
217
- "changes",
218
- "2026",
219
- "08",
220
- "CHG-1",
221
- "decisions",
222
- "DEC-1.md",
223
- ),
330
+ join(root, ".agents", "records", "changes", "2026", "08", "CHG-1", "decisions", "DEC-1.md"),
224
331
  `---
225
332
  schema_version: 2
226
333
  id: DEC-1
@@ -239,7 +346,16 @@ created_at: 2026-08-10T11:01:00.000Z
239
346
  const filesystem = new SqliteReadModelFileSystem(root);
240
347
  expect(filesystem.viewPage("operations_executions", { limit: 100 })).toMatchObject({
241
348
  total_count: 1,
242
- rows: [{ execution_id: "EXEC-1", conversation_id: "CONV-1", invocation_count: 0, duration_ms: null, duration_provenance: "unavailable", lifecycle_elapsed_ms: 300_000 }],
349
+ rows: [
350
+ {
351
+ execution_id: "EXEC-1",
352
+ conversation_id: "CONV-1",
353
+ invocation_count: 0,
354
+ duration_ms: null,
355
+ duration_provenance: "unavailable",
356
+ lifecycle_elapsed_ms: 300_000,
357
+ },
358
+ ],
243
359
  });
244
360
  expect(filesystem.viewPage("operations_conversations", { limit: 100 })).toMatchObject({
245
361
  total_count: 1,
@@ -253,8 +369,8 @@ created_at: 2026-08-10T11:01:00.000Z
253
369
  total_count: 1,
254
370
  rows: [{ id: "DEC-1", title: "Canonical decision", scope_id: "CHG-1" }],
255
371
  });
256
- // Unfiltered Operations pagination is served from one immutable
257
- // generation-local query result, while retaining the public page contract.
372
+ // Operations pagination stays inside SQLite even with no filters: the
373
+ // browser receives only its requested page, never the whole work union.
258
374
  const workListFirst = filesystem.viewPage("operations_work_list", { limit: 1, offset: 0 });
259
375
  const workListNext = filesystem.viewPage("operations_work_list", { limit: 1, offset: 1 });
260
376
  expect(workListFirst.total_count).toBe(workListNext.total_count);
@@ -312,30 +428,84 @@ created_at: 2026-08-10T11:01:00.000Z
312
428
  const events = [...expected.keys()].flatMap((agent, index) => {
313
429
  const runId = `RUN-AGENT-${index}`;
314
430
  const started = {
315
- schema_version: 2, event_id: `${runId}:1`, run_id: runId, sequence: 1,
316
- occurred_at: "2026-08-18T12:00:00.000Z", type: "run.started", attribution_status: "attributed",
317
- phase: "execution", run_role: "subagent", run_purpose: "execution", requires_finalizer: false,
318
- execution_kind: "delivery", execution_eligibility: ["delivery"], entrypoint: "task", work_type: "new",
319
- storage_mode: "tracked_sanitized", client: "codex", agent, agent_name: agent, provider: "openai",
320
- model: "gpt-5", reasoning_effort: null, client_thread_id: runId, client_turn_id: runId,
321
- conversation_id: `CONV-${index}`, execution_id: `EXEC-${index}`, task_id: `TASK-${index}`,
322
- spec_id: null, prd_id: null, change_id: null, parent_run_id: "RUN-ROOT", continuation_of_run_id: null,
323
- retry_of_run_id: null, agent_invocation_id: `AINV-${index}`, root_agent_invocation_id: "AINV-ROOT",
324
- parent_agent_invocation_id: "AINV-ROOT", invocation_kind: "delegated", delegation_depth: 1,
431
+ schema_version: 2,
432
+ event_id: `${runId}:1`,
433
+ run_id: runId,
434
+ sequence: 1,
435
+ occurred_at: "2026-08-18T12:00:00.000Z",
436
+ type: "run.started",
437
+ attribution_status: "attributed",
438
+ phase: "execution",
439
+ run_role: "subagent",
440
+ run_purpose: "execution",
441
+ requires_finalizer: false,
442
+ execution_kind: "delivery",
443
+ execution_eligibility: ["delivery"],
444
+ entrypoint: "task",
445
+ work_type: "new",
446
+ storage_mode: "tracked_sanitized",
447
+ client: "codex",
448
+ agent,
449
+ agent_name: agent,
450
+ provider: "openai",
451
+ model: "gpt-5",
452
+ reasoning_effort: null,
453
+ client_thread_id: runId,
454
+ client_turn_id: runId,
455
+ conversation_id: `CONV-${index}`,
456
+ execution_id: `EXEC-${index}`,
457
+ task_id: `TASK-${index}`,
458
+ spec_id: null,
459
+ prd_id: null,
460
+ change_id: null,
461
+ parent_run_id: "RUN-ROOT",
462
+ continuation_of_run_id: null,
463
+ retry_of_run_id: null,
464
+ agent_invocation_id: `AINV-${index}`,
465
+ root_agent_invocation_id: "AINV-ROOT",
466
+ parent_agent_invocation_id: "AINV-ROOT",
467
+ invocation_kind: "delegated",
468
+ delegation_depth: 1,
325
469
  };
326
470
  const usage = {
327
- schema_version: 2, event_id: `${runId}:2`, run_id: runId, sequence: 2,
328
- occurred_at: "2026-08-18T12:00:01.000Z", type: "usage.recorded", phase: "execution",
329
- activity_kind: "model_usage", classification_source: "explicit",
330
- tokens: { input: 1, cached_input: 0, output: 1, reasoning: 0, total: 2, source: "provider_reported" },
331
- cost: { usd: 0.01, brl: 0.05, fx_rate: 5 }, provider: "openai", model: "gpt-5",
332
- source_segment_key: runId, model_call_id: `MCALL-${index}`, runtime: { reasoning_effort: null, service_tier: null },
333
- supersedes_event_id: null, duration_ms: null, duration_provenance: null,
471
+ schema_version: 2,
472
+ event_id: `${runId}:2`,
473
+ run_id: runId,
474
+ sequence: 2,
475
+ occurred_at: "2026-08-18T12:00:01.000Z",
476
+ type: "usage.recorded",
477
+ phase: "execution",
478
+ activity_kind: "model_usage",
479
+ classification_source: "explicit",
480
+ tokens: {
481
+ input: 1,
482
+ cached_input: 0,
483
+ output: 1,
484
+ reasoning: 0,
485
+ total: 2,
486
+ source: "provider_reported",
487
+ },
488
+ cost: { usd: 0.01, brl: 0.05, fx_rate: 5 },
489
+ provider: "openai",
490
+ model: "gpt-5",
491
+ source_segment_key: runId,
492
+ model_call_id: `MCALL-${index}`,
493
+ runtime: { reasoning_effort: null, service_tier: null },
494
+ supersedes_event_id: null,
495
+ duration_ms: null,
496
+ duration_provenance: null,
334
497
  };
335
498
  const finished = {
336
- schema_version: 2, event_id: `${runId}:3`, run_id: runId, sequence: 3,
337
- occurred_at: "2026-08-18T12:01:00.000Z", type: "run.finished", phase: "execution",
338
- status: "completed", duration_ms: 60_000, duration_provenance: "observed",
499
+ schema_version: 2,
500
+ event_id: `${runId}:3`,
501
+ run_id: runId,
502
+ sequence: 3,
503
+ occurred_at: "2026-08-18T12:01:00.000Z",
504
+ type: "run.finished",
505
+ phase: "execution",
506
+ status: "completed",
507
+ duration_ms: 60_000,
508
+ duration_provenance: "observed",
339
509
  };
340
510
  return [started, usage, finished];
341
511
  });
@@ -343,7 +513,10 @@ created_at: 2026-08-10T11:01:00.000Z
343
513
  [...expected.keys()].map((_, index) =>
344
514
  writeFile(
345
515
  join(root, ".agents", "records", "runs", "2026", "08", `RUN-AGENT-${index}.jsonl`),
346
- `${events.slice(index * 3, index * 3 + 3).map((event) => JSON.stringify(event)).join("\n")}\n`,
516
+ `${events
517
+ .slice(index * 3, index * 3 + 3)
518
+ .map((event) => JSON.stringify(event))
519
+ .join("\n")}\n`,
347
520
  ),
348
521
  ),
349
522
  );
@@ -381,25 +554,87 @@ created_at: 2026-08-10T11:01:00.000Z
381
554
  source: "fixture",
382
555
  disclaimer: "fixture",
383
556
  models: [
384
- { id: "gpt-a", provider: "openai", aliases: [], input_per_million_usd: 2, cached_input_per_million_usd: 0.2, output_per_million_usd: 8, reasoning_per_million_usd: 8, reasoning_billed_separately: false, long_context_threshold_tokens: null, long_context_input_multiplier: 1, long_context_output_multiplier: 1, source_label: "fixture-openai", source_url: "https://example.test/openai", notes: [] },
385
- { id: "claude-b", provider: "anthropic", aliases: [], input_per_million_usd: 3, cached_input_per_million_usd: 0.3, output_per_million_usd: 12, reasoning_per_million_usd: null, reasoning_billed_separately: false, long_context_threshold_tokens: null, long_context_input_multiplier: 1, long_context_output_multiplier: 1, source_label: "fixture-anthropic", source_url: "https://example.test/anthropic", notes: [] },
557
+ {
558
+ id: "gpt-a",
559
+ provider: "openai",
560
+ aliases: [],
561
+ input_per_million_usd: 2,
562
+ cached_input_per_million_usd: 0.2,
563
+ output_per_million_usd: 8,
564
+ reasoning_per_million_usd: 8,
565
+ reasoning_billed_separately: false,
566
+ long_context_threshold_tokens: null,
567
+ long_context_input_multiplier: 1,
568
+ long_context_output_multiplier: 1,
569
+ source_label: "fixture-openai",
570
+ source_url: "https://example.test/openai",
571
+ notes: [],
572
+ },
573
+ {
574
+ id: "claude-b",
575
+ provider: "anthropic",
576
+ aliases: [],
577
+ input_per_million_usd: 3,
578
+ cached_input_per_million_usd: 0.3,
579
+ output_per_million_usd: 12,
580
+ reasoning_per_million_usd: null,
581
+ reasoning_billed_separately: false,
582
+ long_context_threshold_tokens: null,
583
+ long_context_input_multiplier: 1,
584
+ long_context_output_multiplier: 1,
585
+ source_label: "fixture-anthropic",
586
+ source_url: "https://example.test/anthropic",
587
+ notes: [],
588
+ },
386
589
  ],
387
590
  }),
388
591
  );
389
592
  const started = {
390
- schema_version: 2, event_id: "RUN-MISSING:1", run_id: "RUN-MISSING", sequence: 1,
391
- occurred_at: "2026-08-05T12:00:00.000Z", type: "run.started", attribution_status: "attributed",
392
- phase: "conversation", run_role: "orchestrator", run_purpose: "orchestration", requires_finalizer: false,
393
- execution_kind: "interaction", execution_eligibility: ["interaction"], entrypoint: "conversation",
394
- work_type: "new", storage_mode: "tracked_sanitized", client: "codex", agent: "root", agent_name: "root",
395
- provider: null, model: "unknown", reasoning_effort: null, client_thread_id: "missing", client_turn_id: "missing",
396
- conversation_id: "CONV-MISSING", execution_id: null, task_id: null, spec_id: null, prd_id: null,
397
- change_id: null, parent_run_id: null, continuation_of_run_id: null, retry_of_run_id: null,
593
+ schema_version: 2,
594
+ event_id: "RUN-MISSING:1",
595
+ run_id: "RUN-MISSING",
596
+ sequence: 1,
597
+ occurred_at: "2026-08-05T12:00:00.000Z",
598
+ type: "run.started",
599
+ attribution_status: "attributed",
600
+ phase: "conversation",
601
+ run_role: "orchestrator",
602
+ run_purpose: "orchestration",
603
+ requires_finalizer: false,
604
+ execution_kind: "interaction",
605
+ execution_eligibility: ["interaction"],
606
+ entrypoint: "conversation",
607
+ work_type: "new",
608
+ storage_mode: "tracked_sanitized",
609
+ client: "codex",
610
+ agent: "root",
611
+ agent_name: "root",
612
+ provider: null,
613
+ model: "unknown",
614
+ reasoning_effort: null,
615
+ client_thread_id: "missing",
616
+ client_turn_id: "missing",
617
+ conversation_id: "CONV-MISSING",
618
+ execution_id: null,
619
+ task_id: null,
620
+ spec_id: null,
621
+ prd_id: null,
622
+ change_id: null,
623
+ parent_run_id: null,
624
+ continuation_of_run_id: null,
625
+ retry_of_run_id: null,
398
626
  };
399
627
  const finished = {
400
- schema_version: 2, event_id: "RUN-MISSING:2", run_id: "RUN-MISSING", sequence: 2,
401
- occurred_at: "2026-08-05T12:01:00.000Z", type: "run.finished", phase: "conversation",
402
- status: "completed", duration_ms: 60_000, duration_provenance: "observed",
628
+ schema_version: 2,
629
+ event_id: "RUN-MISSING:2",
630
+ run_id: "RUN-MISSING",
631
+ sequence: 2,
632
+ occurred_at: "2026-08-05T12:01:00.000Z",
633
+ type: "run.finished",
634
+ phase: "conversation",
635
+ status: "completed",
636
+ duration_ms: 60_000,
637
+ duration_provenance: "observed",
403
638
  };
404
639
  await writeFile(
405
640
  join(root, ".agents", "records", "runs", "2026", "08", "RUN-MISSING.jsonl"),
@@ -407,6 +642,7 @@ created_at: 2026-08-10T11:01:00.000Z
407
642
  );
408
643
  await rebuildSqliteReadModel(root);
409
644
  const filesystem = new SqliteReadModelFileSystem(root);
645
+ expectFastCostPagesMatchCanonical(root, filesystem);
410
646
  expect(filesystem.dailyPeriods({ from: null, to: null })["2026-08-05"]).toMatchObject({
411
647
  runs: 1,
412
648
  usage: {
@@ -426,26 +662,40 @@ created_at: 2026-08-10T11:01:00.000Z
426
662
  await rebuildSqliteReadModel(root);
427
663
  const filesystem = new SqliteReadModelFileSystem(root);
428
664
  try {
429
- expect(await filesystem.readText(".agents/config/project.yaml")).toBe("zaip:\n enabled: true\n");
665
+ expect(await filesystem.readText(".agents/config/project.yaml")).toBe(
666
+ "zaip:\n enabled: true\n",
667
+ );
430
668
  expect(filesystem.viewPage("operations_work_list", { limit: 10 }).total_count).toBe(0);
431
- const pageCache = (filesystem as unknown as {
432
- viewPageResultCache: Map<string, Record<string, unknown>>;
433
- }).viewPageResultCache;
669
+ const pageCache = (
670
+ filesystem as unknown as {
671
+ viewPageResultCache: Map<string, Record<string, unknown>>;
672
+ }
673
+ ).viewPageResultCache;
434
674
  expect(pageCache.has('operations_work_list:{"limit":10}')).toBe(true);
435
675
  // Change canonical input only after the read-only database has opened:
436
676
  // rebuild must replace the generation rather than taking the cache path.
437
677
  await writeFile(configPath, "zaip:\n enabled: true\nproject:\n id: refreshed-fixture\n");
438
- await expect(filesystem.rebuildAndRefresh(() => rebuildSqliteReadModel(root))).resolves.toBeUndefined();
439
- expect(await filesystem.readText(".agents/config/project.yaml")).toContain("refreshed-fixture");
678
+ await expect(
679
+ filesystem.rebuildAndRefresh(() => rebuildSqliteReadModel(root)),
680
+ ).resolves.toBeUndefined();
681
+ expect(await filesystem.readText(".agents/config/project.yaml")).toContain(
682
+ "refreshed-fixture",
683
+ );
440
684
  expect(pageCache.has('operations_work_list:{"limit":10}')).toBe(false);
441
685
  // Exercise the actual public view on the same reopened instance, not
442
686
  // merely raw filesystem reads after a Windows-safe replacement.
443
- expect(() => filesystem.viewPage("cost_monitor_daily", { limit: 1, offset: 0 })).not.toThrow();
687
+ expect(() =>
688
+ filesystem.viewPage("cost_monitor_daily", { limit: 1, offset: 0 }),
689
+ ).not.toThrow();
444
690
  // A failed rebuild still reopens the existing, complete generation.
445
- await expect(filesystem.rebuildAndRefresh(async () => {
446
- throw new Error("simulated rebuild failure");
447
- })).rejects.toThrow("simulated rebuild failure");
448
- expect(await filesystem.readText(".agents/config/project.yaml")).toContain("refreshed-fixture");
691
+ await expect(
692
+ filesystem.rebuildAndRefresh(async () => {
693
+ throw new Error("simulated rebuild failure");
694
+ }),
695
+ ).rejects.toThrow("simulated rebuild failure");
696
+ expect(await filesystem.readText(".agents/config/project.yaml")).toContain(
697
+ "refreshed-fixture",
698
+ );
449
699
  } finally {
450
700
  filesystem.close();
451
701
  }
@@ -458,7 +708,7 @@ created_at: 2026-08-10T11:01:00.000Z
458
708
  await mkdir(join(root, ".agents", "config"), { recursive: true });
459
709
  await writeFile(
460
710
  join(root, ".agents", "config", "project.yaml"),
461
- "schema_version: 1\nzaip:\n enabled: true\nproject:\n id: sqlite-test\n name: sqlite-test\n timezone: UTC\nstack:\n id: zaip-aios-stack\n overrides: {}\nclients:\n codex: true\n claude: true\ntracking:\n enabled: true\n currency: BRL\n storage_mode: tracked_sanitized\n",
711
+ "schema_version: 1\nzaip:\n enabled: true\nproject:\n id: sqlite-test\n name: sqlite-test\n timezone: UTC\nstack:\n id: zaip-aios-stack\n overrides: {}\nclients:\n codex: true\n claude: true\ntracking:\n enabled: true\n currency: BRL\n storage_mode: tracked_sanitized\n",
462
712
  "utf8",
463
713
  );
464
714
  const started = {
@@ -572,11 +822,24 @@ created_at: 2026-08-10T11:01:00.000Z
572
822
  duration_unknown: 1,
573
823
  });
574
824
  expect(Object.keys(day).sort()).toEqual([
575
- "duration_known", "duration_unknown", "evidence_count", "key", "label",
576
- "prd_count", "spec_count", "task_count", "total_cost_brl", "total_cost_usd",
577
- "total_duration", "total_run_count", "total_tokens", "validation_count",
825
+ "duration_known",
826
+ "duration_unknown",
827
+ "evidence_count",
828
+ "key",
829
+ "label",
830
+ "prd_count",
831
+ "spec_count",
832
+ "task_count",
833
+ "total_cost_brl",
834
+ "total_cost_usd",
835
+ "total_duration",
836
+ "total_run_count",
837
+ "total_tokens",
838
+ "validation_count",
578
839
  ]);
579
- expect(filesystem.costMonitorFactualDurationByDay({ from: null, to: null }).get("2026-08-01")).toEqual({
840
+ expect(
841
+ filesystem.costMonitorFactualDurationByDay({ from: null, to: null }).get("2026-08-01"),
842
+ ).toEqual({
580
843
  known_sum: 0,
581
844
  eligible_runs: 1,
582
845
  known_runs: 0,
@@ -589,7 +852,9 @@ created_at: 2026-08-10T11:01:00.000Z
589
852
  roots.push(root);
590
853
  await mkdir(join(root, ".agents", "records", "runs", "2026", "08"), { recursive: true });
591
854
  await mkdir(join(root, ".agents", "config", "agents"), { recursive: true });
592
- await mkdir(join(root, ".agents", "config", "pricing", "fx", "2026", "08", "04"), { recursive: true });
855
+ await mkdir(join(root, ".agents", "config", "pricing", "fx", "2026", "08", "04"), {
856
+ recursive: true,
857
+ });
593
858
  await writeFile(join(root, ".agents", "config", "project.yaml"), "zaip:\n enabled: true\n");
594
859
  await writeFile(
595
860
  join(root, ".agents", "config", "agents", "catalog.yaml"),
@@ -603,17 +868,117 @@ created_at: 2026-08-10T11:01:00.000Z
603
868
  source: "fixture",
604
869
  disclaimer: "fixture",
605
870
  models: [
606
- { id: "gpt-a", provider: "openai", aliases: [], input_per_million_usd: 2, cached_input_per_million_usd: 0.2, output_per_million_usd: 8, reasoning_per_million_usd: 8, reasoning_billed_separately: false, long_context_threshold_tokens: null, long_context_input_multiplier: 1, long_context_output_multiplier: 1, source_label: "fixture-openai", source_url: "https://example.test/openai", notes: [] },
871
+ {
872
+ id: "gpt-a",
873
+ provider: "openai",
874
+ aliases: [],
875
+ input_per_million_usd: 2,
876
+ cached_input_per_million_usd: 0.2,
877
+ output_per_million_usd: 8,
878
+ reasoning_per_million_usd: 8,
879
+ reasoning_billed_separately: false,
880
+ long_context_threshold_tokens: null,
881
+ long_context_input_multiplier: 1,
882
+ long_context_output_multiplier: 1,
883
+ source_label: "fixture-openai",
884
+ source_url: "https://example.test/openai",
885
+ notes: [],
886
+ },
607
887
  ],
608
888
  }),
609
889
  );
610
890
  await writeFile(
611
891
  join(root, ".agents", "config", "pricing", "fx", "2026", "08", "04", "usd-brl.json"),
612
- JSON.stringify({ schema_version: 1, base: "USD", quote: "BRL", rate: 5.5, as_of: "2026-08-04T00:00:00.000Z", source_label: "fixture", source_url: "https://example.test/fx" }),
892
+ JSON.stringify({
893
+ schema_version: 1,
894
+ base: "USD",
895
+ quote: "BRL",
896
+ rate: 5.5,
897
+ as_of: "2026-08-04T00:00:00.000Z",
898
+ source_label: "fixture",
899
+ source_url: "https://example.test/fx",
900
+ }),
613
901
  );
614
- const started = { schema_version: 2, event_id: "RUN-PRICED:1", run_id: "RUN-PRICED", sequence: 1, occurred_at: "2026-08-08T12:00:00.000Z", type: "run.started", attribution_status: "attributed", phase: "execution", run_role: "orchestrator", run_purpose: "execution", requires_finalizer: false, execution_kind: "delivery", execution_eligibility: ["delivery"], entrypoint: "task", work_type: "new", storage_mode: "tracked_sanitized", client: "codex", agent: "agent", agent_name: "agent", provider: "openai", model: "gpt-a", reasoning_effort: null, client_thread_id: "priced", client_turn_id: "priced", conversation_id: "CONV-PRICED", execution_id: "EXEC-PRICED", task_id: "TASK-PRICED", spec_id: null, prd_id: null, change_id: null, parent_run_id: null, continuation_of_run_id: null, retry_of_run_id: null, agent_invocation_id: "AINV-PRICED", root_agent_invocation_id: "AINV-PRICED", parent_agent_invocation_id: null, invocation_kind: "orchestrator", delegation_depth: 0 };
615
- const usage = { schema_version: 2, event_id: "RUN-PRICED:2", run_id: "RUN-PRICED", sequence: 2, occurred_at: "2026-08-08T12:00:01.000Z", type: "usage.recorded", phase: "execution", activity_kind: "model_usage", classification_source: "explicit", tokens: { input: 5, cached_input: 0, output: 0, reasoning: 0, total: 5, source: "provider_reported" }, cost: { usd: 0.5, brl: 2.5, fx_rate: 5 }, provider: "openai", model: "gpt-a", source_segment_key: "openai-gpt-a", model_call_id: "MCALL-PRICED", runtime: { reasoning_effort: null, service_tier: null }, supersedes_event_id: null, duration_ms: null, duration_provenance: null };
616
- const finished = { schema_version: 2, event_id: "RUN-PRICED:3", run_id: "RUN-PRICED", sequence: 3, occurred_at: "2026-08-08T12:01:00.000Z", type: "run.finished", phase: "execution", status: "completed", duration_ms: 60_000, duration_provenance: "observed" };
902
+ const started = {
903
+ schema_version: 2,
904
+ event_id: "RUN-PRICED:1",
905
+ run_id: "RUN-PRICED",
906
+ sequence: 1,
907
+ occurred_at: "2026-08-08T12:00:00.000Z",
908
+ type: "run.started",
909
+ attribution_status: "attributed",
910
+ phase: "execution",
911
+ run_role: "orchestrator",
912
+ run_purpose: "execution",
913
+ requires_finalizer: false,
914
+ execution_kind: "delivery",
915
+ execution_eligibility: ["delivery"],
916
+ entrypoint: "task",
917
+ work_type: "new",
918
+ storage_mode: "tracked_sanitized",
919
+ client: "codex",
920
+ agent: "agent",
921
+ agent_name: "agent",
922
+ provider: "openai",
923
+ model: "gpt-a",
924
+ reasoning_effort: null,
925
+ client_thread_id: "priced",
926
+ client_turn_id: "priced",
927
+ conversation_id: "CONV-PRICED",
928
+ execution_id: "EXEC-PRICED",
929
+ task_id: "TASK-PRICED",
930
+ spec_id: null,
931
+ prd_id: null,
932
+ change_id: null,
933
+ parent_run_id: null,
934
+ continuation_of_run_id: null,
935
+ retry_of_run_id: null,
936
+ agent_invocation_id: "AINV-PRICED",
937
+ root_agent_invocation_id: "AINV-PRICED",
938
+ parent_agent_invocation_id: null,
939
+ invocation_kind: "orchestrator",
940
+ delegation_depth: 0,
941
+ };
942
+ const usage = {
943
+ schema_version: 2,
944
+ event_id: "RUN-PRICED:2",
945
+ run_id: "RUN-PRICED",
946
+ sequence: 2,
947
+ occurred_at: "2026-08-08T12:00:01.000Z",
948
+ type: "usage.recorded",
949
+ phase: "execution",
950
+ activity_kind: "model_usage",
951
+ classification_source: "explicit",
952
+ tokens: {
953
+ input: 5,
954
+ cached_input: 0,
955
+ output: 0,
956
+ reasoning: 0,
957
+ total: 5,
958
+ source: "provider_reported",
959
+ },
960
+ cost: { usd: 0.5, brl: 2.5, fx_rate: 5 },
961
+ provider: "openai",
962
+ model: "gpt-a",
963
+ source_segment_key: "openai-gpt-a",
964
+ model_call_id: "MCALL-PRICED",
965
+ runtime: { reasoning_effort: null, service_tier: null },
966
+ supersedes_event_id: null,
967
+ duration_ms: null,
968
+ duration_provenance: null,
969
+ };
970
+ const finished = {
971
+ schema_version: 2,
972
+ event_id: "RUN-PRICED:3",
973
+ run_id: "RUN-PRICED",
974
+ sequence: 3,
975
+ occurred_at: "2026-08-08T12:01:00.000Z",
976
+ type: "run.finished",
977
+ phase: "execution",
978
+ status: "completed",
979
+ duration_ms: 60_000,
980
+ duration_provenance: "observed",
981
+ };
617
982
  await writeFile(
618
983
  join(root, ".agents", "records", "runs", "2026", "08", "RUN-PRICED.jsonl"),
619
984
  `${[started, usage, finished].map((row) => JSON.stringify(row)).join("\n")}\n`,
@@ -641,363 +1006,570 @@ created_at: 2026-08-10T11:01:00.000Z
641
1006
  roots.push(root);
642
1007
  await mkdir(join(root, ".agents", "records", "tasks", "2026", "08"), { recursive: true });
643
1008
  await mkdir(join(root, ".agents", "records", "runs", "2026", "08"), { recursive: true });
1009
+ await mkdir(
1010
+ join(
1011
+ root,
1012
+ ".agents",
1013
+ "records",
1014
+ "changes",
1015
+ "2026",
1016
+ "08",
1017
+ "CHG-CANONICAL",
1018
+ "artifacts",
1019
+ "tests",
1020
+ ),
1021
+ { recursive: true },
1022
+ );
1023
+ await mkdir(
1024
+ join(
1025
+ root,
1026
+ ".agents",
1027
+ "records",
1028
+ "changes",
1029
+ "2026",
1030
+ "08",
1031
+ "CHG-CANONICAL",
1032
+ "artifacts",
1033
+ "evidence",
1034
+ ),
1035
+ { recursive: true },
1036
+ );
644
1037
  await mkdir(join(root, ".agents", "config"), { recursive: true });
645
1038
  await writeFile(join(root, ".agents", "config", "project.yaml"), "zaip:\n enabled: true\n");
646
1039
  await writeFile(
647
1040
  join(root, ".agents", "records", "tasks", "2026", "08", "TASK-CANONICAL.md"),
648
- "---\nid: TASK-CANONICAL\ntitle: Titulo semantico canonico\nstatus: ready\nrisk: standard\ncreated_at: 2026-08-08T12:00:00.000Z\n---\n# Titulo semantico canonico\n",
1041
+ "---\nid: TASK-CANONICAL\ntitle: Titulo semantico canonico\nstatus: completed\ncompleted_run_id: RUN-CANONICAL\nrisk: standard\ncreated_at: 2026-08-08T12:00:00.000Z\n---\n# Titulo semantico canonico\n",
649
1042
  );
650
- const run = (id: string, taskId: string, tokens: number) => [
651
- { schema_version: 2, event_id: `${id}:1`, run_id: id, sequence: 1, occurred_at: "2026-08-08T12:00:00.000Z", type: "run.started", attribution_status: "attributed", phase: "execution", run_role: "orchestrator", run_purpose: "execution", requires_finalizer: false, execution_kind: "delivery", execution_eligibility: ["delivery"], entrypoint: "task", work_type: "new", storage_mode: "tracked_sanitized", client: "codex", agent: "agent", agent_name: "agent", provider: "openai", model: "gpt-a", reasoning_effort: null, client_thread_id: id, client_turn_id: id, conversation_id: `CONV-${id}`, execution_id: `EXEC-${id}`, task_id: taskId, spec_id: null, prd_id: null, change_id: null, parent_run_id: null, continuation_of_run_id: null, retry_of_run_id: null, agent_invocation_id: `AINV-${id}`, root_agent_invocation_id: `AINV-${id}`, parent_agent_invocation_id: null, invocation_kind: "orchestrator", delegation_depth: 0 },
652
- { schema_version: 2, event_id: `${id}:2`, run_id: id, sequence: 2, occurred_at: "2026-08-08T12:00:30.000Z", type: "usage.recorded", phase: "execution", activity_kind: "model_usage", classification_source: "explicit", tokens: { input: tokens, cached_input: 0, output: 0, reasoning: 0, total: tokens, source: "provider_reported" }, cost: { usd: tokens / 100, brl: tokens / 20, fx_rate: 5 }, provider: "openai", model: "gpt-a", source_segment_key: id, model_call_id: `MCALL-${id}`, runtime: { reasoning_effort: null, service_tier: null }, supersedes_event_id: null, source_started_at: "2026-08-08T12:00:00.000Z", source_finished_at: "2026-08-08T12:01:00.000Z", duration_ms: null, duration_provenance: null },
653
- { schema_version: 2, event_id: `${id}:3`, run_id: id, sequence: 3, occurred_at: "2026-08-08T12:01:00.000Z", type: "run.finished", phase: "execution", status: "completed", duration_ms: 60_000, duration_provenance: "observed" },
1043
+ const run = (id: string, taskId: string, tokens: number, changeId: string | null = null) => [
1044
+ {
1045
+ schema_version: 2,
1046
+ event_id: `${id}:1`,
1047
+ run_id: id,
1048
+ sequence: 1,
1049
+ occurred_at: "2026-08-08T12:00:00.000Z",
1050
+ type: "run.started",
1051
+ attribution_status: "attributed",
1052
+ phase: "execution",
1053
+ run_role: "orchestrator",
1054
+ run_purpose: "execution",
1055
+ requires_finalizer: false,
1056
+ execution_kind: "delivery",
1057
+ execution_eligibility: ["delivery"],
1058
+ entrypoint: "task",
1059
+ work_type: "new",
1060
+ storage_mode: "tracked_sanitized",
1061
+ client: "codex",
1062
+ agent: "agent",
1063
+ agent_name: "agent",
1064
+ developer_identity: {
1065
+ schema_version: 1,
1066
+ provider: "github",
1067
+ account_id: "42",
1068
+ login_snapshot: "dev-fixture",
1069
+ verified_at: "2026-08-08T12:00:00.000Z",
1070
+ attribution_source: "verified_local_account",
1071
+ },
1072
+ provider: "openai",
1073
+ model: "gpt-a",
1074
+ reasoning_effort: null,
1075
+ client_thread_id: id,
1076
+ client_turn_id: id,
1077
+ conversation_id: `CONV-${id}`,
1078
+ execution_id: `EXEC-${id}`,
1079
+ task_id: taskId,
1080
+ spec_id: null,
1081
+ prd_id: null,
1082
+ change_id: changeId,
1083
+ parent_run_id: null,
1084
+ continuation_of_run_id: null,
1085
+ retry_of_run_id: null,
1086
+ agent_invocation_id: `AINV-${id}`,
1087
+ root_agent_invocation_id: `AINV-${id}`,
1088
+ parent_agent_invocation_id: null,
1089
+ invocation_kind: "orchestrator",
1090
+ delegation_depth: 0,
1091
+ },
1092
+ {
1093
+ schema_version: 2,
1094
+ event_id: `${id}:2`,
1095
+ run_id: id,
1096
+ sequence: 2,
1097
+ occurred_at: "2026-08-08T12:00:30.000Z",
1098
+ type: "usage.recorded",
1099
+ phase: "execution",
1100
+ activity_kind: "model_usage",
1101
+ classification_source: "explicit",
1102
+ tokens: {
1103
+ input: tokens,
1104
+ cached_input: 0,
1105
+ output: 0,
1106
+ reasoning: 0,
1107
+ total: tokens,
1108
+ source: "provider_reported",
1109
+ },
1110
+ cost: { usd: tokens / 100, brl: tokens / 20, fx_rate: 5 },
1111
+ provider: "openai",
1112
+ model: "gpt-a",
1113
+ source_segment_key: id,
1114
+ model_call_id: `MCALL-${id}`,
1115
+ runtime: { reasoning_effort: null, service_tier: null },
1116
+ supersedes_event_id: null,
1117
+ source_started_at: "2026-08-08T12:00:00.000Z",
1118
+ source_finished_at: "2026-08-08T12:01:00.000Z",
1119
+ duration_ms: null,
1120
+ duration_provenance: null,
1121
+ },
1122
+ {
1123
+ schema_version: 2,
1124
+ event_id: `${id}:3`,
1125
+ run_id: id,
1126
+ sequence: 3,
1127
+ occurred_at: "2026-08-08T12:01:00.000Z",
1128
+ type: "run.finished",
1129
+ phase: "execution",
1130
+ status: "completed",
1131
+ duration_ms: 60_000,
1132
+ duration_provenance: "observed",
1133
+ },
654
1134
  ];
655
- await writeFile(join(root, ".agents", "records", "runs", "2026", "08", "RUN-CANONICAL.jsonl"), `${run("RUN-CANONICAL", "TASK-CANONICAL", 7).map((row) => JSON.stringify(row)).join("\n")}\n`);
656
- await writeFile(join(root, ".agents", "records", "runs", "2026", "08", "RUN-ORPHAN.jsonl"), `${run("RUN-ORPHAN", "TASK-ORPHAN-REFERENCE", 11).map((row) => JSON.stringify(row)).join("\n")}\n`);
1135
+ await writeFile(
1136
+ join(root, ".agents", "records", "runs", "2026", "08", "RUN-CANONICAL.jsonl"),
1137
+ `${run("RUN-CANONICAL", "TASK-CANONICAL", 7, "CHG-CANONICAL")
1138
+ .map((row) => JSON.stringify(row))
1139
+ .join("\n")}\n`,
1140
+ );
1141
+ await writeFile(
1142
+ join(root, ".agents", "records", "runs", "2026", "08", "RUN-ORPHAN.jsonl"),
1143
+ `${run("RUN-ORPHAN", "TASK-ORPHAN-REFERENCE", 11)
1144
+ .map((row) => JSON.stringify(row))
1145
+ .join("\n")}\n`,
1146
+ );
1147
+ await writeFile(
1148
+ join(
1149
+ root,
1150
+ ".agents",
1151
+ "records",
1152
+ "changes",
1153
+ "2026",
1154
+ "08",
1155
+ "CHG-CANONICAL",
1156
+ "artifacts",
1157
+ "tests",
1158
+ "TEST-CANONICAL.md",
1159
+ ),
1160
+ "---\nid: TEST-CANONICAL\nkind: test\ntask_id: TASK-CANONICAL\nchange_id: CHG-CANONICAL\nrun_id: RUN-CANONICAL\nexecuted_at: 2026-08-08T12:00:00.000Z\nstatus: passed\n---\n# Test\n",
1161
+ );
1162
+ await writeFile(
1163
+ join(
1164
+ root,
1165
+ ".agents",
1166
+ "records",
1167
+ "changes",
1168
+ "2026",
1169
+ "08",
1170
+ "CHG-CANONICAL",
1171
+ "artifacts",
1172
+ "evidence",
1173
+ "EVD-CANONICAL.md",
1174
+ ),
1175
+ "---\nid: EVD-CANONICAL\ntask_id: TASK-CANONICAL\nchange_id: CHG-CANONICAL\nrun_id: RUN-CANONICAL\nobserved_at: 2026-08-08T12:00:00.000Z\nstatus: passed\n---\n# Evidence\n",
1176
+ );
657
1177
 
658
1178
  await rebuildSqliteReadModel(root);
659
- const snapshot = new DatabaseSync(resolve(root, ".local/dashboard-sqlite/read-model.sqlite"), { readOnly: true });
660
- expect(snapshot.prepare("SELECT value FROM zaip_vw_read_model_metadata WHERE key='schema_version'").get()).toEqual({ value: "60" });
1179
+ const snapshot = new DatabaseSync(resolve(root, ".local/dashboard-sqlite/read-model.sqlite"), {
1180
+ readOnly: true,
1181
+ });
1182
+ expect(
1183
+ snapshot
1184
+ .prepare("SELECT value FROM zaip_vw_read_model_metadata WHERE key='schema_version'")
1185
+ .get(),
1186
+ ).toEqual({ value: "70" });
661
1187
  snapshot.close();
662
1188
  const filesystem = new SqliteReadModelFileSystem(root);
663
1189
  try {
664
1190
  expect(filesystem.viewPage("operations_work_kanban", { limit: 20 }).rows).toEqual([
665
1191
  expect.objectContaining({ id: "TASK-CANONICAL", title: "Titulo semantico canonico" }),
666
1192
  ]);
1193
+ // The List export is sourced from this SQLite view, so its known facts
1194
+ // must survive the public entity union rather than be left as blank XLSX
1195
+ // columns by a mapper that only receives identity fields.
1196
+ expect(filesystem.viewPage("operations_work_list", { limit: 20 }).rows).toContainEqual(
1197
+ expect.objectContaining({
1198
+ id: "TASK-CANONICAL",
1199
+ invocation_count: 1,
1200
+ total_duration: 30_000,
1201
+ total_tokens: 7,
1202
+ total_cost_brl: 0.35,
1203
+ }),
1204
+ );
667
1205
  const costTasks = filesystem.viewPage("cost_monitor_tasks", { limit: 20 }).rows;
668
- expect(costTasks).toContainEqual(expect.objectContaining({ id: "TASK-ORPHAN-REFERENCE", total_tokens: 11, total_cost_brl: 0.55 }));
1206
+ expect(costTasks).toContainEqual(
1207
+ expect.objectContaining({
1208
+ id: "TASK-ORPHAN-REFERENCE",
1209
+ total_tokens: 11,
1210
+ total_cost_brl: 0.55,
1211
+ }),
1212
+ );
1213
+ const developers = filesystem.developerCostAggregate({
1214
+ from: null,
1215
+ to: null,
1216
+ accountIds: ["42"],
1217
+ });
1218
+ expect(developers.rows).toEqual([
1219
+ expect.objectContaining({
1220
+ account_id: "42",
1221
+ login_snapshot: "dev-fixture",
1222
+ prd_count: expect.any(Number),
1223
+ spec_count: expect.any(Number),
1224
+ task_count: 2,
1225
+ run_count: 2,
1226
+ test_count: 1,
1227
+ evidence_count: 1,
1228
+ total_duration_ms: expect.any(Number),
1229
+ completed_task_count: 1,
1230
+ total_cost_brl: 0.9,
1231
+ token_covered_runs: 2,
1232
+ usd_covered_runs: 2,
1233
+ brl_covered_runs: 2,
1234
+ qualification: "verified",
1235
+ completed_tasks: [
1236
+ expect.objectContaining({
1237
+ id: "TASK-CANONICAL",
1238
+ status: "completed",
1239
+ completed_run_id: "RUN-CANONICAL",
1240
+ delivered_by: { account_id: "42" },
1241
+ contributors: [expect.objectContaining({ account_id: "42" })],
1242
+ }),
1243
+ ],
1244
+ }),
1245
+ ]);
1246
+ expect(
1247
+ filesystem.developerCostAggregate({
1248
+ from: "2026-08-08",
1249
+ to: "2026-08-08",
1250
+ accountIds: ["42"],
1251
+ }).rows,
1252
+ ).toEqual([expect.objectContaining({ test_count: 1, evidence_count: 1 })]);
1253
+ expect(
1254
+ filesystem.dailyPeriods({ from: "2026-08-08", to: "2026-08-08" })["2026-08-08"],
1255
+ ).toMatchObject({ validations: 1, evidences: 1 });
1256
+ const operationsDevelopers = filesystem.operationsDeveloperAggregate({
1257
+ from: null,
1258
+ to: null,
1259
+ accountIds: ["42"],
1260
+ });
1261
+ expect(operationsDevelopers.rows).toEqual([
1262
+ expect.objectContaining({
1263
+ account_id: "42",
1264
+ task_count: 2,
1265
+ completed_task_count: 1,
1266
+ status_counts: expect.objectContaining({ completed: 1 }),
1267
+ type_counts: { task: 1 },
1268
+ risk_counts: expect.any(Object),
1269
+ total_duration_ms: expect.any(Number),
1270
+ total_tokens: expect.any(Number),
1271
+ total_cost_brl: 0.9,
1272
+ }),
1273
+ ]);
669
1274
  } finally {
670
1275
  filesystem.close();
671
1276
  }
672
1277
  });
673
1278
 
674
- it("keeps a multi-provider and multi-model Run visible to both filtered financial and duration facts", async () => {
1279
+ it("qualifies factual developer deliveries without inventing missing completion or coverage", async () => {
675
1280
  const root = await createSqliteTestRoot();
676
1281
  roots.push(root);
677
- await mkdir(join(root, ".agents", "records", "runs", "2026", "08"), { recursive: true });
678
- await mkdir(join(root, ".agents", "config"), { recursive: true });
679
- await mkdir(join(root, ".agents", "config", "agents"), { recursive: true });
680
- await mkdir(join(root, ".agents", "config", "pricing"), { recursive: true });
681
- await writeFile(join(root, ".agents", "config", "project.yaml"), "zaip:\n enabled: true\n");
682
- await writeFile(
683
- join(root, ".agents", "config", "agents", "catalog.yaml"),
684
- "agents:\n - id: agent-catalog\n codex_name: agent\n persona: { nome: ana, cargo: quality_engineer }\n role: reviewer\n",
685
- );
1282
+ const runsRoot = join(root, ".agents", "records", "runs", "2026", "08");
1283
+ const tasksRoot = join(root, ".agents", "records", "tasks", "2026", "08");
1284
+ const assignmentsRoot = join(
1285
+ root,
1286
+ ".agents",
1287
+ "records",
1288
+ "lifecycle",
1289
+ "historical-developer-attribution",
1290
+ );
1291
+ await Promise.all([
1292
+ mkdir(runsRoot, { recursive: true }),
1293
+ mkdir(tasksRoot, { recursive: true }),
1294
+ mkdir(assignmentsRoot, { recursive: true }),
1295
+ mkdir(join(root, ".agents", "config"), { recursive: true }),
1296
+ ]);
686
1297
  await writeFile(
687
- join(root, ".agents", "config", "pricing", "models.json"),
688
- JSON.stringify({
689
- schema_version: 1,
690
- updated_at: "2026-08-04T00:00:00.000Z",
691
- source: "fixture",
692
- disclaimer: "fixture",
693
- models: [
694
- { id: "gpt-a", provider: "openai", aliases: [], input_per_million_usd: 2, cached_input_per_million_usd: 0.2, output_per_million_usd: 8, reasoning_per_million_usd: 8, reasoning_billed_separately: false, long_context_threshold_tokens: null, long_context_input_multiplier: 1, long_context_output_multiplier: 1, source_label: "fixture-openai", source_url: "https://example.test/openai", notes: [] },
695
- { id: "claude-b", provider: "anthropic", aliases: [], input_per_million_usd: 3, cached_input_per_million_usd: 0.3, output_per_million_usd: 12, reasoning_per_million_usd: null, reasoning_billed_separately: false, long_context_threshold_tokens: null, long_context_input_multiplier: 1, long_context_output_multiplier: 1, source_label: "fixture-anthropic", source_url: "https://example.test/anthropic", notes: [] },
696
- ],
697
- }),
1298
+ join(root, ".agents", "config", "project.yaml"),
1299
+ "zaip:\n enabled: true\n",
1300
+ "utf8",
698
1301
  );
699
- const started = { schema_version: 2, event_id: "RUN-MULTI:1", run_id: "RUN-MULTI", sequence: 1, occurred_at: "2026-08-04T12:00:00.000Z", type: "run.started", attribution_status: "attributed", phase: "execution", run_role: "orchestrator", run_purpose: "execution", requires_finalizer: false, execution_kind: "delivery", execution_eligibility: ["delivery"], entrypoint: "task", work_type: "new", storage_mode: "tracked_sanitized", client: "codex", agent: "agent", agent_name: "agent", provider: "mixed", model: "mixed", reasoning_effort: null, client_thread_id: "multi", client_turn_id: "multi", conversation_id: "CONV-MULTI", execution_id: "EXEC-MULTI", task_id: "TASK-MULTI", spec_id: null, prd_id: null, change_id: null, parent_run_id: null, continuation_of_run_id: null, retry_of_run_id: null, agent_invocation_id: "AINV-MULTI", root_agent_invocation_id: "AINV-MULTI", parent_agent_invocation_id: null, invocation_kind: "orchestrator", delegation_depth: 0 };
700
- const usage = (sequence: number, provider: string, model: string, tokens: number, brl: number) => ({ schema_version: 2, event_id: `RUN-MULTI:${sequence}`, run_id: "RUN-MULTI", sequence, occurred_at: "2026-08-04T12:00:01.000Z", type: "usage.recorded", phase: "execution", activity_kind: "model_usage", classification_source: "explicit", tokens: { input: tokens, cached_input: 0, output: 0, reasoning: 0, total: tokens, source: "provider_reported" }, cost: { usd: brl / 5, brl, fx_rate: 5 }, provider, model, source_segment_key: `${provider}-${model}`, model_call_id: `MCALL-${sequence}`, runtime: { reasoning_effort: null, service_tier: null }, supersedes_event_id: null, source_started_at: "2026-08-04T12:00:00.000Z", source_finished_at: "2026-08-04T12:01:00.000Z", duration_ms: null, duration_provenance: null });
701
- const finished = { schema_version: 2, event_id: "RUN-MULTI:5", run_id: "RUN-MULTI", sequence: 5, occurred_at: "2026-08-04T12:01:00.000Z", type: "run.finished", phase: "execution", status: "completed", duration_ms: 60_000, duration_provenance: "observed" };
702
- const mixedNullSegment = {
703
- ...usage(4, "openai", "gpt-a", 0, 0),
704
- event_id: "RUN-MULTI:4",
705
- provider: null,
706
- model: null,
707
- source_segment_key: "mixed-null",
708
- model_call_id: "MCALL-MIXED-NULL",
709
- };
710
- await writeFile(join(root, ".agents", "records", "runs", "2026", "08", "RUN-MULTI.jsonl"), `${[started, usage(2, "openai", "gpt-a", 10, 5), usage(3, "anthropic", "claude-b", 20, 10), mixedNullSegment, finished].map((row) => JSON.stringify(row)).join("\n")}\n`);
711
- const unavailableStarted = {
712
- ...started,
713
- event_id: "RUN-UNAVAILABLE:1",
714
- run_id: "RUN-UNAVAILABLE",
715
- occurred_at: "2026-08-04T14:00:00.000Z",
716
- client_turn_id: "unavailable",
717
- conversation_id: "CONV-UNAVAILABLE",
718
- execution_id: "EXEC-UNAVAILABLE",
719
- task_id: "TASK-UNAVAILABLE",
720
- agent_invocation_id: "AINV-UNAVAILABLE",
721
- root_agent_invocation_id: "AINV-UNAVAILABLE",
722
- provider: "unavailable",
723
- model: "unavailable",
724
- };
725
- const unavailableFinished = {
726
- ...finished,
727
- event_id: "RUN-UNAVAILABLE:2",
728
- run_id: "RUN-UNAVAILABLE",
729
- sequence: 3,
730
- occurred_at: "2026-08-04T14:01:00.000Z",
731
- };
732
- const unavailableUsage = {
733
- ...usage(2, "openai", "gpt-a", 0, 0),
734
- event_id: "RUN-UNAVAILABLE:usage",
735
- run_id: "RUN-UNAVAILABLE",
736
- sequence: 2,
737
- occurred_at: "2026-08-04T14:00:01.000Z",
738
- provider: null,
739
- model: null,
740
- source_started_at: "2026-08-04T14:00:00.000Z",
741
- source_finished_at: "2026-08-04T14:01:00.000Z",
742
- source_segment_key: "unknown-segment",
743
- model_call_id: "MCALL-UNAVAILABLE",
744
- };
745
- await writeFile(
746
- join(root, ".agents", "records", "runs", "2026", "08", "RUN-UNAVAILABLE.jsonl"),
747
- `${[unavailableStarted, unavailableUsage, unavailableFinished].map((row) => JSON.stringify(row)).join("\n")}\n`,
748
- );
749
- // It is a canonical activity but not an Agent Invocation. Cost Monitor
750
- // must not blend this population into its token/cost/session rate.
751
- const { agent_invocation_id: _invocation, root_agent_invocation_id: _rootInvocation, parent_agent_invocation_id: _parentInvocation, ...unassistedBase } = started;
752
- const unassistedStarted = {
753
- ...unassistedBase,
754
- event_id: "RUN-UNASSISTED:1",
755
- run_id: "RUN-UNASSISTED",
756
- occurred_at: "2026-08-04T16:00:00.000Z",
757
- client_turn_id: "unassisted",
758
- conversation_id: "CONV-UNASSISTED",
759
- execution_id: "EXEC-MULTI",
760
- task_id: "TASK-MULTI",
1302
+ const task = (id: string, status: string, completedRunId: string | null) =>
1303
+ `---\nid: ${id}\ntitle: ${id}\nstatus: ${status}${completedRunId === null ? "" : `\ncompleted_run_id: ${completedRunId}`}\nrisk: standard\ncreated_at: 2026-08-08T12:00:00.000Z\n---\n# ${id}\n`;
1304
+ await Promise.all([
1305
+ writeFile(
1306
+ join(tasksRoot, "TASK-DELIVERED.md"),
1307
+ task("TASK-DELIVERED", "completed", "RUN-DELIVERED"),
1308
+ ),
1309
+ writeFile(
1310
+ join(tasksRoot, "TASK-NO-COMPLETION.md"),
1311
+ task("TASK-NO-COMPLETION", "completed", null),
1312
+ ),
1313
+ writeFile(
1314
+ join(tasksRoot, "TASK-MISSING-RUN.md"),
1315
+ task("TASK-MISSING-RUN", "completed", "RUN-NOT-FOUND"),
1316
+ ),
1317
+ writeFile(
1318
+ join(tasksRoot, "TASK-NOT-COMPLETED.md"),
1319
+ task("TASK-NOT-COMPLETED", "executing", "RUN-NOT-COMPLETED"),
1320
+ ),
1321
+ writeFile(
1322
+ join(tasksRoot, "TASK-UNKNOWN-COVERAGE.md"),
1323
+ task("TASK-UNKNOWN-COVERAGE", "completed", null),
1324
+ ),
1325
+ writeFile(
1326
+ join(tasksRoot, "TASK-HISTORICAL.md"),
1327
+ task("TASK-HISTORICAL", "completed", "RUN-HISTORICAL"),
1328
+ ),
1329
+ ]);
1330
+ const stream = (
1331
+ id: string,
1332
+ taskId: string,
1333
+ accountId: string | null,
1334
+ day: string,
1335
+ tokens: number | null,
1336
+ ) => {
1337
+ const identity =
1338
+ accountId === null
1339
+ ? null
1340
+ : {
1341
+ schema_version: 1,
1342
+ provider: "github",
1343
+ account_id: accountId,
1344
+ login_snapshot: `dev-${accountId}`,
1345
+ verified_at: `${day}T12:00:00.000Z`,
1346
+ attribution_source: "verified_local_account",
1347
+ };
1348
+ const records: Record<string, unknown>[] = [
1349
+ {
1350
+ schema_version: 2,
1351
+ event_id: `${id}:1`,
1352
+ run_id: id,
1353
+ sequence: 1,
1354
+ occurred_at: `${day}T12:00:00.000Z`,
1355
+ type: "run.started",
1356
+ attribution_status: "attributed",
1357
+ phase: "execution",
1358
+ run_role: "orchestrator",
1359
+ run_purpose: "execution",
1360
+ requires_finalizer: false,
1361
+ execution_kind: "delivery",
1362
+ execution_eligibility: ["delivery"],
1363
+ entrypoint: "task",
1364
+ work_type: "new",
1365
+ storage_mode: "tracked_sanitized",
1366
+ client: "codex",
1367
+ agent: "agent",
1368
+ agent_name: "agent",
1369
+ developer_identity: identity,
1370
+ provider: "openai",
1371
+ model: "gpt-a",
1372
+ reasoning_effort: null,
1373
+ client_thread_id: id,
1374
+ client_turn_id: id,
1375
+ conversation_id: `CONV-${id}`,
1376
+ execution_id: `EXEC-${id}`,
1377
+ task_id: taskId,
1378
+ spec_id: null,
1379
+ prd_id: null,
1380
+ change_id: null,
1381
+ parent_run_id: null,
1382
+ continuation_of_run_id: null,
1383
+ retry_of_run_id: null,
1384
+ agent_invocation_id: `AINV-${id}`,
1385
+ root_agent_invocation_id: `AINV-${id}`,
1386
+ parent_agent_invocation_id: null,
1387
+ invocation_kind: "orchestrator",
1388
+ delegation_depth: 0,
1389
+ },
1390
+ ];
1391
+ if (tokens !== null)
1392
+ records.push({
1393
+ schema_version: 2,
1394
+ event_id: `${id}:2`,
1395
+ run_id: id,
1396
+ sequence: 2,
1397
+ occurred_at: `${day}T12:00:30.000Z`,
1398
+ type: "usage.recorded",
1399
+ phase: "execution",
1400
+ activity_kind: "model_usage",
1401
+ classification_source: "explicit",
1402
+ tokens: {
1403
+ input: tokens,
1404
+ cached_input: 0,
1405
+ output: 0,
1406
+ reasoning: 0,
1407
+ total: tokens,
1408
+ source: "provider_reported",
1409
+ },
1410
+ cost: { usd: tokens / 100, brl: tokens / 20, fx_rate: 5 },
1411
+ provider: "openai",
1412
+ model: "gpt-a",
1413
+ source_segment_key: id,
1414
+ model_call_id: `MCALL-${id}`,
1415
+ runtime: { reasoning_effort: null, service_tier: null },
1416
+ supersedes_event_id: null,
1417
+ source_started_at: `${day}T12:00:00.000Z`,
1418
+ source_finished_at: `${day}T12:01:00.000Z`,
1419
+ duration_ms: null,
1420
+ duration_provenance: null,
1421
+ });
1422
+ records.push({
1423
+ schema_version: 2,
1424
+ event_id: `${id}:3`,
1425
+ run_id: id,
1426
+ sequence: records.length + 1,
1427
+ occurred_at: `${day}T12:01:00.000Z`,
1428
+ type: "run.finished",
1429
+ phase: "execution",
1430
+ status: "completed",
1431
+ duration_ms: 60_000,
1432
+ duration_provenance: "observed",
1433
+ });
1434
+ return `${records.map((record) => JSON.stringify(record)).join("\n")}\n`;
761
1435
  };
762
- const unassistedUsage = {
763
- ...usage(2, "openai", "gpt-a", 1_000, 500),
764
- event_id: "RUN-UNASSISTED:2",
765
- run_id: "RUN-UNASSISTED",
766
- occurred_at: "2026-08-04T16:00:01.000Z",
767
- source_started_at: "2026-08-04T16:00:00.000Z",
768
- source_finished_at: "2026-08-04T16:01:00.000Z",
769
- source_segment_key: "unassisted-segment",
1436
+ const delivered = stream("RUN-DELIVERED", "TASK-DELIVERED", "42", "2026-08-08", 10);
1437
+ const contributor = stream("RUN-CONTRIBUTOR", "TASK-DELIVERED", "99", "2026-08-08", 3);
1438
+ const noCompletion = stream("RUN-NO-COMPLETION", "TASK-NO-COMPLETION", "42", "2026-08-09", 4);
1439
+ const notCompleted = stream("RUN-NOT-COMPLETED", "TASK-NOT-COMPLETED", "42", "2026-08-09", 5);
1440
+ const unknownCoverage = stream(
1441
+ "RUN-UNKNOWN-COVERAGE",
1442
+ "TASK-UNKNOWN-COVERAGE",
1443
+ "42",
1444
+ "2026-08-09",
1445
+ null,
1446
+ );
1447
+ const historical = stream("RUN-HISTORICAL", "TASK-HISTORICAL", null, "2026-08-09", 2);
1448
+ await Promise.all([
1449
+ writeFile(join(runsRoot, "RUN-DELIVERED.jsonl"), delivered),
1450
+ writeFile(join(runsRoot, "RUN-CONTRIBUTOR.jsonl"), contributor),
1451
+ writeFile(join(runsRoot, "RUN-NO-COMPLETION.jsonl"), noCompletion),
1452
+ writeFile(join(runsRoot, "RUN-NOT-COMPLETED.jsonl"), notCompleted),
1453
+ writeFile(join(runsRoot, "RUN-UNKNOWN-COVERAGE.jsonl"), unknownCoverage),
1454
+ writeFile(join(runsRoot, "RUN-HISTORICAL.jsonl"), historical),
1455
+ ]);
1456
+ const historicalPath = ".agents/records/runs/2026/08/RUN-HISTORICAL.jsonl";
1457
+ const unsigned = {
1458
+ schema_version: 1,
1459
+ manifest_id: "HDA-FIXTURE",
1460
+ created_at: "2026-08-09T12:00:00.000Z",
1461
+ kind: "historical_developer_attribution",
1462
+ assignment: {
1463
+ schema_version: 1,
1464
+ provider: "github",
1465
+ account_id: "199126185",
1466
+ login_snapshot: "zaip-ai",
1467
+ attribution_source: "human_assigned",
1468
+ verified_at: null,
1469
+ },
1470
+ source_streams: [
1471
+ {
1472
+ run_id: "RUN-HISTORICAL",
1473
+ path: historicalPath,
1474
+ content_sha256: createHash("sha256").update(historical).digest("hex"),
1475
+ },
1476
+ ],
770
1477
  };
771
1478
  await writeFile(
772
- join(root, ".agents", "records", "runs", "2026", "08", "RUN-UNASSISTED.jsonl"),
773
- `${[unassistedStarted, unassistedUsage, { ...finished, event_id: "RUN-UNASSISTED:3", run_id: "RUN-UNASSISTED", sequence: 3 }].map((row) => JSON.stringify(row)).join("\n")}\n`,
1479
+ join(assignmentsRoot, "HDA-FIXTURE.json"),
1480
+ JSON.stringify({
1481
+ ...unsigned,
1482
+ manifest_hash: createHash("sha256").update(JSON.stringify(unsigned)).digest("hex"),
1483
+ }),
774
1484
  );
775
1485
  await rebuildSqliteReadModel(root);
776
- const aggregateDatabase = new DatabaseSync(resolve(root, ".local/dashboard-sqlite/read-model.sqlite"), {
777
- readOnly: true,
778
- });
779
- try {
780
- const aggregates = aggregateDatabase.prepare(`SELECT
781
- json_extract(payload_json, '$.dimension') AS dimension,
782
- json_extract(payload_json, '$.key') AS key,
783
- json_extract(payload_json, '$.schema_version') AS schema_version,
784
- json_extract(payload_json, '$.total_cost_brl') AS total_cost_brl
785
- FROM zaip_aios_activities
786
- WHERE payload_type = 'cost_dimension_aggregate_v1'`).all();
787
- expect(aggregates).toEqual(expect.arrayContaining([
788
- expect.objectContaining({ dimension: "provider", key: "openai", schema_version: 1, total_cost_brl: 505 }),
789
- expect.objectContaining({ dimension: "model", key: "gpt-a", schema_version: 1, total_cost_brl: 505 }),
790
- ]));
791
- expect(aggregates.map((row) => row.key)).toEqual(expect.arrayContaining(["unavailable"]));
792
- } finally {
793
- aggregateDatabase.close();
794
- }
795
1486
  const filesystem = new SqliteReadModelFileSystem(root);
796
- expect(filesystem.viewPage("cost_monitor_daily", { from: "2026-08-04", to: "2026-08-04" }).rows[0]).toMatchObject({ total_tokens: 1_030, total_cost_brl: 515 });
797
- // The public overview view backs /api/v2/sqlite-views. It must not leak
798
- // Cost Monitor retains all measurable financial activities, including
799
- // historical/unassisted telemetry without an Agent Invocation id.
800
- const publicOverview = filesystem.viewPage("cost_monitor_overview_view", {});
801
- expect(publicOverview.rows).toHaveLength(3);
802
- expect(publicOverview.rows).toEqual(
803
- expect.arrayContaining([
804
- expect.objectContaining({ period_kind: "day", total_run_count: 3, invocation_count: 3, total_tokens: 1_030, total_cost_brl: 515 }),
805
- expect.objectContaining({ period_kind: "month", total_run_count: 3, invocation_count: 3, total_tokens: 1_030, total_cost_brl: 515 }),
806
- expect.objectContaining({ period_kind: "year", total_run_count: 3, invocation_count: 3, total_tokens: 1_030, total_cost_brl: 515 }),
807
- ]),
808
- );
809
- const allAgentGroups = filesystem.viewPage("cost_monitor_zaip_agents", { limit: 20, offset: 0 });
810
- const allCostTotals = publicOverview.rows.find((row) => row.period_kind === "day");
811
- if (allCostTotals === undefined) throw new Error("Expected the daily Cost Monitor overview");
812
- expect(allAgentGroups.rows.reduce((total, row) => total + Number(row.invocation_count ?? 0), 0)).toBe(allCostTotals.total_run_count);
813
- expect(allAgentGroups.rows.reduce((total, row) => total + Number(row.total_tokens ?? 0), 0)).toBe(allCostTotals?.total_tokens);
814
- expect(allAgentGroups.rows.reduce((total, row) => total + Number(row.total_cost_brl ?? 0), 0)).toBe(allCostTotals?.total_cost_brl);
815
- expect(allAgentGroups.rows.reduce((total, row) => total + Number(row.total_cost_usd ?? 0), 0)).toBe(allCostTotals.total_cost_usd);
816
- // Shared Cost Tempo is factual at the activity grain. It remains available
817
- // in the agent-table total even where a multi-dimension invocation cannot
818
- // be assigned to an individual Agent row.
819
- expect(allCostTotals.cost_monitor_total_duration).toBe(120_000);
820
- expect(allAgentGroups.totals).toMatchObject({ invocation_count: allCostTotals.total_run_count, total_duration: 120_000, total_tokens: allCostTotals.total_tokens, total_cost_usd: allCostTotals.total_cost_usd, total_cost_brl: allCostTotals.total_cost_brl });
821
- for (const [providers, models] of [[ ["openai"], ["gpt-a"] ], [["anthropic"], ["claude-b"] ]] as const) {
822
- const rows = filesystem.invocationCostRows({ from: null, to: null, providers, models });
823
- expect(rows).toHaveLength(1);
824
- // Membership is segment-based; once the invocation matches, its
825
- // canonical invocation totals remain intact rather than being split.
826
- expect(rows[0]).toMatchObject({ total_tokens: 30, cost_brl: 15 });
827
- expect([...filesystem.executionDurationByDay({ from: null, to: null, providers, models }).values()]).toEqual([60_000]);
828
- expect([...filesystem.canonicalRunCountByDay({ from: null, to: null, providers, models }).values()]).toEqual([1]);
829
- for (const view of ["cost_monitor_daily", "cost_monitor_monthly", "cost_monitor_annual"] as const) {
830
- const page = filesystem.viewPage(view, { provider: providers[0], model: models[0], limit: 20, offset: 0 });
831
- expect(page.rows[0]).toMatchObject({ total_run_count: 1, total_tokens: 30, total_cost_brl: 15 });
832
- }
833
- const agents = filesystem.viewPage("cost_monitor_zaip_agents", { provider: providers[0], model: models[0], query: "agent" });
834
- const financialRows = filesystem.costMonitorFinancialActivityRows({ from: null, to: null, providers, models });
835
- const financialTotals = financialRows.reduce<{ invocation_count: number; total_tokens: number; total_cost_brl: number }>((total, row) => ({
836
- invocation_count: total.invocation_count + 1,
837
- total_tokens: total.total_tokens + Number(row.total_tokens ?? 0),
838
- total_cost_brl: total.total_cost_brl + Number(row.cost_brl ?? 0),
839
- }), { invocation_count: 0, total_tokens: 0, total_cost_brl: 0 });
840
- expect(agents.rows[0]).toMatchObject({ key: "agent", persona: "ana", job: "quality_engineer", task_count: 1, ...financialTotals });
841
- expect(agents.totals).toMatchObject(financialTotals);
842
- }
843
- const crossed = { from: null, to: null, providers: ["openai"], models: ["claude-b"] };
844
- expect(filesystem.invocationCostRows(crossed)).toHaveLength(0);
845
- expect([...filesystem.executionDurationByDay(crossed).values()]).toEqual([]);
846
- expect([...filesystem.canonicalRunCountByDay(crossed).values()]).toEqual([]);
847
- expect(filesystem.viewPage("cost_monitor_agent_invocations", { provider: "openai", model: "claude-b" }).total_count).toBe(0);
848
- expect(filesystem.viewPage("cost_monitor_zaip_agents", { provider: "openai", model: "claude-b" }).total_count).toBe(0);
849
- for (const view of ["cost_monitor_daily", "cost_monitor_monthly", "cost_monitor_annual"] as const) {
850
- // Lifecycle buckets can remain present independently, but the crossed
851
- // pair must contribute no invocation financial or Run facts.
852
- const row = filesystem.viewPage(view, { provider: "openai", model: "claude-b" }).rows[0];
853
- expect(row).toMatchObject({ total_run_count: 0, total_duration: null, total_tokens: null, total_cost_brl: null });
854
- }
855
- for (const view of ["cost_monitor_daily", "cost_monitor_monthly", "cost_monitor_annual"] as const) {
856
- const originFiltered = filesystem.viewPage(view, { origin: "task" });
857
- expect(originFiltered.rows[0]).toMatchObject({ prd_count: null, spec_count: null, task_count: null, validation_count: null, evidence_count: null });
858
- expect(filesystem.viewPage(view, { workType: "new" }).total_count).toBe(0);
859
- }
860
- expect(filesystem.viewPage("cost_monitor_zaip_agents", { priority: "high" })).toMatchObject({ total_count: 0, rows: [] });
861
- const providerGroups = filesystem.viewPage("cost_monitor_providers", { limit: 20, offset: 0 });
862
- expect(providerGroups.rows).toEqual(expect.arrayContaining([
863
- expect.objectContaining({ key: "openai", total_tokens: 1_010, total_cost_brl: 505 }),
864
- expect.objectContaining({ key: "anthropic", total_tokens: 20, total_cost_brl: 10 }),
865
- ]));
866
- expect(providerGroups.rows.map((row) => row.key)).toEqual(expect.arrayContaining(["unavailable"]));
867
- expect(filesystem.viewPage("cost_monitor_providers", { provider: "openai", model: "gpt-a" }).rows.find((row) => row.key === "openai")).toMatchObject({ total_tokens: 10, total_cost_brl: 5 });
868
- expect(filesystem.viewPage("cost_monitor_providers", { provider: "openai", model: "claude-b" })).toMatchObject({ total_count: 0, rows: [] });
869
- // A source segment can prove its financial facts, but an invocation with
870
- // multiple observed providers cannot prove a provider-specific elapsed
871
- // time. It must not manufacture a "mixed" bucket for that remainder.
872
- const queriedProviderRows = filesystem.viewPage("cost_monitor_providers", { query: "openai" }).rows;
873
- expect(queriedProviderRows).toEqual([
874
- expect.objectContaining({ key: "openai", total_tokens: 10, total_cost_brl: 5 }),
875
- ]);
876
- const modelGroups = filesystem.viewPage("cost_monitor_models", { limit: 20, offset: 0 });
877
- expect(modelGroups.rows).toEqual(expect.arrayContaining([
878
- expect.objectContaining({ key: "gpt-a", total_tokens: 1_010, total_cost_brl: 505 }),
879
- expect.objectContaining({ key: "claude-b", total_tokens: 20, total_cost_brl: 10 }),
880
- ]));
881
- // First-fold transport is aggregate-only, but its overview chart must
882
- // retain the segment-backed model rows instead of falling back to the
883
- // empty availability metadata.
884
- expect(filesystem.costMonitorSummaryAggregate({ from: null, to: null }).model_groups).toEqual(
885
- expect.arrayContaining([
886
- expect.objectContaining({ key: "gpt-a", total_tokens: 1_010, estimated_brl: 505 }),
887
- expect.objectContaining({ key: "claude-b", total_tokens: 20, estimated_brl: 10 }),
888
- ]),
889
- );
890
- expect(modelGroups.rows.map((row) => row.key)).toEqual(expect.arrayContaining(["unavailable"]));
891
- const modelTotals = modelGroups.rows.reduce<{ invocations: number; tasks: number; duration: number; tokens: number; brl: number }>(
892
- (total, row) => ({
893
- invocations: total.invocations + Number(row.invocation_count ?? 0),
894
- tasks: total.tasks + Number(row.task_count ?? 0),
895
- duration: total.duration + Number(row.total_duration ?? 0),
896
- tokens: total.tokens + Number(row.total_tokens ?? 0),
897
- brl: total.brl + Number(row.total_cost_brl ?? 0),
898
- }),
899
- { invocations: 0, tasks: 0, duration: 0, tokens: 0, brl: 0 },
900
- );
901
- expect(modelTotals).toEqual({ invocations: 2, tasks: 3, duration: 60_000, tokens: 1030, brl: 515 });
902
- expect(filesystem.viewPage("cost_monitor_models", { query: "gpt-a" }).rows).toHaveLength(1);
903
- expect(filesystem.viewPage("cost_monitor_models", { provider: "openai", model: "gpt-a" }).rows[0]).toMatchObject({ key: "gpt-a", total_tokens: 1010, total_cost_brl: 505 });
904
- expect(filesystem.viewPage("cost_monitor_models", { provider: "openai", model: "claude-b" })).toMatchObject({ total_count: 0, rows: [] });
905
- expect(filesystem.viewPage("cost_monitor_models", { priority: "high" })).toMatchObject({ total_count: 0, rows: [] });
906
- const unavailable = { from: null, to: null, providers: ["unavailable"], models: ["unavailable"] };
907
- const unavailableRows = filesystem.invocationCostRows(unavailable);
908
- expect(unavailableRows).toHaveLength(1);
909
- // Observed zero telemetry stays zero, while the missing provider/model
910
- // attribute selects this segment rather than a literal sentinel value.
911
- expect(unavailableRows[0]).toMatchObject({ total_tokens: 0, cost_brl: 0 });
912
- // Execution-duration is an Operations compatibility aggregate and still
913
- // includes the unassisted canonical Run. Cost Monitor retains its
914
- // measurable financial activity as an unavailable historical fact.
915
- expect([...filesystem.executionDurationByDay(unavailable).values()]).toEqual([60_000]);
916
- expect([...filesystem.canonicalRunCountByDay(unavailable).values()]).toEqual([2]);
917
- const unavailableInvocation = filesystem.viewPage("cost_monitor_agent_invocations", {
918
- provider: "unavailable",
919
- model: "unavailable",
920
- });
921
- expect(unavailableInvocation).toMatchObject({ total_count: 1 });
922
- expect(unavailableInvocation.rows[0]).toMatchObject({ input_tokens: 0 });
923
- for (const view of ["cost_monitor_daily", "cost_monitor_monthly", "cost_monitor_annual"] as const) {
924
- const row = filesystem.viewPage(view, { provider: "unavailable", model: "unavailable" }).rows[0];
925
- expect(row).toMatchObject({ total_run_count: 2, total_tokens: 1_000, total_cost_brl: 500 });
926
- }
927
-
928
- filesystem.close();
929
- const sameModelStarted = { ...started, event_id: "RUN-SAME-MODEL:1", run_id: "RUN-SAME-MODEL", occurred_at: "2026-08-05T12:00:00.000Z", client_turn_id: "same-model", conversation_id: "CONV-SAME-MODEL", execution_id: "EXEC-SAME-MODEL", task_id: "TASK-SAME-MODEL", agent_invocation_id: "AINV-SAME-MODEL", root_agent_invocation_id: "AINV-SAME-MODEL", provider: "mixed", model: "gpt-a" };
930
- const sameModelUsage = (sequence: number, provider: string, tokens: number, brl: number) => ({ ...usage(sequence, provider, "gpt-a", tokens, brl), event_id: `RUN-SAME-MODEL:${sequence}`, run_id: "RUN-SAME-MODEL", occurred_at: "2026-08-05T12:00:01.000Z", source_started_at: "2026-08-05T12:00:00.000Z", source_finished_at: "2026-08-05T12:01:00.000Z" });
931
- const sameModelFinished = { ...finished, event_id: "RUN-SAME-MODEL:4", run_id: "RUN-SAME-MODEL", sequence: 4, occurred_at: "2026-08-05T12:01:00.000Z" };
932
- await writeFile(join(root, ".agents", "records", "runs", "2026", "08", "RUN-SAME-MODEL.jsonl"), `${[sameModelStarted, sameModelUsage(2, "openai", 3, 1.5), sameModelUsage(3, "anthropic", 4, 2), sameModelFinished].map((row) => JSON.stringify(row)).join("\n")}\n`);
933
- const durationRun = (id: string, day: string, duration: number | null, provenance: "reconciled" | "estimated") => {
934
- const start = { ...sameModelStarted, event_id: `${id}:1`, run_id: id, occurred_at: `${day}T12:00:00.000Z`, client_turn_id: id, conversation_id: `CONV-${id}`, execution_id: `EXEC-${id}`, task_id: `TASK-${id}`, agent_invocation_id: `AINV-${id}`, root_agent_invocation_id: `AINV-${id}` };
935
- const measured = { ...usage(2, "openai", "gpt-a", provenance === "estimated" ? 4_000_000 : 9, provenance === "estimated" ? 0 : 4.5), event_id: `${id}:2`, run_id: id, occurred_at: `${day}T12:00:01.000Z`, source_started_at: `${day}T12:00:00.000Z`, source_finished_at: `${day}T12:01:00.000Z`, ...(duration === null ? {} : { duration_ms: duration, duration_provenance: provenance }) };
936
- const end = { ...finished, event_id: `${id}:3`, run_id: id, sequence: 3, occurred_at: `${day}T12:01:00.000Z`, ...(provenance === "estimated" ? { duration_ms: null, duration_provenance: "unavailable" } : {}) };
937
- return [start, measured, end];
938
- };
939
- await writeFile(join(root, ".agents", "records", "runs", "2026", "08", "RUN-RECONCILED-MODEL.jsonl"), `${durationRun("RUN-RECONCILED-MODEL", "2026-08-06", 45_000, "reconciled").map((row) => JSON.stringify(row)).join("\n")}\n`);
940
- await writeFile(join(root, ".agents", "records", "runs", "2026", "08", "RUN-ESTIMATED-MODEL.jsonl"), `${durationRun("RUN-ESTIMATED-MODEL", "2026-08-07", null, "estimated").map((row) => JSON.stringify(row)).join("\n")}\n`);
941
- const sharedTaskRun = (id: string, model: string, tokens: number, brl: number) => [
942
- { ...sameModelStarted, event_id: `${id}:1`, run_id: id, occurred_at: "2026-08-08T12:00:00.000Z", client_turn_id: id, conversation_id: `CONV-${id}`, execution_id: `EXEC-${id}`, task_id: "TASK-CROSS-MODEL", agent_invocation_id: `AINV-${id}`, root_agent_invocation_id: `AINV-${id}`, provider: "openai", model },
943
- { ...usage(2, "openai", model, tokens, brl), event_id: `${id}:2`, run_id: id, occurred_at: "2026-08-08T12:00:01.000Z", source_started_at: "2026-08-08T12:00:00.000Z", source_finished_at: "2026-08-08T12:01:00.000Z" },
944
- { ...finished, event_id: `${id}:3`, run_id: id, sequence: 3, occurred_at: "2026-08-08T12:01:00.000Z" },
945
- ];
946
- await writeFile(join(root, ".agents", "records", "runs", "2026", "08", "RUN-TASK-GPT.jsonl"), `${sharedTaskRun("RUN-TASK-GPT", "gpt-a", 5, 2.5).map((row) => JSON.stringify(row)).join("\n")}\n`);
947
- await writeFile(join(root, ".agents", "records", "runs", "2026", "08", "RUN-TASK-CLAUDE.jsonl"), `${sharedTaskRun("RUN-TASK-CLAUDE", "claude-b", 6, 3).map((row) => JSON.stringify(row)).join("\n")}\n`);
948
- const subrunStarted = { ...sameModelStarted, event_id: "RUN-PROVIDER-SUBRUN:1", run_id: "RUN-PROVIDER-SUBRUN", occurred_at: "2026-08-09T12:00:00.000Z", client_turn_id: "provider-subrun", conversation_id: "CONV-PROVIDER-SUBRUN", execution_id: "EXEC-PROVIDER-SUBRUN", task_id: "TASK-PROVIDER-SUBRUN", agent_invocation_id: "AINV-PROVIDER-SUBRUN", root_agent_invocation_id: "AINV-SAME-MODEL", parent_agent_invocation_id: "AINV-SAME-MODEL", parent_run_id: "RUN-SAME-MODEL", run_role: "subagent", invocation_kind: "delegated", delegation_depth: 1, provider: "openai", model: "gpt-a" };
949
- const subrunUsage = { ...usage(2, "openai", "gpt-a", 8, 4), event_id: "RUN-PROVIDER-SUBRUN:2", run_id: "RUN-PROVIDER-SUBRUN", occurred_at: "2026-08-09T12:00:01.000Z", source_started_at: "2026-08-09T12:00:00.000Z", source_finished_at: "2026-08-09T12:00:30.000Z" };
950
- const subrunFinished = { ...finished, event_id: "RUN-PROVIDER-SUBRUN:3", run_id: "RUN-PROVIDER-SUBRUN", sequence: 3, occurred_at: "2026-08-09T12:00:30.000Z", duration_ms: 30_000, duration_provenance: "observed" };
951
- await writeFile(join(root, ".agents", "records", "runs", "2026", "08", "RUN-PROVIDER-SUBRUN.jsonl"), `${[subrunStarted, subrunUsage, subrunFinished].map((row) => JSON.stringify(row)).join("\n")}\n`);
952
- await rebuildSqliteReadModel(root);
953
- const sameModelFs = new SqliteReadModelFileSystem(root);
954
- const modelRow = (filter: Record<string, string>) => sameModelFs.viewPage("cost_monitor_models", { from: "2026-08-05", to: "2026-08-05", ...filter }).rows.find((row) => row.key === "gpt-a");
955
- expect(modelRow({ provider: "openai", model: "gpt-a" })).toMatchObject({ invocation_count: 1, task_count: 1, total_duration: 60_000, total_tokens: 3, total_cost_brl: 1.5 });
956
- expect(modelRow({ provider: "anthropic", model: "gpt-a" })).toMatchObject({ invocation_count: 1, task_count: 1, total_duration: 60_000, total_tokens: 4, total_cost_brl: 2 });
957
- expect(modelRow({})).toMatchObject({ invocation_count: 1, task_count: 1, total_duration: 60_000, total_tokens: 7, total_cost_brl: 3.5 });
958
- expect(sameModelFs.viewPage("cost_monitor_models", { from: "2026-08-05", to: "2026-08-05", provider: "openai", model: "claude-b" })).toMatchObject({ total_count: 0, rows: [] });
959
- for (const day of ["2026-08-06", "2026-08-07"]) {
960
- const effective = sameModelFs.invocationCostRows({ from: day, to: day }).reduce((sum, row) => sum + Number(row.duration_ms ?? 0), 0);
961
- const modelDuration = sameModelFs.viewPage("cost_monitor_models", { from: day, to: day }).rows.reduce((sum, row) => sum + Number(row.total_duration ?? 0), 0);
962
- expect(modelDuration).toBe(effective);
963
- }
964
- for (const day of ["2026-08-06", "2026-08-07"]) {
965
- const population = sameModelFs.invocationCostRows({ from: day, to: day });
966
- const providerRows = sameModelFs.viewPage("cost_monitor_providers", { from: day, to: day }).rows;
967
- const providerTotals = providerRows.reduce<{ invocations: number; tasks: number; duration: number; tokens: number; brl: number }>(
968
- (total, row) => ({
969
- invocations: total.invocations + Number(row.invocation_count ?? 0),
970
- tasks: total.tasks + Number(row.task_count ?? 0),
971
- duration: total.duration + Number(row.total_duration ?? 0),
972
- tokens: total.tokens + Number(row.total_tokens ?? 0),
973
- brl: total.brl + Number(row.total_cost_brl ?? 0),
1487
+ try {
1488
+ const all = filesystem.developerCostAggregate({ from: null, to: null });
1489
+ const deliveredBy42 = all.rows.find((row) => row.account_id === "42")!;
1490
+ expect(deliveredBy42).toMatchObject({
1491
+ qualification: "verified",
1492
+ completed_task_count: 1,
1493
+ run_count: 4,
1494
+ token_covered_runs: 3,
1495
+ usd_covered_runs: 3,
1496
+ brl_covered_runs: 3,
1497
+ });
1498
+ expect(deliveredBy42.completed_tasks).toEqual([
1499
+ expect.objectContaining({
1500
+ id: "TASK-DELIVERED",
1501
+ completed_run_id: "RUN-DELIVERED",
1502
+ delivered_by: { account_id: "42" },
1503
+ contributors: expect.arrayContaining([
1504
+ expect.objectContaining({ account_id: "42" }),
1505
+ expect.objectContaining({ account_id: "99" }),
1506
+ ]),
974
1507
  }),
975
- { invocations: 0, tasks: 0, duration: 0, tokens: 0, brl: 0 },
976
- );
977
- expect(providerTotals).toEqual({
978
- invocations: population.length,
979
- tasks: new Set(population.map((row) => row.task_id).filter((id): id is string => typeof id === "string")).size,
980
- duration: population.reduce((sum, row) => sum + Number(row.duration_ms ?? 0), 0),
981
- tokens: population.reduce((sum, row) => sum + Number(row.total_tokens ?? 0), 0),
982
- brl: population.reduce((sum, row) => sum + Number(row.cost_brl ?? 0), 0),
1508
+ ]);
1509
+ // Operations counts completed Tasks from the same canonical Task facts
1510
+ // as its status distribution; no completed_run_id is required there.
1511
+ expect(
1512
+ filesystem
1513
+ .operationsDeveloperAggregate({ from: null, to: null })
1514
+ .rows.find((row) => row.account_id === "42"),
1515
+ ).toMatchObject({
1516
+ completed_task_count: 3,
1517
+ status_counts: expect.objectContaining({ completed: 3 }),
983
1518
  });
1519
+ expect(all.rows.find((row) => row.account_id === "199126185")).toMatchObject({
1520
+ qualification: "human_assigned",
1521
+ completed_task_count: 1,
1522
+ });
1523
+ expect(
1524
+ filesystem.developerCostAggregate({
1525
+ from: "2026-08-08",
1526
+ to: "2026-08-08",
1527
+ accountIds: ["42"],
1528
+ }).rows,
1529
+ ).toHaveLength(1);
1530
+ expect(
1531
+ filesystem.developerCostAggregate({
1532
+ from: "2026-08-09",
1533
+ to: "2026-08-09",
1534
+ accountIds: ["42"],
1535
+ }).rows[0],
1536
+ ).toMatchObject({ completed_task_count: 0 });
1537
+ // The real attributed unknown Run remains linked to account 42. Its
1538
+ // coverage gap is explicit; its absent measures are never a zero.
1539
+ const unknownDay = filesystem.developerCostAggregate({
1540
+ from: "2026-08-09",
1541
+ to: "2026-08-09",
1542
+ accountIds: ["42"],
1543
+ }).rows[0]!;
1544
+ expect(unknownDay).toMatchObject({
1545
+ run_count: 3,
1546
+ token_covered_runs: 2,
1547
+ usd_covered_runs: 2,
1548
+ brl_covered_runs: 2,
1549
+ });
1550
+ expect(unknownDay.total_tokens).toBe(9);
1551
+ expect(
1552
+ filesystem.dailyPeriods({ from: "2026-08-09", to: "2026-08-09" })["2026-08-09"],
1553
+ ).toMatchObject({
1554
+ runs: 4,
1555
+ usage: {
1556
+ total_tokens: { known_sum: 11, unknown: 1 },
1557
+ cost: { known_sum: 0.55, unknown: 1 },
1558
+ },
1559
+ });
1560
+ } finally {
1561
+ filesystem.close();
1562
+ }
1563
+ await writeFile(join(assignmentsRoot, "HDA-FIXTURE.json"), "{corrupt");
1564
+ await rebuildSqliteReadModel(root, { forceCanonical: true });
1565
+ const corrupt = new SqliteReadModelFileSystem(root);
1566
+ try {
1567
+ expect(
1568
+ corrupt.developerCostAggregate({ from: null, to: null }).rows.map((row) => row.account_id),
1569
+ ).not.toContain("199126185");
1570
+ } finally {
1571
+ corrupt.close();
984
1572
  }
985
- const sharedTaskRows = sameModelFs.viewPage("cost_monitor_models", { from: "2026-08-08", to: "2026-08-08" }).rows;
986
- expect(sharedTaskRows).toEqual(expect.arrayContaining([
987
- expect.objectContaining({ key: "gpt-a", invocation_count: 1, task_count: 1, total_duration: 30_000, total_tokens: 5, total_cost_brl: 2.5 }),
988
- expect.objectContaining({ key: "claude-b", invocation_count: 1, task_count: 1, total_duration: 30_000, total_tokens: 6, total_cost_brl: 3 }),
989
- ]));
990
- expect(sharedTaskRows.map((row) => row.key)).not.toContain("mixed");
991
- expect(sharedTaskRows.reduce((sum, row) => sum + Number(row.task_count ?? 0), 0)).toBe(2);
992
- const subrunPopulation = sameModelFs.invocationCostRows({ from: "2026-08-09", to: "2026-08-09", providers: ["openai"], models: ["gpt-a"] });
993
- const subrunProviderRows = sameModelFs.viewPage("cost_monitor_providers", { from: "2026-08-09", to: "2026-08-09", provider: "openai", model: "gpt-a" }).rows;
994
- const subrunProviderTotals = subrunProviderRows.reduce<{ invocations: number; tasks: number; duration: number; tokens: number; brl: number }>(
995
- (total, row) => ({ invocations: total.invocations + Number(row.invocation_count ?? 0), tasks: total.tasks + Number(row.task_count ?? 0), duration: total.duration + Number(row.total_duration ?? 0), tokens: total.tokens + Number(row.total_tokens ?? 0), brl: total.brl + Number(row.total_cost_brl ?? 0) }),
996
- { invocations: 0, tasks: 0, duration: 0, tokens: 0, brl: 0 },
997
- );
998
- expect(subrunProviderTotals).toEqual({ invocations: subrunPopulation.length, tasks: new Set(subrunPopulation.map((row) => row.task_id).filter((id): id is string => typeof id === "string")).size, duration: subrunPopulation.reduce((sum, row) => sum + Number(row.duration_ms ?? 0), 0), tokens: subrunPopulation.reduce((sum, row) => sum + Number(row.total_tokens ?? 0), 0), brl: subrunPopulation.reduce((sum, row) => sum + Number(row.cost_brl ?? 0), 0) });
999
- expect(sameModelFs.viewPage("cost_monitor_providers", { from: "2026-08-09", to: "2026-08-09", provider: "openai", model: "claude-b" })).toMatchObject({ total_count: 0, rows: [] });
1000
- sameModelFs.close();
1001
1573
  });
1002
1574
 
1003
1575
  it("prefers the canonical started-to-finished interval over a token estimate", async () => {
@@ -1007,7 +1579,7 @@ created_at: 2026-08-10T11:01:00.000Z
1007
1579
  await mkdir(join(root, ".agents", "config"), { recursive: true });
1008
1580
  await writeFile(
1009
1581
  join(root, ".agents", "config", "project.yaml"),
1010
- "schema_version: 1\nzaip:\n enabled: true\nproject:\n id: sqlite-test\n name: sqlite-test\n timezone: UTC\nstack:\n id: zaip-aios-stack\n overrides: {}\nclients:\n codex: true\n claude: true\ntracking:\n enabled: true\n currency: BRL\n storage_mode: tracked_sanitized\n",
1582
+ "schema_version: 1\nzaip:\n enabled: true\nproject:\n id: sqlite-test\n name: sqlite-test\n timezone: UTC\nstack:\n id: zaip-aios-stack\n overrides: {}\nclients:\n codex: true\n claude: true\ntracking:\n enabled: true\n currency: BRL\n storage_mode: tracked_sanitized\n",
1011
1583
  "utf8",
1012
1584
  );
1013
1585
  const started = {
@@ -1216,49 +1788,135 @@ created_at: 2026-08-10T11:01:00.000Z
1216
1788
  await mkdir(join(root, ".agents", "records", "runs", "2026", "07"), { recursive: true });
1217
1789
  await mkdir(join(root, ".agents", "config"), { recursive: true });
1218
1790
  await writeFile(join(root, ".agents", "config", "project.yaml"), "zaip:\n enabled: true\n");
1219
- const run = ({ id, phase, sourceStartedAt, sourceFinishedAt, parentRunId = null }: {
1220
- id: string; phase: "conversation" | "planning" | "execution";
1221
- sourceStartedAt: string; sourceFinishedAt: string; parentRunId?: string | null;
1791
+ const run = ({
1792
+ id,
1793
+ phase,
1794
+ sourceStartedAt,
1795
+ sourceFinishedAt,
1796
+ parentRunId = null,
1797
+ }: {
1798
+ id: string;
1799
+ phase: "conversation" | "planning" | "execution";
1800
+ sourceStartedAt: string;
1801
+ sourceFinishedAt: string;
1802
+ parentRunId?: string | null;
1222
1803
  }) => {
1223
1804
  const occurredAt = sourceStartedAt;
1224
1805
  const agentInvocationId = `AINV-${id}`;
1225
1806
  return [
1226
1807
  {
1227
- schema_version: 2, event_id: `${id}:1`, run_id: id, sequence: 1, occurred_at: occurredAt,
1228
- type: "run.started", attribution_status: "attributed", phase, run_role: parentRunId === null ? "orchestrator" : "subagent",
1229
- run_purpose: "orchestration", requires_finalizer: false, execution_kind: "delivery",
1230
- execution_eligibility: ["delivery"], entrypoint: "task", work_type: "new",
1231
- storage_mode: "tracked_sanitized", client: "codex", agent: "agent", agent_name: "agent",
1232
- provider: "openai", model: "gpt-5", reasoning_effort: null, client_thread_id: `thread-${id}`,
1233
- client_turn_id: `turn-${id}`, conversation_id: `CONV-${id}`, execution_id: `EXEC-${id}`,
1234
- task_id: `TASK-${id}`, spec_id: null, prd_id: null, change_id: null, parent_run_id: parentRunId,
1235
- continuation_of_run_id: null, retry_of_run_id: null, agent_invocation_id: agentInvocationId,
1808
+ schema_version: 2,
1809
+ event_id: `${id}:1`,
1810
+ run_id: id,
1811
+ sequence: 1,
1812
+ occurred_at: occurredAt,
1813
+ type: "run.started",
1814
+ attribution_status: "attributed",
1815
+ phase,
1816
+ run_role: parentRunId === null ? "orchestrator" : "subagent",
1817
+ run_purpose: "orchestration",
1818
+ requires_finalizer: false,
1819
+ execution_kind: "delivery",
1820
+ execution_eligibility: ["delivery"],
1821
+ entrypoint: "task",
1822
+ work_type: "new",
1823
+ storage_mode: "tracked_sanitized",
1824
+ client: "codex",
1825
+ agent: "agent",
1826
+ agent_name: "agent",
1827
+ provider: "openai",
1828
+ model: "gpt-5",
1829
+ reasoning_effort: null,
1830
+ client_thread_id: `thread-${id}`,
1831
+ client_turn_id: `turn-${id}`,
1832
+ conversation_id: `CONV-${id}`,
1833
+ execution_id: `EXEC-${id}`,
1834
+ task_id: `TASK-${id}`,
1835
+ spec_id: null,
1836
+ prd_id: null,
1837
+ change_id: null,
1838
+ parent_run_id: parentRunId,
1839
+ continuation_of_run_id: null,
1840
+ retry_of_run_id: null,
1841
+ agent_invocation_id: agentInvocationId,
1236
1842
  root_agent_invocation_id: parentRunId === null ? agentInvocationId : "AINV-root",
1237
1843
  parent_agent_invocation_id: parentRunId === null ? null : "AINV-root",
1238
- invocation_kind: parentRunId === null ? "orchestrator" : "delegated", delegation_depth: parentRunId === null ? 0 : 1,
1844
+ invocation_kind: parentRunId === null ? "orchestrator" : "delegated",
1845
+ delegation_depth: parentRunId === null ? 0 : 1,
1239
1846
  },
1240
1847
  {
1241
- schema_version: 2, event_id: `${id}:2`, run_id: id, sequence: 2, occurred_at: sourceFinishedAt,
1242
- type: "usage.recorded", phase, activity_kind: "retrospective_local_remeasurement",
1243
- classification_source: "current_context", tokens: { input: 1, cached_input: 0, output: 1, reasoning: 0, total: 2, source: "provider_reported" },
1244
- cost: { usd: 1, brl: 5, fx_rate: 5 }, provider: "openai", model: "gpt-5", source_segment_key: id,
1245
- model_call_id: `MCALL-${id}`, runtime: { reasoning_effort: null, service_tier: null }, supersedes_event_id: null,
1246
- retrospective_correction: true, source_occurred_at: sourceFinishedAt, source_started_at: sourceStartedAt,
1247
- source_finished_at: sourceFinishedAt, duration_ms: null, duration_provenance: null,
1848
+ schema_version: 2,
1849
+ event_id: `${id}:2`,
1850
+ run_id: id,
1851
+ sequence: 2,
1852
+ occurred_at: sourceFinishedAt,
1853
+ type: "usage.recorded",
1854
+ phase,
1855
+ activity_kind: "retrospective_local_remeasurement",
1856
+ classification_source: "current_context",
1857
+ tokens: {
1858
+ input: 1,
1859
+ cached_input: 0,
1860
+ output: 1,
1861
+ reasoning: 0,
1862
+ total: 2,
1863
+ source: "provider_reported",
1864
+ },
1865
+ cost: { usd: 1, brl: 5, fx_rate: 5 },
1866
+ provider: "openai",
1867
+ model: "gpt-5",
1868
+ source_segment_key: id,
1869
+ model_call_id: `MCALL-${id}`,
1870
+ runtime: { reasoning_effort: null, service_tier: null },
1871
+ supersedes_event_id: null,
1872
+ retrospective_correction: true,
1873
+ source_occurred_at: sourceFinishedAt,
1874
+ source_started_at: sourceStartedAt,
1875
+ source_finished_at: sourceFinishedAt,
1876
+ duration_ms: null,
1877
+ duration_provenance: null,
1248
1878
  },
1249
1879
  {
1250
- schema_version: 2, event_id: `${id}:3`, run_id: id, sequence: 3,
1251
- occurred_at: new Date(Date.parse(occurredAt) + 60_000).toISOString(), type: "run.finished", phase,
1252
- status: "completed", duration_ms: 60_000, duration_provenance: "observed",
1880
+ schema_version: 2,
1881
+ event_id: `${id}:3`,
1882
+ run_id: id,
1883
+ sequence: 3,
1884
+ occurred_at: new Date(Date.parse(occurredAt) + 60_000).toISOString(),
1885
+ type: "run.finished",
1886
+ phase,
1887
+ status: "completed",
1888
+ duration_ms: 60_000,
1889
+ duration_provenance: "observed",
1253
1890
  },
1254
1891
  ];
1255
1892
  };
1256
1893
  for (const value of [
1257
- // 23:17–01:01 São Paulo: factual duration is split at local midnight.
1258
- { id: "RUN-planning", phase: "planning" as const, sourceStartedAt: "2026-07-23T02:17:00.000Z", sourceFinishedAt: "2026-07-23T04:01:00.000Z" },
1259
- { id: "RUN-conversation", phase: "conversation" as const, sourceStartedAt: "2026-07-23T03:00:00.000Z", sourceFinishedAt: "2026-07-23T04:01:00.000Z" },
1260
- { id: "RUN-execution", phase: "execution" as const, sourceStartedAt: "2026-07-23T03:30:00.000Z", sourceFinishedAt: "2026-07-23T04:30:00.000Z" },
1261
- { id: "RUN-subrun", phase: "execution" as const, parentRunId: "RUN-execution", sourceStartedAt: "2026-07-23T03:45:00.000Z", sourceFinishedAt: "2026-07-23T04:15:00.000Z" },
1894
+ // 23:17–01:01 São Paulo: factual duration is split at local midnight.
1895
+ {
1896
+ id: "RUN-planning",
1897
+ phase: "planning" as const,
1898
+ sourceStartedAt: "2026-07-23T02:17:00.000Z",
1899
+ sourceFinishedAt: "2026-07-23T04:01:00.000Z",
1900
+ },
1901
+ {
1902
+ id: "RUN-conversation",
1903
+ phase: "conversation" as const,
1904
+ sourceStartedAt: "2026-07-23T03:00:00.000Z",
1905
+ sourceFinishedAt: "2026-07-23T04:01:00.000Z",
1906
+ },
1907
+ {
1908
+ id: "RUN-execution",
1909
+ phase: "execution" as const,
1910
+ sourceStartedAt: "2026-07-23T03:30:00.000Z",
1911
+ sourceFinishedAt: "2026-07-23T04:30:00.000Z",
1912
+ },
1913
+ {
1914
+ id: "RUN-subrun",
1915
+ phase: "execution" as const,
1916
+ parentRunId: "RUN-execution",
1917
+ sourceStartedAt: "2026-07-23T03:45:00.000Z",
1918
+ sourceFinishedAt: "2026-07-23T04:15:00.000Z",
1919
+ },
1262
1920
  ]) {
1263
1921
  await writeFile(
1264
1922
  join(root, ".agents", "records", "runs", "2026", "07", `${value.id}.jsonl`),
@@ -1310,18 +1968,53 @@ created_at: 2026-08-10T11:01:00.000Z
1310
1968
  `${[historicalStarted, ...historicalRecords.slice(1)].map((record) => JSON.stringify(record)).join("\n")}\n`,
1311
1969
  );
1312
1970
  await rebuildSqliteReadModel(root);
1313
- const database = new DatabaseSync(resolve(root, ".local/dashboard-sqlite/read-model.sqlite"), { readOnly: true });
1314
- expect(database.prepare("SELECT duration_ms, source_duration_ms, duration_provenance FROM zaip_aios_activities WHERE run_id='RUN-planning'").get()).toEqual({ duration_ms: 4_020_000, source_duration_ms: 6_240_000, duration_provenance: "attributed_token_active" });
1315
- const daily = database.prepare("SELECT day, total_duration, invocation_count, cost_monitor_invocation_count, cost_monitor_total_duration FROM zaip_vw_daily_aggregates WHERE day IN ('2026-07-22', '2026-07-23') ORDER BY day").all();
1971
+ const database = new DatabaseSync(resolve(root, ".local/dashboard-sqlite/read-model.sqlite"), {
1972
+ readOnly: true,
1973
+ });
1974
+ expect(
1975
+ database
1976
+ .prepare(
1977
+ "SELECT duration_ms, source_duration_ms, duration_provenance FROM zaip_aios_activities WHERE run_id='RUN-planning'",
1978
+ )
1979
+ .get(),
1980
+ ).toEqual({
1981
+ duration_ms: 4_020_000,
1982
+ source_duration_ms: 6_240_000,
1983
+ duration_provenance: "attributed_token_active",
1984
+ });
1985
+ const daily = database
1986
+ .prepare(
1987
+ "SELECT day, total_duration, invocation_count, cost_monitor_invocation_count, cost_monitor_total_duration FROM zaip_vw_daily_aggregates WHERE day IN ('2026-07-22', '2026-07-23') ORDER BY day",
1988
+ )
1989
+ .all();
1316
1990
  expect(daily).toEqual([
1317
- { day: "2026-07-22", total_duration: 2_580_000, invocation_count: 1, cost_monitor_invocation_count: 1, cost_monitor_total_duration: 2_580_000 },
1318
- { day: "2026-07-23", total_duration: 5_420_000, invocation_count: 4, cost_monitor_invocation_count: 5, cost_monitor_total_duration: 5_420_000 },
1991
+ {
1992
+ day: "2026-07-22",
1993
+ total_duration: 2_580_000,
1994
+ invocation_count: 1,
1995
+ cost_monitor_invocation_count: 1,
1996
+ cost_monitor_total_duration: 2_580_000,
1997
+ },
1998
+ {
1999
+ day: "2026-07-23",
2000
+ total_duration: 5_420_000,
2001
+ invocation_count: 4,
2002
+ cost_monitor_invocation_count: 5,
2003
+ cost_monitor_total_duration: 5_420_000,
2004
+ },
1319
2005
  ]);
1320
- expect(database.prepare("SELECT COUNT(*) AS count FROM zaip_vw_daily_aggregates WHERE total_duration > 86400000").get()).toEqual({ count: 0 });
2006
+ expect(
2007
+ database
2008
+ .prepare(
2009
+ "SELECT COUNT(*) AS count FROM zaip_vw_daily_aggregates WHERE total_duration > 86400000",
2010
+ )
2011
+ .get(),
2012
+ ).toEqual({ count: 0 });
1321
2013
  database.close();
1322
2014
  const factualFilesystem = new SqliteReadModelFileSystem(root);
1323
2015
  expect(
1324
- factualFilesystem.costMonitorFinancialActivityRows({ from: "2026-07-23", to: "2026-07-23" })
2016
+ factualFilesystem
2017
+ .costMonitorFinancialActivityRows({ from: "2026-07-23", to: "2026-07-23" })
1325
2018
  .some((row) => row.run_id === "RUN-historical-financial"),
1326
2019
  ).toBe(true);
1327
2020
  const compactFinancialRow = factualFilesystem.costMonitorFinancialActivityRows({
@@ -1331,41 +2024,59 @@ created_at: 2026-08-10T11:01:00.000Z
1331
2024
  expect(compactFinancialRow).not.toHaveProperty("payload_json");
1332
2025
  expect(compactFinancialRow).toHaveProperty("total_tokens");
1333
2026
  expect(
1334
- factualFilesystem.costMonitorFinancialActivityRows({ from: "2026-07-24", to: "2026-07-24" })
2027
+ factualFilesystem
2028
+ .costMonitorFinancialActivityRows({ from: "2026-07-24", to: "2026-07-24" })
1335
2029
  .some((row) => row.run_id === "RUN-historical-financial"),
1336
2030
  ).toBe(false);
1337
2031
  expect(
1338
- factualFilesystem.viewPage("operations_agent_invocations", {
1339
- from: "2026-07-23", to: "2026-07-23", limit: 20,
1340
- }).rows.some((row) => row.run_id === "RUN-source-alias"),
2032
+ factualFilesystem
2033
+ .viewPage("operations_agent_invocations", {
2034
+ from: "2026-07-23",
2035
+ to: "2026-07-23",
2036
+ limit: 20,
2037
+ })
2038
+ .rows.some((row) => row.run_id === "RUN-source-alias"),
1341
2039
  ).toBe(true);
1342
2040
  expect(
1343
- factualFilesystem.viewPage("operations_agent_invocations", {
1344
- from: "2026-07-22", to: "2026-07-22", limit: 20,
1345
- }).rows.some((row) => row.run_id === "RUN-source-alias"),
2041
+ factualFilesystem
2042
+ .viewPage("operations_agent_invocations", {
2043
+ from: "2026-07-22",
2044
+ to: "2026-07-22",
2045
+ limit: 20,
2046
+ })
2047
+ .rows.some((row) => row.run_id === "RUN-source-alias"),
1346
2048
  ).toBe(false);
1347
2049
  // Filter dimensions stay in the SQL population: they must retain the
1348
2050
  // source-session day and never require an activity-by-activity lookup.
1349
2051
  expect(
1350
- factualFilesystem.costMonitorFinancialActivityRows({
1351
- from: "2026-07-23",
1352
- to: "2026-07-23",
1353
- phases: ["conversation"],
1354
- providers: ["openai"],
1355
- models: ["gpt-5"],
1356
- }).map((row) => row.run_id),
2052
+ factualFilesystem
2053
+ .costMonitorFinancialActivityRows({
2054
+ from: "2026-07-23",
2055
+ to: "2026-07-23",
2056
+ phases: ["conversation"],
2057
+ providers: ["openai"],
2058
+ models: ["gpt-5"],
2059
+ })
2060
+ .map((row) => row.run_id),
1357
2061
  ).toContain("RUN-historical-financial");
1358
2062
  expect(
1359
- factualFilesystem.costMonitorFinancialActivityRows({
1360
- from: "2026-07-22",
1361
- to: "2026-07-22",
1362
- phases: ["planning"],
1363
- }).map((row) => row.run_id),
2063
+ factualFilesystem
2064
+ .costMonitorFinancialActivityRows({
2065
+ from: "2026-07-22",
2066
+ to: "2026-07-22",
2067
+ phases: ["planning"],
2068
+ })
2069
+ .map((row) => row.run_id),
1364
2070
  ).toEqual(["RUN-planning"]);
1365
- for (const view of ["cost_monitor_daily", "cost_monitor_monthly", "cost_monitor_annual"] as const) {
2071
+ for (const view of [
2072
+ "cost_monitor_daily",
2073
+ "cost_monitor_monthly",
2074
+ "cost_monitor_annual",
2075
+ ] as const) {
1366
2076
  expect(
1367
- factualFilesystem.viewPage(view, { from: "2026-07-23", to: "2026-07-23", limit: 20, offset: 0 }).rows
1368
- .some((row) => Number(row.total_tokens) === 10),
2077
+ factualFilesystem
2078
+ .viewPage(view, { from: "2026-07-23", to: "2026-07-23", limit: 20, offset: 0 })
2079
+ .rows.some((row) => Number(row.total_tokens) === 10),
1369
2080
  ).toBe(true);
1370
2081
  // The API boundary supplies inclusive Sao Paulo days as ISO instants.
1371
2082
  // Do not truncate the UTC end instant into the following calendar day.
@@ -1376,20 +2087,40 @@ created_at: 2026-08-10T11:01:00.000Z
1376
2087
  offset: 0,
1377
2088
  }).rows;
1378
2089
  expect(bounded.some((row) => Number(row.total_tokens) === 10)).toBe(true);
1379
- expect(bounded.some((row) => String(row.period_key).startsWith("2026-07-24") && Number(row.total_tokens) === 10)).toBe(false);
2090
+ expect(
2091
+ bounded.some(
2092
+ (row) =>
2093
+ String(row.period_key).startsWith("2026-07-24") && Number(row.total_tokens) === 10,
2094
+ ),
2095
+ ).toBe(false);
1380
2096
  // A structural day or other source financial fact may still exist on
1381
2097
  // the 24th, but this fixture's source-day-23 aggregate must not leak.
1382
2098
  expect(
1383
- factualFilesystem.viewPage(view, { from: "2026-07-24", to: "2026-07-24", limit: 20, offset: 0 }).rows
1384
- .every((row) => row.total_tokens !== 10),
2099
+ factualFilesystem
2100
+ .viewPage(view, { from: "2026-07-24", to: "2026-07-24", limit: 20, offset: 0 })
2101
+ .rows.every((row) => row.total_tokens !== 10),
1385
2102
  ).toBe(true);
1386
2103
  }
1387
- const allFinancialRows = factualFilesystem.costMonitorFinancialActivityRows({ from: null, to: null });
1388
- const factual = factualFilesystem.costMonitorFactualDurationByDay({ from: null, to: null }, allFinancialRows);
2104
+ const allFinancialRows = factualFilesystem.costMonitorFinancialActivityRows({
2105
+ from: null,
2106
+ to: null,
2107
+ });
2108
+ const factual = factualFilesystem.costMonitorFactualDurationByDay(
2109
+ { from: null, to: null },
2110
+ allFinancialRows,
2111
+ );
1389
2112
  // The cross-midnight session is split at São Paulo midnight and each day
1390
2113
  // is the union of complete source intervals, never above one local day.
1391
- expect(factual.get("2026-07-22")).toEqual({ known_sum: 2_580_000, eligible_runs: 1, known_runs: 1 });
1392
- expect(factual.get("2026-07-23")).toEqual({ known_sum: 5_420_000, eligible_runs: 6, known_runs: 6 });
2114
+ expect(factual.get("2026-07-22")).toEqual({
2115
+ known_sum: 2_580_000,
2116
+ eligible_runs: 1,
2117
+ known_runs: 1,
2118
+ });
2119
+ expect(factual.get("2026-07-23")).toEqual({
2120
+ known_sum: 5_420_000,
2121
+ eligible_runs: 6,
2122
+ known_runs: 6,
2123
+ });
1393
2124
  factualFilesystem.close();
1394
2125
  });
1395
2126
 
@@ -1398,42 +2129,231 @@ created_at: 2026-08-10T11:01:00.000Z
1398
2129
  roots.push(root);
1399
2130
  for (const kind of ["tasks", "specs", "prds"])
1400
2131
  await mkdir(join(root, ".agents", "records", kind, "2026", "08"), { recursive: true });
1401
- await mkdir(join(root, ".agents", "records", "changes", "2026", "08", "CHG-UNIQUE"), { recursive: true });
1402
- await mkdir(join(root, ".agents", "records", "changes", "2026", "08", "CHG-SHARED-A"), { recursive: true });
1403
- await mkdir(join(root, ".agents", "records", "changes", "2026", "08", "CHG-SHARED-B"), { recursive: true });
1404
- await mkdir(join(root, ".agents", "records", "changes", "2026", "08", "CHG-PRD-ONLY"), { recursive: true });
1405
- await mkdir(join(root, ".agents", "records", "changes", "2026", "08", "CHG-NO-MACRO"), { recursive: true });
2132
+ await mkdir(join(root, ".agents", "records", "changes", "2026", "08", "CHG-UNIQUE"), {
2133
+ recursive: true,
2134
+ });
2135
+ await mkdir(join(root, ".agents", "records", "changes", "2026", "08", "CHG-SHARED-A"), {
2136
+ recursive: true,
2137
+ });
2138
+ await mkdir(join(root, ".agents", "records", "changes", "2026", "08", "CHG-SHARED-B"), {
2139
+ recursive: true,
2140
+ });
2141
+ await mkdir(join(root, ".agents", "records", "changes", "2026", "08", "CHG-PRD-ONLY"), {
2142
+ recursive: true,
2143
+ });
2144
+ await mkdir(join(root, ".agents", "records", "changes", "2026", "08", "CHG-NO-MACRO"), {
2145
+ recursive: true,
2146
+ });
1406
2147
  await mkdir(join(root, ".agents", "records", "runs", "2026", "08"), { recursive: true });
1407
2148
  await mkdir(join(root, ".agents", "config"), { recursive: true });
1408
- await writeFile(join(root, ".agents", "config", "project.yaml"), "zaip:\n enabled: true\n", "utf8");
1409
- const item = (id: string, status = "planned") => `---\nid: ${id}\ntitle: ${id}\nstatus: ${status}\nrisk: standard\ncreated_at: 2026-08-12T12:00:00.000Z\n---\n# ${id}\n`;
1410
- for (const id of ["TASK-UNIQUE", "TASK-SHARED-A", "TASK-SHARED-B", "TASK-PRD-ONLY", "TASK-NO-MACRO"])
1411
- await writeFile(join(root, ".agents", "records", "tasks", "2026", "08", `${id}.md`), item(id), "utf8");
2149
+ await writeFile(
2150
+ join(root, ".agents", "config", "project.yaml"),
2151
+ "zaip:\n enabled: true\n",
2152
+ "utf8",
2153
+ );
2154
+ const item = (id: string, status = "planned") =>
2155
+ `---\nid: ${id}\ntitle: ${id}\nstatus: ${status}\nrisk: standard\ncreated_at: 2026-08-12T12:00:00.000Z\n---\n# ${id}\n`;
2156
+ for (const id of [
2157
+ "TASK-UNIQUE",
2158
+ "TASK-SHARED-A",
2159
+ "TASK-SHARED-B",
2160
+ "TASK-PRD-ONLY",
2161
+ "TASK-NO-MACRO",
2162
+ ])
2163
+ await writeFile(
2164
+ join(root, ".agents", "records", "tasks", "2026", "08", `${id}.md`),
2165
+ item(id),
2166
+ "utf8",
2167
+ );
1412
2168
  for (const id of ["SPEC-UNIQUE", "SPEC-SHARED"])
1413
- await writeFile(join(root, ".agents", "records", "specs", "2026", "08", `${id}.md`), item(id, "active"), "utf8");
2169
+ await writeFile(
2170
+ join(root, ".agents", "records", "specs", "2026", "08", `${id}.md`),
2171
+ item(id, "active"),
2172
+ "utf8",
2173
+ );
1414
2174
  for (const id of ["PRD-UNIQUE", "PRD-SHARED", "PRD-ONLY"])
1415
- await writeFile(join(root, ".agents", "records", "prds", "2026", "08", `${id}.md`), item(id, "active"), "utf8");
1416
- const change = (id: string, taskId: string, specId: string | null, prdId: string | null) => `---\nid: ${id}\ntitle: ${id}\nstatus: planned\nrisk: standard\nsource:\n type: ${prdId === null ? "task" : "prd"}\n ${prdId === null ? `task_id: ${taskId}` : `prd_id: ${prdId}`}\n${specId === null ? "" : ` spec_id: ${specId}\n`}task_ids:\n - ${taskId}\ncreated_at: 2026-08-12T12:00:00.000Z\n---\n# ${id}\n`;
1417
- await writeFile(join(root, ".agents", "records", "changes", "2026", "08", "CHG-UNIQUE", "change.md"), change("CHG-UNIQUE", "TASK-UNIQUE", "SPEC-UNIQUE", "PRD-UNIQUE"), "utf8");
1418
- await writeFile(join(root, ".agents", "records", "changes", "2026", "08", "CHG-SHARED-A", "change.md"), change("CHG-SHARED-A", "TASK-SHARED-A", "SPEC-SHARED", "PRD-SHARED"), "utf8");
1419
- await writeFile(join(root, ".agents", "records", "changes", "2026", "08", "CHG-SHARED-B", "change.md"), change("CHG-SHARED-B", "TASK-SHARED-B", "SPEC-SHARED", "PRD-SHARED"), "utf8");
1420
- await writeFile(join(root, ".agents", "records", "changes", "2026", "08", "CHG-PRD-ONLY", "change.md"), change("CHG-PRD-ONLY", "TASK-PRD-ONLY", null, "PRD-ONLY"), "utf8");
1421
- await writeFile(join(root, ".agents", "records", "changes", "2026", "08", "CHG-NO-MACRO", "change.md"), change("CHG-NO-MACRO", "TASK-NO-MACRO", null, null), "utf8");
1422
- const run = (id: string, specId: string | null, prdId: string | null, tokens: number, cost: number, duration: number) => [
1423
- { schema_version: 2, event_id: `${id}:1`, run_id: id, sequence: 1, occurred_at: "2026-08-12T12:00:00.000Z", type: "run.started", attribution_status: "attributed", phase: "planning", run_role: "orchestrator", run_purpose: "orchestration", requires_finalizer: false, execution_kind: "interaction", execution_eligibility: [], entrypoint: specId === null ? (prdId === null ? "conversation" : "prd") : "spec", work_type: "new", storage_mode: "tracked_sanitized", client: "codex", agent: "agent", agent_name: "agent", provider: "openai", model: "gpt-5", reasoning_effort: null, client_thread_id: id, client_turn_id: id, conversation_id: `CONV-${id}`, execution_id: null, task_id: null, spec_id: specId, prd_id: prdId, change_id: null, parent_run_id: null, continuation_of_run_id: null, retry_of_run_id: null, agent_invocation_id: `AINV-${id}`, root_agent_invocation_id: `AINV-${id}`, parent_agent_invocation_id: null, invocation_kind: "orchestrator", delegation_depth: 0 },
1424
- { schema_version: 2, event_id: `${id}:2`, run_id: id, sequence: 2, occurred_at: "2026-08-12T12:01:00.000Z", type: "usage.recorded", phase: "planning", activity_kind: "model_usage", classification_source: "explicit", tokens: { input: tokens, cached_input: 0, output: 0, reasoning: 0, total: tokens, source: "provider_reported" }, cost: { usd: cost / 5, brl: cost, fx_rate: 5 }, provider: "openai", model: "gpt-5", source_segment_key: id, model_call_id: `MCALL-${id}`, runtime: { reasoning_effort: null, service_tier: null }, supersedes_event_id: null, duration_ms: null, duration_provenance: null },
1425
- { schema_version: 2, event_id: `${id}:3`, run_id: id, sequence: 3, occurred_at: "2026-08-12T12:02:00.000Z", type: "run.finished", phase: "planning", status: "completed", duration_ms: duration, duration_provenance: "observed" },
2175
+ await writeFile(
2176
+ join(root, ".agents", "records", "prds", "2026", "08", `${id}.md`),
2177
+ item(id, "active"),
2178
+ "utf8",
2179
+ );
2180
+ const change = (id: string, taskId: string, specId: string | null, prdId: string | null) =>
2181
+ `---\nid: ${id}\ntitle: ${id}\nstatus: planned\nrisk: standard\nsource:\n type: ${prdId === null ? "task" : "prd"}\n ${prdId === null ? `task_id: ${taskId}` : `prd_id: ${prdId}`}\n${specId === null ? "" : ` spec_id: ${specId}\n`}task_ids:\n - ${taskId}\ncreated_at: 2026-08-12T12:00:00.000Z\n---\n# ${id}\n`;
2182
+ await writeFile(
2183
+ join(root, ".agents", "records", "changes", "2026", "08", "CHG-UNIQUE", "change.md"),
2184
+ change("CHG-UNIQUE", "TASK-UNIQUE", "SPEC-UNIQUE", "PRD-UNIQUE"),
2185
+ "utf8",
2186
+ );
2187
+ await writeFile(
2188
+ join(root, ".agents", "records", "changes", "2026", "08", "CHG-SHARED-A", "change.md"),
2189
+ change("CHG-SHARED-A", "TASK-SHARED-A", "SPEC-SHARED", "PRD-SHARED"),
2190
+ "utf8",
2191
+ );
2192
+ await writeFile(
2193
+ join(root, ".agents", "records", "changes", "2026", "08", "CHG-SHARED-B", "change.md"),
2194
+ change("CHG-SHARED-B", "TASK-SHARED-B", "SPEC-SHARED", "PRD-SHARED"),
2195
+ "utf8",
2196
+ );
2197
+ await writeFile(
2198
+ join(root, ".agents", "records", "changes", "2026", "08", "CHG-PRD-ONLY", "change.md"),
2199
+ change("CHG-PRD-ONLY", "TASK-PRD-ONLY", null, "PRD-ONLY"),
2200
+ "utf8",
2201
+ );
2202
+ await writeFile(
2203
+ join(root, ".agents", "records", "changes", "2026", "08", "CHG-NO-MACRO", "change.md"),
2204
+ change("CHG-NO-MACRO", "TASK-NO-MACRO", null, null),
2205
+ "utf8",
2206
+ );
2207
+ const run = (
2208
+ id: string,
2209
+ specId: string | null,
2210
+ prdId: string | null,
2211
+ tokens: number,
2212
+ cost: number,
2213
+ duration: number,
2214
+ ) => [
2215
+ {
2216
+ schema_version: 2,
2217
+ event_id: `${id}:1`,
2218
+ run_id: id,
2219
+ sequence: 1,
2220
+ occurred_at: "2026-08-12T12:00:00.000Z",
2221
+ type: "run.started",
2222
+ attribution_status: "attributed",
2223
+ phase: "planning",
2224
+ run_role: "orchestrator",
2225
+ run_purpose: "orchestration",
2226
+ requires_finalizer: false,
2227
+ execution_kind: "interaction",
2228
+ execution_eligibility: [],
2229
+ entrypoint: specId === null ? (prdId === null ? "conversation" : "prd") : "spec",
2230
+ work_type: "new",
2231
+ storage_mode: "tracked_sanitized",
2232
+ client: "codex",
2233
+ agent: "agent",
2234
+ agent_name: "agent",
2235
+ provider: "openai",
2236
+ model: "gpt-5",
2237
+ reasoning_effort: null,
2238
+ client_thread_id: id,
2239
+ client_turn_id: id,
2240
+ conversation_id: `CONV-${id}`,
2241
+ execution_id: null,
2242
+ task_id: null,
2243
+ spec_id: specId,
2244
+ prd_id: prdId,
2245
+ change_id: null,
2246
+ parent_run_id: null,
2247
+ continuation_of_run_id: null,
2248
+ retry_of_run_id: null,
2249
+ agent_invocation_id: `AINV-${id}`,
2250
+ root_agent_invocation_id: `AINV-${id}`,
2251
+ parent_agent_invocation_id: null,
2252
+ invocation_kind: "orchestrator",
2253
+ delegation_depth: 0,
2254
+ },
2255
+ {
2256
+ schema_version: 2,
2257
+ event_id: `${id}:2`,
2258
+ run_id: id,
2259
+ sequence: 2,
2260
+ occurred_at: "2026-08-12T12:01:00.000Z",
2261
+ type: "usage.recorded",
2262
+ phase: "planning",
2263
+ activity_kind: "model_usage",
2264
+ classification_source: "explicit",
2265
+ tokens: {
2266
+ input: tokens,
2267
+ cached_input: 0,
2268
+ output: 0,
2269
+ reasoning: 0,
2270
+ total: tokens,
2271
+ source: "provider_reported",
2272
+ },
2273
+ cost: { usd: cost / 5, brl: cost, fx_rate: 5 },
2274
+ provider: "openai",
2275
+ model: "gpt-5",
2276
+ source_segment_key: id,
2277
+ model_call_id: `MCALL-${id}`,
2278
+ runtime: { reasoning_effort: null, service_tier: null },
2279
+ supersedes_event_id: null,
2280
+ duration_ms: null,
2281
+ duration_provenance: null,
2282
+ },
2283
+ {
2284
+ schema_version: 2,
2285
+ event_id: `${id}:3`,
2286
+ run_id: id,
2287
+ sequence: 3,
2288
+ occurred_at: "2026-08-12T12:02:00.000Z",
2289
+ type: "run.finished",
2290
+ phase: "planning",
2291
+ status: "completed",
2292
+ duration_ms: duration,
2293
+ duration_provenance: "observed",
2294
+ },
1426
2295
  ];
1427
- for (const [id, specId, prdId, tokens, cost, duration] of [["RUN-UNIQUE", "SPEC-UNIQUE", "PRD-UNIQUE", 7, 3, 120_000], ["RUN-SHARED", "SPEC-SHARED", "PRD-SHARED", 11, 5, 60_000], ["RUN-PRD-ONLY", null, "PRD-ONLY", 13, 6, 90_000], ["RUN-NO-MACRO", null, null, 17, 8, 30_000]] as const)
1428
- await writeFile(join(root, ".agents", "records", "runs", "2026", "08", `${id}.jsonl`), `${run(id, specId, prdId, tokens, cost, duration).map((record) => JSON.stringify(record)).join("\n")}\n`, "utf8");
2296
+ for (const [id, specId, prdId, tokens, cost, duration] of [
2297
+ ["RUN-UNIQUE", "SPEC-UNIQUE", "PRD-UNIQUE", 7, 3, 120_000],
2298
+ ["RUN-SHARED", "SPEC-SHARED", "PRD-SHARED", 11, 5, 60_000],
2299
+ ["RUN-PRD-ONLY", null, "PRD-ONLY", 13, 6, 90_000],
2300
+ ["RUN-NO-MACRO", null, null, 17, 8, 30_000],
2301
+ ] as const)
2302
+ await writeFile(
2303
+ join(root, ".agents", "records", "runs", "2026", "08", `${id}.jsonl`),
2304
+ `${run(id, specId, prdId, tokens, cost, duration)
2305
+ .map((record) => JSON.stringify(record))
2306
+ .join("\n")}\n`,
2307
+ "utf8",
2308
+ );
1429
2309
  await rebuildSqliteReadModel(root);
1430
2310
  const filesystem = new SqliteReadModelFileSystem(root);
1431
2311
  const tasks = filesystem.summaryPage("task", { from: null, to: null }, 0, 10).rows;
1432
- expect(tasks).toContainEqual(expect.objectContaining({ id: "TASK-UNIQUE", invocation_count: 1, total_duration: 62_500, total_tokens: 7, total_cost_brl: 3 }));
1433
- expect(tasks).toContainEqual(expect.objectContaining({ id: "TASK-SHARED-A", invocation_count: null, total_duration: null, total_tokens: null, total_cost_brl: null }));
1434
- expect(tasks).toContainEqual(expect.objectContaining({ id: "TASK-SHARED-B", invocation_count: null, total_duration: null, total_tokens: null, total_cost_brl: null }));
1435
- expect(tasks).toContainEqual(expect.objectContaining({ id: "TASK-PRD-ONLY", invocation_count: 1, total_duration: 32_500, total_tokens: 13, total_cost_brl: 6 }));
1436
- expect(tasks).toContainEqual(expect.objectContaining({ id: "TASK-NO-MACRO", invocation_count: null, total_duration: null, total_tokens: null, total_cost_brl: null }));
2312
+ expect(tasks).toContainEqual(
2313
+ expect.objectContaining({
2314
+ id: "TASK-UNIQUE",
2315
+ invocation_count: 1,
2316
+ total_duration: 62_500,
2317
+ total_tokens: 7,
2318
+ total_cost_brl: 3,
2319
+ }),
2320
+ );
2321
+ expect(tasks).toContainEqual(
2322
+ expect.objectContaining({
2323
+ id: "TASK-SHARED-A",
2324
+ invocation_count: null,
2325
+ total_duration: null,
2326
+ total_tokens: null,
2327
+ total_cost_brl: null,
2328
+ }),
2329
+ );
2330
+ expect(tasks).toContainEqual(
2331
+ expect.objectContaining({
2332
+ id: "TASK-SHARED-B",
2333
+ invocation_count: null,
2334
+ total_duration: null,
2335
+ total_tokens: null,
2336
+ total_cost_brl: null,
2337
+ }),
2338
+ );
2339
+ expect(tasks).toContainEqual(
2340
+ expect.objectContaining({
2341
+ id: "TASK-PRD-ONLY",
2342
+ invocation_count: 1,
2343
+ total_duration: 32_500,
2344
+ total_tokens: 13,
2345
+ total_cost_brl: 6,
2346
+ }),
2347
+ );
2348
+ expect(tasks).toContainEqual(
2349
+ expect.objectContaining({
2350
+ id: "TASK-NO-MACRO",
2351
+ invocation_count: null,
2352
+ total_duration: null,
2353
+ total_tokens: null,
2354
+ total_cost_brl: null,
2355
+ }),
2356
+ );
1437
2357
  filesystem.close();
1438
2358
  });
1439
2359
 
@@ -1448,18 +2368,28 @@ created_at: 2026-08-10T11:01:00.000Z
1448
2368
  { recursive: true },
1449
2369
  );
1450
2370
  await mkdir(
1451
- join(root, ".agents", "records", "changes", "2026", "08", "CHG-ART", "artifacts", "validations"),
2371
+ join(
2372
+ root,
2373
+ ".agents",
2374
+ "records",
2375
+ "changes",
2376
+ "2026",
2377
+ "08",
2378
+ "CHG-ART",
2379
+ "artifacts",
2380
+ "validations",
2381
+ ),
1452
2382
  { recursive: true },
1453
2383
  );
1454
2384
  await mkdir(join(root, ".agents", "config"), { recursive: true });
1455
2385
  await writeFile(
1456
2386
  join(root, ".agents", "config", "project.yaml"),
1457
- "schema_version: 1\nzaip:\n enabled: true\nproject:\n id: sqlite-test\n name: sqlite-test\n timezone: UTC\nstack:\n id: zaip-aios-stack\n overrides: {}\nclients:\n codex: true\n claude: true\ntracking:\n enabled: true\n currency: BRL\n storage_mode: tracked_sanitized\n",
2387
+ "schema_version: 1\nzaip:\n enabled: true\nproject:\n id: sqlite-test\n name: sqlite-test\n timezone: UTC\nstack:\n id: zaip-aios-stack\n overrides: {}\nclients:\n codex: true\n claude: true\ntracking:\n enabled: true\n currency: BRL\n storage_mode: tracked_sanitized\n",
1458
2388
  "utf8",
1459
2389
  );
1460
2390
  await writeFile(
1461
2391
  join(root, ".agents", "config", "framework.lock.yaml"),
1462
- "lock_version: 1\nframework:\n version: 1.0.8\n distribution_sha256: null\nlayout:\n version: 3\nresolved_profile:\n id: null\n sha256: null\nmanaged_files: {}\n",
2392
+ "lock_version: 1\nframework:\n version: 1.3.0\n distribution_sha256: null\nlayout:\n version: 3\nresolved_profile:\n id: null\n sha256: null\nmanaged_files: {}\n",
1463
2393
  "utf8",
1464
2394
  );
1465
2395
  const run = (
@@ -1553,9 +2483,18 @@ created_at: 2026-08-10T11:01:00.000Z
1553
2483
  },
1554
2484
  ];
1555
2485
  for (const [id, records] of [
1556
- ["RUN-R1", run("RUN-R1", "2026-08-01", "TASK-A", 600_000, "12:00:00.000Z", "SPEC-A", "PRD-A")],
1557
- ["RUN-R2", run("RUN-R2", "2026-08-02", "TASK-B", 1_200_000, "12:00:00.000Z", "SPEC-B", "PRD-A")],
1558
- ["RUN-R3", run("RUN-R3", "2026-08-02", "TASK-B", 1_200_000, "12:10:00.000Z", "SPEC-B", "PRD-A")],
2486
+ [
2487
+ "RUN-R1",
2488
+ run("RUN-R1", "2026-08-01", "TASK-A", 600_000, "12:00:00.000Z", "SPEC-A", "PRD-A"),
2489
+ ],
2490
+ [
2491
+ "RUN-R2",
2492
+ run("RUN-R2", "2026-08-02", "TASK-B", 1_200_000, "12:00:00.000Z", "SPEC-B", "PRD-A"),
2493
+ ],
2494
+ [
2495
+ "RUN-R3",
2496
+ run("RUN-R3", "2026-08-02", "TASK-B", 1_200_000, "12:10:00.000Z", "SPEC-B", "PRD-A"),
2497
+ ],
1559
2498
  ] as const) {
1560
2499
  await writeFile(
1561
2500
  join(root, ".agents", "records", "runs", "2026", "08", `${id}.jsonl`),
@@ -1564,16 +2503,42 @@ created_at: 2026-08-10T11:01:00.000Z
1564
2503
  );
1565
2504
  }
1566
2505
  await writeFile(
1567
- join(root, ".agents", "records", "changes", "2026", "08", "CHG-ART", "artifacts", "evidence", "EVD-1.md"),
2506
+ join(
2507
+ root,
2508
+ ".agents",
2509
+ "records",
2510
+ "changes",
2511
+ "2026",
2512
+ "08",
2513
+ "CHG-ART",
2514
+ "artifacts",
2515
+ "evidence",
2516
+ "EVD-1.md",
2517
+ ),
1568
2518
  "---\nid: EVD-1\nobserved_at: 2026-08-01T12:00:00.000Z\n---\n# Evidence\n",
1569
2519
  "utf8",
1570
2520
  );
1571
2521
  await writeFile(
1572
- join(root, ".agents", "records", "changes", "2026", "08", "CHG-ART", "artifacts", "validations", "VAL-1.md"),
2522
+ join(
2523
+ root,
2524
+ ".agents",
2525
+ "records",
2526
+ "changes",
2527
+ "2026",
2528
+ "08",
2529
+ "CHG-ART",
2530
+ "artifacts",
2531
+ "validations",
2532
+ "VAL-1.md",
2533
+ ),
1573
2534
  "---\nid: VAL-1\nexecuted_at: 2026-08-02T12:00:00.000Z\n---\n# Validation\n",
1574
2535
  "utf8",
1575
2536
  );
1576
- for (const [kind, id] of [["tasks", "TASK-NO-RUN"], ["specs", "SPEC-NO-RUN"], ["prds", "PRD-NO-RUN"]] as const)
2537
+ for (const [kind, id] of [
2538
+ ["tasks", "TASK-NO-RUN"],
2539
+ ["specs", "SPEC-NO-RUN"],
2540
+ ["prds", "PRD-NO-RUN"],
2541
+ ] as const)
1577
2542
  await writeFile(
1578
2543
  join(root, ".agents", "records", kind, "2026", "08", `${id}.md`),
1579
2544
  `---\nid: ${id}\ntitle: ${id}\nstatus: draft\ncreated_at: 2026-08-03T12:00:00.000Z\n---\n# ${id}\n`,
@@ -1624,6 +2589,7 @@ created_at: 2026-08-10T11:01:00.000Z
1624
2589
  }),
1625
2590
  );
1626
2591
  const allTime = filesystem.firstFoldAllTime();
2592
+ expectPersistedFirstFoldCaches(root, allTime, filesystem.firstFoldBoardAllTime());
1627
2593
  expect(allTime.aggregate).toMatchObject({
1628
2594
  start_day: "2026-08-01",
1629
2595
  end_day: "2026-08-03",
@@ -1710,7 +2676,11 @@ created_at: 2026-08-10T11:01:00.000Z
1710
2676
  { headers: { "x-zaip-session": "test-session" } },
1711
2677
  );
1712
2678
  const nextMonth = (await nextMonthQuick.json()) as {
1713
- summary: { run_count: number; task_count: number; overview_metrics: { tokens: number | null; duration_ms: number | null } };
2679
+ summary: {
2680
+ run_count: number;
2681
+ task_count: number;
2682
+ overview_metrics: { tokens: number | null; duration_ms: number | null };
2683
+ };
1714
2684
  };
1715
2685
  expect(nextMonth.summary).toMatchObject({
1716
2686
  run_count: 0,
@@ -1808,9 +2778,21 @@ created_at: 2026-08-10T11:01:00.000Z
1808
2778
  ]);
1809
2779
  }
1810
2780
  for (const [view, key, counts] of [
1811
- ["cost_monitor_daily", "2026-08-02", { prd_count: 0, spec_count: 1, task_count: 1, validation_count: 1, evidence_count: 0 }],
1812
- ["cost_monitor_monthly", "2026-08", { prd_count: 2, spec_count: 3, task_count: 3, validation_count: 1, evidence_count: 1 }],
1813
- ["cost_monitor_annual", "2026", { prd_count: 2, spec_count: 3, task_count: 3, validation_count: 1, evidence_count: 1 }],
2781
+ [
2782
+ "cost_monitor_daily",
2783
+ "2026-08-02",
2784
+ { prd_count: 0, spec_count: 1, task_count: 1, validation_count: 1, evidence_count: 0 },
2785
+ ],
2786
+ [
2787
+ "cost_monitor_monthly",
2788
+ "2026-08",
2789
+ { prd_count: 2, spec_count: 3, task_count: 3, validation_count: 1, evidence_count: 1 },
2790
+ ],
2791
+ [
2792
+ "cost_monitor_annual",
2793
+ "2026",
2794
+ { prd_count: 2, spec_count: 3, task_count: 3, validation_count: 1, evidence_count: 1 },
2795
+ ],
1814
2796
  ] as const) {
1815
2797
  expect(filesystem.viewPage(view, { limit: 50 }).rows).toContainEqual(
1816
2798
  expect.objectContaining({ key, ...counts }),
@@ -1828,7 +2810,10 @@ created_at: 2026-08-10T11:01:00.000Z
1828
2810
  const annualCostPage = filesystem.viewPage("cost_monitor_annual", { limit: 50 });
1829
2811
  const dailyCostRows = filesystem.viewPage("cost_monitor_daily", { limit: 50 }).rows;
1830
2812
  const pagedDailyCostPage = filesystem.viewPage("cost_monitor_daily", { limit: 1 });
1831
- expect(pagedDailyCostPage).toMatchObject({ total_count: dailyCostRows.length, rows: [expect.any(Object)] });
2813
+ expect(pagedDailyCostPage).toMatchObject({
2814
+ total_count: dailyCostRows.length,
2815
+ rows: [expect.any(Object)],
2816
+ });
1832
2817
  expect(pagedDailyCostPage.totals).toMatchObject({
1833
2818
  total_tokens: dailyCostRows.reduce((sum, row) => sum + Number(row.total_tokens ?? 0), 0),
1834
2819
  total_cost_brl: dailyCostRows.reduce((sum, row) => sum + Number(row.total_cost_brl ?? 0), 0),
@@ -1841,9 +2826,17 @@ created_at: 2026-08-10T11:01:00.000Z
1841
2826
  const annualCostRow = annualCostPage.rows[0];
1842
2827
  if (annualCostRow === undefined) throw new Error("Expected the consolidated 2026 Cost row");
1843
2828
  for (const metric of [
1844
- "prd_count", "spec_count", "task_count", "validation_count", "evidence_count",
1845
- "total_run_count", "total_duration", "duration_known",
1846
- "total_tokens", "total_cost_usd", "total_cost_brl",
2829
+ "prd_count",
2830
+ "spec_count",
2831
+ "task_count",
2832
+ "validation_count",
2833
+ "evidence_count",
2834
+ "total_run_count",
2835
+ "total_duration",
2836
+ "duration_known",
2837
+ "total_tokens",
2838
+ "total_cost_usd",
2839
+ "total_cost_brl",
1847
2840
  ] as const) {
1848
2841
  const observed = dailyCostRows
1849
2842
  .map((row) => row[metric])
@@ -1883,7 +2876,14 @@ created_at: 2026-08-10T11:01:00.000Z
1883
2876
  total_cost_brl: 15,
1884
2877
  });
1885
2878
  }
1886
- expect(filesystem.viewPage("cost_monitor_tasks", { from: "2026-08-02", to: "2026-08-02", query: "TASK-B", limit: 1 }).totals).toEqual({
2879
+ expect(
2880
+ filesystem.viewPage("cost_monitor_tasks", {
2881
+ from: "2026-08-02",
2882
+ to: "2026-08-02",
2883
+ query: "TASK-B",
2884
+ limit: 1,
2885
+ }).totals,
2886
+ ).toEqual({
1887
2887
  entity_count: 1,
1888
2888
  invocation_count: 2,
1889
2889
  total_duration: 1_800_000,
@@ -1894,24 +2894,75 @@ created_at: 2026-08-10T11:01:00.000Z
1894
2894
  // The compact Cost Monitor tables share the canonical macro population
1895
2895
  // with their big numbers. A macro with no direct invocation must remain
1896
2896
  // paginable and retain unavailable financial facts as null.
1897
- expect(filesystem.viewPage("cost_monitor_specs", { query: "SPEC-NO-RUN", limit: 1 })).toMatchObject({
2897
+ expect(
2898
+ filesystem.viewPage("cost_monitor_specs", { query: "SPEC-NO-RUN", limit: 1 }),
2899
+ ).toMatchObject({
1898
2900
  total_count: 1,
1899
- totals: { entity_count: 1, invocation_count: 0, total_duration: null, total_tokens: null, total_cost_brl: null },
1900
- rows: [expect.objectContaining({ id: "SPEC-NO-RUN", title: "SPEC-NO-RUN", invocation_count: 0, total_duration: null, total_tokens: null, total_cost_brl: null })],
2901
+ totals: {
2902
+ entity_count: 1,
2903
+ invocation_count: 0,
2904
+ total_duration: null,
2905
+ total_tokens: null,
2906
+ total_cost_brl: null,
2907
+ },
2908
+ rows: [
2909
+ expect.objectContaining({
2910
+ id: "SPEC-NO-RUN",
2911
+ title: "SPEC-NO-RUN",
2912
+ invocation_count: 0,
2913
+ total_duration: null,
2914
+ total_tokens: null,
2915
+ total_cost_brl: null,
2916
+ }),
2917
+ ],
1901
2918
  });
1902
- expect(filesystem.viewPage("cost_monitor_prds", { query: "PRD-NO-RUN", limit: 1 })).toMatchObject({
2919
+ expect(
2920
+ filesystem.viewPage("cost_monitor_prds", { query: "PRD-NO-RUN", limit: 1 }),
2921
+ ).toMatchObject({
1903
2922
  total_count: 1,
1904
- totals: { entity_count: 1, invocation_count: 0, total_duration: null, total_tokens: null, total_cost_brl: null },
1905
- rows: [expect.objectContaining({ id: "PRD-NO-RUN", title: "PRD-NO-RUN", invocation_count: 0, total_duration: null, total_tokens: null, total_cost_brl: null })],
2923
+ totals: {
2924
+ entity_count: 1,
2925
+ invocation_count: 0,
2926
+ total_duration: null,
2927
+ total_tokens: null,
2928
+ total_cost_brl: null,
2929
+ },
2930
+ rows: [
2931
+ expect.objectContaining({
2932
+ id: "PRD-NO-RUN",
2933
+ title: "PRD-NO-RUN",
2934
+ invocation_count: 0,
2935
+ total_duration: null,
2936
+ total_tokens: null,
2937
+ total_cost_brl: null,
2938
+ }),
2939
+ ],
1906
2940
  });
1907
- for (const view of ["cost_monitor_tasks", "cost_monitor_specs", "cost_monitor_prds", "cost_monitor_conversations"] as const) {
1908
- const filtered = filesystem.viewPage(view, { phase: "execution", provider: "openai", model: "gpt-5", limit: 1 });
2941
+ for (const view of [
2942
+ "cost_monitor_tasks",
2943
+ "cost_monitor_specs",
2944
+ "cost_monitor_prds",
2945
+ "cost_monitor_conversations",
2946
+ ] as const) {
2947
+ const filtered = filesystem.viewPage(view, {
2948
+ phase: "execution",
2949
+ provider: "openai",
2950
+ model: "gpt-5",
2951
+ limit: 1,
2952
+ });
1909
2953
  // Dimensional membership and the subtotal share one pre-pagination
1910
2954
  // invocation population for every compact lifecycle view.
1911
2955
  expect(filtered.rows).toHaveLength(1);
1912
- expect(filtered.totals).toMatchObject({ invocation_count: 3, total_tokens: 6, total_cost_brl: 15 });
2956
+ expect(filtered.totals).toMatchObject({
2957
+ invocation_count: 3,
2958
+ total_tokens: 6,
2959
+ total_cost_brl: 15,
2960
+ });
1913
2961
  }
1914
- expect(filesystem.viewPage("cost_monitor_tasks", { workType: "new", limit: 1 })).toMatchObject({ total_count: 0, rows: [] });
2962
+ expect(filesystem.viewPage("cost_monitor_tasks", { workType: "new", limit: 1 })).toMatchObject({
2963
+ total_count: 0,
2964
+ rows: [],
2965
+ });
1915
2966
  expect(filesystem.firstFoldAllTime()).toBe(allTime);
1916
2967
  filesystem.close();
1917
2968
 
@@ -1925,26 +2976,61 @@ created_at: 2026-08-10T11:01:00.000Z
1925
2976
  );
1926
2977
  await writeFile(
1927
2978
  join(root, ".agents", "records", "runs", "2026", "08", "RUN-CANONICAL-DAY.jsonl"),
1928
- `${run("RUN-CANONICAL-DAY", "2026-08-02", "TASK-CANONICAL-DAY", 1_000, "12:30:00.000Z", "SPEC-CANONICAL-DAY").map((record) => JSON.stringify(record)).join("\n")}\n`,
2979
+ `${run(
2980
+ "RUN-CANONICAL-DAY",
2981
+ "2026-08-02",
2982
+ "TASK-CANONICAL-DAY",
2983
+ 1_000,
2984
+ "12:30:00.000Z",
2985
+ "SPEC-CANONICAL-DAY",
2986
+ )
2987
+ .map((record) => JSON.stringify(record))
2988
+ .join("\n")}\n`,
1929
2989
  "utf8",
1930
2990
  );
1931
2991
  await writeFile(
1932
2992
  join(root, ".agents", "records", "runs", "2026", "08", "RUN-CANONICAL-DAY-LATE.jsonl"),
1933
- `${run("RUN-CANONICAL-DAY-LATE", "2026-08-04", "TASK-CANONICAL-DAY-LATE", 1_000, "12:30:00.000Z", "SPEC-CANONICAL-DAY").map((record) => JSON.stringify(record)).join("\n")}\n`,
2993
+ `${run(
2994
+ "RUN-CANONICAL-DAY-LATE",
2995
+ "2026-08-04",
2996
+ "TASK-CANONICAL-DAY-LATE",
2997
+ 1_000,
2998
+ "12:30:00.000Z",
2999
+ "SPEC-CANONICAL-DAY",
3000
+ )
3001
+ .map((record) => JSON.stringify(record))
3002
+ .join("\n")}\n`,
1934
3003
  "utf8",
1935
3004
  );
1936
3005
  await rebuildSqliteReadModel(root);
1937
3006
  const canonicalDayFilesystem = new SqliteReadModelFileSystem(root);
1938
- expect(canonicalDayFilesystem.viewPage("cost_monitor_specs", {
1939
- from: "2026-08-03", to: "2026-08-03", query: "canonical title", limit: 1,
1940
- })).toMatchObject({
3007
+ expect(
3008
+ canonicalDayFilesystem.viewPage("cost_monitor_specs", {
3009
+ from: "2026-08-03",
3010
+ to: "2026-08-03",
3011
+ query: "canonical title",
3012
+ limit: 1,
3013
+ }),
3014
+ ).toMatchObject({
1941
3015
  total_count: 1,
1942
3016
  totals: { entity_count: 1, invocation_count: 0, total_tokens: null, total_cost_brl: null },
1943
- rows: [expect.objectContaining({ id: "SPEC-CANONICAL-DAY", invocation_count: 0, total_tokens: null, total_cost_brl: null })],
3017
+ rows: [
3018
+ expect.objectContaining({
3019
+ id: "SPEC-CANONICAL-DAY",
3020
+ invocation_count: 0,
3021
+ total_tokens: null,
3022
+ total_cost_brl: null,
3023
+ }),
3024
+ ],
1944
3025
  });
1945
- expect(canonicalDayFilesystem.viewPage("cost_monitor_specs", {
1946
- from: "2026-08-02", to: "2026-08-02", query: "SPEC-CANONICAL-DAY", limit: 1,
1947
- })).toMatchObject({ total_count: 0, rows: [] });
3026
+ expect(
3027
+ canonicalDayFilesystem.viewPage("cost_monitor_specs", {
3028
+ from: "2026-08-02",
3029
+ to: "2026-08-02",
3030
+ query: "SPEC-CANONICAL-DAY",
3031
+ limit: 1,
3032
+ }),
3033
+ ).toMatchObject({ total_count: 0, rows: [] });
1948
3034
  canonicalDayFilesystem.close();
1949
3035
 
1950
3036
  // A large result set keeps its subtotal for all 270 matching Tasks while
@@ -1953,7 +3039,9 @@ created_at: 2026-08-10T11:01:00.000Z
1953
3039
  const id = `RUN-PAGE-${index}`;
1954
3040
  await writeFile(
1955
3041
  join(root, ".agents", "records", "runs", "2026", "08", `${id}.jsonl`),
1956
- `${run(id, "2026-08-04", `TASK-PAGE-${index}`, 1_000).map((record) => JSON.stringify(record)).join("\n")}\n`,
3042
+ `${run(id, "2026-08-04", `TASK-PAGE-${index}`, 1_000)
3043
+ .map((record) => JSON.stringify(record))
3044
+ .join("\n")}\n`,
1957
3045
  "utf8",
1958
3046
  );
1959
3047
  }