@zaip-ai/cli 2.2.0 → 2.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (420) hide show
  1. package/dist/services/adapters.d.ts +1 -1
  2. package/dist/services/adapters.d.ts.map +1 -1
  3. package/dist/services/adapters.js +23 -9
  4. package/dist/services/adapters.js.map +1 -1
  5. package/dist/services/agent-adapters.js +25 -9
  6. package/dist/services/agent-adapters.js.map +1 -1
  7. package/dist/services/agent-discovery.d.ts +27 -0
  8. package/dist/services/agent-discovery.d.ts.map +1 -0
  9. package/dist/services/agent-discovery.js +73 -0
  10. package/dist/services/agent-discovery.js.map +1 -0
  11. package/dist/services/codex-conversation-lifecycle-hook.d.ts.map +1 -1
  12. package/dist/services/codex-conversation-lifecycle-hook.js +153 -24
  13. package/dist/services/codex-conversation-lifecycle-hook.js.map +1 -1
  14. package/dist/services/codex-pre-tool-hook-template.d.ts.map +1 -1
  15. package/dist/services/codex-pre-tool-hook-template.js +146 -72
  16. package/dist/services/codex-pre-tool-hook-template.js.map +1 -1
  17. package/dist/services/codex-rules.d.ts +1 -1
  18. package/dist/services/codex-rules.d.ts.map +1 -1
  19. package/dist/services/codex-rules.js +3 -3
  20. package/dist/services/codex-subagent-hook-template.d.ts +1 -1
  21. package/dist/services/codex-subagent-hook-template.d.ts.map +1 -1
  22. package/dist/services/codex-subagent-hook-template.js +117 -66
  23. package/dist/services/codex-subagent-hook-template.js.map +1 -1
  24. package/dist/services/install-agents-template.d.ts.map +1 -1
  25. package/dist/services/install-agents-template.js +56 -6
  26. package/dist/services/install-agents-template.js.map +1 -1
  27. package/dist/services/logger.js +1 -1
  28. package/dist/services/logger.js.map +1 -1
  29. package/dist/services/logger.test.js +22 -1
  30. package/dist/services/logger.test.js.map +1 -1
  31. package/dist/services/runtime-template.test.js +129 -0
  32. package/dist/services/runtime-template.test.js.map +1 -1
  33. package/package.json +1 -1
  34. package/templates/.agents/.env.example +9 -3
  35. package/templates/.agents/README-ENG.md +30 -5
  36. package/templates/.agents/README.md +30 -7
  37. package/templates/.agents/architecture/software-architecture.md +1 -59
  38. package/templates/.agents/branding/brandbook.md +3 -0
  39. package/templates/.agents/config/agents/catalog.yaml +22 -10
  40. package/templates/.agents/config/agents/discovery.json +319 -0
  41. package/templates/.agents/config/clients/codex/agents/zaip-agent-backend.toml +2 -2
  42. package/templates/.agents/config/clients/codex/agents/zaip-agent-builder.toml +2 -2
  43. package/templates/.agents/config/clients/codex/agents/zaip-agent-cloud-engineer.toml +11 -8
  44. package/templates/.agents/config/clients/codex/agents/zaip-agent-designer.toml +2 -2
  45. package/templates/.agents/config/clients/codex/agents/zaip-agent-frontend.toml +2 -2
  46. package/templates/.agents/config/clients/codex/agents/zaip-agent-task-executor.toml +2 -2
  47. package/templates/.agents/config/clients/codex/agents/zaip-agent-website-developer.toml +2 -2
  48. package/templates/.agents/config/pricing/models.json +9 -5
  49. package/templates/.agents/config/project.yaml +12 -1
  50. package/templates/.agents/dashboard/.zaip-managed.json +375 -95
  51. package/templates/.agents/dashboard/apps/frontend/dist/assets/CostCalculationGuidePage-CGxeQak4.js +1 -0
  52. package/templates/.agents/dashboard/apps/frontend/dist/assets/{DashboardHelpDialog-DaSllaJp.js → DashboardHelpDialog-tzS7YxYB.js} +57 -33
  53. package/templates/.agents/dashboard/apps/frontend/dist/assets/PricingSettingsDialog-DEbCi1gP.js +1 -0
  54. package/templates/.agents/dashboard/apps/frontend/dist/assets/ProjectSettingsPage-1L7Qw-Gq.js +3 -0
  55. package/templates/.agents/dashboard/apps/frontend/dist/assets/ProjectSettingsPage-EInWr641.css +1 -0
  56. package/templates/.agents/dashboard/apps/frontend/dist/assets/TraceabilityWorkspace-t1Om0Abw.js +1 -0
  57. package/templates/.agents/dashboard/apps/frontend/dist/assets/cost-monitor-B6aZfo5f.js +68 -0
  58. package/templates/.agents/dashboard/apps/frontend/dist/assets/{icons-vendor-TPUT2IUt.js → icons-vendor-DiGC-dsJ.js} +1 -1
  59. package/templates/.agents/dashboard/apps/frontend/dist/assets/index-DgTmNHN5.js +2 -0
  60. package/templates/.agents/dashboard/apps/frontend/dist/assets/{react-vendor-Ct48XHGL.js → react-vendor-kPO6yNed.js} +1 -1
  61. package/templates/.agents/dashboard/apps/frontend/dist/assets/rolldown-runtime-Bh1tDfsg.js +1 -0
  62. package/templates/.agents/dashboard/apps/frontend/dist/assets/traceability-DQpKX9c1.js +1 -0
  63. package/templates/.agents/dashboard/apps/frontend/dist/index.html +6 -6
  64. package/templates/.agents/dashboard/apps/frontend/package.json +1 -1
  65. package/templates/.agents/dashboard/apps/frontend/src/App.tsx +3 -1264
  66. package/templates/.agents/dashboard/apps/frontend/src/AppDashboardContent.tsx +363 -0
  67. package/templates/.agents/dashboard/apps/frontend/src/ProjectSettingsPage.dom.test.ts +99 -0
  68. package/templates/.agents/dashboard/apps/frontend/src/ProjectSettingsPage.tsx +62 -6
  69. package/templates/.agents/dashboard/apps/frontend/src/ProjectStackEditor.tsx +3 -1
  70. package/templates/.agents/dashboard/apps/frontend/src/__tests__/app-composition-support.ts +7 -0
  71. package/templates/.agents/dashboard/apps/frontend/src/cost-period-refresh.test.ts +9 -7
  72. package/templates/.agents/dashboard/apps/frontend/src/dashboard-api-settings.ts +151 -0
  73. package/templates/.agents/dashboard/apps/frontend/src/dashboard-api.ts +28 -153
  74. package/templates/.agents/dashboard/apps/frontend/src/dashboard-app-shell.tsx +33 -0
  75. package/templates/.agents/dashboard/apps/frontend/src/dashboard-cost-facts.ts +30 -0
  76. package/templates/.agents/dashboard/apps/frontend/src/dashboard-project-overview.ts +7 -1
  77. package/templates/.agents/dashboard/apps/frontend/src/dashboard-retry.ts +17 -0
  78. package/templates/.agents/dashboard/apps/frontend/src/dashboard-setup-route.ts +29 -0
  79. package/templates/.agents/dashboard/apps/frontend/src/dashboard-view-actions.ts +66 -0
  80. package/templates/.agents/dashboard/apps/frontend/src/operations-period-render.test.ts +3 -2
  81. package/templates/.agents/dashboard/apps/frontend/src/overview-status-page.test.ts +2 -2
  82. package/templates/.agents/dashboard/apps/frontend/src/project-installation-status.test.ts +48 -0
  83. package/templates/.agents/dashboard/apps/frontend/src/project-installation-status.ts +29 -0
  84. package/templates/.agents/dashboard/apps/frontend/src/project-settings-page.css +68 -0
  85. package/templates/.agents/dashboard/apps/frontend/src/project-settings.test.ts +2 -2
  86. package/templates/.agents/dashboard/apps/frontend/src/sao-paulo-day-rollover.test.ts +36 -0
  87. package/templates/.agents/dashboard/apps/frontend/src/sao-paulo-day-rollover.ts +30 -0
  88. package/templates/.agents/dashboard/apps/frontend/src/snapshot-banner-semantics.test.ts +2 -5
  89. package/templates/.agents/dashboard/apps/frontend/src/snapshot-coherence.test.ts +30 -19
  90. package/templates/.agents/dashboard/apps/frontend/src/use-app-effects.ts +9 -1
  91. package/templates/.agents/dashboard/apps/frontend/src/use-app-trace-task-pagination.ts +77 -0
  92. package/templates/.agents/dashboard/apps/frontend/src/use-app-work-board.ts +397 -0
  93. package/templates/.agents/dashboard/apps/frontend/src/use-dashboard-app-model.tsx +782 -0
  94. package/templates/.agents/dashboard/apps/frontend/src/use-snapshot-notice.tsx +49 -0
  95. package/templates/.agents/dashboard/modules/cost-monitor/package.json +1 -1
  96. package/templates/.agents/dashboard/modules/cost-monitor/src/react/CostDeveloperPanelSlot.tsx +16 -0
  97. package/templates/.agents/dashboard/modules/cost-monitor/src/react/CostGroupsTable.tsx +459 -0
  98. package/templates/.agents/dashboard/modules/cost-monitor/src/react/CostMonitorPage.test.ts +27 -17
  99. package/templates/.agents/dashboard/modules/cost-monitor/src/react/CostMonitorPage.tsx +62 -186
  100. package/templates/.agents/dashboard/modules/cost-monitor/src/react/CostMonitorRunDialog.tsx +20 -0
  101. package/templates/.agents/dashboard/modules/cost-monitor/src/react/CostTables-hides-calls-that-have-no-collected.test.ts +80 -0
  102. package/templates/.agents/dashboard/modules/cost-monitor/src/react/CostTables-keeps-legacy-codex-identity-fields-blank.test.ts +455 -0
  103. package/templates/.agents/dashboard/modules/cost-monitor/src/react/CostTables.test.ts +18 -525
  104. package/templates/.agents/dashboard/modules/cost-monitor/src/react/CostTables.tsx +32 -508
  105. package/templates/.agents/dashboard/modules/cost-monitor/src/react/cost-monitor-export-sources.ts +74 -0
  106. package/templates/.agents/dashboard/modules/cost-monitor/src/react/cost-monitor-page-actions.ts +19 -0
  107. package/templates/.agents/dashboard/modules/cost-monitor/src/react/cost-monitor-page-selectors.ts +49 -0
  108. package/templates/.agents/dashboard/modules/cost-monitor/src/react/cost-table-formatters.ts +115 -0
  109. package/templates/.agents/dashboard/modules/cost-monitor/src/server/build-cost-monitor-projection.test-fixtures.ts +2 -0
  110. package/templates/.agents/dashboard/modules/operations/package.json +1 -1
  111. package/templates/.agents/dashboard/modules/operations/src/contracts.ts +4 -0
  112. package/templates/.agents/dashboard/modules/operations/src/react/EntityTableBadges.tsx +34 -0
  113. package/templates/.agents/dashboard/modules/operations/src/react/EntityTables.tsx +8 -38
  114. package/templates/.agents/dashboard/modules/operations/src/react/OperationsOverview-keeps-structure-classes-mutually-exclusive.test.ts +243 -0
  115. package/templates/.agents/dashboard/modules/operations/src/react/OperationsOverview.test.ts +27 -275
  116. package/templates/.agents/dashboard/modules/operations/src/react/OperationsOverview.tsx +70 -247
  117. package/templates/.agents/dashboard/modules/operations/src/react/OperationsOverviewCharts.tsx +171 -0
  118. package/templates/.agents/dashboard/modules/operations/src/react/OperationsOverviewPanels.tsx +64 -0
  119. package/templates/.agents/dashboard/modules/operations/src/react/OperationsPage.tsx +4 -3
  120. package/templates/.agents/dashboard/modules/operations/src/react/PrdDocumentDialog.test.tsx +2 -1
  121. package/templates/.agents/dashboard/modules/operations/src/react/manual-work-priority.test.ts +2 -1
  122. package/templates/.agents/dashboard/modules/operations/src/react/operations-coverage-toast.test.ts +6 -2
  123. package/templates/.agents/dashboard/modules/operations/src/react/operations-overview-period-filter.test.ts +6 -14
  124. package/templates/.agents/dashboard/modules/operations/src/react/operations-overview.status-cards.test.ts +3 -1
  125. package/templates/.agents/dashboard/modules/operations/src/react/operations-page-contract.ts +2 -0
  126. package/templates/.agents/dashboard/modules/operations/src/react/overview-metric-format.ts +32 -0
  127. package/templates/.agents/dashboard/modules/traceability/package.json +1 -1
  128. package/templates/.agents/dashboard/packages/branding/package.json +1 -1
  129. package/templates/.agents/dashboard/packages/branding/src/index.ts +1 -1
  130. package/templates/.agents/dashboard/packages/contracts/package.json +1 -1
  131. package/templates/.agents/dashboard/packages/data-export/package.json +1 -1
  132. package/templates/.agents/dashboard/packages/local-runtime/dist/server.cjs +1458 -1458
  133. package/templates/.agents/dashboard/packages/local-runtime/dist/sqlite-read-model.cjs +1425 -1425
  134. package/templates/.agents/dashboard/packages/local-runtime/package.json +2 -1
  135. package/templates/.agents/dashboard/packages/local-runtime/scripts/build-sqlite-runtime.mjs +7 -3
  136. package/templates/.agents/dashboard/packages/local-runtime/server.mjs +1458 -1459
  137. package/templates/.agents/dashboard/packages/local-runtime/src/active-codex-telemetry.ts +25 -0
  138. package/templates/.agents/dashboard/packages/local-runtime/src/agent-catalog-settings.test.ts +1 -1
  139. package/templates/.agents/dashboard/packages/local-runtime/src/project-settings.test.ts +53 -8
  140. package/templates/.agents/dashboard/packages/local-runtime/src/project-settings.ts +79 -24
  141. package/templates/.agents/dashboard/packages/local-runtime/src/projection-refresh-diagnostics.ts +35 -0
  142. package/templates/.agents/dashboard/packages/local-runtime/src/server-costs-routes.ts +168 -0
  143. package/templates/.agents/dashboard/packages/local-runtime/src/server-dual-reads-manifest-summaries-without-losing.test.ts +344 -0
  144. package/templates/.agents/dashboard/packages/local-runtime/src/server-http-contracts.ts +31 -0
  145. package/templates/.agents/dashboard/packages/local-runtime/src/server-operations-routes.ts +345 -0
  146. package/templates/.agents/dashboard/packages/local-runtime/src/server-read-projections.ts +461 -0
  147. package/templates/.agents/dashboard/packages/local-runtime/src/server-reconciliation-refresh.test.ts +78 -0
  148. package/templates/.agents/dashboard/packages/local-runtime/src/server-route-context.ts +13 -0
  149. package/templates/.agents/dashboard/packages/local-runtime/src/server-snapshot-synchronization.test.ts +18 -0
  150. package/templates/.agents/dashboard/packages/local-runtime/src/server-snapshot-synchronization.ts +19 -3
  151. package/templates/.agents/dashboard/packages/local-runtime/src/server-snapshot.test.ts +22 -21
  152. package/templates/.agents/dashboard/packages/local-runtime/src/server-sqlite-view-allowlist.test.ts +25 -0
  153. package/templates/.agents/dashboard/packages/local-runtime/src/server-trace-routes.ts +64 -0
  154. package/templates/.agents/dashboard/packages/local-runtime/src/server-work-reconciliation.test.ts +2 -30
  155. package/templates/.agents/dashboard/packages/local-runtime/src/server-work-reconciliation.ts +6 -23
  156. package/templates/.agents/dashboard/packages/local-runtime/src/server.test-fixtures.ts +1 -1
  157. package/templates/.agents/dashboard/packages/local-runtime/src/server.test.ts +2 -330
  158. package/templates/.agents/dashboard/packages/local-runtime/src/server.ts +73 -1060
  159. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-materialize-first-fold.ts +78 -0
  160. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-materialize-projections.ts +561 -0
  161. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-materialize-runs.ts +600 -0
  162. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-metric-contract.test.ts +1 -1
  163. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-query-agent-dimension.ts +269 -0
  164. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-query-context.ts +32 -0
  165. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-query-entity-group.ts +244 -0
  166. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-query-filtered-dimension.ts +292 -0
  167. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-query-financial.ts +547 -0
  168. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-query-model-dimension.ts +360 -0
  169. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-query-provider-dimension.ts +169 -0
  170. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-query-summary.ts +475 -0
  171. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-query-temporal-dimension.ts +132 -0
  172. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-query-timing.ts +299 -0
  173. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-query-view-page.ts +692 -0
  174. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-read-model-counts-every-root-execution-day-returns.test.ts +739 -0
  175. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-read-model-does-not-convert-delayed-historical-finalizer.test.ts +706 -0
  176. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-read-model-filesystem.ts +748 -0
  177. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-read-model-first-fold-types.ts +1 -1
  178. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-read-model-keeps-orphan-telemetry-out-kanban-without.test.ts +710 -0
  179. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-read-model-marks-token-cost-telemetry-unavailable-when.test.ts +618 -0
  180. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-read-model-rebuild.ts +755 -0
  181. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-read-model-rebuilds-disposable-snapshot-serves-zaip-records.test.ts +276 -0
  182. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-read-model-schema.ts +193 -0
  183. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-read-model-types.ts +123 -0
  184. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-read-model.test.ts +1 -2805
  185. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-read-model.ts +17 -6930
  186. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-schema-base-views.ts +385 -0
  187. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-schema-dashboard-views.ts +412 -0
  188. package/templates/.agents/dashboard/packages/local-runtime/src/work-priority-contract.test.ts +4 -3
  189. package/templates/.agents/dashboard/packages/local-runtime/start-dashboard-build.mjs +195 -0
  190. package/templates/.agents/dashboard/packages/local-runtime/start-dashboard-lifecycle.test.mjs +2 -7
  191. package/templates/.agents/dashboard/packages/local-runtime/start-dashboard-logging.mjs +35 -0
  192. package/templates/.agents/dashboard/packages/local-runtime/start-dashboard-navigation.mjs +114 -0
  193. package/templates/.agents/dashboard/packages/local-runtime/start-dashboard-paths.mjs +90 -0
  194. package/templates/.agents/dashboard/packages/local-runtime/start-dashboard.mjs +89 -418
  195. package/templates/.agents/dashboard/packages/local-runtime/start-dashboard.test.mjs +22 -12
  196. package/templates/.agents/dashboard/packages/ui/package.json +1 -1
  197. package/templates/.agents/dashboard/tests/e2e/package.json +1 -1
  198. package/templates/.agents/dashboard/tests/e2e/playwright.config.ts +4 -1
  199. package/templates/.agents/design/.zaip-managed.json +5 -5
  200. package/templates/.agents/design/DESIGN.md +2 -186
  201. package/templates/.agents/design/README.md +12 -2
  202. package/templates/.agents/design/apps/catalog/package.json +1 -1
  203. package/templates/.agents/design/packages/local-runtime/package.json +1 -1
  204. package/templates/.agents/growth/strategy.md +3 -0
  205. package/templates/.agents/marketing/strategy.md +3 -0
  206. package/templates/.agents/requirements/autonomous-assurance.md +2 -1
  207. package/templates/.agents/requirements/cloud-hostinger-autonomy.md +1 -1
  208. package/templates/.agents/requirements/comparative-audit.md +1 -1
  209. package/templates/.agents/requirements/context-engine.md +1 -1
  210. package/templates/.agents/requirements/cost-observability.md +1 -1
  211. package/templates/.agents/requirements/dashboard-launch.md +1 -1
  212. package/templates/.agents/requirements/data-export.md +1 -1
  213. package/templates/.agents/requirements/design-system.md +13 -4
  214. package/templates/.agents/requirements/execution-engine.md +1 -1
  215. package/templates/.agents/requirements/kanban-dashboard.md +1 -1
  216. package/templates/.agents/requirements/model-orchestration.md +1 -1
  217. package/templates/.agents/requirements/public-distribution.md +4 -2
  218. package/templates/.agents/requirements/software-architecture.md +1 -1
  219. package/templates/.agents/requirements/strategic-improvements.md +1 -1
  220. package/templates/.agents/requirements/work-lifecycle.md +3 -3
  221. package/templates/.agents/requirements/zaip-strategic-95.md +1 -1
  222. package/templates/.agents/rules/architecture.md +2 -0
  223. package/templates/.agents/rules/astra-diagnostic.md +1 -1
  224. package/templates/.agents/rules/autonomy-decision.md +3 -1
  225. package/templates/.agents/rules/cloud-hostinger-autonomy.md +2 -0
  226. package/templates/.agents/rules/context.md +2 -1
  227. package/templates/.agents/rules/core.md +3 -3
  228. package/templates/.agents/rules/design-system-central-contract.md +17 -0
  229. package/templates/.agents/rules/evolution.md +3 -1
  230. package/templates/.agents/rules/frontend-lite.md +3 -1
  231. package/templates/.agents/rules/local-sqlite-storage.md +2 -2
  232. package/templates/.agents/rules/meta-mcp.md +3 -1
  233. package/templates/.agents/rules/model-orchestration.md +1 -1
  234. package/templates/.agents/rules/run-lifecycle-closure.md +6 -4
  235. package/templates/.agents/rules/security.md +3 -1
  236. package/templates/.agents/rules/specialist-routing.md +3 -1
  237. package/templates/.agents/rules/text-writing-utf8.md +1 -1
  238. package/templates/.agents/rules/workflow.md +7 -5
  239. package/templates/.agents/runtime/VERSION +1 -1
  240. package/templates/.agents/runtime/bin/zaip.mjs +519 -247
  241. package/templates/.agents/runtime/checksums.sha256 +6 -6
  242. package/templates/.agents/runtime/manifest.json +1 -1
  243. package/templates/.agents/runtime/pnpm-lock.sha256 +1 -1
  244. package/templates/.agents/runtime/provenance.json +5 -5
  245. package/templates/.agents/runtime/sbom.cdx.json +1 -1
  246. package/templates/.agents/sales/playbook.md +3 -0
  247. package/templates/.agents/skills/zaip-aios/SKILL.md +5 -3
  248. package/templates/.agents/skills/zaip-skill-adapt-stack/SKILL.md +1 -0
  249. package/templates/.agents/skills/zaip-skill-api-contracts/SKILL.md +14 -0
  250. package/templates/.agents/skills/zaip-skill-api-contracts/agents/openai.yaml +4 -0
  251. package/templates/.agents/skills/zaip-skill-application-observability/SKILL.md +15 -0
  252. package/templates/.agents/skills/zaip-skill-application-observability/agents/openai.yaml +4 -0
  253. package/templates/.agents/skills/zaip-skill-application-observability/references/signal-design.md +3 -0
  254. package/templates/.agents/skills/zaip-skill-application-readiness/SKILL.md +15 -0
  255. package/templates/.agents/skills/zaip-skill-application-readiness/agents/openai.yaml +4 -0
  256. package/templates/.agents/skills/zaip-skill-application-readiness/references/evidence-matrix.md +3 -0
  257. package/templates/.agents/skills/zaip-skill-architecture-design/SKILL.md +14 -0
  258. package/templates/.agents/skills/zaip-skill-architecture-design/agents/openai.yaml +4 -0
  259. package/templates/.agents/skills/zaip-skill-async-jobs/SKILL.md +14 -0
  260. package/templates/.agents/skills/zaip-skill-async-jobs/agents/openai.yaml +4 -0
  261. package/templates/.agents/skills/zaip-skill-auth-tenancy/SKILL.md +15 -0
  262. package/templates/.agents/skills/zaip-skill-auth-tenancy/agents/openai.yaml +4 -0
  263. package/templates/.agents/skills/zaip-skill-auth-tenancy/references/data-access-paths.md +9 -0
  264. package/templates/.agents/skills/zaip-skill-auth-tenancy/references/worker-scenario.md +5 -0
  265. package/templates/.agents/skills/zaip-skill-auth-tenancy/scripts/worker-contract.test.mjs +27 -0
  266. package/templates/.agents/skills/zaip-skill-author-skills/SKILL.md +2 -0
  267. package/templates/.agents/skills/zaip-skill-author-skills/references/engineering-skill-index.md +9 -0
  268. package/templates/.agents/skills/zaip-skill-author-skills/scripts/audit-skill-catalog.mjs +5 -3
  269. package/templates/.agents/skills/zaip-skill-author-skills/scripts/author-skill-scripts.test.mjs +27 -0
  270. package/templates/.agents/skills/zaip-skill-backend/SKILL.md +4 -0
  271. package/templates/.agents/skills/zaip-skill-backend/references/deployment-environments.md +75 -0
  272. package/templates/.agents/skills/zaip-skill-backend/references/supabase-migration-contract.md +23 -0
  273. package/templates/.agents/skills/zaip-skill-brand-governance/SKILL.md +2 -0
  274. package/templates/.agents/skills/zaip-skill-cache-strategy/SKILL.md +14 -0
  275. package/templates/.agents/skills/zaip-skill-cache-strategy/agents/openai.yaml +4 -0
  276. package/templates/.agents/skills/zaip-skill-change/SKILL.md +1 -1
  277. package/templates/.agents/skills/zaip-skill-cloud-engineering/SKILL.md +7 -0
  278. package/templates/.agents/skills/zaip-skill-cloudflare-github-deploy/SKILL.md +37 -0
  279. package/templates/.agents/skills/zaip-skill-cloudflare-github-deploy/agents/openai.yaml +6 -0
  280. package/templates/.agents/skills/zaip-skill-cloudflare-github-deploy/references/workers-static-assets.md +26 -0
  281. package/templates/.agents/skills/zaip-skill-cloudflare-github-deploy/references/workflow-templates.md +71 -0
  282. package/templates/.agents/skills/zaip-skill-cloudflare-github-deploy/scripts/cloudflare-github-deploy-contract.test.mjs +77 -0
  283. package/templates/.agents/skills/zaip-skill-config/SKILL.md +21 -11
  284. package/templates/.agents/skills/zaip-skill-config/agents/openai.yaml +2 -2
  285. package/templates/.agents/skills/zaip-skill-container-runtime/SKILL.md +14 -0
  286. package/templates/.agents/skills/zaip-skill-container-runtime/agents/openai.yaml +4 -0
  287. package/templates/.agents/skills/zaip-skill-context/SKILL.md +6 -1
  288. package/templates/.agents/skills/zaip-skill-context/references/prd-spec-task-handoff.md +10 -0
  289. package/templates/.agents/skills/zaip-skill-context/references/rule-selection.md +20 -0
  290. package/templates/.agents/skills/zaip-skill-cqrs/SKILL.md +1 -0
  291. package/templates/.agents/skills/zaip-skill-cybersecurity/SKILL.md +18 -0
  292. package/templates/.agents/skills/zaip-skill-cybersecurity/agents/openai.yaml +4 -0
  293. package/templates/.agents/skills/zaip-skill-cybersecurity/references/audit-contract.md +94 -0
  294. package/templates/.agents/skills/zaip-skill-cybersecurity/scripts/score-audit.mjs +185 -0
  295. package/templates/.agents/skills/zaip-skill-cybersecurity/scripts/score-audit.test.mjs +101 -0
  296. package/templates/.agents/skills/zaip-skill-data-modeling/SKILL.md +14 -0
  297. package/templates/.agents/skills/zaip-skill-data-modeling/agents/openai.yaml +4 -0
  298. package/templates/.agents/skills/zaip-skill-database-migrations/SKILL.md +20 -0
  299. package/templates/.agents/skills/zaip-skill-database-migrations/agents/openai.yaml +4 -0
  300. package/templates/.agents/skills/zaip-skill-database-migrations/references/manual-mode.md +15 -0
  301. package/templates/.agents/skills/zaip-skill-database-migrations/references/promotion-example.md +5 -0
  302. package/templates/.agents/skills/zaip-skill-database-migrations/scripts/export-manual-sql.mjs +145 -0
  303. package/templates/.agents/skills/zaip-skill-database-migrations/scripts/export-manual-sql.test.mjs +178 -0
  304. package/templates/.agents/skills/zaip-skill-dependency-upgrade/SKILL.md +14 -0
  305. package/templates/.agents/skills/zaip-skill-dependency-upgrade/agents/openai.yaml +4 -0
  306. package/templates/.agents/skills/zaip-skill-deployment-pipeline/SKILL.md +15 -0
  307. package/templates/.agents/skills/zaip-skill-deployment-pipeline/agents/openai.yaml +4 -0
  308. package/templates/.agents/skills/zaip-skill-deployment-pipeline/references/runtime-shapes.md +3 -0
  309. package/templates/.agents/skills/zaip-skill-design-system/SKILL.md +20 -9
  310. package/templates/.agents/skills/zaip-skill-dev-environment/SKILL.md +14 -0
  311. package/templates/.agents/skills/zaip-skill-dev-environment/agents/openai.yaml +4 -0
  312. package/templates/.agents/skills/zaip-skill-dev-environment/references/inventory-contract.md +7 -0
  313. package/templates/.agents/skills/zaip-skill-dev-environment/scripts/inventory.mjs +77 -0
  314. package/templates/.agents/skills/zaip-skill-disaster-recovery/SKILL.md +15 -0
  315. package/templates/.agents/skills/zaip-skill-disaster-recovery/agents/openai.yaml +4 -0
  316. package/templates/.agents/skills/zaip-skill-disaster-recovery/references/recovery-scope.md +3 -0
  317. package/templates/.agents/skills/zaip-skill-execution/SKILL.md +3 -3
  318. package/templates/.agents/skills/zaip-skill-execution/references/correction-cycle.md +7 -0
  319. package/templates/.agents/skills/zaip-skill-execution/references/runtime-governance.md +1 -5
  320. package/templates/.agents/skills/zaip-skill-external-integrations/SKILL.md +14 -0
  321. package/templates/.agents/skills/zaip-skill-external-integrations/agents/openai.yaml +4 -0
  322. package/templates/.agents/skills/zaip-skill-frontend/SKILL.md +4 -0
  323. package/templates/.agents/skills/zaip-skill-frontend-componentization/SKILL.md +44 -0
  324. package/templates/.agents/skills/zaip-skill-frontend-componentization/agents/openai.yaml +4 -0
  325. package/templates/.agents/skills/zaip-skill-frontend-data-flows/SKILL.md +14 -0
  326. package/templates/.agents/skills/zaip-skill-frontend-data-flows/agents/openai.yaml +4 -0
  327. package/templates/.agents/skills/zaip-skill-general-operations/SKILL.md +2 -0
  328. package/templates/.agents/skills/zaip-skill-github-actions-setup/SKILL.md +36 -0
  329. package/templates/.agents/skills/zaip-skill-github-actions-setup/agents/openai.yaml +4 -0
  330. package/templates/.agents/skills/zaip-skill-github-actions-setup/references/cloudflare-pages.md +33 -0
  331. package/templates/.agents/skills/zaip-skill-github-actions-setup/references/github.md +63 -0
  332. package/templates/.agents/skills/zaip-skill-github-actions-setup/references/hostinger-vps.md +55 -0
  333. package/templates/.agents/skills/zaip-skill-github-actions-setup/references/npm.md +30 -0
  334. package/templates/.agents/skills/zaip-skill-github-actions-setup/scripts/check-skill.mjs +55 -0
  335. package/templates/.agents/skills/zaip-skill-github-actions-setup/scripts/verify-cloudflare.mjs +61 -0
  336. package/templates/.agents/skills/zaip-skill-github-actions-setup/scripts/verify-cloudflare.test.mjs +128 -0
  337. package/templates/.agents/skills/zaip-skill-github-actions-setup/scripts/verify-ssh.integration.test.mjs +106 -0
  338. package/templates/.agents/skills/zaip-skill-github-deploy/SKILL.md +43 -76
  339. package/templates/.agents/skills/zaip-skill-github-deploy/references/deployment-workflow.md +131 -0
  340. package/templates/.agents/skills/zaip-skill-github-deploy/references/github-release-workflow-template.md +31 -0
  341. package/templates/.agents/skills/zaip-skill-github-deploy/references/release-gate-matrix.md +24 -0
  342. package/templates/.agents/skills/zaip-skill-github-deploy/references/release-identity.md +44 -0
  343. package/templates/.agents/skills/zaip-skill-github-deploy/references/release-notes.md +134 -0
  344. package/templates/.agents/skills/zaip-skill-github-deploy/scripts/consumer-release-preparation.mjs +389 -0
  345. package/templates/.agents/skills/zaip-skill-github-deploy/scripts/consumer-release-preparation.test.mjs +134 -0
  346. package/templates/.agents/skills/zaip-skill-github-deploy/scripts/github-deploy-contract.test.mjs +25 -2
  347. package/templates/.agents/skills/zaip-skill-github-deploy/scripts/github-readiness-api.test.mjs +134 -0
  348. package/templates/.agents/skills/zaip-skill-github-deploy/scripts/github-readiness.mjs +98 -0
  349. package/templates/.agents/skills/zaip-skill-github-deploy/scripts/github-readiness.test.mjs +25 -0
  350. package/templates/.agents/skills/zaip-skill-github-deploy/scripts/install-github-readiness-workflow.mjs +159 -0
  351. package/templates/.agents/skills/zaip-skill-github-deploy/scripts/install-github-readiness-workflow.test.mjs +160 -0
  352. package/templates/.agents/skills/zaip-skill-github-deploy/scripts/preflight.mjs +149 -12
  353. package/templates/.agents/skills/zaip-skill-github-deploy/scripts/preflight.test.mjs +64 -5
  354. package/templates/.agents/skills/zaip-skill-github-deploy/scripts/release-notes-coverage.test.mjs +126 -0
  355. package/templates/.agents/skills/zaip-skill-github-deploy/scripts/resolve-release-identity.mjs +78 -0
  356. package/templates/.agents/skills/zaip-skill-github-deploy/scripts/resolve-release-identity.test.mjs +51 -0
  357. package/templates/.agents/skills/zaip-skill-github-deploy/scripts/validate-release-notes.mjs +184 -0
  358. package/templates/.agents/skills/zaip-skill-github-deploy/scripts/validate-release-notes.test.mjs +109 -0
  359. package/templates/.agents/skills/zaip-skill-growth-strategy-revops/SKILL.md +2 -0
  360. package/templates/.agents/skills/zaip-skill-hostinger-cloudflare-terraform/SKILL.md +18 -10
  361. package/templates/.agents/skills/zaip-skill-hostinger-cloudflare-terraform/agents/openai.yaml +3 -4
  362. package/templates/.agents/skills/zaip-skill-hostinger-cloudflare-terraform/references/aws-cli-terraform.md +62 -0
  363. package/templates/.agents/skills/zaip-skill-hostinger-cloudflare-terraform/references/guia-iniciante-hostinger-vps.md +183 -0
  364. package/templates/.agents/skills/zaip-skill-marketing/SKILL.md +2 -0
  365. package/templates/.agents/skills/zaip-skill-module-scaffold/SKILL.md +14 -0
  366. package/templates/.agents/skills/zaip-skill-module-scaffold/agents/openai.yaml +4 -0
  367. package/templates/.agents/skills/zaip-skill-module-scaffold/references/scaffold-contract.md +9 -0
  368. package/templates/.agents/skills/zaip-skill-module-scaffold/scripts/helpers.test.mjs +121 -0
  369. package/templates/.agents/skills/zaip-skill-module-scaffold/scripts/scaffold.mjs +169 -0
  370. package/templates/.agents/skills/zaip-skill-move-prd/SKILL.md +1 -1
  371. package/templates/.agents/skills/zaip-skill-move-spec/SKILL.md +1 -1
  372. package/templates/.agents/skills/zaip-skill-performance-engineering/SKILL.md +14 -0
  373. package/templates/.agents/skills/zaip-skill-performance-engineering/agents/openai.yaml +4 -0
  374. package/templates/.agents/skills/zaip-skill-prd/SKILL.md +1 -1
  375. package/templates/.agents/skills/zaip-skill-reconcile-telemetry/scripts/reconcile-local-telemetry.mjs +1 -0
  376. package/templates/.agents/skills/zaip-skill-reconcile-telemetry/scripts/reconcile-telemetry-lib.mjs +26 -9
  377. package/templates/.agents/skills/zaip-skill-reconcile-telemetry/scripts/reconcile-telemetry-lib.test.mjs +39 -13
  378. package/templates/.agents/skills/zaip-skill-reconcile-telemetry/scripts/reconcile-telemetry-remeasurement.mjs +1 -0
  379. package/templates/.agents/skills/zaip-skill-refactor-landing-page/SKILL.md +66 -0
  380. package/templates/.agents/skills/zaip-skill-refactor-landing-page/agents/openai.yaml +4 -0
  381. package/templates/.agents/skills/zaip-skill-refactor-landing-page/references/behavioral-dry-run.md +23 -0
  382. package/templates/.agents/skills/zaip-skill-release-qualification/SKILL.md +40 -1
  383. package/templates/.agents/skills/zaip-skill-release-qualification/references/local-preparation.md +98 -0
  384. package/templates/.agents/skills/zaip-skill-review/SKILL.md +1 -0
  385. package/templates/.agents/skills/zaip-skill-rules/SKILL.md +3 -3
  386. package/templates/.agents/skills/zaip-skill-sales-methodology/SKILL.md +2 -0
  387. package/templates/.agents/skills/zaip-skill-setup/SKILL.md +19 -21
  388. package/templates/.agents/skills/zaip-skill-setup/agents/openai.yaml +2 -2
  389. package/templates/.agents/skills/zaip-skill-spec/SKILL.md +3 -2
  390. package/templates/.agents/skills/zaip-skill-storage-uploads/SKILL.md +14 -0
  391. package/templates/.agents/skills/zaip-skill-storage-uploads/agents/openai.yaml +4 -0
  392. package/templates/.agents/skills/zaip-skill-systematic-debugging/SKILL.md +14 -0
  393. package/templates/.agents/skills/zaip-skill-systematic-debugging/agents/openai.yaml +4 -0
  394. package/templates/.agents/skills/zaip-skill-task/SKILL.md +16 -7
  395. package/templates/.agents/skills/zaip-skill-task/references/commit-policy.md +25 -0
  396. package/templates/.agents/skills/zaip-skill-test-data/SKILL.md +14 -0
  397. package/templates/.agents/skills/zaip-skill-test-data/agents/openai.yaml +4 -0
  398. package/templates/.agents/skills/zaip-skill-test-data/scripts/generate.mjs +72 -0
  399. package/templates/.agents/skills/zaip-skill-testing-strategy/SKILL.md +15 -0
  400. package/templates/.agents/skills/zaip-skill-testing-strategy/agents/openai.yaml +4 -0
  401. package/templates/.agents/skills/zaip-skill-testing-strategy/references/example-map.md +3 -0
  402. package/templates/.agents/skills/zaip-skill-website-readiness/SKILL.md +8 -0
  403. package/templates/.agents/zaip-aios/VERSION +1 -1
  404. package/templates/.agents/zaip-aios/guides/10-seguranca.md +2 -1
  405. package/templates/.agents/zaip-aios/guides/20-instalacao-detalhada.md +5 -3
  406. package/templates/scripts/validate-cloud-hostinger-contract.mjs +34 -0
  407. package/templates/template-manifest.json +955 -211
  408. package/templates/.agents/branding/.gitkeep +0 -0
  409. package/templates/.agents/dashboard/apps/frontend/dist/assets/CostCalculationGuidePage-snUCQYTC.js +0 -1
  410. package/templates/.agents/dashboard/apps/frontend/dist/assets/PricingSettingsDialog-BPtVUGgs.js +0 -1
  411. package/templates/.agents/dashboard/apps/frontend/dist/assets/ProjectSettingsPage-3Awyaovx.js +0 -3
  412. package/templates/.agents/dashboard/apps/frontend/dist/assets/ProjectSettingsPage-GgzpZ_PY.css +0 -1
  413. package/templates/.agents/dashboard/apps/frontend/dist/assets/TraceabilityWorkspace-BCvZFMEf.js +0 -1
  414. package/templates/.agents/dashboard/apps/frontend/dist/assets/cost-monitor-DbaLbU2q.js +0 -68
  415. package/templates/.agents/dashboard/apps/frontend/dist/assets/index-_MEktQNM.js +0 -2
  416. package/templates/.agents/dashboard/apps/frontend/dist/assets/rolldown-runtime-D9-fqq9M.js +0 -1
  417. package/templates/.agents/dashboard/apps/frontend/dist/assets/traceability-BDe4_Ubl.js +0 -1
  418. package/templates/.agents/growth/.gitkeep +0 -0
  419. package/templates/.agents/marketing/.gitkeep +0 -0
  420. package/templates/.agents/sales/.gitkeep +0 -0
@@ -1,17 +1,13 @@
1
- import { createHash } from "node:crypto";
2
- import { mkdir, mkdtemp, readdir, readFile, rename, rm, utimes, writeFile } from "node:fs/promises";
1
+ import { mkdir, mkdtemp, readdir, rm, utimes, writeFile } from "node:fs/promises";
3
2
  import { join, resolve } from "node:path";
4
3
  import { DatabaseSync } from "node:sqlite";
5
4
  import { afterEach, describe, expect, it, vi } from "vitest";
6
- import { createDashboardApp, projectAllTimeTopTasks } from "./server.js";
7
- import { expectFastCostPagesMatchCanonical } from "./sqlite-cost-fast-page-parity.test-support.js";
8
5
  import {
9
6
  allocateAttributedTokenActiveMs,
10
7
  rebuildSqliteReadModel,
11
8
  SqliteReadModelFileSystem,
12
9
  sourceFingerprint,
13
10
  } from "./sqlite-read-model.js";
14
- import { expectPersistedFirstFoldCaches } from "./sqlite-read-model-cache.test-support.js";
15
11
 
16
12
  const roots: string[] = [];
17
13
  const sqliteTestTempRoot = join(
@@ -42,7 +38,6 @@ describe("SQLite dashboard read model", () => {
42
38
  await writeFile(join(root, ".agents/config/project.yaml"), "zaip:\n enabled: true\n");
43
39
  await expect(rebuildSqliteReadModel(root)).resolves.toMatchObject({ cache: "rebuilt" });
44
40
  });
45
-
46
41
  it("serves an existing model immediately, refreshes on the SP day boundary and removes deleted sources in place", async () => {
47
42
  const root = await createSqliteTestRoot();
48
43
  roots.push(root);
@@ -88,7 +83,6 @@ describe("SQLite dashboard read model", () => {
88
83
  filesystem.close();
89
84
  }
90
85
  });
91
-
92
86
  it("rolls back a failed refresh including first-fold payloads while a reader remains open", async () => {
93
87
  const root = await createSqliteTestRoot();
94
88
  roots.push(root);
@@ -156,7 +150,6 @@ describe("SQLite dashboard read model", () => {
156
150
  expect(preservedMetadata.fingerprint).not.toBe(after.fingerprint);
157
151
  await expect(rebuildSqliteReadModel(root)).resolves.toMatchObject({ files: 2 });
158
152
  });
159
-
160
153
  it("uses current data entities once when the same ID remains in the legacy layout", async () => {
161
154
  const root = await createSqliteTestRoot();
162
155
  roots.push(root);
@@ -222,7 +215,6 @@ describe("SQLite dashboard read model", () => {
222
215
  fallback.close();
223
216
  }
224
217
  });
225
-
226
218
  it("accepts only the canonical C3D4 historical assignment among lifecycle files", async () => {
227
219
  const root = await createSqliteTestRoot();
228
220
  roots.push(root);
@@ -268,7 +260,6 @@ describe("SQLite dashboard read model", () => {
268
260
  path: join(root, ".local", "sqlite", "zaip-aios-dashboard.sqlite"),
269
261
  });
270
262
  });
271
-
272
263
  it("keeps an exact cached range valid with future facts and fast-paths an empty later month", async () => {
273
264
  const root = await createSqliteTestRoot();
274
265
  roots.push(root);
@@ -322,7 +313,6 @@ describe("SQLite dashboard read model", () => {
322
313
  filesystem.close();
323
314
  }
324
315
  });
325
-
326
316
  it("treats an empty snapshot as an exact empty later-month projection", async () => {
327
317
  const root = await createSqliteTestRoot();
328
318
  roots.push(root);
@@ -345,7 +335,6 @@ describe("SQLite dashboard read model", () => {
345
335
  filesystem.close();
346
336
  }
347
337
  });
348
-
349
338
  it("uses only the official persistent path after a rebuild", async () => {
350
339
  const root = await createSqliteTestRoot();
351
340
  roots.push(root);
@@ -372,7 +361,6 @@ describe("SQLite dashboard read model", () => {
372
361
  ),
373
362
  ).toBe(true);
374
363
  });
375
-
376
364
  it("rateia sobreposição e virada de dia na fato temporal aditiva", () => {
377
365
  const overlap = allocateAttributedTokenActiveMs([
378
366
  {
@@ -511,7 +499,6 @@ created_at: 2026-08-10T11:01:00.000Z
511
499
  expect(workListFirst.has_more).toBe(workListFirst.total_count > 1);
512
500
  filesystem.close();
513
501
  });
514
-
515
502
  it("projects catalog personas for canonical, legacy, and host Zaip Agent identities", async () => {
516
503
  const root = await createSqliteTestRoot();
517
504
  roots.push(root);
@@ -667,2795 +654,4 @@ created_at: 2026-08-10T11:01:00.000Z
667
654
  filesystem.close();
668
655
  }
669
656
  });
670
-
671
- it("marks token and cost telemetry unavailable when a canonical day has only Runs without usage", async () => {
672
- const root = await createSqliteTestRoot();
673
- roots.push(root);
674
- await mkdir(join(root, ".agents", "records", "runs", "2026", "08"), { recursive: true });
675
- await mkdir(join(root, ".agents", "config"), { recursive: true });
676
- await mkdir(join(root, ".agents", "config", "agents"), { recursive: true });
677
- await mkdir(join(root, ".agents", "config", "pricing"), { recursive: true });
678
- await writeFile(join(root, ".agents", "config", "project.yaml"), "zaip:\n enabled: true\n");
679
- await writeFile(
680
- join(root, ".agents", "config", "agents", "catalog.yaml"),
681
- "agents:\n - id: agent-catalog\n codex_name: agent\n persona: { nome: ana, cargo: quality_engineer }\n role: reviewer\n",
682
- );
683
- await writeFile(
684
- join(root, ".agents", "config", "pricing", "models.json"),
685
- JSON.stringify({
686
- schema_version: 1,
687
- updated_at: "2026-08-04T00:00:00.000Z",
688
- source: "fixture",
689
- disclaimer: "fixture",
690
- models: [
691
- {
692
- id: "gpt-a",
693
- provider: "openai",
694
- aliases: [],
695
- input_per_million_usd: 2,
696
- cached_input_per_million_usd: 0.2,
697
- output_per_million_usd: 8,
698
- reasoning_per_million_usd: 8,
699
- reasoning_billed_separately: false,
700
- long_context_threshold_tokens: null,
701
- long_context_input_multiplier: 1,
702
- long_context_output_multiplier: 1,
703
- source_label: "fixture-openai",
704
- source_url: "https://example.test/openai",
705
- notes: [],
706
- },
707
- {
708
- id: "claude-b",
709
- provider: "anthropic",
710
- aliases: [],
711
- input_per_million_usd: 3,
712
- cached_input_per_million_usd: 0.3,
713
- output_per_million_usd: 12,
714
- reasoning_per_million_usd: null,
715
- reasoning_billed_separately: false,
716
- long_context_threshold_tokens: null,
717
- long_context_input_multiplier: 1,
718
- long_context_output_multiplier: 1,
719
- source_label: "fixture-anthropic",
720
- source_url: "https://example.test/anthropic",
721
- notes: [],
722
- },
723
- ],
724
- }),
725
- );
726
- const started = {
727
- schema_version: 2,
728
- event_id: "RUN-MISSING:1",
729
- run_id: "RUN-MISSING",
730
- sequence: 1,
731
- occurred_at: "2026-08-05T12:00:00.000Z",
732
- type: "run.started",
733
- attribution_status: "attributed",
734
- phase: "conversation",
735
- run_role: "orchestrator",
736
- run_purpose: "orchestration",
737
- requires_finalizer: false,
738
- execution_kind: "interaction",
739
- execution_eligibility: ["interaction"],
740
- entrypoint: "conversation",
741
- work_type: "new",
742
- storage_mode: "tracked_sanitized",
743
- client: "codex",
744
- agent: "root",
745
- agent_name: "root",
746
- provider: null,
747
- model: "unknown",
748
- reasoning_effort: null,
749
- client_thread_id: "missing",
750
- client_turn_id: "missing",
751
- conversation_id: "CONV-MISSING",
752
- execution_id: null,
753
- task_id: null,
754
- spec_id: null,
755
- prd_id: null,
756
- change_id: null,
757
- parent_run_id: null,
758
- continuation_of_run_id: null,
759
- retry_of_run_id: null,
760
- };
761
- const finished = {
762
- schema_version: 2,
763
- event_id: "RUN-MISSING:2",
764
- run_id: "RUN-MISSING",
765
- sequence: 2,
766
- occurred_at: "2026-08-05T12:01:00.000Z",
767
- type: "run.finished",
768
- phase: "conversation",
769
- status: "completed",
770
- duration_ms: 60_000,
771
- duration_provenance: "observed",
772
- };
773
- await writeFile(
774
- join(root, ".agents", "records", "runs", "2026", "08", "RUN-MISSING.jsonl"),
775
- `${JSON.stringify(started)}\n${JSON.stringify(finished)}\n`,
776
- );
777
- await rebuildSqliteReadModel(root);
778
- const filesystem = new SqliteReadModelFileSystem(root);
779
- expectFastCostPagesMatchCanonical(root, filesystem);
780
- expect(filesystem.dailyPeriods({ from: null, to: null })["2026-08-05"]).toMatchObject({
781
- runs: 1,
782
- usage: {
783
- total_tokens: { known_sum: 0, unknown: 1 },
784
- cost: { known_sum: 0, unknown: 1 },
785
- },
786
- });
787
- filesystem.close();
788
- });
789
-
790
- it("releases the real SQLite handle before replacing a generation and reopens it after failure", async () => {
791
- const root = await createSqliteTestRoot();
792
- roots.push(root);
793
- await mkdir(join(root, ".agents", "config"), { recursive: true });
794
- const configPath = join(root, ".agents", "config", "project.yaml");
795
- await writeFile(configPath, "zaip:\n enabled: true\n");
796
- await rebuildSqliteReadModel(root);
797
- const filesystem = new SqliteReadModelFileSystem(root);
798
- try {
799
- expect(await filesystem.readText(".agents/config/project.yaml")).toBe(
800
- "zaip:\n enabled: true\n",
801
- );
802
- expect(filesystem.viewPage("operations_work_list", { limit: 10 }).total_count).toBe(0);
803
- const pageCache = (
804
- filesystem as unknown as {
805
- viewPageResultCache: Map<string, Record<string, unknown>>;
806
- }
807
- ).viewPageResultCache;
808
- expect(pageCache.has('operations_work_list:{"limit":10}')).toBe(true);
809
- // Change canonical input only after the read-only database has opened:
810
- // rebuild must replace the generation rather than taking the cache path.
811
- await writeFile(configPath, "zaip:\n enabled: true\nproject:\n id: refreshed-fixture\n");
812
- await expect(
813
- filesystem.rebuildAndRefresh(() => rebuildSqliteReadModel(root)),
814
- ).resolves.toBeUndefined();
815
- expect(await filesystem.readText(".agents/config/project.yaml")).toContain(
816
- "refreshed-fixture",
817
- );
818
- expect(pageCache.has('operations_work_list:{"limit":10}')).toBe(false);
819
- // Exercise the actual public view on the same reopened instance, not
820
- // merely raw filesystem reads after a Windows-safe replacement.
821
- expect(() =>
822
- filesystem.viewPage("cost_monitor_daily", { limit: 1, offset: 0 }),
823
- ).not.toThrow();
824
- // A failed rebuild still reopens the existing, complete generation.
825
- await expect(
826
- filesystem.rebuildAndRefresh(async () => {
827
- throw new Error("simulated rebuild failure");
828
- }),
829
- ).rejects.toThrow("simulated rebuild failure");
830
- expect(await filesystem.readText(".agents/config/project.yaml")).toContain(
831
- "refreshed-fixture",
832
- );
833
- } finally {
834
- filesystem.close();
835
- }
836
- });
837
-
838
- it("keeps Tempo unavailable when token telemetry has no source timing", async () => {
839
- const root = await createSqliteTestRoot();
840
- roots.push(root);
841
- await mkdir(join(root, ".agents", "records", "runs", "2026", "08"), { recursive: true });
842
- await mkdir(join(root, ".agents", "config"), { recursive: true });
843
- await writeFile(
844
- join(root, ".agents", "config", "project.yaml"),
845
- "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",
846
- "utf8",
847
- );
848
- const started = {
849
- schema_version: 2,
850
- event_id: "RUN-1:1",
851
- run_id: "RUN-1",
852
- sequence: 1,
853
- occurred_at: "2026-08-01T12:00:00.000Z",
854
- type: "run.started",
855
- attribution_status: "attributed",
856
- phase: "execution",
857
- run_role: "orchestrator",
858
- run_purpose: "execution",
859
- requires_finalizer: false,
860
- execution_kind: "delivery",
861
- execution_eligibility: ["delivery"],
862
- entrypoint: "task",
863
- work_type: "new",
864
- storage_mode: "tracked_sanitized",
865
- client: "codex",
866
- agent: "agent",
867
- agent_name: "agent",
868
- provider: "openai",
869
- model: "gpt-5",
870
- reasoning_effort: null,
871
- client_thread_id: "thread",
872
- client_turn_id: "turn",
873
- conversation_id: "CONV-1",
874
- execution_id: "EXEC-1",
875
- task_id: "TASK-1",
876
- spec_id: null,
877
- prd_id: null,
878
- change_id: null,
879
- parent_run_id: null,
880
- continuation_of_run_id: null,
881
- retry_of_run_id: null,
882
- agent_invocation_id: "AINV-1",
883
- root_agent_invocation_id: "AINV-1",
884
- parent_agent_invocation_id: null,
885
- invocation_kind: "orchestrator",
886
- delegation_depth: 0,
887
- };
888
- const usage = {
889
- schema_version: 2,
890
- event_id: "RUN-1:2",
891
- run_id: "RUN-1",
892
- sequence: 2,
893
- occurred_at: "2026-08-01T12:00:00.000Z",
894
- type: "usage.recorded",
895
- phase: "execution",
896
- activity_kind: "model_usage",
897
- classification_source: "explicit",
898
- tokens: {
899
- input: 0,
900
- cached_input: 0,
901
- output: 4_000_000,
902
- reasoning: 0,
903
- total: 4_000_000,
904
- source: "provider_reported",
905
- },
906
- cost: { usd: null, brl: null, fx_rate: null },
907
- provider: "openai",
908
- model: "gpt-5",
909
- source_segment_key: "segment",
910
- model_call_id: "MCALL-1",
911
- runtime: { reasoning_effort: null, service_tier: null },
912
- supersedes_event_id: null,
913
- duration_ms: null,
914
- duration_provenance: null,
915
- };
916
- const finished = {
917
- schema_version: 2,
918
- event_id: "RUN-1:3",
919
- run_id: "RUN-1",
920
- sequence: 3,
921
- occurred_at: "2026-08-01T12:00:00.000Z",
922
- type: "run.finished",
923
- phase: "execution",
924
- status: "completed",
925
- duration_ms: null,
926
- duration_provenance: "unavailable",
927
- };
928
- await writeFile(
929
- join(root, ".agents", "records", "runs", "2026", "08", "RUN-1.jsonl"),
930
- `${[started, usage, finished].map((record) => JSON.stringify(record)).join("\n")}\n`,
931
- "utf8",
932
- );
933
- await rebuildSqliteReadModel(root);
934
- const database = new DatabaseSync(resolve(root, ".local/sqlite/zaip-aios-dashboard.sqlite"), {
935
- readOnly: true,
936
- });
937
- expect(
938
- database.prepare("SELECT duration_ms, duration_provenance FROM zaip_aios_activities").get(),
939
- ).toEqual({ duration_ms: null, duration_provenance: null });
940
- database.close();
941
- const filesystem = new SqliteReadModelFileSystem(root);
942
- const day = filesystem.viewPage("cost_monitor_daily", {
943
- from: "2026-08-01",
944
- to: "2026-08-01",
945
- limit: 20,
946
- offset: 0,
947
- }).rows[0];
948
- if (day === undefined) throw new Error("Expected the daily Cost Monitor row");
949
- // Token telemetry without a complete source interval remains unavailable;
950
- // a token estimate must never populate the factual Tempo column.
951
- expect(day).toMatchObject({
952
- total_tokens: 4_000_000,
953
- total_duration: null,
954
- total_run_count: 1,
955
- duration_known: 0,
956
- duration_unknown: 1,
957
- });
958
- expect(Object.keys(day).sort()).toEqual([
959
- "duration_known",
960
- "duration_unknown",
961
- "evidence_count",
962
- "key",
963
- "label",
964
- "prd_count",
965
- "spec_count",
966
- "task_count",
967
- "total_cost_brl",
968
- "total_cost_usd",
969
- "total_duration",
970
- "total_run_count",
971
- "total_tokens",
972
- "validation_count",
973
- ]);
974
- expect(
975
- filesystem.costMonitorFactualDurationByDay({ from: null, to: null }).get("2026-08-01"),
976
- ).toEqual({
977
- known_sum: 0,
978
- eligible_runs: 1,
979
- known_runs: 0,
980
- });
981
- filesystem.close();
982
- });
983
-
984
- it("serves canonical model pricing with recorded-period and current FX", async () => {
985
- const root = await createSqliteTestRoot();
986
- roots.push(root);
987
- await mkdir(join(root, ".agents", "records", "runs", "2026", "08"), { recursive: true });
988
- await mkdir(join(root, ".agents", "config", "agents"), { recursive: true });
989
- await mkdir(join(root, ".agents", "config", "pricing", "fx", "2026", "08", "04"), {
990
- recursive: true,
991
- });
992
- await writeFile(join(root, ".agents", "config", "project.yaml"), "zaip:\n enabled: true\n");
993
- await writeFile(
994
- join(root, ".agents", "config", "agents", "catalog.yaml"),
995
- "agents:\n - id: agent-catalog\n codex_name: agent\n persona: { nome: ana, cargo: quality_engineer }\n role: reviewer\n",
996
- );
997
- await writeFile(
998
- join(root, ".agents", "config", "pricing", "models.json"),
999
- JSON.stringify({
1000
- schema_version: 1,
1001
- updated_at: "2026-08-04T00:00:00.000Z",
1002
- source: "fixture",
1003
- disclaimer: "fixture",
1004
- models: [
1005
- {
1006
- id: "gpt-a",
1007
- provider: "openai",
1008
- aliases: [],
1009
- input_per_million_usd: 2,
1010
- cached_input_per_million_usd: 0.2,
1011
- output_per_million_usd: 8,
1012
- reasoning_per_million_usd: 8,
1013
- reasoning_billed_separately: false,
1014
- long_context_threshold_tokens: null,
1015
- long_context_input_multiplier: 1,
1016
- long_context_output_multiplier: 1,
1017
- source_label: "fixture-openai",
1018
- source_url: "https://example.test/openai",
1019
- notes: [],
1020
- },
1021
- ],
1022
- }),
1023
- );
1024
- await writeFile(
1025
- join(root, ".agents", "config", "pricing", "fx", "2026", "08", "04", "usd-brl.json"),
1026
- JSON.stringify({
1027
- schema_version: 1,
1028
- base: "USD",
1029
- quote: "BRL",
1030
- rate: 5.5,
1031
- as_of: "2026-08-04T00:00:00.000Z",
1032
- source_label: "fixture",
1033
- source_url: "https://example.test/fx",
1034
- }),
1035
- );
1036
- const started = {
1037
- schema_version: 2,
1038
- event_id: "RUN-PRICED:1",
1039
- run_id: "RUN-PRICED",
1040
- sequence: 1,
1041
- occurred_at: "2026-08-08T12:00:00.000Z",
1042
- type: "run.started",
1043
- attribution_status: "attributed",
1044
- phase: "execution",
1045
- run_role: "orchestrator",
1046
- run_purpose: "execution",
1047
- requires_finalizer: false,
1048
- execution_kind: "delivery",
1049
- execution_eligibility: ["delivery"],
1050
- entrypoint: "task",
1051
- work_type: "new",
1052
- storage_mode: "tracked_sanitized",
1053
- client: "codex",
1054
- agent: "agent",
1055
- agent_name: "agent",
1056
- provider: "openai",
1057
- model: "gpt-a",
1058
- reasoning_effort: null,
1059
- client_thread_id: "priced",
1060
- client_turn_id: "priced",
1061
- conversation_id: "CONV-PRICED",
1062
- execution_id: "EXEC-PRICED",
1063
- task_id: "TASK-PRICED",
1064
- spec_id: null,
1065
- prd_id: null,
1066
- change_id: null,
1067
- parent_run_id: null,
1068
- continuation_of_run_id: null,
1069
- retry_of_run_id: null,
1070
- agent_invocation_id: "AINV-PRICED",
1071
- root_agent_invocation_id: "AINV-PRICED",
1072
- parent_agent_invocation_id: null,
1073
- invocation_kind: "orchestrator",
1074
- delegation_depth: 0,
1075
- };
1076
- const usage = {
1077
- schema_version: 2,
1078
- event_id: "RUN-PRICED:2",
1079
- run_id: "RUN-PRICED",
1080
- sequence: 2,
1081
- occurred_at: "2026-08-08T12:00:01.000Z",
1082
- type: "usage.recorded",
1083
- phase: "execution",
1084
- activity_kind: "model_usage",
1085
- classification_source: "explicit",
1086
- tokens: {
1087
- input: 5,
1088
- cached_input: 0,
1089
- output: 0,
1090
- reasoning: 0,
1091
- total: 5,
1092
- source: "provider_reported",
1093
- },
1094
- cost: { usd: 0.5, brl: 2.5, fx_rate: 5 },
1095
- provider: "openai",
1096
- model: "gpt-a",
1097
- source_segment_key: "openai-gpt-a",
1098
- model_call_id: "MCALL-PRICED",
1099
- runtime: { reasoning_effort: null, service_tier: null },
1100
- supersedes_event_id: null,
1101
- duration_ms: null,
1102
- duration_provenance: null,
1103
- };
1104
- const finished = {
1105
- schema_version: 2,
1106
- event_id: "RUN-PRICED:3",
1107
- run_id: "RUN-PRICED",
1108
- sequence: 3,
1109
- occurred_at: "2026-08-08T12:01:00.000Z",
1110
- type: "run.finished",
1111
- phase: "execution",
1112
- status: "completed",
1113
- duration_ms: 60_000,
1114
- duration_provenance: "observed",
1115
- };
1116
- await writeFile(
1117
- join(root, ".agents", "records", "runs", "2026", "08", "RUN-PRICED.jsonl"),
1118
- `${[started, usage, finished].map((row) => JSON.stringify(row)).join("\n")}\n`,
1119
- );
1120
- await rebuildSqliteReadModel(root);
1121
- const filesystem = new SqliteReadModelFileSystem(root);
1122
- try {
1123
- expect(filesystem.viewPage("cost_monitor_agent_invocations", {}).rows[0]).toMatchObject({
1124
- input_rate_usd_per_million: 2,
1125
- cached_input_rate_usd_per_million: 0.2,
1126
- output_rate_usd_per_million: 8,
1127
- calculated_cost_usd: 0.00001,
1128
- recorded_cost_usd: 0.5,
1129
- recorded_fx_rate: 5,
1130
- recorded_brl: 2.5,
1131
- current_fx_rate: 5.5,
1132
- });
1133
- } finally {
1134
- filesystem.close();
1135
- }
1136
- });
1137
-
1138
- it("keeps orphan telemetry out of the Kanban without dropping its Cost Monitor fact", async () => {
1139
- const root = await createSqliteTestRoot();
1140
- roots.push(root);
1141
- await mkdir(join(root, ".agents", "records", "tasks", "2026", "08"), { recursive: true });
1142
- await mkdir(join(root, ".agents", "records", "runs", "2026", "08"), { recursive: true });
1143
- await mkdir(
1144
- join(
1145
- root,
1146
- ".agents",
1147
- "records",
1148
- "changes",
1149
- "2026",
1150
- "08",
1151
- "CHG-CANONICAL",
1152
- "artifacts",
1153
- "tests",
1154
- ),
1155
- { recursive: true },
1156
- );
1157
- await mkdir(
1158
- join(
1159
- root,
1160
- ".agents",
1161
- "records",
1162
- "changes",
1163
- "2026",
1164
- "08",
1165
- "CHG-CANONICAL",
1166
- "artifacts",
1167
- "evidence",
1168
- ),
1169
- { recursive: true },
1170
- );
1171
- await mkdir(join(root, ".agents", "config"), { recursive: true });
1172
- await writeFile(join(root, ".agents", "config", "project.yaml"), "zaip:\n enabled: true\n");
1173
- await writeFile(
1174
- join(root, ".agents", "records", "tasks", "2026", "08", "TASK-CANONICAL.md"),
1175
- "---\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",
1176
- );
1177
- const run = (id: string, taskId: string, tokens: number, changeId: string | null = null) => [
1178
- {
1179
- schema_version: 2,
1180
- event_id: `${id}:1`,
1181
- run_id: id,
1182
- sequence: 1,
1183
- occurred_at: "2026-08-08T12:00:00.000Z",
1184
- type: "run.started",
1185
- attribution_status: "attributed",
1186
- phase: "execution",
1187
- run_role: "orchestrator",
1188
- run_purpose: "execution",
1189
- requires_finalizer: false,
1190
- execution_kind: "delivery",
1191
- execution_eligibility: ["delivery"],
1192
- entrypoint: "task",
1193
- work_type: "new",
1194
- storage_mode: "tracked_sanitized",
1195
- client: "codex",
1196
- agent: "agent",
1197
- agent_name: "agent",
1198
- developer_identity: {
1199
- schema_version: 1,
1200
- provider: "github",
1201
- account_id: "42",
1202
- login_snapshot: "dev-fixture",
1203
- verified_at: "2026-08-08T12:00:00.000Z",
1204
- attribution_source: "verified_local_account",
1205
- },
1206
- provider: "openai",
1207
- model: "gpt-a",
1208
- reasoning_effort: null,
1209
- client_thread_id: id,
1210
- client_turn_id: id,
1211
- conversation_id: `CONV-${id}`,
1212
- execution_id: `EXEC-${id}`,
1213
- task_id: taskId,
1214
- spec_id: null,
1215
- prd_id: null,
1216
- change_id: changeId,
1217
- parent_run_id: null,
1218
- continuation_of_run_id: null,
1219
- retry_of_run_id: null,
1220
- agent_invocation_id: `AINV-${id}`,
1221
- root_agent_invocation_id: `AINV-${id}`,
1222
- parent_agent_invocation_id: null,
1223
- invocation_kind: "orchestrator",
1224
- delegation_depth: 0,
1225
- },
1226
- {
1227
- schema_version: 2,
1228
- event_id: `${id}:2`,
1229
- run_id: id,
1230
- sequence: 2,
1231
- occurred_at: "2026-08-08T12:00:30.000Z",
1232
- type: "usage.recorded",
1233
- phase: "execution",
1234
- activity_kind: "model_usage",
1235
- classification_source: "explicit",
1236
- tokens: {
1237
- input: tokens,
1238
- cached_input: 0,
1239
- output: 0,
1240
- reasoning: 0,
1241
- total: tokens,
1242
- source: "provider_reported",
1243
- },
1244
- cost: { usd: tokens / 100, brl: tokens / 20, fx_rate: 5 },
1245
- provider: "openai",
1246
- model: "gpt-a",
1247
- source_segment_key: id,
1248
- model_call_id: `MCALL-${id}`,
1249
- runtime: { reasoning_effort: null, service_tier: null },
1250
- supersedes_event_id: null,
1251
- source_started_at: "2026-08-08T12:00:00.000Z",
1252
- source_finished_at: "2026-08-08T12:01:00.000Z",
1253
- duration_ms: null,
1254
- duration_provenance: null,
1255
- },
1256
- {
1257
- schema_version: 2,
1258
- event_id: `${id}:3`,
1259
- run_id: id,
1260
- sequence: 3,
1261
- occurred_at: "2026-08-08T12:01:00.000Z",
1262
- type: "run.finished",
1263
- phase: "execution",
1264
- status: "completed",
1265
- duration_ms: 60_000,
1266
- duration_provenance: "observed",
1267
- },
1268
- ];
1269
- await writeFile(
1270
- join(root, ".agents", "records", "runs", "2026", "08", "RUN-CANONICAL.jsonl"),
1271
- `${run("RUN-CANONICAL", "TASK-CANONICAL", 7, "CHG-CANONICAL")
1272
- .map((row) => JSON.stringify(row))
1273
- .join("\n")}\n`,
1274
- );
1275
- await writeFile(
1276
- join(root, ".agents", "records", "runs", "2026", "08", "RUN-ORPHAN.jsonl"),
1277
- `${run("RUN-ORPHAN", "TASK-ORPHAN-REFERENCE", 11)
1278
- .map((row) => JSON.stringify(row))
1279
- .join("\n")}\n`,
1280
- );
1281
- await writeFile(
1282
- join(
1283
- root,
1284
- ".agents",
1285
- "records",
1286
- "changes",
1287
- "2026",
1288
- "08",
1289
- "CHG-CANONICAL",
1290
- "artifacts",
1291
- "tests",
1292
- "TEST-CANONICAL.md",
1293
- ),
1294
- "---\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",
1295
- );
1296
- await writeFile(
1297
- join(
1298
- root,
1299
- ".agents",
1300
- "records",
1301
- "changes",
1302
- "2026",
1303
- "08",
1304
- "CHG-CANONICAL",
1305
- "artifacts",
1306
- "evidence",
1307
- "EVD-CANONICAL.md",
1308
- ),
1309
- "---\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",
1310
- );
1311
-
1312
- await rebuildSqliteReadModel(root);
1313
- const snapshot = new DatabaseSync(resolve(root, ".local/sqlite/zaip-aios-dashboard.sqlite"), {
1314
- readOnly: true,
1315
- });
1316
- try {
1317
- expect(
1318
- snapshot
1319
- .prepare("SELECT value FROM zaip_vw_read_model_metadata WHERE key='schema_version'")
1320
- .get(),
1321
- ).toEqual({ value: "74" });
1322
- } finally {
1323
- snapshot.close();
1324
- }
1325
- const filesystem = new SqliteReadModelFileSystem(root);
1326
- try {
1327
- expect(filesystem.viewPage("operations_work_kanban", { limit: 20 }).rows).toEqual([
1328
- expect.objectContaining({ id: "TASK-CANONICAL", title: "Titulo semantico canonico" }),
1329
- ]);
1330
- // The List export is sourced from this SQLite view, so its known facts
1331
- // must survive the public entity union rather than be left as blank XLSX
1332
- // columns by a mapper that only receives identity fields.
1333
- expect(filesystem.viewPage("operations_work_list", { limit: 20 }).rows).toContainEqual(
1334
- expect.objectContaining({
1335
- id: "TASK-CANONICAL",
1336
- invocation_count: 1,
1337
- total_duration: 30_000,
1338
- total_tokens: 7,
1339
- total_cost_brl: 0.35,
1340
- }),
1341
- );
1342
- const costTasks = filesystem.viewPage("cost_monitor_tasks", { limit: 20 }).rows;
1343
- expect(costTasks).toContainEqual(
1344
- expect.objectContaining({
1345
- id: "TASK-ORPHAN-REFERENCE",
1346
- total_tokens: 11,
1347
- total_cost_brl: 0.55,
1348
- }),
1349
- );
1350
- const developers = filesystem.developerCostAggregate({
1351
- from: null,
1352
- to: null,
1353
- accountIds: ["42"],
1354
- });
1355
- expect(developers.rows).toEqual([
1356
- expect.objectContaining({
1357
- account_id: "42",
1358
- login_snapshot: "dev-fixture",
1359
- prd_count: expect.any(Number),
1360
- spec_count: expect.any(Number),
1361
- task_count: 2,
1362
- run_count: 2,
1363
- test_count: 1,
1364
- evidence_count: 1,
1365
- total_duration_ms: expect.any(Number),
1366
- completed_task_count: 1,
1367
- total_cost_brl: 0.9,
1368
- token_covered_runs: 2,
1369
- usd_covered_runs: 2,
1370
- brl_covered_runs: 2,
1371
- qualification: "verified",
1372
- completed_tasks: [
1373
- expect.objectContaining({
1374
- id: "TASK-CANONICAL",
1375
- status: "completed",
1376
- completed_run_id: "RUN-CANONICAL",
1377
- delivered_by: { account_id: "42" },
1378
- contributors: [expect.objectContaining({ account_id: "42" })],
1379
- }),
1380
- ],
1381
- }),
1382
- ]);
1383
- expect(
1384
- filesystem.developerCostAggregate({
1385
- from: "2026-08-08",
1386
- to: "2026-08-08",
1387
- accountIds: ["42"],
1388
- }).rows,
1389
- ).toEqual([expect.objectContaining({ test_count: 1, evidence_count: 1 })]);
1390
- expect(
1391
- filesystem.dailyPeriods({ from: "2026-08-08", to: "2026-08-08" })["2026-08-08"],
1392
- ).toMatchObject({ validations: 1, evidences: 1 });
1393
- const operationsDevelopers = filesystem.operationsDeveloperAggregate({
1394
- from: null,
1395
- to: null,
1396
- accountIds: ["42"],
1397
- });
1398
- expect(operationsDevelopers.rows).toEqual([
1399
- expect.objectContaining({
1400
- account_id: "42",
1401
- task_count: 2,
1402
- completed_task_count: 1,
1403
- status_counts: expect.objectContaining({ completed: 1 }),
1404
- type_counts: { task: 1 },
1405
- risk_counts: expect.any(Object),
1406
- total_duration_ms: expect.any(Number),
1407
- total_tokens: expect.any(Number),
1408
- total_cost_brl: 0.9,
1409
- }),
1410
- ]);
1411
- } finally {
1412
- filesystem.close();
1413
- }
1414
- });
1415
-
1416
- it("qualifies factual developer deliveries without inventing missing completion or coverage", async () => {
1417
- const root = await createSqliteTestRoot();
1418
- roots.push(root);
1419
- const runsRoot = join(root, ".agents", "records", "runs", "2026", "08");
1420
- const tasksRoot = join(root, ".agents", "records", "tasks", "2026", "08");
1421
- const assignmentsRoot = join(
1422
- root,
1423
- ".agents",
1424
- "records",
1425
- "lifecycle",
1426
- "historical-developer-attribution",
1427
- );
1428
- await Promise.all([
1429
- mkdir(runsRoot, { recursive: true }),
1430
- mkdir(tasksRoot, { recursive: true }),
1431
- mkdir(assignmentsRoot, { recursive: true }),
1432
- mkdir(join(root, ".agents", "config"), { recursive: true }),
1433
- ]);
1434
- await writeFile(
1435
- join(root, ".agents", "config", "project.yaml"),
1436
- "zaip:\n enabled: true\n",
1437
- "utf8",
1438
- );
1439
- const task = (id: string, status: string, completedRunId: string | null) =>
1440
- `---\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`;
1441
- await Promise.all([
1442
- writeFile(
1443
- join(tasksRoot, "TASK-DELIVERED.md"),
1444
- task("TASK-DELIVERED", "completed", "RUN-DELIVERED"),
1445
- ),
1446
- writeFile(
1447
- join(tasksRoot, "TASK-NO-COMPLETION.md"),
1448
- task("TASK-NO-COMPLETION", "completed", null),
1449
- ),
1450
- writeFile(
1451
- join(tasksRoot, "TASK-MISSING-RUN.md"),
1452
- task("TASK-MISSING-RUN", "completed", "RUN-NOT-FOUND"),
1453
- ),
1454
- writeFile(
1455
- join(tasksRoot, "TASK-NOT-COMPLETED.md"),
1456
- task("TASK-NOT-COMPLETED", "executing", "RUN-NOT-COMPLETED"),
1457
- ),
1458
- writeFile(
1459
- join(tasksRoot, "TASK-UNKNOWN-COVERAGE.md"),
1460
- task("TASK-UNKNOWN-COVERAGE", "completed", null),
1461
- ),
1462
- writeFile(
1463
- join(tasksRoot, "TASK-HISTORICAL.md"),
1464
- task("TASK-HISTORICAL", "completed", "RUN-HISTORICAL"),
1465
- ),
1466
- ]);
1467
- const stream = (
1468
- id: string,
1469
- taskId: string,
1470
- accountId: string | null,
1471
- day: string,
1472
- tokens: number | null,
1473
- ) => {
1474
- const identity =
1475
- accountId === null
1476
- ? null
1477
- : {
1478
- schema_version: 1,
1479
- provider: "github",
1480
- account_id: accountId,
1481
- login_snapshot: `dev-${accountId}`,
1482
- verified_at: `${day}T12:00:00.000Z`,
1483
- attribution_source: "verified_local_account",
1484
- };
1485
- const records: Record<string, unknown>[] = [
1486
- {
1487
- schema_version: 2,
1488
- event_id: `${id}:1`,
1489
- run_id: id,
1490
- sequence: 1,
1491
- occurred_at: `${day}T12:00:00.000Z`,
1492
- type: "run.started",
1493
- attribution_status: "attributed",
1494
- phase: "execution",
1495
- run_role: "orchestrator",
1496
- run_purpose: "execution",
1497
- requires_finalizer: false,
1498
- execution_kind: "delivery",
1499
- execution_eligibility: ["delivery"],
1500
- entrypoint: "task",
1501
- work_type: "new",
1502
- storage_mode: "tracked_sanitized",
1503
- client: "codex",
1504
- agent: "agent",
1505
- agent_name: "agent",
1506
- developer_identity: identity,
1507
- provider: "openai",
1508
- model: "gpt-a",
1509
- reasoning_effort: null,
1510
- client_thread_id: id,
1511
- client_turn_id: id,
1512
- conversation_id: `CONV-${id}`,
1513
- execution_id: `EXEC-${id}`,
1514
- task_id: taskId,
1515
- spec_id: null,
1516
- prd_id: null,
1517
- change_id: null,
1518
- parent_run_id: null,
1519
- continuation_of_run_id: null,
1520
- retry_of_run_id: null,
1521
- agent_invocation_id: `AINV-${id}`,
1522
- root_agent_invocation_id: `AINV-${id}`,
1523
- parent_agent_invocation_id: null,
1524
- invocation_kind: "orchestrator",
1525
- delegation_depth: 0,
1526
- },
1527
- ];
1528
- if (tokens !== null)
1529
- records.push({
1530
- schema_version: 2,
1531
- event_id: `${id}:2`,
1532
- run_id: id,
1533
- sequence: 2,
1534
- occurred_at: `${day}T12:00:30.000Z`,
1535
- type: "usage.recorded",
1536
- phase: "execution",
1537
- activity_kind: "model_usage",
1538
- classification_source: "explicit",
1539
- tokens: {
1540
- input: tokens,
1541
- cached_input: 0,
1542
- output: 0,
1543
- reasoning: 0,
1544
- total: tokens,
1545
- source: "provider_reported",
1546
- },
1547
- cost: { usd: tokens / 100, brl: tokens / 20, fx_rate: 5 },
1548
- provider: "openai",
1549
- model: "gpt-a",
1550
- source_segment_key: id,
1551
- model_call_id: `MCALL-${id}`,
1552
- runtime: { reasoning_effort: null, service_tier: null },
1553
- supersedes_event_id: null,
1554
- source_started_at: `${day}T12:00:00.000Z`,
1555
- source_finished_at: `${day}T12:01:00.000Z`,
1556
- duration_ms: null,
1557
- duration_provenance: null,
1558
- });
1559
- records.push({
1560
- schema_version: 2,
1561
- event_id: `${id}:3`,
1562
- run_id: id,
1563
- sequence: records.length + 1,
1564
- occurred_at: `${day}T12:01:00.000Z`,
1565
- type: "run.finished",
1566
- phase: "execution",
1567
- status: "completed",
1568
- duration_ms: 60_000,
1569
- duration_provenance: "observed",
1570
- });
1571
- return `${records.map((record) => JSON.stringify(record)).join("\n")}\n`;
1572
- };
1573
- const delivered = stream("RUN-DELIVERED", "TASK-DELIVERED", "42", "2026-08-08", 10);
1574
- const contributor = stream("RUN-CONTRIBUTOR", "TASK-DELIVERED", "99", "2026-08-08", 3);
1575
- const noCompletion = stream("RUN-NO-COMPLETION", "TASK-NO-COMPLETION", "42", "2026-08-09", 4);
1576
- const notCompleted = stream("RUN-NOT-COMPLETED", "TASK-NOT-COMPLETED", "42", "2026-08-09", 5);
1577
- const unknownCoverage = stream(
1578
- "RUN-UNKNOWN-COVERAGE",
1579
- "TASK-UNKNOWN-COVERAGE",
1580
- "42",
1581
- "2026-08-09",
1582
- null,
1583
- );
1584
- const historical = stream("RUN-HISTORICAL", "TASK-HISTORICAL", null, "2026-08-09", 2);
1585
- await Promise.all([
1586
- writeFile(join(runsRoot, "RUN-DELIVERED.jsonl"), delivered),
1587
- writeFile(join(runsRoot, "RUN-CONTRIBUTOR.jsonl"), contributor),
1588
- writeFile(join(runsRoot, "RUN-NO-COMPLETION.jsonl"), noCompletion),
1589
- writeFile(join(runsRoot, "RUN-NOT-COMPLETED.jsonl"), notCompleted),
1590
- writeFile(join(runsRoot, "RUN-UNKNOWN-COVERAGE.jsonl"), unknownCoverage),
1591
- writeFile(join(runsRoot, "RUN-HISTORICAL.jsonl"), historical),
1592
- ]);
1593
- const historicalPath = ".agents/records/runs/2026/08/RUN-HISTORICAL.jsonl";
1594
- const unsigned = {
1595
- schema_version: 1,
1596
- manifest_id: "HDA-FIXTURE",
1597
- created_at: "2026-08-09T12:00:00.000Z",
1598
- kind: "historical_developer_attribution",
1599
- assignment: {
1600
- schema_version: 1,
1601
- provider: "github",
1602
- account_id: "199126185",
1603
- login_snapshot: "zaip-ai",
1604
- attribution_source: "human_assigned",
1605
- verified_at: null,
1606
- },
1607
- source_streams: [
1608
- {
1609
- run_id: "RUN-HISTORICAL",
1610
- path: historicalPath,
1611
- content_sha256: createHash("sha256").update(historical).digest("hex"),
1612
- },
1613
- ],
1614
- };
1615
- await writeFile(
1616
- join(assignmentsRoot, "HDA-FIXTURE.json"),
1617
- JSON.stringify({
1618
- ...unsigned,
1619
- manifest_hash: createHash("sha256").update(JSON.stringify(unsigned)).digest("hex"),
1620
- }),
1621
- );
1622
- await rebuildSqliteReadModel(root);
1623
- const filesystem = new SqliteReadModelFileSystem(root);
1624
- try {
1625
- const all = filesystem.developerCostAggregate({ from: null, to: null });
1626
- const deliveredBy42 = all.rows.find((row) => row.account_id === "42")!;
1627
- expect(deliveredBy42).toMatchObject({
1628
- qualification: "verified",
1629
- completed_task_count: 1,
1630
- run_count: 4,
1631
- token_covered_runs: 3,
1632
- usd_covered_runs: 3,
1633
- brl_covered_runs: 3,
1634
- });
1635
- expect(deliveredBy42.completed_tasks).toEqual([
1636
- expect.objectContaining({
1637
- id: "TASK-DELIVERED",
1638
- completed_run_id: "RUN-DELIVERED",
1639
- delivered_by: { account_id: "42" },
1640
- contributors: expect.arrayContaining([
1641
- expect.objectContaining({ account_id: "42" }),
1642
- expect.objectContaining({ account_id: "99" }),
1643
- ]),
1644
- }),
1645
- ]);
1646
- // Operations counts completed Tasks from the same canonical Task facts
1647
- // as its status distribution; no completed_run_id is required there.
1648
- expect(
1649
- filesystem
1650
- .operationsDeveloperAggregate({ from: null, to: null })
1651
- .rows.find((row) => row.account_id === "42"),
1652
- ).toMatchObject({
1653
- completed_task_count: 3,
1654
- status_counts: expect.objectContaining({ completed: 3 }),
1655
- });
1656
- expect(all.rows.find((row) => row.account_id === "199126185")).toMatchObject({
1657
- qualification: "human_assigned",
1658
- completed_task_count: 1,
1659
- });
1660
- expect(
1661
- filesystem.developerCostAggregate({
1662
- from: "2026-08-08",
1663
- to: "2026-08-08",
1664
- accountIds: ["42"],
1665
- }).rows,
1666
- ).toHaveLength(1);
1667
- expect(
1668
- filesystem.developerCostAggregate({
1669
- from: "2026-08-09",
1670
- to: "2026-08-09",
1671
- accountIds: ["42"],
1672
- }).rows[0],
1673
- ).toMatchObject({ completed_task_count: 0 });
1674
- // The real attributed unknown Run remains linked to account 42. Its
1675
- // coverage gap is explicit; its absent measures are never a zero.
1676
- const unknownDay = filesystem.developerCostAggregate({
1677
- from: "2026-08-09",
1678
- to: "2026-08-09",
1679
- accountIds: ["42"],
1680
- }).rows[0]!;
1681
- expect(unknownDay).toMatchObject({
1682
- run_count: 3,
1683
- token_covered_runs: 2,
1684
- usd_covered_runs: 2,
1685
- brl_covered_runs: 2,
1686
- });
1687
- expect(unknownDay.total_tokens).toBe(9);
1688
- expect(
1689
- filesystem.dailyPeriods({ from: "2026-08-09", to: "2026-08-09" })["2026-08-09"],
1690
- ).toMatchObject({
1691
- runs: 4,
1692
- usage: {
1693
- total_tokens: { known_sum: 11, unknown: 1 },
1694
- cost: { known_sum: 0.55, unknown: 1 },
1695
- },
1696
- });
1697
- } finally {
1698
- filesystem.close();
1699
- }
1700
- await writeFile(join(assignmentsRoot, "HDA-FIXTURE.json"), "{corrupt");
1701
- await rebuildSqliteReadModel(root, { forceCanonical: true });
1702
- const corrupt = new SqliteReadModelFileSystem(root);
1703
- try {
1704
- expect(
1705
- corrupt.developerCostAggregate({ from: null, to: null }).rows.map((row) => row.account_id),
1706
- ).not.toContain("199126185");
1707
- } finally {
1708
- corrupt.close();
1709
- }
1710
- });
1711
-
1712
- it("prefers the canonical started-to-finished interval over a token estimate", async () => {
1713
- const root = await createSqliteTestRoot();
1714
- roots.push(root);
1715
- await mkdir(join(root, ".agents", "records", "runs", "2026", "08"), { recursive: true });
1716
- await mkdir(join(root, ".agents", "config"), { recursive: true });
1717
- await writeFile(
1718
- join(root, ".agents", "config", "project.yaml"),
1719
- "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",
1720
- "utf8",
1721
- );
1722
- const started = {
1723
- schema_version: 2,
1724
- event_id: "RUN-2:1",
1725
- run_id: "RUN-2",
1726
- sequence: 1,
1727
- occurred_at: "2026-08-01T12:00:00.000Z",
1728
- type: "run.started",
1729
- attribution_status: "attributed",
1730
- phase: "execution",
1731
- run_role: "orchestrator",
1732
- run_purpose: "execution",
1733
- requires_finalizer: false,
1734
- execution_kind: "delivery",
1735
- execution_eligibility: ["delivery"],
1736
- entrypoint: "task",
1737
- work_type: "new",
1738
- storage_mode: "tracked_sanitized",
1739
- client: "codex",
1740
- agent: "agent",
1741
- agent_name: "agent",
1742
- provider: "openai",
1743
- model: "gpt-5",
1744
- reasoning_effort: null,
1745
- client_thread_id: "thread",
1746
- client_turn_id: "turn",
1747
- conversation_id: "CONV-2",
1748
- execution_id: "EXEC-2",
1749
- task_id: "TASK-2",
1750
- spec_id: null,
1751
- prd_id: null,
1752
- change_id: null,
1753
- parent_run_id: null,
1754
- continuation_of_run_id: null,
1755
- retry_of_run_id: null,
1756
- agent_invocation_id: "AINV-2",
1757
- root_agent_invocation_id: "AINV-2",
1758
- parent_agent_invocation_id: null,
1759
- invocation_kind: "orchestrator",
1760
- delegation_depth: 0,
1761
- };
1762
- const usage = {
1763
- schema_version: 2,
1764
- event_id: "RUN-2:2",
1765
- run_id: "RUN-2",
1766
- sequence: 2,
1767
- occurred_at: "2026-08-01T12:10:00.000Z",
1768
- type: "usage.recorded",
1769
- phase: "execution",
1770
- activity_kind: "model_usage",
1771
- classification_source: "explicit",
1772
- tokens: {
1773
- input: 4_000_000,
1774
- cached_input: 0,
1775
- output: 0,
1776
- reasoning: 0,
1777
- total: 4_000_000,
1778
- source: "provider_reported",
1779
- },
1780
- cost: { usd: null, brl: null, fx_rate: null },
1781
- provider: "openai",
1782
- model: "gpt-5",
1783
- source_segment_key: "segment",
1784
- model_call_id: "MCALL-2",
1785
- runtime: { reasoning_effort: null, service_tier: null },
1786
- supersedes_event_id: null,
1787
- duration_ms: null,
1788
- duration_provenance: null,
1789
- };
1790
- const finished = {
1791
- schema_version: 2,
1792
- event_id: "RUN-2:3",
1793
- run_id: "RUN-2",
1794
- sequence: 3,
1795
- occurred_at: "2026-08-01T12:30:00.000Z",
1796
- type: "run.finished",
1797
- phase: "execution",
1798
- status: "completed",
1799
- duration_ms: null,
1800
- duration_provenance: "unavailable",
1801
- };
1802
- await writeFile(
1803
- join(root, ".agents", "records", "runs", "2026", "08", "RUN-2.jsonl"),
1804
- `${[started, usage, finished].map((record) => JSON.stringify(record)).join("\n")}\n`,
1805
- "utf8",
1806
- );
1807
- await rebuildSqliteReadModel(root);
1808
- const database = new DatabaseSync(resolve(root, ".local/sqlite/zaip-aios-dashboard.sqlite"), {
1809
- readOnly: true,
1810
- });
1811
- expect(
1812
- database
1813
- .prepare(
1814
- "SELECT duration_ms, duration_provenance FROM zaip_aios_activities WHERE payload_type IS NULL",
1815
- )
1816
- .get(),
1817
- ).toEqual({ duration_ms: 1_800_000, duration_provenance: "attributed_token_active" });
1818
- database.close();
1819
- });
1820
-
1821
- it("does not convert a delayed historical finalizer into execution time", async () => {
1822
- const root = await createSqliteTestRoot();
1823
- roots.push(root);
1824
- await mkdir(join(root, ".agents", "records", "runs", "2026", "08"), { recursive: true });
1825
- await mkdir(join(root, ".agents", "config"), { recursive: true });
1826
- await writeFile(
1827
- join(root, ".agents", "config", "project.yaml"),
1828
- "zaip:\n enabled: true\n",
1829
- "utf8",
1830
- );
1831
- const started = {
1832
- schema_version: 2,
1833
- event_id: "RUN-3:1",
1834
- run_id: "RUN-3",
1835
- sequence: 1,
1836
- occurred_at: "2026-08-01T12:00:00.000Z",
1837
- type: "run.started",
1838
- attribution_status: "attributed",
1839
- phase: "execution",
1840
- run_role: "orchestrator",
1841
- run_purpose: "execution",
1842
- requires_finalizer: false,
1843
- execution_kind: "delivery",
1844
- execution_eligibility: ["delivery"],
1845
- entrypoint: "task",
1846
- work_type: "new",
1847
- storage_mode: "tracked_sanitized",
1848
- client: "codex",
1849
- agent: "agent",
1850
- agent_name: "agent",
1851
- provider: "openai",
1852
- model: "gpt-5",
1853
- reasoning_effort: null,
1854
- client_thread_id: "thread",
1855
- client_turn_id: "turn",
1856
- conversation_id: "CONV-3",
1857
- execution_id: "EXEC-3",
1858
- task_id: "TASK-3",
1859
- spec_id: null,
1860
- prd_id: null,
1861
- change_id: null,
1862
- parent_run_id: null,
1863
- continuation_of_run_id: null,
1864
- retry_of_run_id: null,
1865
- agent_invocation_id: "AINV-3",
1866
- root_agent_invocation_id: "AINV-3",
1867
- parent_agent_invocation_id: null,
1868
- invocation_kind: "orchestrator",
1869
- delegation_depth: 0,
1870
- };
1871
- const usage = {
1872
- schema_version: 2,
1873
- event_id: "RUN-3:2",
1874
- run_id: "RUN-3",
1875
- sequence: 2,
1876
- occurred_at: "2026-08-01T12:10:00.000Z",
1877
- type: "usage.recorded",
1878
- phase: "execution",
1879
- activity_kind: "model_usage",
1880
- classification_source: "explicit",
1881
- tokens: {
1882
- input: 20_000_000,
1883
- cached_input: 19_000_000,
1884
- output: 400_000,
1885
- reasoning: 0,
1886
- total: 20_400_000,
1887
- source: "provider_reported",
1888
- },
1889
- cost: { usd: null, brl: null, fx_rate: null },
1890
- provider: "openai",
1891
- model: "gpt-5",
1892
- source_segment_key: "segment",
1893
- model_call_id: "MCALL-3",
1894
- runtime: { reasoning_effort: null, service_tier: null },
1895
- supersedes_event_id: null,
1896
- duration_ms: null,
1897
- duration_provenance: null,
1898
- };
1899
- const finished = {
1900
- schema_version: 2,
1901
- event_id: "RUN-3:3",
1902
- run_id: "RUN-3",
1903
- sequence: 3,
1904
- occurred_at: "2026-08-03T12:00:00.000Z",
1905
- type: "run.finished",
1906
- phase: "execution",
1907
- status: "completed",
1908
- duration_ms: null,
1909
- duration_provenance: "unavailable",
1910
- };
1911
- await writeFile(
1912
- join(root, ".agents", "records", "runs", "2026", "08", "RUN-3.jsonl"),
1913
- `${[started, usage, finished].map((record) => JSON.stringify(record)).join("\n")}\n`,
1914
- "utf8",
1915
- );
1916
- await rebuildSqliteReadModel(root);
1917
- const database = new DatabaseSync(resolve(root, ".local/sqlite/zaip-aios-dashboard.sqlite"), {
1918
- readOnly: true,
1919
- });
1920
- expect(
1921
- database.prepare("SELECT duration_ms, duration_provenance FROM zaip_aios_activities").get(),
1922
- ).toEqual({ duration_ms: null, duration_provenance: null });
1923
- database.close();
1924
- });
1925
-
1926
- it("unions overlapping source intervals, deduplicates source-segment aliases, and keeps cross-midnight financial facts in their source day", async () => {
1927
- const root = await createSqliteTestRoot();
1928
- roots.push(root);
1929
- await mkdir(join(root, ".agents", "records", "runs", "2026", "07"), { recursive: true });
1930
- await mkdir(join(root, ".agents", "config"), { recursive: true });
1931
- await writeFile(join(root, ".agents", "config", "project.yaml"), "zaip:\n enabled: true\n");
1932
- const run = ({
1933
- id,
1934
- phase,
1935
- sourceStartedAt,
1936
- sourceFinishedAt,
1937
- parentRunId = null,
1938
- }: {
1939
- id: string;
1940
- phase: "conversation" | "planning" | "execution";
1941
- sourceStartedAt: string;
1942
- sourceFinishedAt: string;
1943
- parentRunId?: string | null;
1944
- }) => {
1945
- const occurredAt = sourceStartedAt;
1946
- const agentInvocationId = `AINV-${id}`;
1947
- return [
1948
- {
1949
- schema_version: 2,
1950
- event_id: `${id}:1`,
1951
- run_id: id,
1952
- sequence: 1,
1953
- occurred_at: occurredAt,
1954
- type: "run.started",
1955
- attribution_status: "attributed",
1956
- phase,
1957
- run_role: parentRunId === null ? "orchestrator" : "subagent",
1958
- run_purpose: "orchestration",
1959
- requires_finalizer: false,
1960
- execution_kind: "delivery",
1961
- execution_eligibility: ["delivery"],
1962
- entrypoint: "task",
1963
- work_type: "new",
1964
- storage_mode: "tracked_sanitized",
1965
- client: "codex",
1966
- agent: "agent",
1967
- agent_name: "agent",
1968
- provider: "openai",
1969
- model: "gpt-5",
1970
- reasoning_effort: null,
1971
- client_thread_id: `thread-${id}`,
1972
- client_turn_id: `turn-${id}`,
1973
- conversation_id: `CONV-${id}`,
1974
- execution_id: `EXEC-${id}`,
1975
- task_id: `TASK-${id}`,
1976
- spec_id: null,
1977
- prd_id: null,
1978
- change_id: null,
1979
- parent_run_id: parentRunId,
1980
- continuation_of_run_id: null,
1981
- retry_of_run_id: null,
1982
- agent_invocation_id: agentInvocationId,
1983
- root_agent_invocation_id: parentRunId === null ? agentInvocationId : "AINV-root",
1984
- parent_agent_invocation_id: parentRunId === null ? null : "AINV-root",
1985
- invocation_kind: parentRunId === null ? "orchestrator" : "delegated",
1986
- delegation_depth: parentRunId === null ? 0 : 1,
1987
- },
1988
- {
1989
- schema_version: 2,
1990
- event_id: `${id}:2`,
1991
- run_id: id,
1992
- sequence: 2,
1993
- occurred_at: sourceFinishedAt,
1994
- type: "usage.recorded",
1995
- phase,
1996
- activity_kind: "retrospective_local_remeasurement",
1997
- classification_source: "current_context",
1998
- tokens: {
1999
- input: 1,
2000
- cached_input: 0,
2001
- output: 1,
2002
- reasoning: 0,
2003
- total: 2,
2004
- source: "provider_reported",
2005
- },
2006
- cost: { usd: 1, brl: 5, fx_rate: 5 },
2007
- provider: "openai",
2008
- model: "gpt-5",
2009
- source_segment_key: id,
2010
- model_call_id: `MCALL-${id}`,
2011
- runtime: { reasoning_effort: null, service_tier: null },
2012
- supersedes_event_id: null,
2013
- retrospective_correction: true,
2014
- source_occurred_at: sourceFinishedAt,
2015
- source_started_at: sourceStartedAt,
2016
- source_finished_at: sourceFinishedAt,
2017
- duration_ms: null,
2018
- duration_provenance: null,
2019
- },
2020
- {
2021
- schema_version: 2,
2022
- event_id: `${id}:3`,
2023
- run_id: id,
2024
- sequence: 3,
2025
- occurred_at: new Date(Date.parse(occurredAt) + 60_000).toISOString(),
2026
- type: "run.finished",
2027
- phase,
2028
- status: "completed",
2029
- duration_ms: 60_000,
2030
- duration_provenance: "observed",
2031
- },
2032
- ];
2033
- };
2034
- for (const value of [
2035
- // 23:17–01:01 São Paulo: factual duration is split at local midnight.
2036
- {
2037
- id: "RUN-planning",
2038
- phase: "planning" as const,
2039
- sourceStartedAt: "2026-07-23T02:17:00.000Z",
2040
- sourceFinishedAt: "2026-07-23T04:01:00.000Z",
2041
- },
2042
- {
2043
- id: "RUN-conversation",
2044
- phase: "conversation" as const,
2045
- sourceStartedAt: "2026-07-23T03:00:00.000Z",
2046
- sourceFinishedAt: "2026-07-23T04:01:00.000Z",
2047
- },
2048
- {
2049
- id: "RUN-execution",
2050
- phase: "execution" as const,
2051
- sourceStartedAt: "2026-07-23T03:30:00.000Z",
2052
- sourceFinishedAt: "2026-07-23T04:30:00.000Z",
2053
- },
2054
- {
2055
- id: "RUN-subrun",
2056
- phase: "execution" as const,
2057
- parentRunId: "RUN-execution",
2058
- sourceStartedAt: "2026-07-23T03:45:00.000Z",
2059
- sourceFinishedAt: "2026-07-23T04:15:00.000Z",
2060
- },
2061
- ]) {
2062
- await writeFile(
2063
- join(root, ".agents", "records", "runs", "2026", "07", `${value.id}.jsonl`),
2064
- `${run(value)
2065
- .map((record) => JSON.stringify(record))
2066
- .join("\n")}\n`,
2067
- );
2068
- }
2069
- const aliasRecords = run({
2070
- id: "RUN-source-alias",
2071
- phase: "execution",
2072
- sourceStartedAt: "2026-07-23T04:10:00.000Z",
2073
- sourceFinishedAt: "2026-07-23T04:20:00.000Z",
2074
- });
2075
- const aliasUsage = {
2076
- ...aliasRecords[1],
2077
- event_id: "RUN-source-alias:3",
2078
- sequence: 3,
2079
- };
2080
- const aliasStarted = {
2081
- ...aliasRecords[0],
2082
- // Administrative capture predates the factual source session. Every
2083
- // token/time/invocation surface must classify this record by the source.
2084
- occurred_at: "2026-07-22T12:00:00.000Z",
2085
- };
2086
- const aliasFinished = { ...aliasRecords[2], event_id: "RUN-source-alias:4", sequence: 4 };
2087
- await writeFile(
2088
- join(root, ".agents", "records", "runs", "2026", "07", "RUN-source-alias.jsonl"),
2089
- `${[aliasStarted, aliasRecords[1], aliasUsage, aliasFinished].map((record) => JSON.stringify(record)).join("\n")}\n`,
2090
- );
2091
- // Historical financial telemetry can have no agent_invocation_id. It is
2092
- // still a Cost Monitor financial fact and must not disappear merely
2093
- // because agent-specific views cannot address it.
2094
- const historicalRecords = run({
2095
- id: "RUN-historical-financial",
2096
- phase: "conversation",
2097
- sourceStartedAt: "2026-07-23T06:00:00.000Z",
2098
- sourceFinishedAt: "2026-07-23T06:00:20.000Z",
2099
- });
2100
- const historicalStarted = { ...historicalRecords[0] } as Record<string, unknown>;
2101
- // The record was captured the following day, while its source session is
2102
- // 23 July. Cost Monitor filters must follow the latter.
2103
- historicalStarted.occurred_at = "2026-07-24T12:00:00.000Z";
2104
- delete historicalStarted.agent_invocation_id;
2105
- delete historicalStarted.root_agent_invocation_id;
2106
- delete historicalStarted.parent_agent_invocation_id;
2107
- await writeFile(
2108
- join(root, ".agents", "records", "runs", "2026", "07", "RUN-historical-financial.jsonl"),
2109
- `${[historicalStarted, ...historicalRecords.slice(1)].map((record) => JSON.stringify(record)).join("\n")}\n`,
2110
- );
2111
- await rebuildSqliteReadModel(root);
2112
- const database = new DatabaseSync(resolve(root, ".local/sqlite/zaip-aios-dashboard.sqlite"), {
2113
- readOnly: true,
2114
- });
2115
- expect(
2116
- database
2117
- .prepare(
2118
- "SELECT duration_ms, source_duration_ms, duration_provenance FROM zaip_aios_activities WHERE run_id='RUN-planning'",
2119
- )
2120
- .get(),
2121
- ).toEqual({
2122
- duration_ms: 4_020_000,
2123
- source_duration_ms: 6_240_000,
2124
- duration_provenance: "attributed_token_active",
2125
- });
2126
- const daily = database
2127
- .prepare(
2128
- "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",
2129
- )
2130
- .all();
2131
- expect(daily).toEqual([
2132
- {
2133
- day: "2026-07-22",
2134
- total_duration: 2_580_000,
2135
- invocation_count: 1,
2136
- cost_monitor_invocation_count: 1,
2137
- cost_monitor_total_duration: 2_580_000,
2138
- },
2139
- {
2140
- day: "2026-07-23",
2141
- total_duration: 5_420_000,
2142
- invocation_count: 4,
2143
- cost_monitor_invocation_count: 5,
2144
- cost_monitor_total_duration: 5_420_000,
2145
- },
2146
- ]);
2147
- expect(
2148
- database
2149
- .prepare(
2150
- "SELECT COUNT(*) AS count FROM zaip_vw_daily_aggregates WHERE total_duration > 86400000",
2151
- )
2152
- .get(),
2153
- ).toEqual({ count: 0 });
2154
- database.close();
2155
- const factualFilesystem = new SqliteReadModelFileSystem(root);
2156
- expect(
2157
- factualFilesystem
2158
- .costMonitorFinancialActivityRows({ from: "2026-07-23", to: "2026-07-23" })
2159
- .some((row) => row.run_id === "RUN-historical-financial"),
2160
- ).toBe(true);
2161
- const compactFinancialRow = factualFilesystem.costMonitorFinancialActivityRows({
2162
- from: "2026-07-23",
2163
- to: "2026-07-23",
2164
- })[0];
2165
- expect(compactFinancialRow).not.toHaveProperty("payload_json");
2166
- expect(compactFinancialRow).toHaveProperty("total_tokens");
2167
- expect(
2168
- factualFilesystem
2169
- .costMonitorFinancialActivityRows({ from: "2026-07-24", to: "2026-07-24" })
2170
- .some((row) => row.run_id === "RUN-historical-financial"),
2171
- ).toBe(false);
2172
- expect(
2173
- factualFilesystem
2174
- .viewPage("operations_agent_invocations", {
2175
- from: "2026-07-23",
2176
- to: "2026-07-23",
2177
- limit: 20,
2178
- })
2179
- .rows.some((row) => row.run_id === "RUN-source-alias"),
2180
- ).toBe(true);
2181
- expect(
2182
- factualFilesystem
2183
- .viewPage("operations_agent_invocations", {
2184
- from: "2026-07-22",
2185
- to: "2026-07-22",
2186
- limit: 20,
2187
- })
2188
- .rows.some((row) => row.run_id === "RUN-source-alias"),
2189
- ).toBe(false);
2190
- // Filter dimensions stay in the SQL population: they must retain the
2191
- // source-session day and never require an activity-by-activity lookup.
2192
- expect(
2193
- factualFilesystem
2194
- .costMonitorFinancialActivityRows({
2195
- from: "2026-07-23",
2196
- to: "2026-07-23",
2197
- phases: ["conversation"],
2198
- providers: ["openai"],
2199
- models: ["gpt-5"],
2200
- })
2201
- .map((row) => row.run_id),
2202
- ).toContain("RUN-historical-financial");
2203
- expect(
2204
- factualFilesystem
2205
- .costMonitorFinancialActivityRows({
2206
- from: "2026-07-22",
2207
- to: "2026-07-22",
2208
- phases: ["planning"],
2209
- })
2210
- .map((row) => row.run_id),
2211
- ).toEqual(["RUN-planning"]);
2212
- for (const view of [
2213
- "cost_monitor_daily",
2214
- "cost_monitor_monthly",
2215
- "cost_monitor_annual",
2216
- ] as const) {
2217
- expect(
2218
- factualFilesystem
2219
- .viewPage(view, { from: "2026-07-23", to: "2026-07-23", limit: 20, offset: 0 })
2220
- .rows.some((row) => Number(row.total_tokens) === 10),
2221
- ).toBe(true);
2222
- // The API boundary supplies inclusive Sao Paulo days as ISO instants.
2223
- // Do not truncate the UTC end instant into the following calendar day.
2224
- const bounded = factualFilesystem.viewPage(view, {
2225
- from: "2026-07-23T03:00:00.000Z",
2226
- to: "2026-07-24T02:59:59.999Z",
2227
- limit: 20,
2228
- offset: 0,
2229
- }).rows;
2230
- expect(bounded.some((row) => Number(row.total_tokens) === 10)).toBe(true);
2231
- expect(
2232
- bounded.some(
2233
- (row) =>
2234
- String(row.period_key).startsWith("2026-07-24") && Number(row.total_tokens) === 10,
2235
- ),
2236
- ).toBe(false);
2237
- // A structural day or other source financial fact may still exist on
2238
- // the 24th, but this fixture's source-day-23 aggregate must not leak.
2239
- expect(
2240
- factualFilesystem
2241
- .viewPage(view, { from: "2026-07-24", to: "2026-07-24", limit: 20, offset: 0 })
2242
- .rows.every((row) => row.total_tokens !== 10),
2243
- ).toBe(true);
2244
- }
2245
- const allFinancialRows = factualFilesystem.costMonitorFinancialActivityRows({
2246
- from: null,
2247
- to: null,
2248
- });
2249
- const factual = factualFilesystem.costMonitorFactualDurationByDay(
2250
- { from: null, to: null },
2251
- allFinancialRows,
2252
- );
2253
- // The cross-midnight session is split at São Paulo midnight and each day
2254
- // is the union of complete source intervals, never above one local day.
2255
- expect(factual.get("2026-07-22")).toEqual({
2256
- known_sum: 2_580_000,
2257
- eligible_runs: 1,
2258
- known_runs: 1,
2259
- });
2260
- expect(factual.get("2026-07-23")).toEqual({
2261
- known_sum: 5_420_000,
2262
- eligible_runs: 6,
2263
- known_runs: 6,
2264
- });
2265
- factualFilesystem.close();
2266
- });
2267
-
2268
- it("inherits unambiguous SPEC/PRD creation telemetry for planned Tasks without copying it to siblings", async () => {
2269
- const root = await createSqliteTestRoot();
2270
- roots.push(root);
2271
- for (const kind of ["tasks", "specs", "prds"])
2272
- await mkdir(join(root, ".agents", "records", kind, "2026", "08"), { recursive: true });
2273
- await mkdir(join(root, ".agents", "records", "changes", "2026", "08", "CHG-UNIQUE"), {
2274
- recursive: true,
2275
- });
2276
- await mkdir(join(root, ".agents", "records", "changes", "2026", "08", "CHG-SHARED-A"), {
2277
- recursive: true,
2278
- });
2279
- await mkdir(join(root, ".agents", "records", "changes", "2026", "08", "CHG-SHARED-B"), {
2280
- recursive: true,
2281
- });
2282
- await mkdir(join(root, ".agents", "records", "changes", "2026", "08", "CHG-PRD-ONLY"), {
2283
- recursive: true,
2284
- });
2285
- await mkdir(join(root, ".agents", "records", "changes", "2026", "08", "CHG-NO-MACRO"), {
2286
- recursive: true,
2287
- });
2288
- await mkdir(join(root, ".agents", "records", "runs", "2026", "08"), { recursive: true });
2289
- await mkdir(join(root, ".agents", "config"), { recursive: true });
2290
- await writeFile(
2291
- join(root, ".agents", "config", "project.yaml"),
2292
- "zaip:\n enabled: true\n",
2293
- "utf8",
2294
- );
2295
- const item = (id: string, status = "planned") =>
2296
- `---\nid: ${id}\ntitle: ${id}\nstatus: ${status}\nrisk: standard\ncreated_at: 2026-08-12T12:00:00.000Z\n---\n# ${id}\n`;
2297
- for (const id of [
2298
- "TASK-UNIQUE",
2299
- "TASK-SHARED-A",
2300
- "TASK-SHARED-B",
2301
- "TASK-PRD-ONLY",
2302
- "TASK-NO-MACRO",
2303
- ])
2304
- await writeFile(
2305
- join(root, ".agents", "records", "tasks", "2026", "08", `${id}.md`),
2306
- item(id),
2307
- "utf8",
2308
- );
2309
- for (const id of ["SPEC-UNIQUE", "SPEC-SHARED"])
2310
- await writeFile(
2311
- join(root, ".agents", "records", "specs", "2026", "08", `${id}.md`),
2312
- item(id, "active"),
2313
- "utf8",
2314
- );
2315
- for (const id of ["PRD-UNIQUE", "PRD-SHARED", "PRD-ONLY"])
2316
- await writeFile(
2317
- join(root, ".agents", "records", "prds", "2026", "08", `${id}.md`),
2318
- item(id, "active"),
2319
- "utf8",
2320
- );
2321
- const change = (id: string, taskId: string, specId: string | null, prdId: string | null) =>
2322
- `---\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`;
2323
- await writeFile(
2324
- join(root, ".agents", "records", "changes", "2026", "08", "CHG-UNIQUE", "change.md"),
2325
- change("CHG-UNIQUE", "TASK-UNIQUE", "SPEC-UNIQUE", "PRD-UNIQUE"),
2326
- "utf8",
2327
- );
2328
- await writeFile(
2329
- join(root, ".agents", "records", "changes", "2026", "08", "CHG-SHARED-A", "change.md"),
2330
- change("CHG-SHARED-A", "TASK-SHARED-A", "SPEC-SHARED", "PRD-SHARED"),
2331
- "utf8",
2332
- );
2333
- await writeFile(
2334
- join(root, ".agents", "records", "changes", "2026", "08", "CHG-SHARED-B", "change.md"),
2335
- change("CHG-SHARED-B", "TASK-SHARED-B", "SPEC-SHARED", "PRD-SHARED"),
2336
- "utf8",
2337
- );
2338
- await writeFile(
2339
- join(root, ".agents", "records", "changes", "2026", "08", "CHG-PRD-ONLY", "change.md"),
2340
- change("CHG-PRD-ONLY", "TASK-PRD-ONLY", null, "PRD-ONLY"),
2341
- "utf8",
2342
- );
2343
- await writeFile(
2344
- join(root, ".agents", "records", "changes", "2026", "08", "CHG-NO-MACRO", "change.md"),
2345
- change("CHG-NO-MACRO", "TASK-NO-MACRO", null, null),
2346
- "utf8",
2347
- );
2348
- const run = (
2349
- id: string,
2350
- specId: string | null,
2351
- prdId: string | null,
2352
- tokens: number,
2353
- cost: number,
2354
- duration: number,
2355
- ) => [
2356
- {
2357
- schema_version: 2,
2358
- event_id: `${id}:1`,
2359
- run_id: id,
2360
- sequence: 1,
2361
- occurred_at: "2026-08-12T12:00:00.000Z",
2362
- type: "run.started",
2363
- attribution_status: "attributed",
2364
- phase: "planning",
2365
- run_role: "orchestrator",
2366
- run_purpose: "orchestration",
2367
- requires_finalizer: false,
2368
- execution_kind: "interaction",
2369
- execution_eligibility: [],
2370
- entrypoint: specId === null ? (prdId === null ? "conversation" : "prd") : "spec",
2371
- work_type: "new",
2372
- storage_mode: "tracked_sanitized",
2373
- client: "codex",
2374
- agent: "agent",
2375
- agent_name: "agent",
2376
- provider: "openai",
2377
- model: "gpt-5",
2378
- reasoning_effort: null,
2379
- client_thread_id: id,
2380
- client_turn_id: id,
2381
- conversation_id: `CONV-${id}`,
2382
- execution_id: null,
2383
- task_id: null,
2384
- spec_id: specId,
2385
- prd_id: prdId,
2386
- change_id: null,
2387
- parent_run_id: null,
2388
- continuation_of_run_id: null,
2389
- retry_of_run_id: null,
2390
- agent_invocation_id: `AINV-${id}`,
2391
- root_agent_invocation_id: `AINV-${id}`,
2392
- parent_agent_invocation_id: null,
2393
- invocation_kind: "orchestrator",
2394
- delegation_depth: 0,
2395
- },
2396
- {
2397
- schema_version: 2,
2398
- event_id: `${id}:2`,
2399
- run_id: id,
2400
- sequence: 2,
2401
- occurred_at: "2026-08-12T12:01:00.000Z",
2402
- type: "usage.recorded",
2403
- phase: "planning",
2404
- activity_kind: "model_usage",
2405
- classification_source: "explicit",
2406
- tokens: {
2407
- input: tokens,
2408
- cached_input: 0,
2409
- output: 0,
2410
- reasoning: 0,
2411
- total: tokens,
2412
- source: "provider_reported",
2413
- },
2414
- cost: { usd: cost / 5, brl: cost, fx_rate: 5 },
2415
- provider: "openai",
2416
- model: "gpt-5",
2417
- source_segment_key: id,
2418
- model_call_id: `MCALL-${id}`,
2419
- runtime: { reasoning_effort: null, service_tier: null },
2420
- supersedes_event_id: null,
2421
- duration_ms: null,
2422
- duration_provenance: null,
2423
- },
2424
- {
2425
- schema_version: 2,
2426
- event_id: `${id}:3`,
2427
- run_id: id,
2428
- sequence: 3,
2429
- occurred_at: "2026-08-12T12:02:00.000Z",
2430
- type: "run.finished",
2431
- phase: "planning",
2432
- status: "completed",
2433
- duration_ms: duration,
2434
- duration_provenance: "observed",
2435
- },
2436
- ];
2437
- for (const [id, specId, prdId, tokens, cost, duration] of [
2438
- ["RUN-UNIQUE", "SPEC-UNIQUE", "PRD-UNIQUE", 7, 3, 120_000],
2439
- ["RUN-SHARED", "SPEC-SHARED", "PRD-SHARED", 11, 5, 60_000],
2440
- ["RUN-PRD-ONLY", null, "PRD-ONLY", 13, 6, 90_000],
2441
- ["RUN-NO-MACRO", null, null, 17, 8, 30_000],
2442
- ] as const)
2443
- await writeFile(
2444
- join(root, ".agents", "records", "runs", "2026", "08", `${id}.jsonl`),
2445
- `${run(id, specId, prdId, tokens, cost, duration)
2446
- .map((record) => JSON.stringify(record))
2447
- .join("\n")}\n`,
2448
- "utf8",
2449
- );
2450
- await rebuildSqliteReadModel(root);
2451
- const filesystem = new SqliteReadModelFileSystem(root);
2452
- const tasks = filesystem.summaryPage("task", { from: null, to: null }, 0, 10).rows;
2453
- expect(tasks).toContainEqual(
2454
- expect.objectContaining({
2455
- id: "TASK-UNIQUE",
2456
- invocation_count: 1,
2457
- total_duration: 62_500,
2458
- total_tokens: 7,
2459
- total_cost_brl: 3,
2460
- }),
2461
- );
2462
- expect(tasks).toContainEqual(
2463
- expect.objectContaining({
2464
- id: "TASK-SHARED-A",
2465
- invocation_count: null,
2466
- total_duration: null,
2467
- total_tokens: null,
2468
- total_cost_brl: null,
2469
- }),
2470
- );
2471
- expect(tasks).toContainEqual(
2472
- expect.objectContaining({
2473
- id: "TASK-SHARED-B",
2474
- invocation_count: null,
2475
- total_duration: null,
2476
- total_tokens: null,
2477
- total_cost_brl: null,
2478
- }),
2479
- );
2480
- expect(tasks).toContainEqual(
2481
- expect.objectContaining({
2482
- id: "TASK-PRD-ONLY",
2483
- invocation_count: 1,
2484
- total_duration: 32_500,
2485
- total_tokens: 13,
2486
- total_cost_brl: 6,
2487
- }),
2488
- );
2489
- expect(tasks).toContainEqual(
2490
- expect.objectContaining({
2491
- id: "TASK-NO-MACRO",
2492
- invocation_count: null,
2493
- total_duration: null,
2494
- total_tokens: null,
2495
- total_cost_brl: null,
2496
- }),
2497
- );
2498
- filesystem.close();
2499
- });
2500
-
2501
- it("counts every root execution day and returns task duration leaders", async () => {
2502
- const root = await createSqliteTestRoot();
2503
- roots.push(root);
2504
- await mkdir(join(root, ".agents", "records", "runs", "2026", "08"), { recursive: true });
2505
- for (const kind of ["tasks", "specs", "prds"])
2506
- await mkdir(join(root, ".agents", "records", kind, "2026", "08"), { recursive: true });
2507
- await mkdir(
2508
- join(root, ".agents", "records", "changes", "2026", "08", "CHG-ART", "artifacts", "evidence"),
2509
- { recursive: true },
2510
- );
2511
- await mkdir(
2512
- join(
2513
- root,
2514
- ".agents",
2515
- "records",
2516
- "changes",
2517
- "2026",
2518
- "08",
2519
- "CHG-ART",
2520
- "artifacts",
2521
- "validations",
2522
- ),
2523
- { recursive: true },
2524
- );
2525
- await mkdir(join(root, ".agents", "config"), { recursive: true });
2526
- await writeFile(
2527
- join(root, ".agents", "config", "project.yaml"),
2528
- "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",
2529
- "utf8",
2530
- );
2531
- await writeFile(
2532
- join(root, ".agents", "config", "framework.lock.yaml"),
2533
- "lock_version: 1\nframework:\n version: 2.2.0\n distribution_sha256: null\nlayout:\n version: 3\nresolved_profile:\n id: null\n sha256: null\nmanaged_files: {}\n",
2534
- "utf8",
2535
- );
2536
- const run = (
2537
- id: string,
2538
- day: string,
2539
- task: string,
2540
- duration: number,
2541
- time = "12:00:00.000Z",
2542
- spec: string | null = null,
2543
- prd: string | null = null,
2544
- ) => [
2545
- {
2546
- schema_version: 2,
2547
- event_id: `${id}:1`,
2548
- run_id: id,
2549
- sequence: 1,
2550
- occurred_at: `${day}T${time}`,
2551
- type: "run.started",
2552
- attribution_status: "attributed",
2553
- phase: "execution",
2554
- run_role: "orchestrator",
2555
- run_purpose: "execution",
2556
- requires_finalizer: false,
2557
- execution_kind: "delivery",
2558
- execution_eligibility: ["delivery"],
2559
- entrypoint: "task",
2560
- work_type: "new",
2561
- storage_mode: "tracked_sanitized",
2562
- client: "codex",
2563
- agent: "agent",
2564
- agent_name: "agent",
2565
- provider: "openai",
2566
- model: "gpt-5",
2567
- reasoning_effort: null,
2568
- client_thread_id: id,
2569
- client_turn_id: id,
2570
- conversation_id: `CONV-${id}`,
2571
- execution_id: `EXEC-${id}`,
2572
- task_id: task,
2573
- spec_id: spec,
2574
- prd_id: prd,
2575
- change_id: null,
2576
- parent_run_id: null,
2577
- continuation_of_run_id: null,
2578
- retry_of_run_id: null,
2579
- agent_invocation_id: `AINV-${id}`,
2580
- root_agent_invocation_id: `AINV-${id}`,
2581
- parent_agent_invocation_id: null,
2582
- invocation_kind: "orchestrator",
2583
- delegation_depth: 0,
2584
- },
2585
- {
2586
- schema_version: 2,
2587
- event_id: `${id}:2`,
2588
- run_id: id,
2589
- sequence: 2,
2590
- occurred_at: `${day}T12:00:01.000Z`,
2591
- type: "usage.recorded",
2592
- phase: "execution",
2593
- activity_kind: "model_usage",
2594
- classification_source: "explicit",
2595
- tokens: {
2596
- input: 1,
2597
- cached_input: 0,
2598
- output: 1,
2599
- reasoning: 0,
2600
- total: 2,
2601
- source: "provider_reported",
2602
- },
2603
- cost: { usd: 1, brl: 5, fx_rate: 5 },
2604
- provider: "openai",
2605
- model: "gpt-5",
2606
- source_segment_key: id,
2607
- model_call_id: `MCALL-${id}`,
2608
- runtime: { reasoning_effort: null, service_tier: null },
2609
- supersedes_event_id: null,
2610
- duration_ms: null,
2611
- duration_provenance: null,
2612
- },
2613
- {
2614
- schema_version: 2,
2615
- event_id: `${id}:3`,
2616
- run_id: id,
2617
- sequence: 3,
2618
- occurred_at: `${day}T12:00:02.000Z`,
2619
- type: "run.finished",
2620
- phase: "execution",
2621
- status: "completed",
2622
- duration_ms: duration,
2623
- duration_provenance: "observed",
2624
- },
2625
- ];
2626
- for (const [id, records] of [
2627
- [
2628
- "RUN-R1",
2629
- run("RUN-R1", "2026-08-01", "TASK-A", 600_000, "12:00:00.000Z", "SPEC-A", "PRD-A"),
2630
- ],
2631
- [
2632
- "RUN-R2",
2633
- run("RUN-R2", "2026-08-02", "TASK-B", 1_200_000, "12:00:00.000Z", "SPEC-B", "PRD-A"),
2634
- ],
2635
- [
2636
- "RUN-R3",
2637
- run("RUN-R3", "2026-08-02", "TASK-B", 1_200_000, "12:10:00.000Z", "SPEC-B", "PRD-A"),
2638
- ],
2639
- ] as const) {
2640
- await writeFile(
2641
- join(root, ".agents", "records", "runs", "2026", "08", `${id}.jsonl`),
2642
- `${records.map((record) => JSON.stringify(record)).join("\n")}\n`,
2643
- "utf8",
2644
- );
2645
- }
2646
- await writeFile(
2647
- join(
2648
- root,
2649
- ".agents",
2650
- "records",
2651
- "changes",
2652
- "2026",
2653
- "08",
2654
- "CHG-ART",
2655
- "artifacts",
2656
- "evidence",
2657
- "EVD-1.md",
2658
- ),
2659
- "---\nid: EVD-1\nobserved_at: 2026-08-01T12:00:00.000Z\n---\n# Evidence\n",
2660
- "utf8",
2661
- );
2662
- await writeFile(
2663
- join(
2664
- root,
2665
- ".agents",
2666
- "records",
2667
- "changes",
2668
- "2026",
2669
- "08",
2670
- "CHG-ART",
2671
- "artifacts",
2672
- "validations",
2673
- "VAL-1.md",
2674
- ),
2675
- "---\nid: VAL-1\nexecuted_at: 2026-08-02T12:00:00.000Z\n---\n# Validation\n",
2676
- "utf8",
2677
- );
2678
- for (const [kind, id] of [
2679
- ["tasks", "TASK-NO-RUN"],
2680
- ["specs", "SPEC-NO-RUN"],
2681
- ["prds", "PRD-NO-RUN"],
2682
- ] as const)
2683
- await writeFile(
2684
- join(root, ".agents", "records", kind, "2026", "08", `${id}.md`),
2685
- `---\nid: ${id}\ntitle: ${id}\nstatus: draft\ncreated_at: 2026-08-03T12:00:00.000Z\n---\n# ${id}\n`,
2686
- "utf8",
2687
- );
2688
- await rebuildSqliteReadModel(root);
2689
- const filesystem = new SqliteReadModelFileSystem(root);
2690
- expect(filesystem.firstFoldAggregate({ from: null, to: null }).execution_day_count).toBe(2);
2691
- expect(filesystem.firstFoldAggregate({ from: null, to: null }).duration_ms).toBe(2_400_000);
2692
- expect(filesystem.topTasks({ from: null, to: null })).toMatchObject([
2693
- { task_id: "TASK-B", duration_ms: 1_800_000 },
2694
- { task_id: "TASK-A", duration_ms: 600_000 },
2695
- ]);
2696
- expect(filesystem.summaryPage("task", { from: null, to: null }, 0, 50).rows).toContainEqual(
2697
- expect.objectContaining({
2698
- id: "TASK-B",
2699
- invocation_count: 2,
2700
- total_duration: 1_800_000,
2701
- total_tokens: 4,
2702
- total_cost_brl: 10,
2703
- }),
2704
- );
2705
- expect(filesystem.summaryPage("spec", { from: null, to: null }, 0, 50).rows).toContainEqual(
2706
- expect.objectContaining({
2707
- id: "SPEC-B",
2708
- invocation_count: 2,
2709
- total_duration: 1_800_000,
2710
- total_tokens: 4,
2711
- total_cost_brl: 10,
2712
- }),
2713
- );
2714
- expect(filesystem.summaryPage("prd", { from: null, to: null }, 0, 50).rows).toContainEqual(
2715
- expect.objectContaining({
2716
- id: "PRD-A",
2717
- invocation_count: 3,
2718
- total_duration: 2_400_000,
2719
- total_tokens: 6,
2720
- total_cost_brl: 15,
2721
- }),
2722
- );
2723
- expect(filesystem.summaryPage("task", { from: null, to: null }, 0, 50).rows).toContainEqual(
2724
- expect.objectContaining({
2725
- id: "TASK-NO-RUN",
2726
- invocation_count: null,
2727
- total_duration: null,
2728
- total_tokens: null,
2729
- total_cost_brl: null,
2730
- }),
2731
- );
2732
- const allTime = filesystem.firstFoldAllTime();
2733
- expectPersistedFirstFoldCaches(root, allTime, filesystem.firstFoldBoardAllTime());
2734
- expect(allTime.aggregate).toMatchObject({
2735
- start_day: "2026-08-01",
2736
- end_day: "2026-08-03",
2737
- task_count: 3,
2738
- spec_count: 3,
2739
- prd_count: 2,
2740
- total_run_count: 3,
2741
- duration_ms: 2_400_000,
2742
- total_tokens: 6,
2743
- cost_brl: 15,
2744
- execution_day_count: 2,
2745
- });
2746
- expect(allTime.task_status_counts).toEqual({ draft: 3 });
2747
- // The served quick projection uses this deliberately lean subset. It must
2748
- // remain factually identical to the rich projection for the six cards and
2749
- // two first-fold charts, while leaving rankings and macro metrics lazy.
2750
- const viewport = filesystem.firstFoldViewportAllTime();
2751
- expect(viewport.aggregate).toEqual(allTime.aggregate);
2752
- expect(viewport.task_status_counts).toEqual(allTime.task_status_counts);
2753
- expect(viewport.task_risk_counts).toEqual(allTime.task_risk_counts);
2754
- expect(allTime.top_tasks).toMatchObject([
2755
- { rank: 1, task_id: "TASK-B", total_duration_ms: 1_800_000 },
2756
- { rank: 2, task_id: "TASK-A", total_duration_ms: 600_000 },
2757
- ]);
2758
- expect(filesystem.firstFoldTopTasksAllTime()).toEqual(allTime.top_tasks);
2759
- expect(
2760
- projectAllTimeTopTasks([
2761
- {
2762
- task_id: "TASK-NO-USAGE",
2763
- total_duration_ms: null,
2764
- total_tokens: null,
2765
- total_cost_usd: null,
2766
- total_cost_brl: null,
2767
- total_run_count: 1,
2768
- },
2769
- ]),
2770
- ).toEqual([
2771
- {
2772
- task_id: "TASK-NO-USAGE",
2773
- duration_ms: null,
2774
- total_tokens: null,
2775
- total_cost_usd: null,
2776
- cost_brl: null,
2777
- run_count: 1,
2778
- },
2779
- ]);
2780
- const app = createDashboardApp(root, "test-session", undefined, { filesystem });
2781
- const allTimeQuick = await app.request("/api/v2/operations?scope=quick", {
2782
- headers: { "x-zaip-session": "test-session" },
2783
- });
2784
- const boundedQuick = await app.request(
2785
- "/api/v2/operations?scope=quick&from=2026-08-02&to=2026-08-02",
2786
- { headers: { "x-zaip-session": "test-session" } },
2787
- );
2788
- const topTasks = (await allTimeQuick.json()) as {
2789
- summary: { overview_metrics?: { top_tasks?: unknown[] } };
2790
- };
2791
- const boundedTopTasks = (await boundedQuick.json()) as {
2792
- summary: { overview_metrics?: { top_tasks?: unknown[] } };
2793
- };
2794
- expect(topTasks.summary.overview_metrics?.top_tasks).toEqual(
2795
- expect.arrayContaining([
2796
- expect.objectContaining({
2797
- task_id: "TASK-B",
2798
- duration_ms: 1_800_000,
2799
- total_tokens: 4,
2800
- cost_brl: 10,
2801
- }),
2802
- ]),
2803
- );
2804
- expect(boundedTopTasks.summary.overview_metrics?.top_tasks).toEqual([
2805
- expect.objectContaining({
2806
- task_id: "TASK-B",
2807
- duration_ms: 1_800_000,
2808
- total_tokens: 4,
2809
- cost_brl: 10,
2810
- }),
2811
- ]);
2812
- // A new calendar month after this immutable snapshot has no factual rows.
2813
- // It must be a fast exact empty projection, not a slow scan caused by the
2814
- // default date range changing at midnight on the first day of the month.
2815
- const nextMonthQuick = await app.request(
2816
- "/api/v2/operations?scope=quick&from=2026-09-01&to=2026-09-01",
2817
- { headers: { "x-zaip-session": "test-session" } },
2818
- );
2819
- const nextMonth = (await nextMonthQuick.json()) as {
2820
- summary: {
2821
- run_count: number;
2822
- task_count: number;
2823
- overview_metrics: { tokens: number | null; duration_ms: number | null };
2824
- };
2825
- };
2826
- expect(nextMonth.summary).toMatchObject({
2827
- run_count: 0,
2828
- task_count: 0,
2829
- overview_metrics: { tokens: null, duration_ms: null },
2830
- });
2831
- expect(allTime.macro_metrics.specs).toMatchObject({
2832
- entity_count: 3,
2833
- status_counts: { planning: 3 },
2834
- classification_counts: { structured: 2 },
2835
- total_run_count: 3,
2836
- total_duration_ms: 2_400_000,
2837
- total_tokens: 6,
2838
- total_cost_brl: 15,
2839
- average_duration_ms: 800_000,
2840
- });
2841
- expect(allTime.macro_metrics.specs.top_entities.slice(0, 2)).toMatchObject([
2842
- { rank: 1, entity_id: "SPEC-B", total_duration_ms: 1_800_000 },
2843
- { rank: 2, entity_id: "SPEC-A", total_duration_ms: 600_000 },
2844
- ]);
2845
- expect(allTime.macro_metrics.prds).toMatchObject({
2846
- entity_count: 2,
2847
- status_counts: { definition: 2 },
2848
- classification_counts: { structured: 1 },
2849
- total_run_count: 3,
2850
- total_duration_ms: 2_400_000,
2851
- total_tokens: 6,
2852
- total_cost_brl: 15,
2853
- average_duration_ms: 1_200_000,
2854
- });
2855
- const operationDays = filesystem.dailyPeriods({ from: null, to: null });
2856
- expect(Object.keys(operationDays)).toEqual(["2026-08-01", "2026-08-02", "2026-08-03"]);
2857
- expect(operationDays["2026-08-02"]).toMatchObject({
2858
- runs: 2,
2859
- specs: 1,
2860
- tasks: 1,
2861
- validations: 1,
2862
- evidences: 0,
2863
- usage: {
2864
- total_tokens: { known_sum: 4, unknown: 0 },
2865
- cost: { known_sum: 10, unknown: 0 },
2866
- },
2867
- duration: { known_sum: 1_800_000, unknown: 0 },
2868
- });
2869
- expect(filesystem.viewPage("operations_daily", { limit: 50 }).rows).toContainEqual(
2870
- expect.objectContaining({
2871
- day: "2026-08-02",
2872
- task_count: 1,
2873
- spec_count: 1,
2874
- validation_count: 1,
2875
- evidence_count: 0,
2876
- total_run_count: 2,
2877
- operations_total_duration: 1_800_000,
2878
- total_tokens: 4,
2879
- total_cost_brl: 10,
2880
- }),
2881
- );
2882
- for (const [view, key] of [
2883
- ["operations_monthly", "2026-08"],
2884
- ["operations_annual", "2026"],
2885
- ] as const) {
2886
- expect(filesystem.viewPage(view, { limit: 50 }).rows).toContainEqual(
2887
- expect.objectContaining({
2888
- period_key: key,
2889
- prd_count: 2,
2890
- spec_count: 3,
2891
- task_count: 3,
2892
- validation_count: 1,
2893
- evidence_count: 1,
2894
- total_run_count: 3,
2895
- operations_total_duration: 2_400_000,
2896
- total_tokens: 6,
2897
- total_cost_brl: 15,
2898
- }),
2899
- );
2900
- }
2901
- for (const view of ["operations_monthly", "operations_annual"] as const) {
2902
- expect(
2903
- filesystem.viewPage(view, {
2904
- from: "2026-08-02T03:00:00.000Z",
2905
- to: "2026-08-02T23:59:59.999Z",
2906
- limit: 50,
2907
- }).rows,
2908
- ).toEqual([
2909
- expect.objectContaining({
2910
- start_day: "2026-08-02",
2911
- end_day: "2026-08-02",
2912
- total_run_count: 2,
2913
- invocation_count: 2,
2914
- operations_total_duration: 1_800_000,
2915
- total_tokens: 4,
2916
- total_cost_usd: 2,
2917
- total_cost_brl: 10,
2918
- }),
2919
- ]);
2920
- }
2921
- for (const [view, key, counts] of [
2922
- [
2923
- "cost_monitor_daily",
2924
- "2026-08-02",
2925
- { prd_count: 0, spec_count: 1, task_count: 1, validation_count: 1, evidence_count: 0 },
2926
- ],
2927
- [
2928
- "cost_monitor_monthly",
2929
- "2026-08",
2930
- { prd_count: 2, spec_count: 3, task_count: 3, validation_count: 1, evidence_count: 1 },
2931
- ],
2932
- [
2933
- "cost_monitor_annual",
2934
- "2026",
2935
- { prd_count: 2, spec_count: 3, task_count: 3, validation_count: 1, evidence_count: 1 },
2936
- ],
2937
- ] as const) {
2938
- expect(filesystem.viewPage(view, { limit: 50 }).rows).toContainEqual(
2939
- expect.objectContaining({ key, ...counts }),
2940
- );
2941
- }
2942
- expect(filesystem.viewPage("cost_monitor_daily", { limit: 50 }).rows).toContainEqual(
2943
- expect.objectContaining({ key: "2026-08-03", prd_count: 1, spec_count: 1, task_count: 1 }),
2944
- );
2945
- expect(filesystem.viewPage("cost_monitor_monthly", { limit: 50 }).rows).toContainEqual(
2946
- expect.objectContaining({ key: "2026-08", prd_count: 2, spec_count: 3, task_count: 3 }),
2947
- );
2948
- expect(filesystem.viewPage("cost_monitor_annual", { limit: 50 }).rows).toContainEqual(
2949
- expect.objectContaining({ key: "2026", prd_count: 2, spec_count: 3, task_count: 3 }),
2950
- );
2951
- const annualCostPage = filesystem.viewPage("cost_monitor_annual", { limit: 50 });
2952
- const dailyCostRows = filesystem.viewPage("cost_monitor_daily", { limit: 50 }).rows;
2953
- const pagedDailyCostPage = filesystem.viewPage("cost_monitor_daily", { limit: 1 });
2954
- expect(pagedDailyCostPage).toMatchObject({
2955
- total_count: dailyCostRows.length,
2956
- rows: [expect.any(Object)],
2957
- });
2958
- expect(pagedDailyCostPage.totals).toMatchObject({
2959
- total_tokens: dailyCostRows.reduce((sum, row) => sum + Number(row.total_tokens ?? 0), 0),
2960
- total_cost_brl: dailyCostRows.reduce((sum, row) => sum + Number(row.total_cost_brl ?? 0), 0),
2961
- total_duration: dailyCostRows.reduce((sum, row) => sum + Number(row.total_duration ?? 0), 0),
2962
- });
2963
- expect(annualCostPage).toMatchObject({
2964
- total_count: 1,
2965
- rows: [expect.objectContaining({ key: "2026" })],
2966
- });
2967
- const annualCostRow = annualCostPage.rows[0];
2968
- if (annualCostRow === undefined) throw new Error("Expected the consolidated 2026 Cost row");
2969
- for (const metric of [
2970
- "prd_count",
2971
- "spec_count",
2972
- "task_count",
2973
- "validation_count",
2974
- "evidence_count",
2975
- "total_run_count",
2976
- "total_duration",
2977
- "duration_known",
2978
- "total_tokens",
2979
- "total_cost_usd",
2980
- "total_cost_brl",
2981
- ] as const) {
2982
- const observed = dailyCostRows
2983
- .map((row) => row[metric])
2984
- .filter((value): value is number => typeof value === "number");
2985
- expect(annualCostRow[metric]).toBe(
2986
- observed.length === 0 ? null : observed.reduce((sum, value) => sum + value, 0),
2987
- );
2988
- }
2989
- expect(
2990
- filesystem.viewPage("cost_monitor_daily", { limit: 50, provider: "openai" }).rows,
2991
- ).toContainEqual(
2992
- expect.objectContaining({
2993
- key: "2026-08-02",
2994
- prd_count: 0,
2995
- spec_count: 1,
2996
- task_count: 1,
2997
- validation_count: 1,
2998
- evidence_count: 0,
2999
- }),
3000
- );
3001
- for (const [view, entityCount] of [
3002
- ["cost_monitor_tasks", 2],
3003
- ["cost_monitor_specs", 3],
3004
- ["cost_monitor_prds", 2],
3005
- ["cost_monitor_conversations", 3],
3006
- ] as const) {
3007
- const page = filesystem.viewPage(view, { limit: 1 });
3008
- // The subtotal is computed before pagination and reconciles the full
3009
- // filtered population, rather than the single visible row.
3010
- expect(page).toMatchObject({ total_count: entityCount, rows: [expect.any(Object)] });
3011
- expect(page.totals).toEqual({
3012
- entity_count: entityCount,
3013
- invocation_count: 3,
3014
- total_duration: 2_400_000,
3015
- total_tokens: 6,
3016
- total_cost_usd: 3,
3017
- total_cost_brl: 15,
3018
- });
3019
- }
3020
- expect(
3021
- filesystem.viewPage("cost_monitor_tasks", {
3022
- from: "2026-08-02",
3023
- to: "2026-08-02",
3024
- query: "TASK-B",
3025
- limit: 1,
3026
- }).totals,
3027
- ).toEqual({
3028
- entity_count: 1,
3029
- invocation_count: 2,
3030
- total_duration: 1_800_000,
3031
- total_tokens: 4,
3032
- total_cost_usd: 2,
3033
- total_cost_brl: 10,
3034
- });
3035
- // The compact Cost Monitor tables share the canonical macro population
3036
- // with their big numbers. A macro with no direct invocation must remain
3037
- // paginable and retain unavailable financial facts as null.
3038
- expect(
3039
- filesystem.viewPage("cost_monitor_specs", { query: "SPEC-NO-RUN", limit: 1 }),
3040
- ).toMatchObject({
3041
- total_count: 1,
3042
- totals: {
3043
- entity_count: 1,
3044
- invocation_count: 0,
3045
- total_duration: null,
3046
- total_tokens: null,
3047
- total_cost_brl: null,
3048
- },
3049
- rows: [
3050
- expect.objectContaining({
3051
- id: "SPEC-NO-RUN",
3052
- title: "SPEC-NO-RUN",
3053
- invocation_count: 0,
3054
- total_duration: null,
3055
- total_tokens: null,
3056
- total_cost_brl: null,
3057
- }),
3058
- ],
3059
- });
3060
- expect(
3061
- filesystem.viewPage("cost_monitor_prds", { query: "PRD-NO-RUN", limit: 1 }),
3062
- ).toMatchObject({
3063
- total_count: 1,
3064
- totals: {
3065
- entity_count: 1,
3066
- invocation_count: 0,
3067
- total_duration: null,
3068
- total_tokens: null,
3069
- total_cost_brl: null,
3070
- },
3071
- rows: [
3072
- expect.objectContaining({
3073
- id: "PRD-NO-RUN",
3074
- title: "PRD-NO-RUN",
3075
- invocation_count: 0,
3076
- total_duration: null,
3077
- total_tokens: null,
3078
- total_cost_brl: null,
3079
- }),
3080
- ],
3081
- });
3082
- for (const view of [
3083
- "cost_monitor_tasks",
3084
- "cost_monitor_specs",
3085
- "cost_monitor_prds",
3086
- "cost_monitor_conversations",
3087
- ] as const) {
3088
- const filtered = filesystem.viewPage(view, {
3089
- phase: "execution",
3090
- provider: "openai",
3091
- model: "gpt-5",
3092
- limit: 1,
3093
- });
3094
- // Dimensional membership and the subtotal share one pre-pagination
3095
- // invocation population for every compact lifecycle view.
3096
- expect(filtered.rows).toHaveLength(1);
3097
- expect(filtered.totals).toMatchObject({
3098
- invocation_count: 3,
3099
- total_tokens: 6,
3100
- total_cost_brl: 15,
3101
- });
3102
- }
3103
- expect(filesystem.viewPage("cost_monitor_tasks", { workType: "new", limit: 1 })).toMatchObject({
3104
- total_count: 0,
3105
- rows: [],
3106
- });
3107
- expect(filesystem.firstFoldAllTime()).toBe(allTime);
3108
- filesystem.close();
3109
-
3110
- // Period membership follows the canonical macro day, not an invocation
3111
- // that happened on another day. Search accepts either the macro ID or
3112
- // title, and totals are still calculated before its one-row page.
3113
- await writeFile(
3114
- join(root, ".agents", "records", "specs", "2026", "08", "SPEC-CANONICAL-DAY.md"),
3115
- "---\nid: SPEC-CANONICAL-DAY\ntitle: Macro by canonical title\nstatus: draft\ncreated_at: 2026-08-03T12:00:00.000Z\n---\n# Macro\n",
3116
- "utf8",
3117
- );
3118
- await writeFile(
3119
- join(root, ".agents", "records", "runs", "2026", "08", "RUN-CANONICAL-DAY.jsonl"),
3120
- `${run(
3121
- "RUN-CANONICAL-DAY",
3122
- "2026-08-02",
3123
- "TASK-CANONICAL-DAY",
3124
- 1_000,
3125
- "12:30:00.000Z",
3126
- "SPEC-CANONICAL-DAY",
3127
- )
3128
- .map((record) => JSON.stringify(record))
3129
- .join("\n")}\n`,
3130
- "utf8",
3131
- );
3132
- await writeFile(
3133
- join(root, ".agents", "records", "runs", "2026", "08", "RUN-CANONICAL-DAY-LATE.jsonl"),
3134
- `${run(
3135
- "RUN-CANONICAL-DAY-LATE",
3136
- "2026-08-04",
3137
- "TASK-CANONICAL-DAY-LATE",
3138
- 1_000,
3139
- "12:30:00.000Z",
3140
- "SPEC-CANONICAL-DAY",
3141
- )
3142
- .map((record) => JSON.stringify(record))
3143
- .join("\n")}\n`,
3144
- "utf8",
3145
- );
3146
- await rebuildSqliteReadModel(root);
3147
- const canonicalDayFilesystem = new SqliteReadModelFileSystem(root);
3148
- expect(
3149
- canonicalDayFilesystem.viewPage("cost_monitor_specs", {
3150
- from: "2026-08-03",
3151
- to: "2026-08-03",
3152
- query: "canonical title",
3153
- limit: 1,
3154
- }),
3155
- ).toMatchObject({
3156
- total_count: 1,
3157
- totals: { entity_count: 1, invocation_count: 0, total_tokens: null, total_cost_brl: null },
3158
- rows: [
3159
- expect.objectContaining({
3160
- id: "SPEC-CANONICAL-DAY",
3161
- invocation_count: 0,
3162
- total_tokens: null,
3163
- total_cost_brl: null,
3164
- }),
3165
- ],
3166
- });
3167
- expect(
3168
- canonicalDayFilesystem.viewPage("cost_monitor_specs", {
3169
- from: "2026-08-02",
3170
- to: "2026-08-02",
3171
- query: "SPEC-CANONICAL-DAY",
3172
- limit: 1,
3173
- }),
3174
- ).toMatchObject({ total_count: 0, rows: [] });
3175
- canonicalDayFilesystem.close();
3176
-
3177
- // A large result set keeps its subtotal for all 270 matching Tasks while
3178
- // the page transports only 50 records.
3179
- for (let index = 0; index < 270; index += 1) {
3180
- const id = `RUN-PAGE-${index}`;
3181
- await writeFile(
3182
- join(root, ".agents", "records", "runs", "2026", "08", `${id}.jsonl`),
3183
- `${run(id, "2026-08-04", `TASK-PAGE-${index}`, 1_000)
3184
- .map((record) => JSON.stringify(record))
3185
- .join("\n")}\n`,
3186
- "utf8",
3187
- );
3188
- }
3189
- await rebuildSqliteReadModel(root);
3190
- const pageFilesystem = new SqliteReadModelFileSystem(root);
3191
- const paged = pageFilesystem.viewPage("cost_monitor_tasks", {
3192
- from: "2026-08-04",
3193
- to: "2026-08-04",
3194
- query: "TASK-PAGE-",
3195
- offset: 50,
3196
- limit: 50,
3197
- });
3198
- expect(paged).toMatchObject({ total_count: 270, has_more: true });
3199
- expect(paged.rows).toHaveLength(50);
3200
- expect(paged.totals).toEqual({
3201
- entity_count: 270,
3202
- invocation_count: 270,
3203
- total_duration: 1_000,
3204
- total_tokens: 540,
3205
- total_cost_usd: 270,
3206
- total_cost_brl: 1_350,
3207
- });
3208
- pageFilesystem.close();
3209
- });
3210
-
3211
- it("rebuilds a disposable snapshot and serves ZAIP records from SQLite", async () => {
3212
- const root = await createSqliteTestRoot();
3213
- roots.push(root);
3214
- await mkdir(join(root, ".agents", "records", "tasks"), { recursive: true });
3215
- await mkdir(join(root, ".agents", "config"), { recursive: true });
3216
- await writeFile(join(root, ".agents", "records", "tasks", "task.md"), "# task\n", "utf8");
3217
- await writeFile(
3218
- join(root, ".agents", "config", "project.yaml"),
3219
- "zaip:\n enabled: true\n",
3220
- "utf8",
3221
- );
3222
- const result = await rebuildSqliteReadModel(root);
3223
- const filesystem = new SqliteReadModelFileSystem(root);
3224
- expect(result.files).toBe(2);
3225
- await expect(filesystem.readText(".agents/records/tasks/task.md")).resolves.toContain("task");
3226
- await expect(filesystem.listFiles(".agents/records", ".md")).resolves.toEqual([
3227
- ".agents/records/tasks/task.md",
3228
- ]);
3229
- filesystem.close();
3230
- });
3231
-
3232
- it("serves canonical Task trace inputs without lifecycle manifests", async () => {
3233
- const root = await createSqliteTestRoot();
3234
- roots.push(root);
3235
- await mkdir(join(root, ".agents", "records", "tasks", "2026", "08"), {
3236
- recursive: true,
3237
- });
3238
- await mkdir(join(root, ".agents", "config"), { recursive: true });
3239
- await writeFile(
3240
- join(root, ".agents", "config", "project.yaml"),
3241
- "zaip:\n enabled: true\n",
3242
- "utf8",
3243
- );
3244
- await writeFile(
3245
- join(root, ".agents", "records", "tasks", "2026", "08", "TASK-TRACE.md"),
3246
- "---\nid: TASK-TRACE\ntitle: Canonical trace\nstatus: completed\nrisk: standard\ncreated_at: 2026-08-01T12:00:00.000Z\n---\n# Canonical trace\n",
3247
- "utf8",
3248
- );
3249
- await rebuildSqliteReadModel(root);
3250
- const filesystem = new SqliteReadModelFileSystem(root);
3251
- expect(filesystem.canonicalTraceFiles(["TASK-TRACE"])).toMatchObject([
3252
- { path: ".agents/records/tasks/2026/08/TASK-TRACE.md" },
3253
- ]);
3254
- expect(filesystem.taskTraceUsage("TASK-TRACE")).toEqual({
3255
- run_count: 0,
3256
- duration_ms: { value: null, known_runs: 0, unknown_runs: 0, coverage_ratio: 1 },
3257
- total_tokens: { value: null, known_runs: 0, unknown_runs: 0, coverage_ratio: 1 },
3258
- cost: {
3259
- value: null,
3260
- known_runs: 0,
3261
- unknown_runs: 0,
3262
- coverage_ratio: 1,
3263
- currency: null,
3264
- },
3265
- });
3266
- filesystem.close();
3267
- });
3268
-
3269
- it("invalidates a nested canonical source change and ignores legacy aggregate telemetry", async () => {
3270
- const root = await createSqliteTestRoot();
3271
- roots.push(root);
3272
- const nested = join(root, ".agents", "records", "tasks", "nested", "task.md");
3273
- await mkdir(join(root, ".agents", "config"), { recursive: true });
3274
- await mkdir(join(root, ".agents", "records", "tasks", "nested"), { recursive: true });
3275
- await writeFile(
3276
- join(root, ".agents", "config", "project.yaml"),
3277
- "zaip:\n enabled: true\n",
3278
- "utf8",
3279
- );
3280
- await writeFile(nested, "# before\n", "utf8");
3281
- await rebuildSqliteReadModel(root);
3282
- await writeFile(nested, "# after\n", "utf8");
3283
- const changedAt = new Date(Date.now() + 2_000);
3284
- await utimes(nested, changedAt, changedAt);
3285
- await rebuildSqliteReadModel(root);
3286
- const updated = new SqliteReadModelFileSystem(root);
3287
- await expect(updated.readText(".agents/records/tasks/nested/task.md")).resolves.toContain(
3288
- "after",
3289
- );
3290
- updated.close();
3291
-
3292
- const duplicate = join(
3293
- root,
3294
- ".agents",
3295
- "records",
3296
- "telemetry",
3297
- "2026",
3298
- "08",
3299
- "writers",
3300
- "w",
3301
- "chunks",
3302
- "c.jsonl",
3303
- );
3304
- await mkdir(
3305
- join(root, ".agents", "records", "telemetry", "2026", "08", "writers", "w", "chunks"),
3306
- { recursive: true },
3307
- );
3308
- await writeFile(
3309
- join(root, ".agents", "records", "telemetry", "2026", "08", "writers", "w", "manifest.json"),
3310
- JSON.stringify({
3311
- chunks: [{ path: ".agents/records/telemetry/2026/08/writers/w/chunks/c.jsonl" }],
3312
- }),
3313
- "utf8",
3314
- );
3315
- await writeFile(
3316
- duplicate,
3317
- `${JSON.stringify({ agent_invocation_id: "same", summary_hash: "one" })}\n${JSON.stringify({ agent_invocation_id: "same", summary_hash: "two" })}\n`,
3318
- "utf8",
3319
- );
3320
- await expect(rebuildSqliteReadModel(root)).resolves.toMatchObject({ files: 2 });
3321
- expect(await readFile(nested, "utf8")).toContain("after");
3322
- const retained = new SqliteReadModelFileSystem(root);
3323
- await expect(retained.readText(".agents/records/tasks/nested/task.md")).resolves.toContain(
3324
- "after",
3325
- );
3326
- retained.close();
3327
- });
3328
-
3329
- it("does not promote legacy aggregate telemetry into canonical activity facts", async () => {
3330
- const root = await createSqliteTestRoot();
3331
- roots.push(root);
3332
- await mkdir(
3333
- join(root, ".agents", "records", "telemetry", "2026", "08", "writers", "w", "chunks"),
3334
- { recursive: true },
3335
- );
3336
- await mkdir(join(root, ".agents", "config"), { recursive: true });
3337
- await writeFile(
3338
- join(root, ".agents", "config", "project.yaml"),
3339
- "zaip:\n enabled: true\n",
3340
- "utf8",
3341
- );
3342
- const summary = {
3343
- agent_invocation_id: "root",
3344
- summary_hash: "hash",
3345
- root_agent_invocation_id: "root",
3346
- parent_agent_invocation_id: null,
3347
- execution_id: null,
3348
- task_id: null,
3349
- spec_id: null,
3350
- prd_id: null,
3351
- change_id: null,
3352
- run_id: "RUN-1",
3353
- occurred_at: "2026-08-01T12:00:00.000Z",
3354
- invocation_kind: "orchestrator",
3355
- delegation_depth: 0,
3356
- source_event_count: 1,
3357
- historical_cost: {
3358
- estimated_usd: 2,
3359
- estimated_brl: 10,
3360
- fx_rate: 5,
3361
- pricing_model: "model",
3362
- pricing_source: "canonical",
3363
- },
3364
- quantitative_metrics: { duration_ms: { known_sum: 5 }, tokens_total: { known_sum: 0 } },
3365
- usage_segments: [
3366
- {
3367
- provider: "openai",
3368
- model: "model",
3369
- service_tier: "default",
3370
- reasoning_effort: "medium",
3371
- tokens: { input: 0, cached_input: 0, output: 0, reasoning: 0, total: 0 },
3372
- historical_cost: {
3373
- estimated_usd: 2,
3374
- estimated_brl: 10,
3375
- fx_rate: 5,
3376
- pricing_model: "model",
3377
- pricing_source: "canonical",
3378
- },
3379
- },
3380
- ],
3381
- };
3382
- await writeFile(
3383
- join(
3384
- root,
3385
- ".agents",
3386
- "records",
3387
- "telemetry",
3388
- "2026",
3389
- "08",
3390
- "writers",
3391
- "w",
3392
- "chunks",
3393
- "c.jsonl",
3394
- ),
3395
- `${JSON.stringify(summary)}\n`,
3396
- "utf8",
3397
- );
3398
- await writeFile(
3399
- join(root, ".agents", "records", "telemetry", "2026", "08", "writers", "w", "manifest.json"),
3400
- JSON.stringify({
3401
- chunks: [{ path: ".agents/records/telemetry/2026/08/writers/w/chunks/c.jsonl" }],
3402
- }),
3403
- "utf8",
3404
- );
3405
- await rebuildSqliteReadModel(root);
3406
- const filesystem = new SqliteReadModelFileSystem(root);
3407
- expect(filesystem.firstFoldAggregate({ from: "2026-08-01", to: "2026-08-01" })).toEqual({
3408
- days: 0,
3409
- total_run_count: 0,
3410
- agent_invocation_count: 0,
3411
- llm_call_count: null,
3412
- duration_ms: null,
3413
- total_tokens: null,
3414
- cost_brl: null,
3415
- execution_day_count: 0,
3416
- });
3417
- const database = new DatabaseSync(resolve(root, ".local/sqlite/zaip-aios-dashboard.sqlite"), {
3418
- readOnly: true,
3419
- });
3420
- const columns = (table: string) =>
3421
- (database.prepare(`PRAGMA table_info(${table})`).all() as Array<{ name: string }>).map(
3422
- (row) => row.name,
3423
- );
3424
- expect(columns("zaip_vw_daily_aggregates")).toEqual(
3425
- expect.arrayContaining([
3426
- "day",
3427
- "invocation_count",
3428
- "total_duration",
3429
- "total_tokens",
3430
- "total_cost_usd",
3431
- "total_cost_brl",
3432
- ]),
3433
- );
3434
- expect(columns("zaip_vw_daily_aggregates")).not.toContain(["sub", "run_count"].join(""));
3435
- expect(columns("zaip_vw_invocations")).toEqual(
3436
- expect.arrayContaining([
3437
- "cost_usd",
3438
- "cost_brl",
3439
- "cost_method",
3440
- "pricing_model",
3441
- "pricing_source",
3442
- "fx_rate",
3443
- ]),
3444
- );
3445
- expect(columns("zaip_vw_invocations")).not.toEqual(
3446
- expect.arrayContaining([
3447
- "coverage",
3448
- "_coverage",
3449
- "usage_segments_json",
3450
- "estimated_usd",
3451
- "estimated_brl",
3452
- ]),
3453
- );
3454
- expect(columns("zaip_vw_invocation_usage")).not.toContain("coverage");
3455
- expect(database.prepare("SELECT COUNT(*) AS count FROM zaip_vw_invocations").get()).toEqual({
3456
- count: 0,
3457
- });
3458
- database.close();
3459
- filesystem.close();
3460
- });
3461
657
  });