@zaip-ai/cli 1.0.8 → 1.3.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.
- package/README.md +1 -1
- package/dist/services/adapters.d.ts +1 -1
- package/dist/services/adapters.js +1 -1
- package/dist/services/agent-adapters.js +2 -2
- package/dist/services/agent-adapters.js.map +1 -1
- package/dist/services/agent-adapters.test.js +5 -0
- package/dist/services/agent-adapters.test.js.map +1 -1
- package/dist/services/logger.test.js +2 -2
- package/dist/services/runtime-template.test.js +6 -6
- package/dist/services/template-manifest.d.ts.map +1 -1
- package/dist/services/template-manifest.js +5 -0
- package/dist/services/template-manifest.js.map +1 -1
- package/package.json +1 -1
- package/templates/.agents/architecture/software-architecture.md +131 -0
- package/templates/.agents/branding/brandbook.docx +0 -0
- package/templates/.agents/branding/brandbook.md +60 -0
- package/templates/.agents/config/clients/codex/agents/zaip-agent-finalizer.toml +1 -1
- package/templates/.agents/config/clients/codex/agents/zaip-agent-orchestrator.toml +1 -1
- package/templates/.agents/dashboard/.tmp-run-list.json +254 -0
- package/templates/.agents/dashboard/.zaip-managed.json +252 -136
- package/templates/.agents/dashboard/apps/frontend/dist/assets/{CostCalculationGuidePage-Z60df2r-.js → CostCalculationGuidePage-DxR_pgSV.js} +1 -1
- package/templates/.agents/dashboard/apps/frontend/dist/assets/DashboardHelpDialog-4jZLTWE_.js +2156 -0
- package/templates/.agents/dashboard/apps/frontend/dist/assets/{PricingSettingsDialog-Coc6pA-1.js → PricingSettingsDialog-CKcsqb-r.js} +1 -1
- package/templates/.agents/dashboard/apps/frontend/dist/assets/ProjectSettingsPage-BomxqCBU.css +1 -0
- package/templates/.agents/dashboard/apps/frontend/dist/assets/ProjectSettingsPage-DmmJD2Th.js +3 -0
- package/templates/.agents/dashboard/apps/frontend/dist/assets/TraceabilityWorkspace-BwtitWa_.js +1 -0
- package/templates/.agents/dashboard/apps/frontend/dist/assets/cost-monitor-N5Csr0RP.js +68 -0
- package/templates/.agents/dashboard/apps/frontend/dist/assets/{icons-vendor-DFBuc_qp.js → icons-vendor-C0fj2uU9.js} +1 -1
- package/templates/.agents/dashboard/apps/frontend/dist/assets/index-C4aIB1PV.js +2 -0
- package/templates/.agents/dashboard/apps/frontend/dist/assets/{react-vendor-CCQOHdVI.js → react-vendor-BEsJ-FYH.js} +1 -1
- package/templates/.agents/dashboard/apps/frontend/dist/assets/{traceability-pC2_0J8x.js → traceability-B6y6Gw12.js} +1 -1
- package/templates/.agents/dashboard/apps/frontend/dist/index.html +5 -5
- package/templates/.agents/dashboard/apps/frontend/package.json +1 -1
- package/templates/.agents/dashboard/apps/frontend/src/App.tsx +204 -32
- package/templates/.agents/dashboard/apps/frontend/src/DashboardAlternateContent.tsx +11 -11
- package/templates/.agents/dashboard/apps/frontend/src/ProjectSettingsPage.tsx +14 -7
- package/templates/.agents/dashboard/apps/frontend/src/ProjectStackEditor.tsx +4 -2
- package/templates/.agents/dashboard/apps/frontend/src/TraceabilityWorkspace.test.ts +3 -1
- package/templates/.agents/dashboard/apps/frontend/src/TraceabilityWorkspace.tsx +14 -11
- package/templates/.agents/dashboard/apps/frontend/src/cost-period-refresh.test.ts +19 -4
- package/templates/.agents/dashboard/apps/frontend/src/dashboard-api.test.ts +24 -2
- package/templates/.agents/dashboard/apps/frontend/src/dashboard-api.ts +22 -1
- package/templates/.agents/dashboard/apps/frontend/src/overview-status-page.test.ts +3 -1
- package/templates/.agents/dashboard/apps/frontend/src/project-settings-page.css +36 -26
- package/templates/.agents/dashboard/apps/frontend/src/project-settings.test.ts +2 -2
- package/templates/.agents/dashboard/apps/frontend/src/snapshot-banner-semantics.test.ts +40 -6
- package/templates/.agents/dashboard/apps/frontend/src/snapshot-coherence.test.ts +39 -1
- package/templates/.agents/dashboard/apps/frontend/src/use-app-cost-loaders.test.ts +89 -23
- package/templates/.agents/dashboard/apps/frontend/src/use-app-cost-loaders.ts +219 -29
- package/templates/.agents/dashboard/apps/frontend/src/use-app-effects.ts +61 -7
- package/templates/.agents/dashboard/apps/frontend/src/use-app-operations-pages.ts +3 -6
- package/templates/.agents/dashboard/apps/frontend/src/work-list-pagination.test.ts +2 -2
- package/templates/.agents/dashboard/apps/frontend/src/work-list-pagination.ts +3 -4
- package/templates/.agents/dashboard/apps/frontend/vite.config.ts +4 -1
- package/templates/.agents/dashboard/modules/cost-monitor/package.json +1 -1
- package/templates/.agents/dashboard/modules/cost-monitor/src/react/CompactLifecycleCostTable.test.ts +89 -19
- package/templates/.agents/dashboard/modules/cost-monitor/src/react/CompactLifecycleCostTable.tsx +31 -16
- package/templates/.agents/dashboard/modules/cost-monitor/src/react/CostCharts.test.ts +43 -14
- package/templates/.agents/dashboard/modules/cost-monitor/src/react/CostCharts.tsx +5 -5
- package/templates/.agents/dashboard/modules/cost-monitor/src/react/CostModelsAuditTable.tsx +1 -1
- package/templates/.agents/dashboard/modules/cost-monitor/src/react/CostMonitorContent.tsx +67 -42
- package/templates/.agents/dashboard/modules/cost-monitor/src/react/CostMonitorPage.test.ts +115 -39
- package/templates/.agents/dashboard/modules/cost-monitor/src/react/CostMonitorPage.tsx +188 -38
- package/templates/.agents/dashboard/modules/cost-monitor/src/react/CostTables.test.ts +75 -17
- package/templates/.agents/dashboard/modules/cost-monitor/src/react/CostTables.tsx +147 -58
- package/templates/.agents/dashboard/modules/cost-monitor/src/react/cost-monitor.css +5 -2
- package/templates/.agents/dashboard/modules/cost-monitor/src/react/index.ts +2 -2
- package/templates/.agents/dashboard/modules/cost-monitor/src/react/period-cost-groups.ts +2 -1
- package/templates/.agents/dashboard/modules/cost-monitor/src/react/use-compact-cost-page.ts +18 -7
- package/templates/.agents/dashboard/modules/cost-monitor/src/react/use-cost-group-page.ts +95 -9
- package/templates/.agents/dashboard/modules/cost-monitor/src/react/use-cost-run-page.ts +29 -17
- package/templates/.agents/dashboard/modules/cost-monitor/src/server/build-cost-monitor-projection.test.ts +0 -24
- package/templates/.agents/dashboard/modules/cost-monitor/src/server/build-cost-summary-projection.test.ts +225 -424
- package/templates/.agents/dashboard/modules/cost-monitor/src/server/build-cost-summary-projection.ts +24 -15
- package/templates/.agents/dashboard/modules/cost-monitor/src/server/build-cost-summary-terminal-day.test.ts +6 -1
- package/templates/.agents/dashboard/modules/cost-monitor/src/server/source-size-cost-server/build-cost-monitor-projection-agents.test.ts +31 -0
- package/templates/.agents/dashboard/modules/cost-monitor/src/server/source-size-cost-server/build-cost-summary-projection-duration.test.ts +414 -0
- package/templates/.agents/dashboard/modules/operations/package.json +1 -1
- package/templates/.agents/dashboard/modules/operations/src/contracts.ts +26 -23
- package/templates/.agents/dashboard/modules/operations/src/react/EntityTables.tsx +31 -11
- package/templates/.agents/dashboard/modules/operations/src/react/OperationsOverview.test.ts +3 -1
- package/templates/.agents/dashboard/modules/operations/src/react/OperationsOverview.tsx +51 -21
- package/templates/.agents/dashboard/modules/operations/src/react/OperationsPage.tsx +47 -5
- package/templates/.agents/dashboard/modules/operations/src/react/OperationsPageNavigation.tsx +1 -4
- package/templates/.agents/dashboard/modules/operations/src/react/PeriodSummaryTable.tsx +32 -10
- package/templates/.agents/dashboard/modules/operations/src/react/TaskDetailsDialog.tsx +9 -3
- package/templates/.agents/dashboard/modules/operations/src/react/UnifiedWorkBoard.tsx +13 -5
- package/templates/.agents/dashboard/modules/operations/src/react/UnifiedWorkList.test.ts +12 -4
- package/templates/.agents/dashboard/modules/operations/src/react/UnifiedWorkList.tsx +1 -4
- package/templates/.agents/dashboard/modules/operations/src/react/conversation-rows.ts +1 -2
- package/templates/.agents/dashboard/modules/operations/src/react/export/ExcelExportAction.test.ts +385 -4
- package/templates/.agents/dashboard/modules/operations/src/react/export/ExcelExportAction.tsx +481 -61
- package/templates/.agents/dashboard/modules/operations/src/react/export/export-layout.test.ts +14 -1
- package/templates/.agents/dashboard/modules/operations/src/react/export/xlsx-runtime-e2e.test.ts +248 -0
- package/templates/.agents/dashboard/modules/operations/src/react/operation-duration.test.ts +4 -4
- package/templates/.agents/dashboard/modules/operations/src/react/operation-duration.ts +6 -4
- package/templates/.agents/dashboard/modules/operations/src/react/operations-global-filters.test.ts +4 -1
- package/templates/.agents/dashboard/modules/operations/src/react/operations-overview-period-filter.test.ts +1 -1
- package/templates/.agents/dashboard/modules/operations/src/react/operations-overview.status-cards.test.ts +1 -1
- package/templates/.agents/dashboard/modules/operations/src/react/operations-page-contract.ts +46 -6
- package/templates/.agents/dashboard/modules/operations/src/react/operations-view-order.test.ts +1 -4
- package/templates/.agents/dashboard/modules/operations/src/react/period-summary.test.ts +82 -6
- package/templates/.agents/dashboard/modules/operations/src/react/work-board-model.test.ts +2 -1
- package/templates/.agents/dashboard/modules/operations/src/react/work-board-model.ts +1 -1
- package/templates/.agents/dashboard/modules/operations/src/server/execution-relationship-counts.test.ts +19 -7
- package/templates/.agents/dashboard/modules/operations/src/server/execution-relationship-counts.ts +4 -1
- package/templates/.agents/dashboard/modules/operations/src/server/quick-daily-operations-projection.ts +11 -5
- package/templates/.agents/dashboard/modules/traceability/package.json +1 -1
- package/templates/.agents/dashboard/packages/branding/package.json +1 -1
- package/templates/.agents/dashboard/packages/branding/src/index.ts +1 -1
- package/templates/.agents/dashboard/packages/contracts/package.json +1 -1
- package/templates/.agents/dashboard/packages/contracts/src/index.ts +1 -0
- package/templates/.agents/dashboard/packages/data-export/package.json +1 -1
- package/templates/.agents/dashboard/packages/local-runtime/dist/server.cjs +152 -149
- package/templates/.agents/dashboard/packages/local-runtime/dist/server.cjs.metafile.json +7333 -0
- package/templates/.agents/dashboard/packages/local-runtime/dist/sqlite-read-model.cjs +149 -146
- package/templates/.agents/dashboard/packages/local-runtime/package.json +1 -1
- package/templates/.agents/dashboard/packages/local-runtime/scripts/build-sqlite-dashboard.mjs +15 -7
- package/templates/.agents/dashboard/packages/local-runtime/scripts/build-sqlite-runtime.mjs +44 -13
- package/templates/.agents/dashboard/packages/local-runtime/scripts/rebuild-sqlite-read-model.mjs +5 -2
- package/templates/.agents/dashboard/packages/local-runtime/scripts/source-size-runtime-scripts/sqlite-read-model-fixture.mjs +397 -0
- package/templates/.agents/dashboard/packages/local-runtime/scripts/test-sqlite-read-model.mjs +472 -145
- package/templates/.agents/dashboard/packages/local-runtime/scripts/test-unix-launchers.mjs +15 -3
- package/templates/.agents/dashboard/packages/local-runtime/scripts/validate-sqlite-read-model.mjs +129 -31
- package/templates/.agents/dashboard/packages/local-runtime/server.mjs +153 -150
- package/templates/.agents/dashboard/packages/local-runtime/src/project-settings.test.ts +6 -2
- package/templates/.agents/dashboard/packages/local-runtime/src/project-settings.ts +3 -3
- package/templates/.agents/dashboard/packages/local-runtime/src/server-board.test.ts +55 -16
- package/templates/.agents/dashboard/packages/local-runtime/src/server-board.ts +23 -13
- package/templates/.agents/dashboard/packages/local-runtime/src/server-snapshot.test.ts +19 -4
- package/templates/.agents/dashboard/packages/local-runtime/src/server-workspace.ts +7 -3
- package/templates/.agents/dashboard/packages/local-runtime/src/server.test.ts +132 -9
- package/templates/.agents/dashboard/packages/local-runtime/src/server.ts +126 -60
- package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-metric-contract.ts +16 -2
- package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-read-model.test.ts +1861 -350
- package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-read-model.ts +1218 -352
- package/templates/.agents/dashboard/packages/local-runtime/start-dashboard.mjs +119 -42
- package/templates/.agents/dashboard/packages/local-runtime/start-dashboard.test.mjs +45 -20
- package/templates/.agents/dashboard/packages/ui/package.json +1 -1
- package/templates/.agents/dashboard/tests/e2e/package.json +1 -1
- package/templates/.agents/dashboard/tests/e2e/specs/dashboard.spec.ts +7 -5
- package/templates/.agents/design/.zaip-managed.json +3 -3
- package/templates/.agents/design/apps/catalog/package.json +1 -1
- package/templates/.agents/design/packages/local-runtime/package.json +1 -1
- package/templates/.agents/growth/estrategia-bootstrap-90-dias.md +169 -0
- package/templates/.agents/growth/strategy.md +27 -0
- package/templates/.agents/marketing/estrategia-marketing-zaip-90-dias.md +197 -0
- package/templates/.agents/marketing/strategy.md +29 -0
- package/templates/.agents/requirements/autonomous-assurance.md +1 -1
- package/templates/.agents/requirements/comparative-audit.md +1 -1
- package/templates/.agents/requirements/context-engine.md +1 -1
- package/templates/.agents/requirements/cost-observability.md +1 -1
- package/templates/.agents/requirements/dashboard-launch.md +1 -1
- package/templates/.agents/requirements/data-export.md +1 -1
- package/templates/.agents/requirements/design-system.md +1 -1
- package/templates/.agents/requirements/execution-engine.md +1 -1
- package/templates/.agents/requirements/kanban-dashboard.md +1 -1
- package/templates/.agents/requirements/model-orchestration.md +1 -1
- package/templates/.agents/requirements/public-distribution.md +1 -1
- package/templates/.agents/requirements/software-architecture.md +1 -1
- package/templates/.agents/requirements/strategic-improvements.md +1 -1
- package/templates/.agents/requirements/work-lifecycle.md +1 -1
- package/templates/.agents/requirements/zaip-strategic-95.md +1 -1
- package/templates/.agents/runtime/VERSION +1 -1
- package/templates/.agents/runtime/bin/zaip.mjs +30 -29
- package/templates/.agents/runtime/checksums.sha256 +6 -6
- package/templates/.agents/runtime/manifest.json +1 -1
- package/templates/.agents/runtime/pnpm-lock.sha256 +1 -1
- package/templates/.agents/runtime/provenance.json +5 -5
- package/templates/.agents/runtime/sbom.cdx.json +3 -3
- package/templates/.agents/sales/playbook.md +32 -0
- package/templates/.agents/sales/roteiro-comercial-zaip.md +252 -0
- package/templates/.agents/skills/zaip-aios/SKILL.md +1 -1
- package/templates/.agents/skills/zaip-skill-brand-governance/SKILL.md +9 -2
- package/templates/.agents/skills/zaip-skill-brand-governance/references/brandbook-framework.md +39 -0
- package/templates/.agents/skills/zaip-skill-brand-governance/references/brandbook-standards.md +1 -1
- package/templates/.agents/skills/zaip-skill-enforce-architecture/SKILL.md +2 -0
- package/templates/.agents/skills/zaip-skill-growth-strategy-revops/SKILL.md +6 -0
- package/templates/.agents/skills/zaip-skill-marketing/SKILL.md +6 -0
- package/templates/.agents/skills/zaip-skill-reconcile-telemetry/scripts/reconcile-local-telemetry.mjs +39 -82
- package/templates/.agents/skills/zaip-skill-reconcile-telemetry/scripts/reconcile-telemetry-lib.mjs +13 -8
- package/templates/.agents/skills/zaip-skill-reconcile-telemetry/scripts/reconcile-telemetry-lib.test.mjs +44 -14
- package/templates/.agents/skills/zaip-skill-reconcile-telemetry/scripts/reconcile-telemetry-remeasurement.mjs +19 -9
- package/templates/.agents/skills/zaip-skill-reconcile-telemetry/scripts/reconcile-telemetry-remeasurement.test.mjs +29 -5
- package/templates/.agents/skills/zaip-skill-reconcile-telemetry/scripts/source-size-telemetry/model-identity-reconciliation.mjs +77 -0
- package/templates/.agents/skills/zaip-skill-sales-methodology/SKILL.md +6 -0
- package/templates/.agents/skills/zaip-skill-sqlite-read-model/scripts/ensure-node.mjs +28 -5
- package/templates/.agents/zaip-aios/INDEX.md +10 -0
- package/templates/.agents/zaip-aios/README.md +2 -1
- package/templates/.agents/zaip-aios/VERSION +1 -1
- package/templates/.agents/zaip-aios/guides/18-catalogo-de-agentes.md +76 -0
- package/templates/.agents/zaip-aios/guides/19-assurance-e-autonomia.md +72 -0
- package/templates/.agents/zaip-aios/guides/20-instalacao-detalhada.md +330 -0
- package/templates/.agents/zaip-aios/guides/21-telemetria-monitor-custos.md +52 -0
- package/templates/.agents/zaip-aios/guides/22-fluxos-e-roteamento.md +69 -0
- package/templates/.agents/zaip-aios/guides/23-orquestracao-de-modelos.md +483 -0
- package/templates/.agents/zaip-aios/guides/24-calculo-de-custos-openai.md +85 -0
- package/templates/.agents/zaip-aios/guides/25-fontes-de-precos-openai.md +18 -0
- package/templates/.agents/zaip-aios/guides/26-qualidade-e-release.md +44 -0
- package/templates/.agents/zaip-aios/guides/27-telemetria-git-native.md +167 -0
- package/templates/.agents/zaip-aios/guides/28-lifecycle-completo.md +144 -0
- package/templates/.agents/zaip-aios/guides/assets/diagrams/lifecycles-task-spec-prd.png +0 -0
- package/templates/.agents/zaip-aios/guides/assets/diagrams/prd-lifecycle.png +0 -0
- package/templates/.agents/zaip-aios/guides/assets/diagrams/spec-lifecycle.png +0 -0
- package/templates/.agents/zaip-aios/guides/assets/diagrams/task-lifecycle.png +0 -0
- package/templates/template-manifest.json +313 -177
- package/templates/.agents/dashboard/apps/frontend/dist/assets/DashboardHelpDialog-Cs6dzDmW.js +0 -1505
- package/templates/.agents/dashboard/apps/frontend/dist/assets/ProjectSettingsPage-QE1k9yZB.css +0 -1
- package/templates/.agents/dashboard/apps/frontend/dist/assets/ProjectSettingsPage-_Pf5DA_A.js +0 -3
- package/templates/.agents/dashboard/apps/frontend/dist/assets/TraceabilityWorkspace-BVlz3DLZ.js +0 -1
- package/templates/.agents/dashboard/apps/frontend/dist/assets/cost-monitor-Cf9ctPVt.js +0 -68
- package/templates/.agents/dashboard/apps/frontend/dist/assets/index-8A4DcNXM.js +0 -2
|
@@ -1,15 +1,24 @@
|
|
|
1
|
-
import { mkdir, mkdtemp,
|
|
1
|
+
import { mkdir, mkdtemp, readdir, readFile, rename, utimes, writeFile } from "node:fs/promises";
|
|
2
2
|
import { join, resolve } from "node:path";
|
|
3
3
|
import { DatabaseSync } from "node:sqlite";
|
|
4
4
|
import { afterEach, describe, expect, it } from "vitest";
|
|
5
5
|
import { createDashboardApp, projectAllTimeTopTasks } from "./server.js";
|
|
6
|
-
import {
|
|
6
|
+
import {
|
|
7
|
+
allocateAttributedTokenActiveMs,
|
|
8
|
+
rebuildSqliteReadModel,
|
|
9
|
+
SqliteReadModelFileSystem,
|
|
10
|
+
sourceFingerprint,
|
|
11
|
+
} from "./sqlite-read-model.js";
|
|
7
12
|
|
|
8
13
|
const roots: string[] = [];
|
|
9
14
|
// Windows can deny SQLite's sidecar files below the system TEMP directory.
|
|
10
15
|
// Keep disposable fixtures in the workspace-local test area instead; each
|
|
11
16
|
// test still receives its own root and never touches the live read model.
|
|
12
|
-
const sqliteTestTempRoot = join(
|
|
17
|
+
const sqliteTestTempRoot = join(
|
|
18
|
+
resolve(import.meta.dirname, "../../../../../.."),
|
|
19
|
+
".tmp",
|
|
20
|
+
"sqlite-read-model-tests",
|
|
21
|
+
);
|
|
13
22
|
async function createSqliteTestRoot(): Promise<string> {
|
|
14
23
|
await mkdir(sqliteTestTempRoot, { recursive: true });
|
|
15
24
|
return mkdtemp(join(sqliteTestTempRoot, "fixture-"));
|
|
@@ -33,7 +42,11 @@ describe("SQLite dashboard read model", () => {
|
|
|
33
42
|
await mkdir(join(root, ".agents", "records", "tasks", "nested"), { recursive: true });
|
|
34
43
|
await mkdir(join(root, ".agents", "records", "telemetry"), { recursive: true });
|
|
35
44
|
await mkdir(join(root, ".agents", "config"), { recursive: true });
|
|
36
|
-
await writeFile(
|
|
45
|
+
await writeFile(
|
|
46
|
+
join(root, ".agents", "config", "project.yaml"),
|
|
47
|
+
"zaip:\n enabled: true\n",
|
|
48
|
+
"utf8",
|
|
49
|
+
);
|
|
37
50
|
await writeFile(included, "# included\n", "utf8");
|
|
38
51
|
await writeFile(excluded, "ignored\n", "utf8");
|
|
39
52
|
|
|
@@ -56,7 +69,11 @@ describe("SQLite dashboard read model", () => {
|
|
|
56
69
|
const task = join(root, ".agents", "records", "tasks", "task.md");
|
|
57
70
|
await mkdir(join(root, ".agents", "records", "tasks"), { recursive: true });
|
|
58
71
|
await mkdir(join(root, ".agents", "config"), { recursive: true });
|
|
59
|
-
await writeFile(
|
|
72
|
+
await writeFile(
|
|
73
|
+
join(root, ".agents", "config", "project.yaml"),
|
|
74
|
+
"zaip:\n enabled: true\n",
|
|
75
|
+
"utf8",
|
|
76
|
+
);
|
|
60
77
|
await writeFile(task, "# original\n", "utf8");
|
|
61
78
|
await expect(rebuildSqliteReadModel(root)).resolves.toMatchObject({ cache: "rebuilt" });
|
|
62
79
|
await writeFile(task, "# changed canonically\n", "utf8");
|
|
@@ -65,7 +82,14 @@ describe("SQLite dashboard read model", () => {
|
|
|
65
82
|
try {
|
|
66
83
|
process.env.ZAIP_SQLITE_DB_PATH = join(root, ".local", "dashboard-sqlite", "next.sqlite");
|
|
67
84
|
process.env.ZAIP_SQLITE_PREFER_LAST_VALID_SEED = "1";
|
|
68
|
-
await expect(rebuildSqliteReadModel(root)).resolves.toMatchObject({
|
|
85
|
+
await expect(rebuildSqliteReadModel(root)).resolves.toMatchObject({
|
|
86
|
+
cache: "stale_seed",
|
|
87
|
+
files: 2,
|
|
88
|
+
});
|
|
89
|
+
await expect(rebuildSqliteReadModel(root, { forceCanonical: true })).resolves.toMatchObject({
|
|
90
|
+
cache: "rebuilt",
|
|
91
|
+
files: 2,
|
|
92
|
+
});
|
|
69
93
|
} finally {
|
|
70
94
|
if (previousPath === undefined) delete process.env.ZAIP_SQLITE_DB_PATH;
|
|
71
95
|
else process.env.ZAIP_SQLITE_DB_PATH = previousPath;
|
|
@@ -79,38 +103,76 @@ describe("SQLite dashboard read model", () => {
|
|
|
79
103
|
roots.push(root);
|
|
80
104
|
await mkdir(join(root, ".agents", "records", "tasks"), { recursive: true });
|
|
81
105
|
await mkdir(join(root, ".agents", "config"), { recursive: true });
|
|
82
|
-
await writeFile(
|
|
106
|
+
await writeFile(
|
|
107
|
+
join(root, ".agents", "config", "project.yaml"),
|
|
108
|
+
"zaip:\n enabled: true\n",
|
|
109
|
+
"utf8",
|
|
110
|
+
);
|
|
83
111
|
await expect(rebuildSqliteReadModel(root)).resolves.toMatchObject({ cache: "rebuilt" });
|
|
84
112
|
const path = join(root, ".local", "dashboard-sqlite", "read-model.sqlite");
|
|
85
113
|
const database = new DatabaseSync(path);
|
|
86
|
-
database
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
114
|
+
database
|
|
115
|
+
.prepare(
|
|
116
|
+
"UPDATE zaip_aios_activities SET payload_json=? WHERE payload_type='first_fold_monthly_quick_cache'",
|
|
117
|
+
)
|
|
118
|
+
.run(
|
|
119
|
+
JSON.stringify({
|
|
120
|
+
from_day: "2026-08-01",
|
|
121
|
+
to_day: "2026-08-18",
|
|
122
|
+
source_latest_day: "2026-08-30",
|
|
123
|
+
aggregate: {
|
|
124
|
+
days: 0,
|
|
125
|
+
total_run_count: 0,
|
|
126
|
+
agent_invocation_count: 0,
|
|
127
|
+
llm_call_count: null,
|
|
128
|
+
duration_ms: null,
|
|
129
|
+
total_tokens: null,
|
|
130
|
+
cost_brl: null,
|
|
131
|
+
execution_day_count: 0,
|
|
132
|
+
},
|
|
133
|
+
pages: { task: [], spec: [], prd: [] },
|
|
134
|
+
top_tasks: [],
|
|
135
|
+
}),
|
|
136
|
+
);
|
|
91
137
|
database.close();
|
|
92
138
|
const filesystem = new SqliteReadModelFileSystem(root);
|
|
93
139
|
try {
|
|
94
|
-
expect(
|
|
140
|
+
expect(
|
|
141
|
+
filesystem.firstFoldMonthlyQuick({ from: "2026-08-01", to: "2026-08-18" }),
|
|
142
|
+
).not.toBeNull();
|
|
95
143
|
expect(filesystem.firstFoldMonthlyQuick({ from: "2026-08-01", to: "2026-08-19" })).toBeNull();
|
|
96
|
-
expect(
|
|
97
|
-
|
|
144
|
+
expect(
|
|
145
|
+
filesystem.firstFoldMonthlyQuick({ from: "2026-09-01", to: "2026-09-01" }),
|
|
146
|
+
).toMatchObject({
|
|
147
|
+
aggregate: { total_run_count: 0 },
|
|
148
|
+
pages: { task: [], spec: [], prd: [] },
|
|
98
149
|
});
|
|
99
|
-
} finally {
|
|
150
|
+
} finally {
|
|
151
|
+
filesystem.close();
|
|
152
|
+
}
|
|
100
153
|
});
|
|
101
154
|
|
|
102
155
|
it("treats an empty snapshot as an exact empty later-month projection", async () => {
|
|
103
156
|
const root = await createSqliteTestRoot();
|
|
104
157
|
roots.push(root);
|
|
105
158
|
await mkdir(join(root, ".agents", "config"), { recursive: true });
|
|
106
|
-
await writeFile(
|
|
159
|
+
await writeFile(
|
|
160
|
+
join(root, ".agents", "config", "project.yaml"),
|
|
161
|
+
"zaip:\n enabled: true\n",
|
|
162
|
+
"utf8",
|
|
163
|
+
);
|
|
107
164
|
await expect(rebuildSqliteReadModel(root)).resolves.toMatchObject({ cache: "rebuilt" });
|
|
108
165
|
const filesystem = new SqliteReadModelFileSystem(root);
|
|
109
166
|
try {
|
|
110
|
-
expect(
|
|
111
|
-
|
|
167
|
+
expect(
|
|
168
|
+
filesystem.firstFoldMonthlyQuick({ from: "2099-01-01", to: "2099-01-01" }),
|
|
169
|
+
).toMatchObject({
|
|
170
|
+
aggregate: { total_run_count: 0 },
|
|
171
|
+
pages: { task: [], spec: [], prd: [] },
|
|
112
172
|
});
|
|
113
|
-
} finally {
|
|
173
|
+
} finally {
|
|
174
|
+
filesystem.close();
|
|
175
|
+
}
|
|
114
176
|
});
|
|
115
177
|
|
|
116
178
|
it("does not serve a schema 59 seed during the one-time SQLite cache migration", async () => {
|
|
@@ -118,16 +180,26 @@ describe("SQLite dashboard read model", () => {
|
|
|
118
180
|
roots.push(root);
|
|
119
181
|
await mkdir(join(root, ".agents", "records", "tasks"), { recursive: true });
|
|
120
182
|
await mkdir(join(root, ".agents", "config"), { recursive: true });
|
|
121
|
-
await writeFile(
|
|
183
|
+
await writeFile(
|
|
184
|
+
join(root, ".agents", "config", "project.yaml"),
|
|
185
|
+
"zaip:\n enabled: true\n",
|
|
186
|
+
"utf8",
|
|
187
|
+
);
|
|
122
188
|
await writeFile(join(root, ".agents", "records", "tasks", "task.md"), "# task\n", "utf8");
|
|
123
189
|
await expect(rebuildSqliteReadModel(root)).resolves.toMatchObject({ cache: "rebuilt" });
|
|
124
190
|
const cacheDirectory = join(root, ".local", "dashboard-sqlite", "cache");
|
|
125
|
-
const current = (await readdir(cacheDirectory)).find(
|
|
191
|
+
const current = (await readdir(cacheDirectory)).find(
|
|
192
|
+
(entry) => entry.startsWith("v60-") && entry.endsWith(".sqlite"),
|
|
193
|
+
);
|
|
126
194
|
expect(current).toBeDefined();
|
|
127
195
|
const legacy = join(cacheDirectory, current!.replace("v60-", ""));
|
|
128
196
|
await rename(join(cacheDirectory, current!), legacy);
|
|
129
197
|
const oldSeed = new DatabaseSync(legacy);
|
|
130
|
-
oldSeed
|
|
198
|
+
oldSeed
|
|
199
|
+
.prepare(
|
|
200
|
+
"UPDATE zaip_aios_activities SET payload_json=json_set(payload_json, '$.value', '59') WHERE payload_type='metadata' AND json_extract(payload_json, '$.key')='schema_version'",
|
|
201
|
+
)
|
|
202
|
+
.run();
|
|
131
203
|
oldSeed.close();
|
|
132
204
|
const priorPath = process.env.ZAIP_SQLITE_DB_PATH;
|
|
133
205
|
const priorSeed = process.env.ZAIP_SQLITE_PREFER_LAST_VALID_SEED;
|
|
@@ -145,19 +217,41 @@ describe("SQLite dashboard read model", () => {
|
|
|
145
217
|
|
|
146
218
|
it("rateia sobreposição e virada de dia na fato temporal aditiva", () => {
|
|
147
219
|
const overlap = allocateAttributedTokenActiveMs([
|
|
148
|
-
{
|
|
149
|
-
|
|
220
|
+
{
|
|
221
|
+
activityRowId: "A",
|
|
222
|
+
startMs: Date.parse("2026-08-10T12:00:00.000Z"),
|
|
223
|
+
endMs: Date.parse("2026-08-10T13:00:00.000Z"),
|
|
224
|
+
},
|
|
225
|
+
{
|
|
226
|
+
activityRowId: "B",
|
|
227
|
+
startMs: Date.parse("2026-08-10T12:30:00.000Z"),
|
|
228
|
+
endMs: Date.parse("2026-08-10T13:30:00.000Z"),
|
|
229
|
+
},
|
|
150
230
|
]);
|
|
151
231
|
expect(overlap.reduce((sum, fact) => sum + fact.value, 0)).toBe(5_400_000);
|
|
152
|
-
expect(
|
|
153
|
-
|
|
232
|
+
expect(
|
|
233
|
+
overlap
|
|
234
|
+
.filter((fact) => fact.activityRowId === "A")
|
|
235
|
+
.reduce((sum, fact) => sum + fact.value, 0),
|
|
236
|
+
).toBe(2_700_000);
|
|
237
|
+
expect(
|
|
238
|
+
overlap
|
|
239
|
+
.filter((fact) => fact.activityRowId === "B")
|
|
240
|
+
.reduce((sum, fact) => sum + fact.value, 0),
|
|
241
|
+
).toBe(2_700_000);
|
|
154
242
|
const midnight = allocateAttributedTokenActiveMs([
|
|
155
|
-
{
|
|
243
|
+
{
|
|
244
|
+
activityRowId: "MID",
|
|
245
|
+
startMs: Date.parse("2026-08-11T02:30:00.000Z"),
|
|
246
|
+
endMs: Date.parse("2026-08-11T03:30:00.000Z"),
|
|
247
|
+
},
|
|
156
248
|
]);
|
|
157
|
-
expect(midnight).toEqual(
|
|
158
|
-
expect.
|
|
159
|
-
|
|
160
|
-
|
|
249
|
+
expect(midnight).toEqual(
|
|
250
|
+
expect.arrayContaining([
|
|
251
|
+
expect.objectContaining({ day: "2026-08-10", value: 1_800_000 }),
|
|
252
|
+
expect.objectContaining({ day: "2026-08-11", value: 1_800_000 }),
|
|
253
|
+
]),
|
|
254
|
+
);
|
|
161
255
|
});
|
|
162
256
|
it("projects canonical executions, conversations, changes and decisions without lifecycle aggregates", async () => {
|
|
163
257
|
const root = await createSqliteTestRoot();
|
|
@@ -166,10 +260,9 @@ describe("SQLite dashboard read model", () => {
|
|
|
166
260
|
await mkdir(join(root, ".agents", "records", "executions", "2026", "08", "EXEC-1"), {
|
|
167
261
|
recursive: true,
|
|
168
262
|
});
|
|
169
|
-
await mkdir(
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
);
|
|
263
|
+
await mkdir(join(root, ".agents", "records", "changes", "2026", "08", "CHG-1", "decisions"), {
|
|
264
|
+
recursive: true,
|
|
265
|
+
});
|
|
173
266
|
await writeFile(join(root, ".agents", "config", "project.yaml"), "zaip:\n enabled: true\n");
|
|
174
267
|
await writeFile(
|
|
175
268
|
join(root, ".agents", "records", "executions", "2026", "08", "EXEC-1", "execution.md"),
|
|
@@ -210,17 +303,7 @@ created_at: 2026-08-10T11:00:00.000Z
|
|
|
210
303
|
`,
|
|
211
304
|
);
|
|
212
305
|
await writeFile(
|
|
213
|
-
join(
|
|
214
|
-
root,
|
|
215
|
-
".agents",
|
|
216
|
-
"records",
|
|
217
|
-
"changes",
|
|
218
|
-
"2026",
|
|
219
|
-
"08",
|
|
220
|
-
"CHG-1",
|
|
221
|
-
"decisions",
|
|
222
|
-
"DEC-1.md",
|
|
223
|
-
),
|
|
306
|
+
join(root, ".agents", "records", "changes", "2026", "08", "CHG-1", "decisions", "DEC-1.md"),
|
|
224
307
|
`---
|
|
225
308
|
schema_version: 2
|
|
226
309
|
id: DEC-1
|
|
@@ -239,7 +322,16 @@ created_at: 2026-08-10T11:01:00.000Z
|
|
|
239
322
|
const filesystem = new SqliteReadModelFileSystem(root);
|
|
240
323
|
expect(filesystem.viewPage("operations_executions", { limit: 100 })).toMatchObject({
|
|
241
324
|
total_count: 1,
|
|
242
|
-
rows: [
|
|
325
|
+
rows: [
|
|
326
|
+
{
|
|
327
|
+
execution_id: "EXEC-1",
|
|
328
|
+
conversation_id: "CONV-1",
|
|
329
|
+
invocation_count: 0,
|
|
330
|
+
duration_ms: null,
|
|
331
|
+
duration_provenance: "unavailable",
|
|
332
|
+
lifecycle_elapsed_ms: 300_000,
|
|
333
|
+
},
|
|
334
|
+
],
|
|
243
335
|
});
|
|
244
336
|
expect(filesystem.viewPage("operations_conversations", { limit: 100 })).toMatchObject({
|
|
245
337
|
total_count: 1,
|
|
@@ -312,30 +404,84 @@ created_at: 2026-08-10T11:01:00.000Z
|
|
|
312
404
|
const events = [...expected.keys()].flatMap((agent, index) => {
|
|
313
405
|
const runId = `RUN-AGENT-${index}`;
|
|
314
406
|
const started = {
|
|
315
|
-
schema_version: 2,
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
407
|
+
schema_version: 2,
|
|
408
|
+
event_id: `${runId}:1`,
|
|
409
|
+
run_id: runId,
|
|
410
|
+
sequence: 1,
|
|
411
|
+
occurred_at: "2026-08-18T12:00:00.000Z",
|
|
412
|
+
type: "run.started",
|
|
413
|
+
attribution_status: "attributed",
|
|
414
|
+
phase: "execution",
|
|
415
|
+
run_role: "subagent",
|
|
416
|
+
run_purpose: "execution",
|
|
417
|
+
requires_finalizer: false,
|
|
418
|
+
execution_kind: "delivery",
|
|
419
|
+
execution_eligibility: ["delivery"],
|
|
420
|
+
entrypoint: "task",
|
|
421
|
+
work_type: "new",
|
|
422
|
+
storage_mode: "tracked_sanitized",
|
|
423
|
+
client: "codex",
|
|
424
|
+
agent,
|
|
425
|
+
agent_name: agent,
|
|
426
|
+
provider: "openai",
|
|
427
|
+
model: "gpt-5",
|
|
428
|
+
reasoning_effort: null,
|
|
429
|
+
client_thread_id: runId,
|
|
430
|
+
client_turn_id: runId,
|
|
431
|
+
conversation_id: `CONV-${index}`,
|
|
432
|
+
execution_id: `EXEC-${index}`,
|
|
433
|
+
task_id: `TASK-${index}`,
|
|
434
|
+
spec_id: null,
|
|
435
|
+
prd_id: null,
|
|
436
|
+
change_id: null,
|
|
437
|
+
parent_run_id: "RUN-ROOT",
|
|
438
|
+
continuation_of_run_id: null,
|
|
439
|
+
retry_of_run_id: null,
|
|
440
|
+
agent_invocation_id: `AINV-${index}`,
|
|
441
|
+
root_agent_invocation_id: "AINV-ROOT",
|
|
442
|
+
parent_agent_invocation_id: "AINV-ROOT",
|
|
443
|
+
invocation_kind: "delegated",
|
|
444
|
+
delegation_depth: 1,
|
|
325
445
|
};
|
|
326
446
|
const usage = {
|
|
327
|
-
schema_version: 2,
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
447
|
+
schema_version: 2,
|
|
448
|
+
event_id: `${runId}:2`,
|
|
449
|
+
run_id: runId,
|
|
450
|
+
sequence: 2,
|
|
451
|
+
occurred_at: "2026-08-18T12:00:01.000Z",
|
|
452
|
+
type: "usage.recorded",
|
|
453
|
+
phase: "execution",
|
|
454
|
+
activity_kind: "model_usage",
|
|
455
|
+
classification_source: "explicit",
|
|
456
|
+
tokens: {
|
|
457
|
+
input: 1,
|
|
458
|
+
cached_input: 0,
|
|
459
|
+
output: 1,
|
|
460
|
+
reasoning: 0,
|
|
461
|
+
total: 2,
|
|
462
|
+
source: "provider_reported",
|
|
463
|
+
},
|
|
464
|
+
cost: { usd: 0.01, brl: 0.05, fx_rate: 5 },
|
|
465
|
+
provider: "openai",
|
|
466
|
+
model: "gpt-5",
|
|
467
|
+
source_segment_key: runId,
|
|
468
|
+
model_call_id: `MCALL-${index}`,
|
|
469
|
+
runtime: { reasoning_effort: null, service_tier: null },
|
|
470
|
+
supersedes_event_id: null,
|
|
471
|
+
duration_ms: null,
|
|
472
|
+
duration_provenance: null,
|
|
334
473
|
};
|
|
335
474
|
const finished = {
|
|
336
|
-
schema_version: 2,
|
|
337
|
-
|
|
338
|
-
|
|
475
|
+
schema_version: 2,
|
|
476
|
+
event_id: `${runId}:3`,
|
|
477
|
+
run_id: runId,
|
|
478
|
+
sequence: 3,
|
|
479
|
+
occurred_at: "2026-08-18T12:01:00.000Z",
|
|
480
|
+
type: "run.finished",
|
|
481
|
+
phase: "execution",
|
|
482
|
+
status: "completed",
|
|
483
|
+
duration_ms: 60_000,
|
|
484
|
+
duration_provenance: "observed",
|
|
339
485
|
};
|
|
340
486
|
return [started, usage, finished];
|
|
341
487
|
});
|
|
@@ -343,7 +489,10 @@ created_at: 2026-08-10T11:01:00.000Z
|
|
|
343
489
|
[...expected.keys()].map((_, index) =>
|
|
344
490
|
writeFile(
|
|
345
491
|
join(root, ".agents", "records", "runs", "2026", "08", `RUN-AGENT-${index}.jsonl`),
|
|
346
|
-
`${events
|
|
492
|
+
`${events
|
|
493
|
+
.slice(index * 3, index * 3 + 3)
|
|
494
|
+
.map((event) => JSON.stringify(event))
|
|
495
|
+
.join("\n")}\n`,
|
|
347
496
|
),
|
|
348
497
|
),
|
|
349
498
|
);
|
|
@@ -381,25 +530,87 @@ created_at: 2026-08-10T11:01:00.000Z
|
|
|
381
530
|
source: "fixture",
|
|
382
531
|
disclaimer: "fixture",
|
|
383
532
|
models: [
|
|
384
|
-
{
|
|
385
|
-
|
|
533
|
+
{
|
|
534
|
+
id: "gpt-a",
|
|
535
|
+
provider: "openai",
|
|
536
|
+
aliases: [],
|
|
537
|
+
input_per_million_usd: 2,
|
|
538
|
+
cached_input_per_million_usd: 0.2,
|
|
539
|
+
output_per_million_usd: 8,
|
|
540
|
+
reasoning_per_million_usd: 8,
|
|
541
|
+
reasoning_billed_separately: false,
|
|
542
|
+
long_context_threshold_tokens: null,
|
|
543
|
+
long_context_input_multiplier: 1,
|
|
544
|
+
long_context_output_multiplier: 1,
|
|
545
|
+
source_label: "fixture-openai",
|
|
546
|
+
source_url: "https://example.test/openai",
|
|
547
|
+
notes: [],
|
|
548
|
+
},
|
|
549
|
+
{
|
|
550
|
+
id: "claude-b",
|
|
551
|
+
provider: "anthropic",
|
|
552
|
+
aliases: [],
|
|
553
|
+
input_per_million_usd: 3,
|
|
554
|
+
cached_input_per_million_usd: 0.3,
|
|
555
|
+
output_per_million_usd: 12,
|
|
556
|
+
reasoning_per_million_usd: null,
|
|
557
|
+
reasoning_billed_separately: false,
|
|
558
|
+
long_context_threshold_tokens: null,
|
|
559
|
+
long_context_input_multiplier: 1,
|
|
560
|
+
long_context_output_multiplier: 1,
|
|
561
|
+
source_label: "fixture-anthropic",
|
|
562
|
+
source_url: "https://example.test/anthropic",
|
|
563
|
+
notes: [],
|
|
564
|
+
},
|
|
386
565
|
],
|
|
387
566
|
}),
|
|
388
567
|
);
|
|
389
568
|
const started = {
|
|
390
|
-
schema_version: 2,
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
569
|
+
schema_version: 2,
|
|
570
|
+
event_id: "RUN-MISSING:1",
|
|
571
|
+
run_id: "RUN-MISSING",
|
|
572
|
+
sequence: 1,
|
|
573
|
+
occurred_at: "2026-08-05T12:00:00.000Z",
|
|
574
|
+
type: "run.started",
|
|
575
|
+
attribution_status: "attributed",
|
|
576
|
+
phase: "conversation",
|
|
577
|
+
run_role: "orchestrator",
|
|
578
|
+
run_purpose: "orchestration",
|
|
579
|
+
requires_finalizer: false,
|
|
580
|
+
execution_kind: "interaction",
|
|
581
|
+
execution_eligibility: ["interaction"],
|
|
582
|
+
entrypoint: "conversation",
|
|
583
|
+
work_type: "new",
|
|
584
|
+
storage_mode: "tracked_sanitized",
|
|
585
|
+
client: "codex",
|
|
586
|
+
agent: "root",
|
|
587
|
+
agent_name: "root",
|
|
588
|
+
provider: null,
|
|
589
|
+
model: "unknown",
|
|
590
|
+
reasoning_effort: null,
|
|
591
|
+
client_thread_id: "missing",
|
|
592
|
+
client_turn_id: "missing",
|
|
593
|
+
conversation_id: "CONV-MISSING",
|
|
594
|
+
execution_id: null,
|
|
595
|
+
task_id: null,
|
|
596
|
+
spec_id: null,
|
|
597
|
+
prd_id: null,
|
|
598
|
+
change_id: null,
|
|
599
|
+
parent_run_id: null,
|
|
600
|
+
continuation_of_run_id: null,
|
|
601
|
+
retry_of_run_id: null,
|
|
398
602
|
};
|
|
399
603
|
const finished = {
|
|
400
|
-
schema_version: 2,
|
|
401
|
-
|
|
402
|
-
|
|
604
|
+
schema_version: 2,
|
|
605
|
+
event_id: "RUN-MISSING:2",
|
|
606
|
+
run_id: "RUN-MISSING",
|
|
607
|
+
sequence: 2,
|
|
608
|
+
occurred_at: "2026-08-05T12:01:00.000Z",
|
|
609
|
+
type: "run.finished",
|
|
610
|
+
phase: "conversation",
|
|
611
|
+
status: "completed",
|
|
612
|
+
duration_ms: 60_000,
|
|
613
|
+
duration_provenance: "observed",
|
|
403
614
|
};
|
|
404
615
|
await writeFile(
|
|
405
616
|
join(root, ".agents", "records", "runs", "2026", "08", "RUN-MISSING.jsonl"),
|
|
@@ -426,26 +637,40 @@ created_at: 2026-08-10T11:01:00.000Z
|
|
|
426
637
|
await rebuildSqliteReadModel(root);
|
|
427
638
|
const filesystem = new SqliteReadModelFileSystem(root);
|
|
428
639
|
try {
|
|
429
|
-
expect(await filesystem.readText(".agents/config/project.yaml")).toBe(
|
|
640
|
+
expect(await filesystem.readText(".agents/config/project.yaml")).toBe(
|
|
641
|
+
"zaip:\n enabled: true\n",
|
|
642
|
+
);
|
|
430
643
|
expect(filesystem.viewPage("operations_work_list", { limit: 10 }).total_count).toBe(0);
|
|
431
|
-
const pageCache = (
|
|
432
|
-
|
|
433
|
-
|
|
644
|
+
const pageCache = (
|
|
645
|
+
filesystem as unknown as {
|
|
646
|
+
viewPageResultCache: Map<string, Record<string, unknown>>;
|
|
647
|
+
}
|
|
648
|
+
).viewPageResultCache;
|
|
434
649
|
expect(pageCache.has('operations_work_list:{"limit":10}')).toBe(true);
|
|
435
650
|
// Change canonical input only after the read-only database has opened:
|
|
436
651
|
// rebuild must replace the generation rather than taking the cache path.
|
|
437
652
|
await writeFile(configPath, "zaip:\n enabled: true\nproject:\n id: refreshed-fixture\n");
|
|
438
|
-
await expect(
|
|
439
|
-
|
|
653
|
+
await expect(
|
|
654
|
+
filesystem.rebuildAndRefresh(() => rebuildSqliteReadModel(root)),
|
|
655
|
+
).resolves.toBeUndefined();
|
|
656
|
+
expect(await filesystem.readText(".agents/config/project.yaml")).toContain(
|
|
657
|
+
"refreshed-fixture",
|
|
658
|
+
);
|
|
440
659
|
expect(pageCache.has('operations_work_list:{"limit":10}')).toBe(false);
|
|
441
660
|
// Exercise the actual public view on the same reopened instance, not
|
|
442
661
|
// merely raw filesystem reads after a Windows-safe replacement.
|
|
443
|
-
expect(() =>
|
|
662
|
+
expect(() =>
|
|
663
|
+
filesystem.viewPage("cost_monitor_daily", { limit: 1, offset: 0 }),
|
|
664
|
+
).not.toThrow();
|
|
444
665
|
// A failed rebuild still reopens the existing, complete generation.
|
|
445
|
-
await expect(
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
666
|
+
await expect(
|
|
667
|
+
filesystem.rebuildAndRefresh(async () => {
|
|
668
|
+
throw new Error("simulated rebuild failure");
|
|
669
|
+
}),
|
|
670
|
+
).rejects.toThrow("simulated rebuild failure");
|
|
671
|
+
expect(await filesystem.readText(".agents/config/project.yaml")).toContain(
|
|
672
|
+
"refreshed-fixture",
|
|
673
|
+
);
|
|
449
674
|
} finally {
|
|
450
675
|
filesystem.close();
|
|
451
676
|
}
|
|
@@ -458,7 +683,7 @@ created_at: 2026-08-10T11:01:00.000Z
|
|
|
458
683
|
await mkdir(join(root, ".agents", "config"), { recursive: true });
|
|
459
684
|
await writeFile(
|
|
460
685
|
join(root, ".agents", "config", "project.yaml"),
|
|
461
|
-
|
|
686
|
+
"schema_version: 1\nzaip:\n enabled: true\nproject:\n id: sqlite-test\n name: sqlite-test\n timezone: UTC\nstack:\n id: zaip-aios-stack\n overrides: {}\nclients:\n codex: true\n claude: true\ntracking:\n enabled: true\n currency: BRL\n storage_mode: tracked_sanitized\n",
|
|
462
687
|
"utf8",
|
|
463
688
|
);
|
|
464
689
|
const started = {
|
|
@@ -572,11 +797,24 @@ created_at: 2026-08-10T11:01:00.000Z
|
|
|
572
797
|
duration_unknown: 1,
|
|
573
798
|
});
|
|
574
799
|
expect(Object.keys(day).sort()).toEqual([
|
|
575
|
-
"duration_known",
|
|
576
|
-
"
|
|
577
|
-
"
|
|
800
|
+
"duration_known",
|
|
801
|
+
"duration_unknown",
|
|
802
|
+
"evidence_count",
|
|
803
|
+
"key",
|
|
804
|
+
"label",
|
|
805
|
+
"prd_count",
|
|
806
|
+
"spec_count",
|
|
807
|
+
"task_count",
|
|
808
|
+
"total_cost_brl",
|
|
809
|
+
"total_cost_usd",
|
|
810
|
+
"total_duration",
|
|
811
|
+
"total_run_count",
|
|
812
|
+
"total_tokens",
|
|
813
|
+
"validation_count",
|
|
578
814
|
]);
|
|
579
|
-
expect(
|
|
815
|
+
expect(
|
|
816
|
+
filesystem.costMonitorFactualDurationByDay({ from: null, to: null }).get("2026-08-01"),
|
|
817
|
+
).toEqual({
|
|
580
818
|
known_sum: 0,
|
|
581
819
|
eligible_runs: 1,
|
|
582
820
|
known_runs: 0,
|
|
@@ -589,7 +827,9 @@ created_at: 2026-08-10T11:01:00.000Z
|
|
|
589
827
|
roots.push(root);
|
|
590
828
|
await mkdir(join(root, ".agents", "records", "runs", "2026", "08"), { recursive: true });
|
|
591
829
|
await mkdir(join(root, ".agents", "config", "agents"), { recursive: true });
|
|
592
|
-
await mkdir(join(root, ".agents", "config", "pricing", "fx", "2026", "08", "04"), {
|
|
830
|
+
await mkdir(join(root, ".agents", "config", "pricing", "fx", "2026", "08", "04"), {
|
|
831
|
+
recursive: true,
|
|
832
|
+
});
|
|
593
833
|
await writeFile(join(root, ".agents", "config", "project.yaml"), "zaip:\n enabled: true\n");
|
|
594
834
|
await writeFile(
|
|
595
835
|
join(root, ".agents", "config", "agents", "catalog.yaml"),
|
|
@@ -603,17 +843,117 @@ created_at: 2026-08-10T11:01:00.000Z
|
|
|
603
843
|
source: "fixture",
|
|
604
844
|
disclaimer: "fixture",
|
|
605
845
|
models: [
|
|
606
|
-
{
|
|
846
|
+
{
|
|
847
|
+
id: "gpt-a",
|
|
848
|
+
provider: "openai",
|
|
849
|
+
aliases: [],
|
|
850
|
+
input_per_million_usd: 2,
|
|
851
|
+
cached_input_per_million_usd: 0.2,
|
|
852
|
+
output_per_million_usd: 8,
|
|
853
|
+
reasoning_per_million_usd: 8,
|
|
854
|
+
reasoning_billed_separately: false,
|
|
855
|
+
long_context_threshold_tokens: null,
|
|
856
|
+
long_context_input_multiplier: 1,
|
|
857
|
+
long_context_output_multiplier: 1,
|
|
858
|
+
source_label: "fixture-openai",
|
|
859
|
+
source_url: "https://example.test/openai",
|
|
860
|
+
notes: [],
|
|
861
|
+
},
|
|
607
862
|
],
|
|
608
863
|
}),
|
|
609
864
|
);
|
|
610
865
|
await writeFile(
|
|
611
866
|
join(root, ".agents", "config", "pricing", "fx", "2026", "08", "04", "usd-brl.json"),
|
|
612
|
-
JSON.stringify({
|
|
867
|
+
JSON.stringify({
|
|
868
|
+
schema_version: 1,
|
|
869
|
+
base: "USD",
|
|
870
|
+
quote: "BRL",
|
|
871
|
+
rate: 5.5,
|
|
872
|
+
as_of: "2026-08-04T00:00:00.000Z",
|
|
873
|
+
source_label: "fixture",
|
|
874
|
+
source_url: "https://example.test/fx",
|
|
875
|
+
}),
|
|
613
876
|
);
|
|
614
|
-
const started = {
|
|
615
|
-
|
|
616
|
-
|
|
877
|
+
const started = {
|
|
878
|
+
schema_version: 2,
|
|
879
|
+
event_id: "RUN-PRICED:1",
|
|
880
|
+
run_id: "RUN-PRICED",
|
|
881
|
+
sequence: 1,
|
|
882
|
+
occurred_at: "2026-08-08T12:00:00.000Z",
|
|
883
|
+
type: "run.started",
|
|
884
|
+
attribution_status: "attributed",
|
|
885
|
+
phase: "execution",
|
|
886
|
+
run_role: "orchestrator",
|
|
887
|
+
run_purpose: "execution",
|
|
888
|
+
requires_finalizer: false,
|
|
889
|
+
execution_kind: "delivery",
|
|
890
|
+
execution_eligibility: ["delivery"],
|
|
891
|
+
entrypoint: "task",
|
|
892
|
+
work_type: "new",
|
|
893
|
+
storage_mode: "tracked_sanitized",
|
|
894
|
+
client: "codex",
|
|
895
|
+
agent: "agent",
|
|
896
|
+
agent_name: "agent",
|
|
897
|
+
provider: "openai",
|
|
898
|
+
model: "gpt-a",
|
|
899
|
+
reasoning_effort: null,
|
|
900
|
+
client_thread_id: "priced",
|
|
901
|
+
client_turn_id: "priced",
|
|
902
|
+
conversation_id: "CONV-PRICED",
|
|
903
|
+
execution_id: "EXEC-PRICED",
|
|
904
|
+
task_id: "TASK-PRICED",
|
|
905
|
+
spec_id: null,
|
|
906
|
+
prd_id: null,
|
|
907
|
+
change_id: null,
|
|
908
|
+
parent_run_id: null,
|
|
909
|
+
continuation_of_run_id: null,
|
|
910
|
+
retry_of_run_id: null,
|
|
911
|
+
agent_invocation_id: "AINV-PRICED",
|
|
912
|
+
root_agent_invocation_id: "AINV-PRICED",
|
|
913
|
+
parent_agent_invocation_id: null,
|
|
914
|
+
invocation_kind: "orchestrator",
|
|
915
|
+
delegation_depth: 0,
|
|
916
|
+
};
|
|
917
|
+
const usage = {
|
|
918
|
+
schema_version: 2,
|
|
919
|
+
event_id: "RUN-PRICED:2",
|
|
920
|
+
run_id: "RUN-PRICED",
|
|
921
|
+
sequence: 2,
|
|
922
|
+
occurred_at: "2026-08-08T12:00:01.000Z",
|
|
923
|
+
type: "usage.recorded",
|
|
924
|
+
phase: "execution",
|
|
925
|
+
activity_kind: "model_usage",
|
|
926
|
+
classification_source: "explicit",
|
|
927
|
+
tokens: {
|
|
928
|
+
input: 5,
|
|
929
|
+
cached_input: 0,
|
|
930
|
+
output: 0,
|
|
931
|
+
reasoning: 0,
|
|
932
|
+
total: 5,
|
|
933
|
+
source: "provider_reported",
|
|
934
|
+
},
|
|
935
|
+
cost: { usd: 0.5, brl: 2.5, fx_rate: 5 },
|
|
936
|
+
provider: "openai",
|
|
937
|
+
model: "gpt-a",
|
|
938
|
+
source_segment_key: "openai-gpt-a",
|
|
939
|
+
model_call_id: "MCALL-PRICED",
|
|
940
|
+
runtime: { reasoning_effort: null, service_tier: null },
|
|
941
|
+
supersedes_event_id: null,
|
|
942
|
+
duration_ms: null,
|
|
943
|
+
duration_provenance: null,
|
|
944
|
+
};
|
|
945
|
+
const finished = {
|
|
946
|
+
schema_version: 2,
|
|
947
|
+
event_id: "RUN-PRICED:3",
|
|
948
|
+
run_id: "RUN-PRICED",
|
|
949
|
+
sequence: 3,
|
|
950
|
+
occurred_at: "2026-08-08T12:01:00.000Z",
|
|
951
|
+
type: "run.finished",
|
|
952
|
+
phase: "execution",
|
|
953
|
+
status: "completed",
|
|
954
|
+
duration_ms: 60_000,
|
|
955
|
+
duration_provenance: "observed",
|
|
956
|
+
};
|
|
617
957
|
await writeFile(
|
|
618
958
|
join(root, ".agents", "records", "runs", "2026", "08", "RUN-PRICED.jsonl"),
|
|
619
959
|
`${[started, usage, finished].map((row) => JSON.stringify(row)).join("\n")}\n`,
|
|
@@ -648,24 +988,137 @@ created_at: 2026-08-10T11:01:00.000Z
|
|
|
648
988
|
"---\nid: TASK-CANONICAL\ntitle: Titulo semantico canonico\nstatus: ready\nrisk: standard\ncreated_at: 2026-08-08T12:00:00.000Z\n---\n# Titulo semantico canonico\n",
|
|
649
989
|
);
|
|
650
990
|
const run = (id: string, taskId: string, tokens: number) => [
|
|
651
|
-
{
|
|
652
|
-
|
|
653
|
-
|
|
991
|
+
{
|
|
992
|
+
schema_version: 2,
|
|
993
|
+
event_id: `${id}:1`,
|
|
994
|
+
run_id: id,
|
|
995
|
+
sequence: 1,
|
|
996
|
+
occurred_at: "2026-08-08T12:00:00.000Z",
|
|
997
|
+
type: "run.started",
|
|
998
|
+
attribution_status: "attributed",
|
|
999
|
+
phase: "execution",
|
|
1000
|
+
run_role: "orchestrator",
|
|
1001
|
+
run_purpose: "execution",
|
|
1002
|
+
requires_finalizer: false,
|
|
1003
|
+
execution_kind: "delivery",
|
|
1004
|
+
execution_eligibility: ["delivery"],
|
|
1005
|
+
entrypoint: "task",
|
|
1006
|
+
work_type: "new",
|
|
1007
|
+
storage_mode: "tracked_sanitized",
|
|
1008
|
+
client: "codex",
|
|
1009
|
+
agent: "agent",
|
|
1010
|
+
agent_name: "agent",
|
|
1011
|
+
provider: "openai",
|
|
1012
|
+
model: "gpt-a",
|
|
1013
|
+
reasoning_effort: null,
|
|
1014
|
+
client_thread_id: id,
|
|
1015
|
+
client_turn_id: id,
|
|
1016
|
+
conversation_id: `CONV-${id}`,
|
|
1017
|
+
execution_id: `EXEC-${id}`,
|
|
1018
|
+
task_id: taskId,
|
|
1019
|
+
spec_id: null,
|
|
1020
|
+
prd_id: null,
|
|
1021
|
+
change_id: null,
|
|
1022
|
+
parent_run_id: null,
|
|
1023
|
+
continuation_of_run_id: null,
|
|
1024
|
+
retry_of_run_id: null,
|
|
1025
|
+
agent_invocation_id: `AINV-${id}`,
|
|
1026
|
+
root_agent_invocation_id: `AINV-${id}`,
|
|
1027
|
+
parent_agent_invocation_id: null,
|
|
1028
|
+
invocation_kind: "orchestrator",
|
|
1029
|
+
delegation_depth: 0,
|
|
1030
|
+
},
|
|
1031
|
+
{
|
|
1032
|
+
schema_version: 2,
|
|
1033
|
+
event_id: `${id}:2`,
|
|
1034
|
+
run_id: id,
|
|
1035
|
+
sequence: 2,
|
|
1036
|
+
occurred_at: "2026-08-08T12:00:30.000Z",
|
|
1037
|
+
type: "usage.recorded",
|
|
1038
|
+
phase: "execution",
|
|
1039
|
+
activity_kind: "model_usage",
|
|
1040
|
+
classification_source: "explicit",
|
|
1041
|
+
tokens: {
|
|
1042
|
+
input: tokens,
|
|
1043
|
+
cached_input: 0,
|
|
1044
|
+
output: 0,
|
|
1045
|
+
reasoning: 0,
|
|
1046
|
+
total: tokens,
|
|
1047
|
+
source: "provider_reported",
|
|
1048
|
+
},
|
|
1049
|
+
cost: { usd: tokens / 100, brl: tokens / 20, fx_rate: 5 },
|
|
1050
|
+
provider: "openai",
|
|
1051
|
+
model: "gpt-a",
|
|
1052
|
+
source_segment_key: id,
|
|
1053
|
+
model_call_id: `MCALL-${id}`,
|
|
1054
|
+
runtime: { reasoning_effort: null, service_tier: null },
|
|
1055
|
+
supersedes_event_id: null,
|
|
1056
|
+
source_started_at: "2026-08-08T12:00:00.000Z",
|
|
1057
|
+
source_finished_at: "2026-08-08T12:01:00.000Z",
|
|
1058
|
+
duration_ms: null,
|
|
1059
|
+
duration_provenance: null,
|
|
1060
|
+
},
|
|
1061
|
+
{
|
|
1062
|
+
schema_version: 2,
|
|
1063
|
+
event_id: `${id}:3`,
|
|
1064
|
+
run_id: id,
|
|
1065
|
+
sequence: 3,
|
|
1066
|
+
occurred_at: "2026-08-08T12:01:00.000Z",
|
|
1067
|
+
type: "run.finished",
|
|
1068
|
+
phase: "execution",
|
|
1069
|
+
status: "completed",
|
|
1070
|
+
duration_ms: 60_000,
|
|
1071
|
+
duration_provenance: "observed",
|
|
1072
|
+
},
|
|
654
1073
|
];
|
|
655
|
-
await writeFile(
|
|
656
|
-
|
|
1074
|
+
await writeFile(
|
|
1075
|
+
join(root, ".agents", "records", "runs", "2026", "08", "RUN-CANONICAL.jsonl"),
|
|
1076
|
+
`${run("RUN-CANONICAL", "TASK-CANONICAL", 7)
|
|
1077
|
+
.map((row) => JSON.stringify(row))
|
|
1078
|
+
.join("\n")}\n`,
|
|
1079
|
+
);
|
|
1080
|
+
await writeFile(
|
|
1081
|
+
join(root, ".agents", "records", "runs", "2026", "08", "RUN-ORPHAN.jsonl"),
|
|
1082
|
+
`${run("RUN-ORPHAN", "TASK-ORPHAN-REFERENCE", 11)
|
|
1083
|
+
.map((row) => JSON.stringify(row))
|
|
1084
|
+
.join("\n")}\n`,
|
|
1085
|
+
);
|
|
657
1086
|
|
|
658
1087
|
await rebuildSqliteReadModel(root);
|
|
659
|
-
const snapshot = new DatabaseSync(resolve(root, ".local/dashboard-sqlite/read-model.sqlite"), {
|
|
660
|
-
|
|
1088
|
+
const snapshot = new DatabaseSync(resolve(root, ".local/dashboard-sqlite/read-model.sqlite"), {
|
|
1089
|
+
readOnly: true,
|
|
1090
|
+
});
|
|
1091
|
+
expect(
|
|
1092
|
+
snapshot
|
|
1093
|
+
.prepare("SELECT value FROM zaip_vw_read_model_metadata WHERE key='schema_version'")
|
|
1094
|
+
.get(),
|
|
1095
|
+
).toEqual({ value: "60" });
|
|
661
1096
|
snapshot.close();
|
|
662
1097
|
const filesystem = new SqliteReadModelFileSystem(root);
|
|
663
1098
|
try {
|
|
664
1099
|
expect(filesystem.viewPage("operations_work_kanban", { limit: 20 }).rows).toEqual([
|
|
665
1100
|
expect.objectContaining({ id: "TASK-CANONICAL", title: "Titulo semantico canonico" }),
|
|
666
1101
|
]);
|
|
1102
|
+
// The List export is sourced from this SQLite view, so its known facts
|
|
1103
|
+
// must survive the public entity union rather than be left as blank XLSX
|
|
1104
|
+
// columns by a mapper that only receives identity fields.
|
|
1105
|
+
expect(filesystem.viewPage("operations_work_list", { limit: 20 }).rows).toContainEqual(
|
|
1106
|
+
expect.objectContaining({
|
|
1107
|
+
id: "TASK-CANONICAL",
|
|
1108
|
+
invocation_count: 1,
|
|
1109
|
+
total_duration: 30_000,
|
|
1110
|
+
total_tokens: 7,
|
|
1111
|
+
total_cost_brl: 0.35,
|
|
1112
|
+
}),
|
|
1113
|
+
);
|
|
667
1114
|
const costTasks = filesystem.viewPage("cost_monitor_tasks", { limit: 20 }).rows;
|
|
668
|
-
expect(costTasks).toContainEqual(
|
|
1115
|
+
expect(costTasks).toContainEqual(
|
|
1116
|
+
expect.objectContaining({
|
|
1117
|
+
id: "TASK-ORPHAN-REFERENCE",
|
|
1118
|
+
total_tokens: 11,
|
|
1119
|
+
total_cost_brl: 0.55,
|
|
1120
|
+
}),
|
|
1121
|
+
);
|
|
669
1122
|
} finally {
|
|
670
1123
|
filesystem.close();
|
|
671
1124
|
}
|
|
@@ -691,14 +1144,129 @@ created_at: 2026-08-10T11:01:00.000Z
|
|
|
691
1144
|
source: "fixture",
|
|
692
1145
|
disclaimer: "fixture",
|
|
693
1146
|
models: [
|
|
694
|
-
{
|
|
695
|
-
|
|
1147
|
+
{
|
|
1148
|
+
id: "gpt-a",
|
|
1149
|
+
provider: "openai",
|
|
1150
|
+
aliases: [],
|
|
1151
|
+
input_per_million_usd: 2,
|
|
1152
|
+
cached_input_per_million_usd: 0.2,
|
|
1153
|
+
output_per_million_usd: 8,
|
|
1154
|
+
reasoning_per_million_usd: 8,
|
|
1155
|
+
reasoning_billed_separately: false,
|
|
1156
|
+
long_context_threshold_tokens: null,
|
|
1157
|
+
long_context_input_multiplier: 1,
|
|
1158
|
+
long_context_output_multiplier: 1,
|
|
1159
|
+
source_label: "fixture-openai",
|
|
1160
|
+
source_url: "https://example.test/openai",
|
|
1161
|
+
notes: [],
|
|
1162
|
+
},
|
|
1163
|
+
{
|
|
1164
|
+
id: "claude-b",
|
|
1165
|
+
provider: "anthropic",
|
|
1166
|
+
aliases: [],
|
|
1167
|
+
input_per_million_usd: 3,
|
|
1168
|
+
cached_input_per_million_usd: 0.3,
|
|
1169
|
+
output_per_million_usd: 12,
|
|
1170
|
+
reasoning_per_million_usd: null,
|
|
1171
|
+
reasoning_billed_separately: false,
|
|
1172
|
+
long_context_threshold_tokens: null,
|
|
1173
|
+
long_context_input_multiplier: 1,
|
|
1174
|
+
long_context_output_multiplier: 1,
|
|
1175
|
+
source_label: "fixture-anthropic",
|
|
1176
|
+
source_url: "https://example.test/anthropic",
|
|
1177
|
+
notes: [],
|
|
1178
|
+
},
|
|
696
1179
|
],
|
|
697
1180
|
}),
|
|
698
1181
|
);
|
|
699
|
-
const started = {
|
|
700
|
-
|
|
701
|
-
|
|
1182
|
+
const started = {
|
|
1183
|
+
schema_version: 2,
|
|
1184
|
+
event_id: "RUN-MULTI:1",
|
|
1185
|
+
run_id: "RUN-MULTI",
|
|
1186
|
+
sequence: 1,
|
|
1187
|
+
occurred_at: "2026-08-04T12:00:00.000Z",
|
|
1188
|
+
type: "run.started",
|
|
1189
|
+
attribution_status: "attributed",
|
|
1190
|
+
phase: "execution",
|
|
1191
|
+
run_role: "orchestrator",
|
|
1192
|
+
run_purpose: "execution",
|
|
1193
|
+
requires_finalizer: false,
|
|
1194
|
+
execution_kind: "delivery",
|
|
1195
|
+
execution_eligibility: ["delivery"],
|
|
1196
|
+
entrypoint: "task",
|
|
1197
|
+
work_type: "new",
|
|
1198
|
+
storage_mode: "tracked_sanitized",
|
|
1199
|
+
client: "codex",
|
|
1200
|
+
agent: "agent",
|
|
1201
|
+
agent_name: "agent",
|
|
1202
|
+
provider: "mixed",
|
|
1203
|
+
model: "mixed",
|
|
1204
|
+
reasoning_effort: null,
|
|
1205
|
+
client_thread_id: "multi",
|
|
1206
|
+
client_turn_id: "multi",
|
|
1207
|
+
conversation_id: "CONV-MULTI",
|
|
1208
|
+
execution_id: "EXEC-MULTI",
|
|
1209
|
+
task_id: "TASK-MULTI",
|
|
1210
|
+
spec_id: null,
|
|
1211
|
+
prd_id: null,
|
|
1212
|
+
change_id: null,
|
|
1213
|
+
parent_run_id: null,
|
|
1214
|
+
continuation_of_run_id: null,
|
|
1215
|
+
retry_of_run_id: null,
|
|
1216
|
+
agent_invocation_id: "AINV-MULTI",
|
|
1217
|
+
root_agent_invocation_id: "AINV-MULTI",
|
|
1218
|
+
parent_agent_invocation_id: null,
|
|
1219
|
+
invocation_kind: "orchestrator",
|
|
1220
|
+
delegation_depth: 0,
|
|
1221
|
+
};
|
|
1222
|
+
const usage = (
|
|
1223
|
+
sequence: number,
|
|
1224
|
+
provider: string,
|
|
1225
|
+
model: string,
|
|
1226
|
+
tokens: number,
|
|
1227
|
+
brl: number,
|
|
1228
|
+
) => ({
|
|
1229
|
+
schema_version: 2,
|
|
1230
|
+
event_id: `RUN-MULTI:${sequence}`,
|
|
1231
|
+
run_id: "RUN-MULTI",
|
|
1232
|
+
sequence,
|
|
1233
|
+
occurred_at: "2026-08-04T12:00:01.000Z",
|
|
1234
|
+
type: "usage.recorded",
|
|
1235
|
+
phase: "execution",
|
|
1236
|
+
activity_kind: "model_usage",
|
|
1237
|
+
classification_source: "explicit",
|
|
1238
|
+
tokens: {
|
|
1239
|
+
input: tokens,
|
|
1240
|
+
cached_input: 0,
|
|
1241
|
+
output: 0,
|
|
1242
|
+
reasoning: 0,
|
|
1243
|
+
total: tokens,
|
|
1244
|
+
source: "provider_reported",
|
|
1245
|
+
},
|
|
1246
|
+
cost: { usd: brl / 5, brl, fx_rate: 5 },
|
|
1247
|
+
provider,
|
|
1248
|
+
model,
|
|
1249
|
+
source_segment_key: `${provider}-${model}`,
|
|
1250
|
+
model_call_id: `MCALL-${sequence}`,
|
|
1251
|
+
runtime: { reasoning_effort: null, service_tier: null },
|
|
1252
|
+
supersedes_event_id: null,
|
|
1253
|
+
source_started_at: "2026-08-04T12:00:00.000Z",
|
|
1254
|
+
source_finished_at: "2026-08-04T12:01:00.000Z",
|
|
1255
|
+
duration_ms: null,
|
|
1256
|
+
duration_provenance: null,
|
|
1257
|
+
});
|
|
1258
|
+
const finished = {
|
|
1259
|
+
schema_version: 2,
|
|
1260
|
+
event_id: "RUN-MULTI:5",
|
|
1261
|
+
run_id: "RUN-MULTI",
|
|
1262
|
+
sequence: 5,
|
|
1263
|
+
occurred_at: "2026-08-04T12:01:00.000Z",
|
|
1264
|
+
type: "run.finished",
|
|
1265
|
+
phase: "execution",
|
|
1266
|
+
status: "completed",
|
|
1267
|
+
duration_ms: 60_000,
|
|
1268
|
+
duration_provenance: "observed",
|
|
1269
|
+
};
|
|
702
1270
|
const mixedNullSegment = {
|
|
703
1271
|
...usage(4, "openai", "gpt-a", 0, 0),
|
|
704
1272
|
event_id: "RUN-MULTI:4",
|
|
@@ -707,7 +1275,10 @@ created_at: 2026-08-10T11:01:00.000Z
|
|
|
707
1275
|
source_segment_key: "mixed-null",
|
|
708
1276
|
model_call_id: "MCALL-MIXED-NULL",
|
|
709
1277
|
};
|
|
710
|
-
await writeFile(
|
|
1278
|
+
await writeFile(
|
|
1279
|
+
join(root, ".agents", "records", "runs", "2026", "08", "RUN-MULTI.jsonl"),
|
|
1280
|
+
`${[started, usage(2, "openai", "gpt-a", 10, 5), usage(3, "anthropic", "claude-b", 20, 10), mixedNullSegment, finished].map((row) => JSON.stringify(row)).join("\n")}\n`,
|
|
1281
|
+
);
|
|
711
1282
|
const unavailableStarted = {
|
|
712
1283
|
...started,
|
|
713
1284
|
event_id: "RUN-UNAVAILABLE:1",
|
|
@@ -748,7 +1319,12 @@ created_at: 2026-08-10T11:01:00.000Z
|
|
|
748
1319
|
);
|
|
749
1320
|
// It is a canonical activity but not an Agent Invocation. Cost Monitor
|
|
750
1321
|
// must not blend this population into its token/cost/session rate.
|
|
751
|
-
const {
|
|
1322
|
+
const {
|
|
1323
|
+
agent_invocation_id: _invocation,
|
|
1324
|
+
root_agent_invocation_id: _rootInvocation,
|
|
1325
|
+
parent_agent_invocation_id: _parentInvocation,
|
|
1326
|
+
...unassistedBase
|
|
1327
|
+
} = started;
|
|
752
1328
|
const unassistedStarted = {
|
|
753
1329
|
...unassistedBase,
|
|
754
1330
|
event_id: "RUN-UNASSISTED:1",
|
|
@@ -773,27 +1349,46 @@ created_at: 2026-08-10T11:01:00.000Z
|
|
|
773
1349
|
`${[unassistedStarted, unassistedUsage, { ...finished, event_id: "RUN-UNASSISTED:3", run_id: "RUN-UNASSISTED", sequence: 3 }].map((row) => JSON.stringify(row)).join("\n")}\n`,
|
|
774
1350
|
);
|
|
775
1351
|
await rebuildSqliteReadModel(root);
|
|
776
|
-
const aggregateDatabase = new DatabaseSync(
|
|
777
|
-
|
|
778
|
-
|
|
1352
|
+
const aggregateDatabase = new DatabaseSync(
|
|
1353
|
+
resolve(root, ".local/dashboard-sqlite/read-model.sqlite"),
|
|
1354
|
+
{
|
|
1355
|
+
readOnly: true,
|
|
1356
|
+
},
|
|
1357
|
+
);
|
|
779
1358
|
try {
|
|
780
|
-
const aggregates = aggregateDatabase
|
|
1359
|
+
const aggregates = aggregateDatabase
|
|
1360
|
+
.prepare(`SELECT
|
|
781
1361
|
json_extract(payload_json, '$.dimension') AS dimension,
|
|
782
1362
|
json_extract(payload_json, '$.key') AS key,
|
|
783
1363
|
json_extract(payload_json, '$.schema_version') AS schema_version,
|
|
784
1364
|
json_extract(payload_json, '$.total_cost_brl') AS total_cost_brl
|
|
785
1365
|
FROM zaip_aios_activities
|
|
786
|
-
WHERE payload_type = 'cost_dimension_aggregate_v1'`)
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
expect.
|
|
790
|
-
|
|
1366
|
+
WHERE payload_type = 'cost_dimension_aggregate_v1'`)
|
|
1367
|
+
.all();
|
|
1368
|
+
expect(aggregates).toEqual(
|
|
1369
|
+
expect.arrayContaining([
|
|
1370
|
+
expect.objectContaining({
|
|
1371
|
+
dimension: "provider",
|
|
1372
|
+
key: "openai",
|
|
1373
|
+
schema_version: 1,
|
|
1374
|
+
total_cost_brl: 505,
|
|
1375
|
+
}),
|
|
1376
|
+
expect.objectContaining({
|
|
1377
|
+
dimension: "model",
|
|
1378
|
+
key: "gpt-a",
|
|
1379
|
+
schema_version: 1,
|
|
1380
|
+
total_cost_brl: 505,
|
|
1381
|
+
}),
|
|
1382
|
+
]),
|
|
1383
|
+
);
|
|
791
1384
|
expect(aggregates.map((row) => row.key)).toEqual(expect.arrayContaining(["unavailable"]));
|
|
792
1385
|
} finally {
|
|
793
1386
|
aggregateDatabase.close();
|
|
794
1387
|
}
|
|
795
1388
|
const filesystem = new SqliteReadModelFileSystem(root);
|
|
796
|
-
expect(
|
|
1389
|
+
expect(
|
|
1390
|
+
filesystem.viewPage("cost_monitor_daily", { from: "2026-08-04", to: "2026-08-04" }).rows[0],
|
|
1391
|
+
).toMatchObject({ total_tokens: 1_030, total_cost_brl: 515 });
|
|
797
1392
|
// The public overview view backs /api/v2/sqlite-views. It must not leak
|
|
798
1393
|
// Cost Monitor retains all measurable financial activities, including
|
|
799
1394
|
// historical/unassisted telemetry without an Agent Invocation id.
|
|
@@ -801,83 +1396,204 @@ created_at: 2026-08-10T11:01:00.000Z
|
|
|
801
1396
|
expect(publicOverview.rows).toHaveLength(3);
|
|
802
1397
|
expect(publicOverview.rows).toEqual(
|
|
803
1398
|
expect.arrayContaining([
|
|
804
|
-
expect.objectContaining({
|
|
805
|
-
|
|
806
|
-
|
|
1399
|
+
expect.objectContaining({
|
|
1400
|
+
period_kind: "day",
|
|
1401
|
+
total_run_count: 3,
|
|
1402
|
+
invocation_count: 3,
|
|
1403
|
+
total_tokens: 1_030,
|
|
1404
|
+
total_cost_brl: 515,
|
|
1405
|
+
}),
|
|
1406
|
+
expect.objectContaining({
|
|
1407
|
+
period_kind: "month",
|
|
1408
|
+
total_run_count: 3,
|
|
1409
|
+
invocation_count: 3,
|
|
1410
|
+
total_tokens: 1_030,
|
|
1411
|
+
total_cost_brl: 515,
|
|
1412
|
+
}),
|
|
1413
|
+
expect.objectContaining({
|
|
1414
|
+
period_kind: "year",
|
|
1415
|
+
total_run_count: 3,
|
|
1416
|
+
invocation_count: 3,
|
|
1417
|
+
total_tokens: 1_030,
|
|
1418
|
+
total_cost_brl: 515,
|
|
1419
|
+
}),
|
|
807
1420
|
]),
|
|
808
1421
|
);
|
|
809
|
-
const allAgentGroups = filesystem.viewPage("cost_monitor_zaip_agents", {
|
|
1422
|
+
const allAgentGroups = filesystem.viewPage("cost_monitor_zaip_agents", {
|
|
1423
|
+
limit: 20,
|
|
1424
|
+
offset: 0,
|
|
1425
|
+
});
|
|
810
1426
|
const allCostTotals = publicOverview.rows.find((row) => row.period_kind === "day");
|
|
811
1427
|
if (allCostTotals === undefined) throw new Error("Expected the daily Cost Monitor overview");
|
|
812
|
-
expect(
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
expect(
|
|
1428
|
+
expect(
|
|
1429
|
+
allAgentGroups.rows.reduce((total, row) => total + Number(row.invocation_count ?? 0), 0),
|
|
1430
|
+
).toBe(allCostTotals.total_run_count);
|
|
1431
|
+
expect(
|
|
1432
|
+
allAgentGroups.rows.reduce((total, row) => total + Number(row.total_tokens ?? 0), 0),
|
|
1433
|
+
).toBe(allCostTotals?.total_tokens);
|
|
1434
|
+
expect(
|
|
1435
|
+
allAgentGroups.rows.reduce((total, row) => total + Number(row.total_cost_brl ?? 0), 0),
|
|
1436
|
+
).toBe(allCostTotals?.total_cost_brl);
|
|
1437
|
+
expect(
|
|
1438
|
+
allAgentGroups.rows.reduce((total, row) => total + Number(row.total_cost_usd ?? 0), 0),
|
|
1439
|
+
).toBe(allCostTotals.total_cost_usd);
|
|
816
1440
|
// Shared Cost Tempo is factual at the activity grain. It remains available
|
|
817
1441
|
// in the agent-table total even where a multi-dimension invocation cannot
|
|
818
1442
|
// be assigned to an individual Agent row.
|
|
819
1443
|
expect(allCostTotals.cost_monitor_total_duration).toBe(120_000);
|
|
820
|
-
expect(allAgentGroups.totals).toMatchObject({
|
|
821
|
-
|
|
1444
|
+
expect(allAgentGroups.totals).toMatchObject({
|
|
1445
|
+
invocation_count: allCostTotals.total_run_count,
|
|
1446
|
+
total_duration: 120_000,
|
|
1447
|
+
total_tokens: allCostTotals.total_tokens,
|
|
1448
|
+
total_cost_usd: allCostTotals.total_cost_usd,
|
|
1449
|
+
total_cost_brl: allCostTotals.total_cost_brl,
|
|
1450
|
+
});
|
|
1451
|
+
for (const [providers, models] of [
|
|
1452
|
+
[["openai"], ["gpt-a"]],
|
|
1453
|
+
[["anthropic"], ["claude-b"]],
|
|
1454
|
+
] as const) {
|
|
822
1455
|
const rows = filesystem.invocationCostRows({ from: null, to: null, providers, models });
|
|
823
1456
|
expect(rows).toHaveLength(1);
|
|
824
1457
|
// Membership is segment-based; once the invocation matches, its
|
|
825
1458
|
// canonical invocation totals remain intact rather than being split.
|
|
826
1459
|
expect(rows[0]).toMatchObject({ total_tokens: 30, cost_brl: 15 });
|
|
827
|
-
expect([
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
1460
|
+
expect([
|
|
1461
|
+
...filesystem.executionDurationByDay({ from: null, to: null, providers, models }).values(),
|
|
1462
|
+
]).toEqual([60_000]);
|
|
1463
|
+
expect([
|
|
1464
|
+
...filesystem.canonicalRunCountByDay({ from: null, to: null, providers, models }).values(),
|
|
1465
|
+
]).toEqual([1]);
|
|
1466
|
+
for (const view of [
|
|
1467
|
+
"cost_monitor_daily",
|
|
1468
|
+
"cost_monitor_monthly",
|
|
1469
|
+
"cost_monitor_annual",
|
|
1470
|
+
] as const) {
|
|
1471
|
+
const page = filesystem.viewPage(view, {
|
|
1472
|
+
provider: providers[0],
|
|
1473
|
+
model: models[0],
|
|
1474
|
+
limit: 20,
|
|
1475
|
+
offset: 0,
|
|
1476
|
+
});
|
|
1477
|
+
expect(page.rows[0]).toMatchObject({
|
|
1478
|
+
total_run_count: 1,
|
|
1479
|
+
total_tokens: 30,
|
|
1480
|
+
total_cost_brl: 15,
|
|
1481
|
+
});
|
|
832
1482
|
}
|
|
833
|
-
const agents = filesystem.viewPage("cost_monitor_zaip_agents", {
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
1483
|
+
const agents = filesystem.viewPage("cost_monitor_zaip_agents", {
|
|
1484
|
+
provider: providers[0],
|
|
1485
|
+
model: models[0],
|
|
1486
|
+
query: "agent",
|
|
1487
|
+
});
|
|
1488
|
+
const financialRows = filesystem.costMonitorFinancialActivityRows({
|
|
1489
|
+
from: null,
|
|
1490
|
+
to: null,
|
|
1491
|
+
providers,
|
|
1492
|
+
models,
|
|
1493
|
+
});
|
|
1494
|
+
const financialTotals = financialRows.reduce<{
|
|
1495
|
+
invocation_count: number;
|
|
1496
|
+
total_tokens: number;
|
|
1497
|
+
total_cost_brl: number;
|
|
1498
|
+
}>(
|
|
1499
|
+
(total, row) => ({
|
|
1500
|
+
invocation_count: total.invocation_count + 1,
|
|
1501
|
+
total_tokens: total.total_tokens + Number(row.total_tokens ?? 0),
|
|
1502
|
+
total_cost_brl: total.total_cost_brl + Number(row.cost_brl ?? 0),
|
|
1503
|
+
}),
|
|
1504
|
+
{ invocation_count: 0, total_tokens: 0, total_cost_brl: 0 },
|
|
1505
|
+
);
|
|
1506
|
+
expect(agents.rows[0]).toMatchObject({
|
|
1507
|
+
key: "agent",
|
|
1508
|
+
persona: "ana",
|
|
1509
|
+
job: "quality_engineer",
|
|
1510
|
+
task_count: 1,
|
|
1511
|
+
...financialTotals,
|
|
1512
|
+
});
|
|
841
1513
|
expect(agents.totals).toMatchObject(financialTotals);
|
|
842
1514
|
}
|
|
843
1515
|
const crossed = { from: null, to: null, providers: ["openai"], models: ["claude-b"] };
|
|
844
1516
|
expect(filesystem.invocationCostRows(crossed)).toHaveLength(0);
|
|
845
1517
|
expect([...filesystem.executionDurationByDay(crossed).values()]).toEqual([]);
|
|
846
1518
|
expect([...filesystem.canonicalRunCountByDay(crossed).values()]).toEqual([]);
|
|
847
|
-
expect(
|
|
848
|
-
|
|
849
|
-
|
|
1519
|
+
expect(
|
|
1520
|
+
filesystem.viewPage("cost_monitor_agent_invocations", {
|
|
1521
|
+
provider: "openai",
|
|
1522
|
+
model: "claude-b",
|
|
1523
|
+
}).total_count,
|
|
1524
|
+
).toBe(0);
|
|
1525
|
+
expect(
|
|
1526
|
+
filesystem.viewPage("cost_monitor_zaip_agents", { provider: "openai", model: "claude-b" })
|
|
1527
|
+
.total_count,
|
|
1528
|
+
).toBe(0);
|
|
1529
|
+
for (const view of [
|
|
1530
|
+
"cost_monitor_daily",
|
|
1531
|
+
"cost_monitor_monthly",
|
|
1532
|
+
"cost_monitor_annual",
|
|
1533
|
+
] as const) {
|
|
850
1534
|
// Lifecycle buckets can remain present independently, but the crossed
|
|
851
1535
|
// pair must contribute no invocation financial or Run facts.
|
|
852
1536
|
const row = filesystem.viewPage(view, { provider: "openai", model: "claude-b" }).rows[0];
|
|
853
|
-
expect(row).toMatchObject({
|
|
1537
|
+
expect(row).toMatchObject({
|
|
1538
|
+
total_run_count: 0,
|
|
1539
|
+
total_duration: null,
|
|
1540
|
+
total_tokens: null,
|
|
1541
|
+
total_cost_brl: null,
|
|
1542
|
+
});
|
|
854
1543
|
}
|
|
855
|
-
for (const view of [
|
|
1544
|
+
for (const view of [
|
|
1545
|
+
"cost_monitor_daily",
|
|
1546
|
+
"cost_monitor_monthly",
|
|
1547
|
+
"cost_monitor_annual",
|
|
1548
|
+
] as const) {
|
|
856
1549
|
const originFiltered = filesystem.viewPage(view, { origin: "task" });
|
|
857
|
-
expect(originFiltered.rows[0]).toMatchObject({
|
|
1550
|
+
expect(originFiltered.rows[0]).toMatchObject({
|
|
1551
|
+
prd_count: null,
|
|
1552
|
+
spec_count: null,
|
|
1553
|
+
task_count: null,
|
|
1554
|
+
validation_count: null,
|
|
1555
|
+
evidence_count: null,
|
|
1556
|
+
});
|
|
858
1557
|
expect(filesystem.viewPage(view, { workType: "new" }).total_count).toBe(0);
|
|
859
1558
|
}
|
|
860
|
-
expect(filesystem.viewPage("cost_monitor_zaip_agents", { priority: "high" })).toMatchObject({
|
|
1559
|
+
expect(filesystem.viewPage("cost_monitor_zaip_agents", { priority: "high" })).toMatchObject({
|
|
1560
|
+
total_count: 0,
|
|
1561
|
+
rows: [],
|
|
1562
|
+
});
|
|
861
1563
|
const providerGroups = filesystem.viewPage("cost_monitor_providers", { limit: 20, offset: 0 });
|
|
862
|
-
expect(providerGroups.rows).toEqual(
|
|
863
|
-
expect.
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
expect(
|
|
1564
|
+
expect(providerGroups.rows).toEqual(
|
|
1565
|
+
expect.arrayContaining([
|
|
1566
|
+
expect.objectContaining({ key: "openai", total_tokens: 1_010, total_cost_brl: 505 }),
|
|
1567
|
+
expect.objectContaining({ key: "anthropic", total_tokens: 20, total_cost_brl: 10 }),
|
|
1568
|
+
]),
|
|
1569
|
+
);
|
|
1570
|
+
expect(providerGroups.rows.map((row) => row.key)).toEqual(
|
|
1571
|
+
expect.arrayContaining(["unavailable"]),
|
|
1572
|
+
);
|
|
1573
|
+
expect(
|
|
1574
|
+
filesystem
|
|
1575
|
+
.viewPage("cost_monitor_providers", { provider: "openai", model: "gpt-a" })
|
|
1576
|
+
.rows.find((row) => row.key === "openai"),
|
|
1577
|
+
).toMatchObject({ total_tokens: 10, total_cost_brl: 5 });
|
|
1578
|
+
expect(
|
|
1579
|
+
filesystem.viewPage("cost_monitor_providers", { provider: "openai", model: "claude-b" }),
|
|
1580
|
+
).toMatchObject({ total_count: 0, rows: [] });
|
|
869
1581
|
// A source segment can prove its financial facts, but an invocation with
|
|
870
1582
|
// multiple observed providers cannot prove a provider-specific elapsed
|
|
871
1583
|
// time. It must not manufacture a "mixed" bucket for that remainder.
|
|
872
|
-
const queriedProviderRows = filesystem.viewPage("cost_monitor_providers", {
|
|
1584
|
+
const queriedProviderRows = filesystem.viewPage("cost_monitor_providers", {
|
|
1585
|
+
query: "openai",
|
|
1586
|
+
}).rows;
|
|
873
1587
|
expect(queriedProviderRows).toEqual([
|
|
874
1588
|
expect.objectContaining({ key: "openai", total_tokens: 10, total_cost_brl: 5 }),
|
|
875
1589
|
]);
|
|
876
1590
|
const modelGroups = filesystem.viewPage("cost_monitor_models", { limit: 20, offset: 0 });
|
|
877
|
-
expect(modelGroups.rows).toEqual(
|
|
878
|
-
expect.
|
|
879
|
-
|
|
880
|
-
|
|
1591
|
+
expect(modelGroups.rows).toEqual(
|
|
1592
|
+
expect.arrayContaining([
|
|
1593
|
+
expect.objectContaining({ key: "gpt-a", total_tokens: 1_010, total_cost_brl: 505 }),
|
|
1594
|
+
expect.objectContaining({ key: "claude-b", total_tokens: 20, total_cost_brl: 10 }),
|
|
1595
|
+
]),
|
|
1596
|
+
);
|
|
881
1597
|
// First-fold transport is aggregate-only, but its overview chart must
|
|
882
1598
|
// retain the segment-backed model rows instead of falling back to the
|
|
883
1599
|
// empty availability metadata.
|
|
@@ -888,7 +1604,13 @@ created_at: 2026-08-10T11:01:00.000Z
|
|
|
888
1604
|
]),
|
|
889
1605
|
);
|
|
890
1606
|
expect(modelGroups.rows.map((row) => row.key)).toEqual(expect.arrayContaining(["unavailable"]));
|
|
891
|
-
const modelTotals = modelGroups.rows.reduce<{
|
|
1607
|
+
const modelTotals = modelGroups.rows.reduce<{
|
|
1608
|
+
invocations: number;
|
|
1609
|
+
tasks: number;
|
|
1610
|
+
duration: number;
|
|
1611
|
+
tokens: number;
|
|
1612
|
+
brl: number;
|
|
1613
|
+
}>(
|
|
892
1614
|
(total, row) => ({
|
|
893
1615
|
invocations: total.invocations + Number(row.invocation_count ?? 0),
|
|
894
1616
|
tasks: total.tasks + Number(row.task_count ?? 0),
|
|
@@ -898,12 +1620,30 @@ created_at: 2026-08-10T11:01:00.000Z
|
|
|
898
1620
|
}),
|
|
899
1621
|
{ invocations: 0, tasks: 0, duration: 0, tokens: 0, brl: 0 },
|
|
900
1622
|
);
|
|
901
|
-
expect(modelTotals).toEqual({
|
|
1623
|
+
expect(modelTotals).toEqual({
|
|
1624
|
+
invocations: 2,
|
|
1625
|
+
tasks: 3,
|
|
1626
|
+
duration: 60_000,
|
|
1627
|
+
tokens: 1030,
|
|
1628
|
+
brl: 515,
|
|
1629
|
+
});
|
|
902
1630
|
expect(filesystem.viewPage("cost_monitor_models", { query: "gpt-a" }).rows).toHaveLength(1);
|
|
903
|
-
expect(
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
1631
|
+
expect(
|
|
1632
|
+
filesystem.viewPage("cost_monitor_models", { provider: "openai", model: "gpt-a" }).rows[0],
|
|
1633
|
+
).toMatchObject({ key: "gpt-a", total_tokens: 1010, total_cost_brl: 505 });
|
|
1634
|
+
expect(
|
|
1635
|
+
filesystem.viewPage("cost_monitor_models", { provider: "openai", model: "claude-b" }),
|
|
1636
|
+
).toMatchObject({ total_count: 0, rows: [] });
|
|
1637
|
+
expect(filesystem.viewPage("cost_monitor_models", { priority: "high" })).toMatchObject({
|
|
1638
|
+
total_count: 0,
|
|
1639
|
+
rows: [],
|
|
1640
|
+
});
|
|
1641
|
+
const unavailable = {
|
|
1642
|
+
from: null,
|
|
1643
|
+
to: null,
|
|
1644
|
+
providers: ["unavailable"],
|
|
1645
|
+
models: ["unavailable"],
|
|
1646
|
+
};
|
|
907
1647
|
const unavailableRows = filesystem.invocationCostRows(unavailable);
|
|
908
1648
|
expect(unavailableRows).toHaveLength(1);
|
|
909
1649
|
// Observed zero telemetry stays zero, while the missing provider/model
|
|
@@ -920,51 +1660,247 @@ created_at: 2026-08-10T11:01:00.000Z
|
|
|
920
1660
|
});
|
|
921
1661
|
expect(unavailableInvocation).toMatchObject({ total_count: 1 });
|
|
922
1662
|
expect(unavailableInvocation.rows[0]).toMatchObject({ input_tokens: 0 });
|
|
923
|
-
for (const view of [
|
|
924
|
-
|
|
1663
|
+
for (const view of [
|
|
1664
|
+
"cost_monitor_daily",
|
|
1665
|
+
"cost_monitor_monthly",
|
|
1666
|
+
"cost_monitor_annual",
|
|
1667
|
+
] as const) {
|
|
1668
|
+
const row = filesystem.viewPage(view, { provider: "unavailable", model: "unavailable" })
|
|
1669
|
+
.rows[0];
|
|
925
1670
|
expect(row).toMatchObject({ total_run_count: 2, total_tokens: 1_000, total_cost_brl: 500 });
|
|
926
1671
|
}
|
|
927
1672
|
|
|
928
1673
|
filesystem.close();
|
|
929
|
-
const sameModelStarted = {
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
1674
|
+
const sameModelStarted = {
|
|
1675
|
+
...started,
|
|
1676
|
+
event_id: "RUN-SAME-MODEL:1",
|
|
1677
|
+
run_id: "RUN-SAME-MODEL",
|
|
1678
|
+
occurred_at: "2026-08-05T12:00:00.000Z",
|
|
1679
|
+
client_turn_id: "same-model",
|
|
1680
|
+
conversation_id: "CONV-SAME-MODEL",
|
|
1681
|
+
execution_id: "EXEC-SAME-MODEL",
|
|
1682
|
+
task_id: "TASK-SAME-MODEL",
|
|
1683
|
+
agent_invocation_id: "AINV-SAME-MODEL",
|
|
1684
|
+
root_agent_invocation_id: "AINV-SAME-MODEL",
|
|
1685
|
+
provider: "mixed",
|
|
1686
|
+
model: "gpt-a",
|
|
1687
|
+
};
|
|
1688
|
+
const sameModelUsage = (sequence: number, provider: string, tokens: number, brl: number) => ({
|
|
1689
|
+
...usage(sequence, provider, "gpt-a", tokens, brl),
|
|
1690
|
+
event_id: `RUN-SAME-MODEL:${sequence}`,
|
|
1691
|
+
run_id: "RUN-SAME-MODEL",
|
|
1692
|
+
occurred_at: "2026-08-05T12:00:01.000Z",
|
|
1693
|
+
source_started_at: "2026-08-05T12:00:00.000Z",
|
|
1694
|
+
source_finished_at: "2026-08-05T12:01:00.000Z",
|
|
1695
|
+
});
|
|
1696
|
+
const sameModelFinished = {
|
|
1697
|
+
...finished,
|
|
1698
|
+
event_id: "RUN-SAME-MODEL:4",
|
|
1699
|
+
run_id: "RUN-SAME-MODEL",
|
|
1700
|
+
sequence: 4,
|
|
1701
|
+
occurred_at: "2026-08-05T12:01:00.000Z",
|
|
1702
|
+
};
|
|
1703
|
+
await writeFile(
|
|
1704
|
+
join(root, ".agents", "records", "runs", "2026", "08", "RUN-SAME-MODEL.jsonl"),
|
|
1705
|
+
`${[sameModelStarted, sameModelUsage(2, "openai", 3, 1.5), sameModelUsage(3, "anthropic", 4, 2), sameModelFinished].map((row) => JSON.stringify(row)).join("\n")}\n`,
|
|
1706
|
+
);
|
|
1707
|
+
const durationRun = (
|
|
1708
|
+
id: string,
|
|
1709
|
+
day: string,
|
|
1710
|
+
duration: number | null,
|
|
1711
|
+
provenance: "reconciled" | "estimated",
|
|
1712
|
+
) => {
|
|
1713
|
+
const start = {
|
|
1714
|
+
...sameModelStarted,
|
|
1715
|
+
event_id: `${id}:1`,
|
|
1716
|
+
run_id: id,
|
|
1717
|
+
occurred_at: `${day}T12:00:00.000Z`,
|
|
1718
|
+
client_turn_id: id,
|
|
1719
|
+
conversation_id: `CONV-${id}`,
|
|
1720
|
+
execution_id: `EXEC-${id}`,
|
|
1721
|
+
task_id: `TASK-${id}`,
|
|
1722
|
+
agent_invocation_id: `AINV-${id}`,
|
|
1723
|
+
root_agent_invocation_id: `AINV-${id}`,
|
|
1724
|
+
};
|
|
1725
|
+
const measured = {
|
|
1726
|
+
...usage(
|
|
1727
|
+
2,
|
|
1728
|
+
"openai",
|
|
1729
|
+
"gpt-a",
|
|
1730
|
+
provenance === "estimated" ? 4_000_000 : 9,
|
|
1731
|
+
provenance === "estimated" ? 0 : 4.5,
|
|
1732
|
+
),
|
|
1733
|
+
event_id: `${id}:2`,
|
|
1734
|
+
run_id: id,
|
|
1735
|
+
occurred_at: `${day}T12:00:01.000Z`,
|
|
1736
|
+
source_started_at: `${day}T12:00:00.000Z`,
|
|
1737
|
+
source_finished_at: `${day}T12:01:00.000Z`,
|
|
1738
|
+
...(duration === null ? {} : { duration_ms: duration, duration_provenance: provenance }),
|
|
1739
|
+
};
|
|
1740
|
+
const end = {
|
|
1741
|
+
...finished,
|
|
1742
|
+
event_id: `${id}:3`,
|
|
1743
|
+
run_id: id,
|
|
1744
|
+
sequence: 3,
|
|
1745
|
+
occurred_at: `${day}T12:01:00.000Z`,
|
|
1746
|
+
...(provenance === "estimated"
|
|
1747
|
+
? { duration_ms: null, duration_provenance: "unavailable" }
|
|
1748
|
+
: {}),
|
|
1749
|
+
};
|
|
937
1750
|
return [start, measured, end];
|
|
938
1751
|
};
|
|
939
|
-
await writeFile(
|
|
940
|
-
|
|
1752
|
+
await writeFile(
|
|
1753
|
+
join(root, ".agents", "records", "runs", "2026", "08", "RUN-RECONCILED-MODEL.jsonl"),
|
|
1754
|
+
`${durationRun("RUN-RECONCILED-MODEL", "2026-08-06", 45_000, "reconciled")
|
|
1755
|
+
.map((row) => JSON.stringify(row))
|
|
1756
|
+
.join("\n")}\n`,
|
|
1757
|
+
);
|
|
1758
|
+
await writeFile(
|
|
1759
|
+
join(root, ".agents", "records", "runs", "2026", "08", "RUN-ESTIMATED-MODEL.jsonl"),
|
|
1760
|
+
`${durationRun("RUN-ESTIMATED-MODEL", "2026-08-07", null, "estimated")
|
|
1761
|
+
.map((row) => JSON.stringify(row))
|
|
1762
|
+
.join("\n")}\n`,
|
|
1763
|
+
);
|
|
941
1764
|
const sharedTaskRun = (id: string, model: string, tokens: number, brl: number) => [
|
|
942
|
-
{
|
|
943
|
-
|
|
944
|
-
|
|
1765
|
+
{
|
|
1766
|
+
...sameModelStarted,
|
|
1767
|
+
event_id: `${id}:1`,
|
|
1768
|
+
run_id: id,
|
|
1769
|
+
occurred_at: "2026-08-08T12:00:00.000Z",
|
|
1770
|
+
client_turn_id: id,
|
|
1771
|
+
conversation_id: `CONV-${id}`,
|
|
1772
|
+
execution_id: `EXEC-${id}`,
|
|
1773
|
+
task_id: "TASK-CROSS-MODEL",
|
|
1774
|
+
agent_invocation_id: `AINV-${id}`,
|
|
1775
|
+
root_agent_invocation_id: `AINV-${id}`,
|
|
1776
|
+
provider: "openai",
|
|
1777
|
+
model,
|
|
1778
|
+
},
|
|
1779
|
+
{
|
|
1780
|
+
...usage(2, "openai", model, tokens, brl),
|
|
1781
|
+
event_id: `${id}:2`,
|
|
1782
|
+
run_id: id,
|
|
1783
|
+
occurred_at: "2026-08-08T12:00:01.000Z",
|
|
1784
|
+
source_started_at: "2026-08-08T12:00:00.000Z",
|
|
1785
|
+
source_finished_at: "2026-08-08T12:01:00.000Z",
|
|
1786
|
+
},
|
|
1787
|
+
{
|
|
1788
|
+
...finished,
|
|
1789
|
+
event_id: `${id}:3`,
|
|
1790
|
+
run_id: id,
|
|
1791
|
+
sequence: 3,
|
|
1792
|
+
occurred_at: "2026-08-08T12:01:00.000Z",
|
|
1793
|
+
},
|
|
945
1794
|
];
|
|
946
|
-
await writeFile(
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
1795
|
+
await writeFile(
|
|
1796
|
+
join(root, ".agents", "records", "runs", "2026", "08", "RUN-TASK-GPT.jsonl"),
|
|
1797
|
+
`${sharedTaskRun("RUN-TASK-GPT", "gpt-a", 5, 2.5)
|
|
1798
|
+
.map((row) => JSON.stringify(row))
|
|
1799
|
+
.join("\n")}\n`,
|
|
1800
|
+
);
|
|
1801
|
+
await writeFile(
|
|
1802
|
+
join(root, ".agents", "records", "runs", "2026", "08", "RUN-TASK-CLAUDE.jsonl"),
|
|
1803
|
+
`${sharedTaskRun("RUN-TASK-CLAUDE", "claude-b", 6, 3)
|
|
1804
|
+
.map((row) => JSON.stringify(row))
|
|
1805
|
+
.join("\n")}\n`,
|
|
1806
|
+
);
|
|
1807
|
+
const subrunStarted = {
|
|
1808
|
+
...sameModelStarted,
|
|
1809
|
+
event_id: "RUN-PROVIDER-SUBRUN:1",
|
|
1810
|
+
run_id: "RUN-PROVIDER-SUBRUN",
|
|
1811
|
+
occurred_at: "2026-08-09T12:00:00.000Z",
|
|
1812
|
+
client_turn_id: "provider-subrun",
|
|
1813
|
+
conversation_id: "CONV-PROVIDER-SUBRUN",
|
|
1814
|
+
execution_id: "EXEC-PROVIDER-SUBRUN",
|
|
1815
|
+
task_id: "TASK-PROVIDER-SUBRUN",
|
|
1816
|
+
agent_invocation_id: "AINV-PROVIDER-SUBRUN",
|
|
1817
|
+
root_agent_invocation_id: "AINV-SAME-MODEL",
|
|
1818
|
+
parent_agent_invocation_id: "AINV-SAME-MODEL",
|
|
1819
|
+
parent_run_id: "RUN-SAME-MODEL",
|
|
1820
|
+
run_role: "subagent",
|
|
1821
|
+
invocation_kind: "delegated",
|
|
1822
|
+
delegation_depth: 1,
|
|
1823
|
+
provider: "openai",
|
|
1824
|
+
model: "gpt-a",
|
|
1825
|
+
};
|
|
1826
|
+
const subrunUsage = {
|
|
1827
|
+
...usage(2, "openai", "gpt-a", 8, 4),
|
|
1828
|
+
event_id: "RUN-PROVIDER-SUBRUN:2",
|
|
1829
|
+
run_id: "RUN-PROVIDER-SUBRUN",
|
|
1830
|
+
occurred_at: "2026-08-09T12:00:01.000Z",
|
|
1831
|
+
source_started_at: "2026-08-09T12:00:00.000Z",
|
|
1832
|
+
source_finished_at: "2026-08-09T12:00:30.000Z",
|
|
1833
|
+
};
|
|
1834
|
+
const subrunFinished = {
|
|
1835
|
+
...finished,
|
|
1836
|
+
event_id: "RUN-PROVIDER-SUBRUN:3",
|
|
1837
|
+
run_id: "RUN-PROVIDER-SUBRUN",
|
|
1838
|
+
sequence: 3,
|
|
1839
|
+
occurred_at: "2026-08-09T12:00:30.000Z",
|
|
1840
|
+
duration_ms: 30_000,
|
|
1841
|
+
duration_provenance: "observed",
|
|
1842
|
+
};
|
|
1843
|
+
await writeFile(
|
|
1844
|
+
join(root, ".agents", "records", "runs", "2026", "08", "RUN-PROVIDER-SUBRUN.jsonl"),
|
|
1845
|
+
`${[subrunStarted, subrunUsage, subrunFinished].map((row) => JSON.stringify(row)).join("\n")}\n`,
|
|
1846
|
+
);
|
|
952
1847
|
await rebuildSqliteReadModel(root);
|
|
953
1848
|
const sameModelFs = new SqliteReadModelFileSystem(root);
|
|
954
|
-
const modelRow = (filter: Record<string, string>) =>
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
expect(
|
|
1849
|
+
const modelRow = (filter: Record<string, string>) =>
|
|
1850
|
+
sameModelFs
|
|
1851
|
+
.viewPage("cost_monitor_models", { from: "2026-08-05", to: "2026-08-05", ...filter })
|
|
1852
|
+
.rows.find((row) => row.key === "gpt-a");
|
|
1853
|
+
expect(modelRow({ provider: "openai", model: "gpt-a" })).toMatchObject({
|
|
1854
|
+
invocation_count: 1,
|
|
1855
|
+
task_count: 1,
|
|
1856
|
+
total_duration: 60_000,
|
|
1857
|
+
total_tokens: 3,
|
|
1858
|
+
total_cost_brl: 1.5,
|
|
1859
|
+
});
|
|
1860
|
+
expect(modelRow({ provider: "anthropic", model: "gpt-a" })).toMatchObject({
|
|
1861
|
+
invocation_count: 1,
|
|
1862
|
+
task_count: 1,
|
|
1863
|
+
total_duration: 60_000,
|
|
1864
|
+
total_tokens: 4,
|
|
1865
|
+
total_cost_brl: 2,
|
|
1866
|
+
});
|
|
1867
|
+
expect(modelRow({})).toMatchObject({
|
|
1868
|
+
invocation_count: 1,
|
|
1869
|
+
task_count: 1,
|
|
1870
|
+
total_duration: 60_000,
|
|
1871
|
+
total_tokens: 7,
|
|
1872
|
+
total_cost_brl: 3.5,
|
|
1873
|
+
});
|
|
1874
|
+
expect(
|
|
1875
|
+
sameModelFs.viewPage("cost_monitor_models", {
|
|
1876
|
+
from: "2026-08-05",
|
|
1877
|
+
to: "2026-08-05",
|
|
1878
|
+
provider: "openai",
|
|
1879
|
+
model: "claude-b",
|
|
1880
|
+
}),
|
|
1881
|
+
).toMatchObject({ total_count: 0, rows: [] });
|
|
959
1882
|
for (const day of ["2026-08-06", "2026-08-07"]) {
|
|
960
|
-
const effective = sameModelFs
|
|
961
|
-
|
|
1883
|
+
const effective = sameModelFs
|
|
1884
|
+
.invocationCostRows({ from: day, to: day })
|
|
1885
|
+
.reduce((sum, row) => sum + Number(row.duration_ms ?? 0), 0);
|
|
1886
|
+
const modelDuration = sameModelFs
|
|
1887
|
+
.viewPage("cost_monitor_models", { from: day, to: day })
|
|
1888
|
+
.rows.reduce((sum, row) => sum + Number(row.total_duration ?? 0), 0);
|
|
962
1889
|
expect(modelDuration).toBe(effective);
|
|
963
1890
|
}
|
|
964
1891
|
for (const day of ["2026-08-06", "2026-08-07"]) {
|
|
965
1892
|
const population = sameModelFs.invocationCostRows({ from: day, to: day });
|
|
966
|
-
const providerRows = sameModelFs.viewPage("cost_monitor_providers", {
|
|
967
|
-
|
|
1893
|
+
const providerRows = sameModelFs.viewPage("cost_monitor_providers", {
|
|
1894
|
+
from: day,
|
|
1895
|
+
to: day,
|
|
1896
|
+
}).rows;
|
|
1897
|
+
const providerTotals = providerRows.reduce<{
|
|
1898
|
+
invocations: number;
|
|
1899
|
+
tasks: number;
|
|
1900
|
+
duration: number;
|
|
1901
|
+
tokens: number;
|
|
1902
|
+
brl: number;
|
|
1903
|
+
}>(
|
|
968
1904
|
(total, row) => ({
|
|
969
1905
|
invocations: total.invocations + Number(row.invocation_count ?? 0),
|
|
970
1906
|
tasks: total.tasks + Number(row.task_count ?? 0),
|
|
@@ -976,27 +1912,87 @@ created_at: 2026-08-10T11:01:00.000Z
|
|
|
976
1912
|
);
|
|
977
1913
|
expect(providerTotals).toEqual({
|
|
978
1914
|
invocations: population.length,
|
|
979
|
-
tasks: new Set(
|
|
1915
|
+
tasks: new Set(
|
|
1916
|
+
population.map((row) => row.task_id).filter((id): id is string => typeof id === "string"),
|
|
1917
|
+
).size,
|
|
980
1918
|
duration: population.reduce((sum, row) => sum + Number(row.duration_ms ?? 0), 0),
|
|
981
1919
|
tokens: population.reduce((sum, row) => sum + Number(row.total_tokens ?? 0), 0),
|
|
982
1920
|
brl: population.reduce((sum, row) => sum + Number(row.cost_brl ?? 0), 0),
|
|
983
1921
|
});
|
|
984
1922
|
}
|
|
985
|
-
const sharedTaskRows = sameModelFs.viewPage("cost_monitor_models", {
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
1923
|
+
const sharedTaskRows = sameModelFs.viewPage("cost_monitor_models", {
|
|
1924
|
+
from: "2026-08-08",
|
|
1925
|
+
to: "2026-08-08",
|
|
1926
|
+
}).rows;
|
|
1927
|
+
expect(sharedTaskRows).toEqual(
|
|
1928
|
+
expect.arrayContaining([
|
|
1929
|
+
expect.objectContaining({
|
|
1930
|
+
key: "gpt-a",
|
|
1931
|
+
invocation_count: 1,
|
|
1932
|
+
task_count: 1,
|
|
1933
|
+
total_duration: 30_000,
|
|
1934
|
+
total_tokens: 5,
|
|
1935
|
+
total_cost_brl: 2.5,
|
|
1936
|
+
}),
|
|
1937
|
+
expect.objectContaining({
|
|
1938
|
+
key: "claude-b",
|
|
1939
|
+
invocation_count: 1,
|
|
1940
|
+
task_count: 1,
|
|
1941
|
+
total_duration: 30_000,
|
|
1942
|
+
total_tokens: 6,
|
|
1943
|
+
total_cost_brl: 3,
|
|
1944
|
+
}),
|
|
1945
|
+
]),
|
|
1946
|
+
);
|
|
990
1947
|
expect(sharedTaskRows.map((row) => row.key)).not.toContain("mixed");
|
|
991
1948
|
expect(sharedTaskRows.reduce((sum, row) => sum + Number(row.task_count ?? 0), 0)).toBe(2);
|
|
992
|
-
const subrunPopulation = sameModelFs.invocationCostRows({
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
1949
|
+
const subrunPopulation = sameModelFs.invocationCostRows({
|
|
1950
|
+
from: "2026-08-09",
|
|
1951
|
+
to: "2026-08-09",
|
|
1952
|
+
providers: ["openai"],
|
|
1953
|
+
models: ["gpt-a"],
|
|
1954
|
+
});
|
|
1955
|
+
const subrunProviderRows = sameModelFs.viewPage("cost_monitor_providers", {
|
|
1956
|
+
from: "2026-08-09",
|
|
1957
|
+
to: "2026-08-09",
|
|
1958
|
+
provider: "openai",
|
|
1959
|
+
model: "gpt-a",
|
|
1960
|
+
}).rows;
|
|
1961
|
+
const subrunProviderTotals = subrunProviderRows.reduce<{
|
|
1962
|
+
invocations: number;
|
|
1963
|
+
tasks: number;
|
|
1964
|
+
duration: number;
|
|
1965
|
+
tokens: number;
|
|
1966
|
+
brl: number;
|
|
1967
|
+
}>(
|
|
1968
|
+
(total, row) => ({
|
|
1969
|
+
invocations: total.invocations + Number(row.invocation_count ?? 0),
|
|
1970
|
+
tasks: total.tasks + Number(row.task_count ?? 0),
|
|
1971
|
+
duration: total.duration + Number(row.total_duration ?? 0),
|
|
1972
|
+
tokens: total.tokens + Number(row.total_tokens ?? 0),
|
|
1973
|
+
brl: total.brl + Number(row.total_cost_brl ?? 0),
|
|
1974
|
+
}),
|
|
996
1975
|
{ invocations: 0, tasks: 0, duration: 0, tokens: 0, brl: 0 },
|
|
997
1976
|
);
|
|
998
|
-
expect(subrunProviderTotals).toEqual({
|
|
999
|
-
|
|
1977
|
+
expect(subrunProviderTotals).toEqual({
|
|
1978
|
+
invocations: subrunPopulation.length,
|
|
1979
|
+
tasks: new Set(
|
|
1980
|
+
subrunPopulation
|
|
1981
|
+
.map((row) => row.task_id)
|
|
1982
|
+
.filter((id): id is string => typeof id === "string"),
|
|
1983
|
+
).size,
|
|
1984
|
+
duration: subrunPopulation.reduce((sum, row) => sum + Number(row.duration_ms ?? 0), 0),
|
|
1985
|
+
tokens: subrunPopulation.reduce((sum, row) => sum + Number(row.total_tokens ?? 0), 0),
|
|
1986
|
+
brl: subrunPopulation.reduce((sum, row) => sum + Number(row.cost_brl ?? 0), 0),
|
|
1987
|
+
});
|
|
1988
|
+
expect(
|
|
1989
|
+
sameModelFs.viewPage("cost_monitor_providers", {
|
|
1990
|
+
from: "2026-08-09",
|
|
1991
|
+
to: "2026-08-09",
|
|
1992
|
+
provider: "openai",
|
|
1993
|
+
model: "claude-b",
|
|
1994
|
+
}),
|
|
1995
|
+
).toMatchObject({ total_count: 0, rows: [] });
|
|
1000
1996
|
sameModelFs.close();
|
|
1001
1997
|
});
|
|
1002
1998
|
|
|
@@ -1007,7 +2003,7 @@ created_at: 2026-08-10T11:01:00.000Z
|
|
|
1007
2003
|
await mkdir(join(root, ".agents", "config"), { recursive: true });
|
|
1008
2004
|
await writeFile(
|
|
1009
2005
|
join(root, ".agents", "config", "project.yaml"),
|
|
1010
|
-
|
|
2006
|
+
"schema_version: 1\nzaip:\n enabled: true\nproject:\n id: sqlite-test\n name: sqlite-test\n timezone: UTC\nstack:\n id: zaip-aios-stack\n overrides: {}\nclients:\n codex: true\n claude: true\ntracking:\n enabled: true\n currency: BRL\n storage_mode: tracked_sanitized\n",
|
|
1011
2007
|
"utf8",
|
|
1012
2008
|
);
|
|
1013
2009
|
const started = {
|
|
@@ -1216,49 +2212,135 @@ created_at: 2026-08-10T11:01:00.000Z
|
|
|
1216
2212
|
await mkdir(join(root, ".agents", "records", "runs", "2026", "07"), { recursive: true });
|
|
1217
2213
|
await mkdir(join(root, ".agents", "config"), { recursive: true });
|
|
1218
2214
|
await writeFile(join(root, ".agents", "config", "project.yaml"), "zaip:\n enabled: true\n");
|
|
1219
|
-
const run = ({
|
|
1220
|
-
id
|
|
1221
|
-
|
|
2215
|
+
const run = ({
|
|
2216
|
+
id,
|
|
2217
|
+
phase,
|
|
2218
|
+
sourceStartedAt,
|
|
2219
|
+
sourceFinishedAt,
|
|
2220
|
+
parentRunId = null,
|
|
2221
|
+
}: {
|
|
2222
|
+
id: string;
|
|
2223
|
+
phase: "conversation" | "planning" | "execution";
|
|
2224
|
+
sourceStartedAt: string;
|
|
2225
|
+
sourceFinishedAt: string;
|
|
2226
|
+
parentRunId?: string | null;
|
|
1222
2227
|
}) => {
|
|
1223
2228
|
const occurredAt = sourceStartedAt;
|
|
1224
2229
|
const agentInvocationId = `AINV-${id}`;
|
|
1225
2230
|
return [
|
|
1226
2231
|
{
|
|
1227
|
-
schema_version: 2,
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
2232
|
+
schema_version: 2,
|
|
2233
|
+
event_id: `${id}:1`,
|
|
2234
|
+
run_id: id,
|
|
2235
|
+
sequence: 1,
|
|
2236
|
+
occurred_at: occurredAt,
|
|
2237
|
+
type: "run.started",
|
|
2238
|
+
attribution_status: "attributed",
|
|
2239
|
+
phase,
|
|
2240
|
+
run_role: parentRunId === null ? "orchestrator" : "subagent",
|
|
2241
|
+
run_purpose: "orchestration",
|
|
2242
|
+
requires_finalizer: false,
|
|
2243
|
+
execution_kind: "delivery",
|
|
2244
|
+
execution_eligibility: ["delivery"],
|
|
2245
|
+
entrypoint: "task",
|
|
2246
|
+
work_type: "new",
|
|
2247
|
+
storage_mode: "tracked_sanitized",
|
|
2248
|
+
client: "codex",
|
|
2249
|
+
agent: "agent",
|
|
2250
|
+
agent_name: "agent",
|
|
2251
|
+
provider: "openai",
|
|
2252
|
+
model: "gpt-5",
|
|
2253
|
+
reasoning_effort: null,
|
|
2254
|
+
client_thread_id: `thread-${id}`,
|
|
2255
|
+
client_turn_id: `turn-${id}`,
|
|
2256
|
+
conversation_id: `CONV-${id}`,
|
|
2257
|
+
execution_id: `EXEC-${id}`,
|
|
2258
|
+
task_id: `TASK-${id}`,
|
|
2259
|
+
spec_id: null,
|
|
2260
|
+
prd_id: null,
|
|
2261
|
+
change_id: null,
|
|
2262
|
+
parent_run_id: parentRunId,
|
|
2263
|
+
continuation_of_run_id: null,
|
|
2264
|
+
retry_of_run_id: null,
|
|
2265
|
+
agent_invocation_id: agentInvocationId,
|
|
1236
2266
|
root_agent_invocation_id: parentRunId === null ? agentInvocationId : "AINV-root",
|
|
1237
2267
|
parent_agent_invocation_id: parentRunId === null ? null : "AINV-root",
|
|
1238
|
-
invocation_kind: parentRunId === null ? "orchestrator" : "delegated",
|
|
2268
|
+
invocation_kind: parentRunId === null ? "orchestrator" : "delegated",
|
|
2269
|
+
delegation_depth: parentRunId === null ? 0 : 1,
|
|
1239
2270
|
},
|
|
1240
2271
|
{
|
|
1241
|
-
schema_version: 2,
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
2272
|
+
schema_version: 2,
|
|
2273
|
+
event_id: `${id}:2`,
|
|
2274
|
+
run_id: id,
|
|
2275
|
+
sequence: 2,
|
|
2276
|
+
occurred_at: sourceFinishedAt,
|
|
2277
|
+
type: "usage.recorded",
|
|
2278
|
+
phase,
|
|
2279
|
+
activity_kind: "retrospective_local_remeasurement",
|
|
2280
|
+
classification_source: "current_context",
|
|
2281
|
+
tokens: {
|
|
2282
|
+
input: 1,
|
|
2283
|
+
cached_input: 0,
|
|
2284
|
+
output: 1,
|
|
2285
|
+
reasoning: 0,
|
|
2286
|
+
total: 2,
|
|
2287
|
+
source: "provider_reported",
|
|
2288
|
+
},
|
|
2289
|
+
cost: { usd: 1, brl: 5, fx_rate: 5 },
|
|
2290
|
+
provider: "openai",
|
|
2291
|
+
model: "gpt-5",
|
|
2292
|
+
source_segment_key: id,
|
|
2293
|
+
model_call_id: `MCALL-${id}`,
|
|
2294
|
+
runtime: { reasoning_effort: null, service_tier: null },
|
|
2295
|
+
supersedes_event_id: null,
|
|
2296
|
+
retrospective_correction: true,
|
|
2297
|
+
source_occurred_at: sourceFinishedAt,
|
|
2298
|
+
source_started_at: sourceStartedAt,
|
|
2299
|
+
source_finished_at: sourceFinishedAt,
|
|
2300
|
+
duration_ms: null,
|
|
2301
|
+
duration_provenance: null,
|
|
1248
2302
|
},
|
|
1249
2303
|
{
|
|
1250
|
-
schema_version: 2,
|
|
1251
|
-
|
|
1252
|
-
|
|
2304
|
+
schema_version: 2,
|
|
2305
|
+
event_id: `${id}:3`,
|
|
2306
|
+
run_id: id,
|
|
2307
|
+
sequence: 3,
|
|
2308
|
+
occurred_at: new Date(Date.parse(occurredAt) + 60_000).toISOString(),
|
|
2309
|
+
type: "run.finished",
|
|
2310
|
+
phase,
|
|
2311
|
+
status: "completed",
|
|
2312
|
+
duration_ms: 60_000,
|
|
2313
|
+
duration_provenance: "observed",
|
|
1253
2314
|
},
|
|
1254
2315
|
];
|
|
1255
2316
|
};
|
|
1256
2317
|
for (const value of [
|
|
1257
|
-
|
|
1258
|
-
{
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
2318
|
+
// 23:17–01:01 São Paulo: factual duration is split at local midnight.
|
|
2319
|
+
{
|
|
2320
|
+
id: "RUN-planning",
|
|
2321
|
+
phase: "planning" as const,
|
|
2322
|
+
sourceStartedAt: "2026-07-23T02:17:00.000Z",
|
|
2323
|
+
sourceFinishedAt: "2026-07-23T04:01:00.000Z",
|
|
2324
|
+
},
|
|
2325
|
+
{
|
|
2326
|
+
id: "RUN-conversation",
|
|
2327
|
+
phase: "conversation" as const,
|
|
2328
|
+
sourceStartedAt: "2026-07-23T03:00:00.000Z",
|
|
2329
|
+
sourceFinishedAt: "2026-07-23T04:01:00.000Z",
|
|
2330
|
+
},
|
|
2331
|
+
{
|
|
2332
|
+
id: "RUN-execution",
|
|
2333
|
+
phase: "execution" as const,
|
|
2334
|
+
sourceStartedAt: "2026-07-23T03:30:00.000Z",
|
|
2335
|
+
sourceFinishedAt: "2026-07-23T04:30:00.000Z",
|
|
2336
|
+
},
|
|
2337
|
+
{
|
|
2338
|
+
id: "RUN-subrun",
|
|
2339
|
+
phase: "execution" as const,
|
|
2340
|
+
parentRunId: "RUN-execution",
|
|
2341
|
+
sourceStartedAt: "2026-07-23T03:45:00.000Z",
|
|
2342
|
+
sourceFinishedAt: "2026-07-23T04:15:00.000Z",
|
|
2343
|
+
},
|
|
1262
2344
|
]) {
|
|
1263
2345
|
await writeFile(
|
|
1264
2346
|
join(root, ".agents", "records", "runs", "2026", "07", `${value.id}.jsonl`),
|
|
@@ -1310,18 +2392,53 @@ created_at: 2026-08-10T11:01:00.000Z
|
|
|
1310
2392
|
`${[historicalStarted, ...historicalRecords.slice(1)].map((record) => JSON.stringify(record)).join("\n")}\n`,
|
|
1311
2393
|
);
|
|
1312
2394
|
await rebuildSqliteReadModel(root);
|
|
1313
|
-
const database = new DatabaseSync(resolve(root, ".local/dashboard-sqlite/read-model.sqlite"), {
|
|
1314
|
-
|
|
1315
|
-
|
|
2395
|
+
const database = new DatabaseSync(resolve(root, ".local/dashboard-sqlite/read-model.sqlite"), {
|
|
2396
|
+
readOnly: true,
|
|
2397
|
+
});
|
|
2398
|
+
expect(
|
|
2399
|
+
database
|
|
2400
|
+
.prepare(
|
|
2401
|
+
"SELECT duration_ms, source_duration_ms, duration_provenance FROM zaip_aios_activities WHERE run_id='RUN-planning'",
|
|
2402
|
+
)
|
|
2403
|
+
.get(),
|
|
2404
|
+
).toEqual({
|
|
2405
|
+
duration_ms: 4_020_000,
|
|
2406
|
+
source_duration_ms: 6_240_000,
|
|
2407
|
+
duration_provenance: "attributed_token_active",
|
|
2408
|
+
});
|
|
2409
|
+
const daily = database
|
|
2410
|
+
.prepare(
|
|
2411
|
+
"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",
|
|
2412
|
+
)
|
|
2413
|
+
.all();
|
|
1316
2414
|
expect(daily).toEqual([
|
|
1317
|
-
{
|
|
1318
|
-
|
|
2415
|
+
{
|
|
2416
|
+
day: "2026-07-22",
|
|
2417
|
+
total_duration: 2_580_000,
|
|
2418
|
+
invocation_count: 1,
|
|
2419
|
+
cost_monitor_invocation_count: 1,
|
|
2420
|
+
cost_monitor_total_duration: 2_580_000,
|
|
2421
|
+
},
|
|
2422
|
+
{
|
|
2423
|
+
day: "2026-07-23",
|
|
2424
|
+
total_duration: 5_420_000,
|
|
2425
|
+
invocation_count: 4,
|
|
2426
|
+
cost_monitor_invocation_count: 5,
|
|
2427
|
+
cost_monitor_total_duration: 5_420_000,
|
|
2428
|
+
},
|
|
1319
2429
|
]);
|
|
1320
|
-
expect(
|
|
2430
|
+
expect(
|
|
2431
|
+
database
|
|
2432
|
+
.prepare(
|
|
2433
|
+
"SELECT COUNT(*) AS count FROM zaip_vw_daily_aggregates WHERE total_duration > 86400000",
|
|
2434
|
+
)
|
|
2435
|
+
.get(),
|
|
2436
|
+
).toEqual({ count: 0 });
|
|
1321
2437
|
database.close();
|
|
1322
2438
|
const factualFilesystem = new SqliteReadModelFileSystem(root);
|
|
1323
2439
|
expect(
|
|
1324
|
-
factualFilesystem
|
|
2440
|
+
factualFilesystem
|
|
2441
|
+
.costMonitorFinancialActivityRows({ from: "2026-07-23", to: "2026-07-23" })
|
|
1325
2442
|
.some((row) => row.run_id === "RUN-historical-financial"),
|
|
1326
2443
|
).toBe(true);
|
|
1327
2444
|
const compactFinancialRow = factualFilesystem.costMonitorFinancialActivityRows({
|
|
@@ -1331,41 +2448,59 @@ created_at: 2026-08-10T11:01:00.000Z
|
|
|
1331
2448
|
expect(compactFinancialRow).not.toHaveProperty("payload_json");
|
|
1332
2449
|
expect(compactFinancialRow).toHaveProperty("total_tokens");
|
|
1333
2450
|
expect(
|
|
1334
|
-
factualFilesystem
|
|
2451
|
+
factualFilesystem
|
|
2452
|
+
.costMonitorFinancialActivityRows({ from: "2026-07-24", to: "2026-07-24" })
|
|
1335
2453
|
.some((row) => row.run_id === "RUN-historical-financial"),
|
|
1336
2454
|
).toBe(false);
|
|
1337
2455
|
expect(
|
|
1338
|
-
factualFilesystem
|
|
1339
|
-
|
|
1340
|
-
|
|
2456
|
+
factualFilesystem
|
|
2457
|
+
.viewPage("operations_agent_invocations", {
|
|
2458
|
+
from: "2026-07-23",
|
|
2459
|
+
to: "2026-07-23",
|
|
2460
|
+
limit: 20,
|
|
2461
|
+
})
|
|
2462
|
+
.rows.some((row) => row.run_id === "RUN-source-alias"),
|
|
1341
2463
|
).toBe(true);
|
|
1342
2464
|
expect(
|
|
1343
|
-
factualFilesystem
|
|
1344
|
-
|
|
1345
|
-
|
|
2465
|
+
factualFilesystem
|
|
2466
|
+
.viewPage("operations_agent_invocations", {
|
|
2467
|
+
from: "2026-07-22",
|
|
2468
|
+
to: "2026-07-22",
|
|
2469
|
+
limit: 20,
|
|
2470
|
+
})
|
|
2471
|
+
.rows.some((row) => row.run_id === "RUN-source-alias"),
|
|
1346
2472
|
).toBe(false);
|
|
1347
2473
|
// Filter dimensions stay in the SQL population: they must retain the
|
|
1348
2474
|
// source-session day and never require an activity-by-activity lookup.
|
|
1349
2475
|
expect(
|
|
1350
|
-
factualFilesystem
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
|
|
2476
|
+
factualFilesystem
|
|
2477
|
+
.costMonitorFinancialActivityRows({
|
|
2478
|
+
from: "2026-07-23",
|
|
2479
|
+
to: "2026-07-23",
|
|
2480
|
+
phases: ["conversation"],
|
|
2481
|
+
providers: ["openai"],
|
|
2482
|
+
models: ["gpt-5"],
|
|
2483
|
+
})
|
|
2484
|
+
.map((row) => row.run_id),
|
|
1357
2485
|
).toContain("RUN-historical-financial");
|
|
1358
2486
|
expect(
|
|
1359
|
-
factualFilesystem
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
2487
|
+
factualFilesystem
|
|
2488
|
+
.costMonitorFinancialActivityRows({
|
|
2489
|
+
from: "2026-07-22",
|
|
2490
|
+
to: "2026-07-22",
|
|
2491
|
+
phases: ["planning"],
|
|
2492
|
+
})
|
|
2493
|
+
.map((row) => row.run_id),
|
|
1364
2494
|
).toEqual(["RUN-planning"]);
|
|
1365
|
-
for (const view of [
|
|
2495
|
+
for (const view of [
|
|
2496
|
+
"cost_monitor_daily",
|
|
2497
|
+
"cost_monitor_monthly",
|
|
2498
|
+
"cost_monitor_annual",
|
|
2499
|
+
] as const) {
|
|
1366
2500
|
expect(
|
|
1367
|
-
factualFilesystem
|
|
1368
|
-
.
|
|
2501
|
+
factualFilesystem
|
|
2502
|
+
.viewPage(view, { from: "2026-07-23", to: "2026-07-23", limit: 20, offset: 0 })
|
|
2503
|
+
.rows.some((row) => Number(row.total_tokens) === 10),
|
|
1369
2504
|
).toBe(true);
|
|
1370
2505
|
// The API boundary supplies inclusive Sao Paulo days as ISO instants.
|
|
1371
2506
|
// Do not truncate the UTC end instant into the following calendar day.
|
|
@@ -1376,20 +2511,40 @@ created_at: 2026-08-10T11:01:00.000Z
|
|
|
1376
2511
|
offset: 0,
|
|
1377
2512
|
}).rows;
|
|
1378
2513
|
expect(bounded.some((row) => Number(row.total_tokens) === 10)).toBe(true);
|
|
1379
|
-
expect(
|
|
2514
|
+
expect(
|
|
2515
|
+
bounded.some(
|
|
2516
|
+
(row) =>
|
|
2517
|
+
String(row.period_key).startsWith("2026-07-24") && Number(row.total_tokens) === 10,
|
|
2518
|
+
),
|
|
2519
|
+
).toBe(false);
|
|
1380
2520
|
// A structural day or other source financial fact may still exist on
|
|
1381
2521
|
// the 24th, but this fixture's source-day-23 aggregate must not leak.
|
|
1382
2522
|
expect(
|
|
1383
|
-
factualFilesystem
|
|
1384
|
-
.
|
|
2523
|
+
factualFilesystem
|
|
2524
|
+
.viewPage(view, { from: "2026-07-24", to: "2026-07-24", limit: 20, offset: 0 })
|
|
2525
|
+
.rows.every((row) => row.total_tokens !== 10),
|
|
1385
2526
|
).toBe(true);
|
|
1386
2527
|
}
|
|
1387
|
-
const allFinancialRows = factualFilesystem.costMonitorFinancialActivityRows({
|
|
1388
|
-
|
|
2528
|
+
const allFinancialRows = factualFilesystem.costMonitorFinancialActivityRows({
|
|
2529
|
+
from: null,
|
|
2530
|
+
to: null,
|
|
2531
|
+
});
|
|
2532
|
+
const factual = factualFilesystem.costMonitorFactualDurationByDay(
|
|
2533
|
+
{ from: null, to: null },
|
|
2534
|
+
allFinancialRows,
|
|
2535
|
+
);
|
|
1389
2536
|
// The cross-midnight session is split at São Paulo midnight and each day
|
|
1390
2537
|
// is the union of complete source intervals, never above one local day.
|
|
1391
|
-
expect(factual.get("2026-07-22")).toEqual({
|
|
1392
|
-
|
|
2538
|
+
expect(factual.get("2026-07-22")).toEqual({
|
|
2539
|
+
known_sum: 2_580_000,
|
|
2540
|
+
eligible_runs: 1,
|
|
2541
|
+
known_runs: 1,
|
|
2542
|
+
});
|
|
2543
|
+
expect(factual.get("2026-07-23")).toEqual({
|
|
2544
|
+
known_sum: 5_420_000,
|
|
2545
|
+
eligible_runs: 6,
|
|
2546
|
+
known_runs: 6,
|
|
2547
|
+
});
|
|
1393
2548
|
factualFilesystem.close();
|
|
1394
2549
|
});
|
|
1395
2550
|
|
|
@@ -1398,42 +2553,231 @@ created_at: 2026-08-10T11:01:00.000Z
|
|
|
1398
2553
|
roots.push(root);
|
|
1399
2554
|
for (const kind of ["tasks", "specs", "prds"])
|
|
1400
2555
|
await mkdir(join(root, ".agents", "records", kind, "2026", "08"), { recursive: true });
|
|
1401
|
-
await mkdir(join(root, ".agents", "records", "changes", "2026", "08", "CHG-UNIQUE"), {
|
|
1402
|
-
|
|
1403
|
-
|
|
1404
|
-
await mkdir(join(root, ".agents", "records", "changes", "2026", "08", "CHG-
|
|
1405
|
-
|
|
2556
|
+
await mkdir(join(root, ".agents", "records", "changes", "2026", "08", "CHG-UNIQUE"), {
|
|
2557
|
+
recursive: true,
|
|
2558
|
+
});
|
|
2559
|
+
await mkdir(join(root, ".agents", "records", "changes", "2026", "08", "CHG-SHARED-A"), {
|
|
2560
|
+
recursive: true,
|
|
2561
|
+
});
|
|
2562
|
+
await mkdir(join(root, ".agents", "records", "changes", "2026", "08", "CHG-SHARED-B"), {
|
|
2563
|
+
recursive: true,
|
|
2564
|
+
});
|
|
2565
|
+
await mkdir(join(root, ".agents", "records", "changes", "2026", "08", "CHG-PRD-ONLY"), {
|
|
2566
|
+
recursive: true,
|
|
2567
|
+
});
|
|
2568
|
+
await mkdir(join(root, ".agents", "records", "changes", "2026", "08", "CHG-NO-MACRO"), {
|
|
2569
|
+
recursive: true,
|
|
2570
|
+
});
|
|
1406
2571
|
await mkdir(join(root, ".agents", "records", "runs", "2026", "08"), { recursive: true });
|
|
1407
2572
|
await mkdir(join(root, ".agents", "config"), { recursive: true });
|
|
1408
|
-
await writeFile(
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
|
|
2573
|
+
await writeFile(
|
|
2574
|
+
join(root, ".agents", "config", "project.yaml"),
|
|
2575
|
+
"zaip:\n enabled: true\n",
|
|
2576
|
+
"utf8",
|
|
2577
|
+
);
|
|
2578
|
+
const item = (id: string, status = "planned") =>
|
|
2579
|
+
`---\nid: ${id}\ntitle: ${id}\nstatus: ${status}\nrisk: standard\ncreated_at: 2026-08-12T12:00:00.000Z\n---\n# ${id}\n`;
|
|
2580
|
+
for (const id of [
|
|
2581
|
+
"TASK-UNIQUE",
|
|
2582
|
+
"TASK-SHARED-A",
|
|
2583
|
+
"TASK-SHARED-B",
|
|
2584
|
+
"TASK-PRD-ONLY",
|
|
2585
|
+
"TASK-NO-MACRO",
|
|
2586
|
+
])
|
|
2587
|
+
await writeFile(
|
|
2588
|
+
join(root, ".agents", "records", "tasks", "2026", "08", `${id}.md`),
|
|
2589
|
+
item(id),
|
|
2590
|
+
"utf8",
|
|
2591
|
+
);
|
|
1412
2592
|
for (const id of ["SPEC-UNIQUE", "SPEC-SHARED"])
|
|
1413
|
-
await writeFile(
|
|
2593
|
+
await writeFile(
|
|
2594
|
+
join(root, ".agents", "records", "specs", "2026", "08", `${id}.md`),
|
|
2595
|
+
item(id, "active"),
|
|
2596
|
+
"utf8",
|
|
2597
|
+
);
|
|
1414
2598
|
for (const id of ["PRD-UNIQUE", "PRD-SHARED", "PRD-ONLY"])
|
|
1415
|
-
await writeFile(
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
|
|
1421
|
-
|
|
1422
|
-
|
|
1423
|
-
|
|
1424
|
-
|
|
1425
|
-
|
|
2599
|
+
await writeFile(
|
|
2600
|
+
join(root, ".agents", "records", "prds", "2026", "08", `${id}.md`),
|
|
2601
|
+
item(id, "active"),
|
|
2602
|
+
"utf8",
|
|
2603
|
+
);
|
|
2604
|
+
const change = (id: string, taskId: string, specId: string | null, prdId: string | null) =>
|
|
2605
|
+
`---\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`;
|
|
2606
|
+
await writeFile(
|
|
2607
|
+
join(root, ".agents", "records", "changes", "2026", "08", "CHG-UNIQUE", "change.md"),
|
|
2608
|
+
change("CHG-UNIQUE", "TASK-UNIQUE", "SPEC-UNIQUE", "PRD-UNIQUE"),
|
|
2609
|
+
"utf8",
|
|
2610
|
+
);
|
|
2611
|
+
await writeFile(
|
|
2612
|
+
join(root, ".agents", "records", "changes", "2026", "08", "CHG-SHARED-A", "change.md"),
|
|
2613
|
+
change("CHG-SHARED-A", "TASK-SHARED-A", "SPEC-SHARED", "PRD-SHARED"),
|
|
2614
|
+
"utf8",
|
|
2615
|
+
);
|
|
2616
|
+
await writeFile(
|
|
2617
|
+
join(root, ".agents", "records", "changes", "2026", "08", "CHG-SHARED-B", "change.md"),
|
|
2618
|
+
change("CHG-SHARED-B", "TASK-SHARED-B", "SPEC-SHARED", "PRD-SHARED"),
|
|
2619
|
+
"utf8",
|
|
2620
|
+
);
|
|
2621
|
+
await writeFile(
|
|
2622
|
+
join(root, ".agents", "records", "changes", "2026", "08", "CHG-PRD-ONLY", "change.md"),
|
|
2623
|
+
change("CHG-PRD-ONLY", "TASK-PRD-ONLY", null, "PRD-ONLY"),
|
|
2624
|
+
"utf8",
|
|
2625
|
+
);
|
|
2626
|
+
await writeFile(
|
|
2627
|
+
join(root, ".agents", "records", "changes", "2026", "08", "CHG-NO-MACRO", "change.md"),
|
|
2628
|
+
change("CHG-NO-MACRO", "TASK-NO-MACRO", null, null),
|
|
2629
|
+
"utf8",
|
|
2630
|
+
);
|
|
2631
|
+
const run = (
|
|
2632
|
+
id: string,
|
|
2633
|
+
specId: string | null,
|
|
2634
|
+
prdId: string | null,
|
|
2635
|
+
tokens: number,
|
|
2636
|
+
cost: number,
|
|
2637
|
+
duration: number,
|
|
2638
|
+
) => [
|
|
2639
|
+
{
|
|
2640
|
+
schema_version: 2,
|
|
2641
|
+
event_id: `${id}:1`,
|
|
2642
|
+
run_id: id,
|
|
2643
|
+
sequence: 1,
|
|
2644
|
+
occurred_at: "2026-08-12T12:00:00.000Z",
|
|
2645
|
+
type: "run.started",
|
|
2646
|
+
attribution_status: "attributed",
|
|
2647
|
+
phase: "planning",
|
|
2648
|
+
run_role: "orchestrator",
|
|
2649
|
+
run_purpose: "orchestration",
|
|
2650
|
+
requires_finalizer: false,
|
|
2651
|
+
execution_kind: "interaction",
|
|
2652
|
+
execution_eligibility: [],
|
|
2653
|
+
entrypoint: specId === null ? (prdId === null ? "conversation" : "prd") : "spec",
|
|
2654
|
+
work_type: "new",
|
|
2655
|
+
storage_mode: "tracked_sanitized",
|
|
2656
|
+
client: "codex",
|
|
2657
|
+
agent: "agent",
|
|
2658
|
+
agent_name: "agent",
|
|
2659
|
+
provider: "openai",
|
|
2660
|
+
model: "gpt-5",
|
|
2661
|
+
reasoning_effort: null,
|
|
2662
|
+
client_thread_id: id,
|
|
2663
|
+
client_turn_id: id,
|
|
2664
|
+
conversation_id: `CONV-${id}`,
|
|
2665
|
+
execution_id: null,
|
|
2666
|
+
task_id: null,
|
|
2667
|
+
spec_id: specId,
|
|
2668
|
+
prd_id: prdId,
|
|
2669
|
+
change_id: null,
|
|
2670
|
+
parent_run_id: null,
|
|
2671
|
+
continuation_of_run_id: null,
|
|
2672
|
+
retry_of_run_id: null,
|
|
2673
|
+
agent_invocation_id: `AINV-${id}`,
|
|
2674
|
+
root_agent_invocation_id: `AINV-${id}`,
|
|
2675
|
+
parent_agent_invocation_id: null,
|
|
2676
|
+
invocation_kind: "orchestrator",
|
|
2677
|
+
delegation_depth: 0,
|
|
2678
|
+
},
|
|
2679
|
+
{
|
|
2680
|
+
schema_version: 2,
|
|
2681
|
+
event_id: `${id}:2`,
|
|
2682
|
+
run_id: id,
|
|
2683
|
+
sequence: 2,
|
|
2684
|
+
occurred_at: "2026-08-12T12:01:00.000Z",
|
|
2685
|
+
type: "usage.recorded",
|
|
2686
|
+
phase: "planning",
|
|
2687
|
+
activity_kind: "model_usage",
|
|
2688
|
+
classification_source: "explicit",
|
|
2689
|
+
tokens: {
|
|
2690
|
+
input: tokens,
|
|
2691
|
+
cached_input: 0,
|
|
2692
|
+
output: 0,
|
|
2693
|
+
reasoning: 0,
|
|
2694
|
+
total: tokens,
|
|
2695
|
+
source: "provider_reported",
|
|
2696
|
+
},
|
|
2697
|
+
cost: { usd: cost / 5, brl: cost, fx_rate: 5 },
|
|
2698
|
+
provider: "openai",
|
|
2699
|
+
model: "gpt-5",
|
|
2700
|
+
source_segment_key: id,
|
|
2701
|
+
model_call_id: `MCALL-${id}`,
|
|
2702
|
+
runtime: { reasoning_effort: null, service_tier: null },
|
|
2703
|
+
supersedes_event_id: null,
|
|
2704
|
+
duration_ms: null,
|
|
2705
|
+
duration_provenance: null,
|
|
2706
|
+
},
|
|
2707
|
+
{
|
|
2708
|
+
schema_version: 2,
|
|
2709
|
+
event_id: `${id}:3`,
|
|
2710
|
+
run_id: id,
|
|
2711
|
+
sequence: 3,
|
|
2712
|
+
occurred_at: "2026-08-12T12:02:00.000Z",
|
|
2713
|
+
type: "run.finished",
|
|
2714
|
+
phase: "planning",
|
|
2715
|
+
status: "completed",
|
|
2716
|
+
duration_ms: duration,
|
|
2717
|
+
duration_provenance: "observed",
|
|
2718
|
+
},
|
|
1426
2719
|
];
|
|
1427
|
-
for (const [id, specId, prdId, tokens, cost, duration] of [
|
|
1428
|
-
|
|
2720
|
+
for (const [id, specId, prdId, tokens, cost, duration] of [
|
|
2721
|
+
["RUN-UNIQUE", "SPEC-UNIQUE", "PRD-UNIQUE", 7, 3, 120_000],
|
|
2722
|
+
["RUN-SHARED", "SPEC-SHARED", "PRD-SHARED", 11, 5, 60_000],
|
|
2723
|
+
["RUN-PRD-ONLY", null, "PRD-ONLY", 13, 6, 90_000],
|
|
2724
|
+
["RUN-NO-MACRO", null, null, 17, 8, 30_000],
|
|
2725
|
+
] as const)
|
|
2726
|
+
await writeFile(
|
|
2727
|
+
join(root, ".agents", "records", "runs", "2026", "08", `${id}.jsonl`),
|
|
2728
|
+
`${run(id, specId, prdId, tokens, cost, duration)
|
|
2729
|
+
.map((record) => JSON.stringify(record))
|
|
2730
|
+
.join("\n")}\n`,
|
|
2731
|
+
"utf8",
|
|
2732
|
+
);
|
|
1429
2733
|
await rebuildSqliteReadModel(root);
|
|
1430
2734
|
const filesystem = new SqliteReadModelFileSystem(root);
|
|
1431
2735
|
const tasks = filesystem.summaryPage("task", { from: null, to: null }, 0, 10).rows;
|
|
1432
|
-
expect(tasks).toContainEqual(
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
|
|
1436
|
-
|
|
2736
|
+
expect(tasks).toContainEqual(
|
|
2737
|
+
expect.objectContaining({
|
|
2738
|
+
id: "TASK-UNIQUE",
|
|
2739
|
+
invocation_count: 1,
|
|
2740
|
+
total_duration: 62_500,
|
|
2741
|
+
total_tokens: 7,
|
|
2742
|
+
total_cost_brl: 3,
|
|
2743
|
+
}),
|
|
2744
|
+
);
|
|
2745
|
+
expect(tasks).toContainEqual(
|
|
2746
|
+
expect.objectContaining({
|
|
2747
|
+
id: "TASK-SHARED-A",
|
|
2748
|
+
invocation_count: null,
|
|
2749
|
+
total_duration: null,
|
|
2750
|
+
total_tokens: null,
|
|
2751
|
+
total_cost_brl: null,
|
|
2752
|
+
}),
|
|
2753
|
+
);
|
|
2754
|
+
expect(tasks).toContainEqual(
|
|
2755
|
+
expect.objectContaining({
|
|
2756
|
+
id: "TASK-SHARED-B",
|
|
2757
|
+
invocation_count: null,
|
|
2758
|
+
total_duration: null,
|
|
2759
|
+
total_tokens: null,
|
|
2760
|
+
total_cost_brl: null,
|
|
2761
|
+
}),
|
|
2762
|
+
);
|
|
2763
|
+
expect(tasks).toContainEqual(
|
|
2764
|
+
expect.objectContaining({
|
|
2765
|
+
id: "TASK-PRD-ONLY",
|
|
2766
|
+
invocation_count: 1,
|
|
2767
|
+
total_duration: 32_500,
|
|
2768
|
+
total_tokens: 13,
|
|
2769
|
+
total_cost_brl: 6,
|
|
2770
|
+
}),
|
|
2771
|
+
);
|
|
2772
|
+
expect(tasks).toContainEqual(
|
|
2773
|
+
expect.objectContaining({
|
|
2774
|
+
id: "TASK-NO-MACRO",
|
|
2775
|
+
invocation_count: null,
|
|
2776
|
+
total_duration: null,
|
|
2777
|
+
total_tokens: null,
|
|
2778
|
+
total_cost_brl: null,
|
|
2779
|
+
}),
|
|
2780
|
+
);
|
|
1437
2781
|
filesystem.close();
|
|
1438
2782
|
});
|
|
1439
2783
|
|
|
@@ -1448,18 +2792,28 @@ created_at: 2026-08-10T11:01:00.000Z
|
|
|
1448
2792
|
{ recursive: true },
|
|
1449
2793
|
);
|
|
1450
2794
|
await mkdir(
|
|
1451
|
-
join(
|
|
2795
|
+
join(
|
|
2796
|
+
root,
|
|
2797
|
+
".agents",
|
|
2798
|
+
"records",
|
|
2799
|
+
"changes",
|
|
2800
|
+
"2026",
|
|
2801
|
+
"08",
|
|
2802
|
+
"CHG-ART",
|
|
2803
|
+
"artifacts",
|
|
2804
|
+
"validations",
|
|
2805
|
+
),
|
|
1452
2806
|
{ recursive: true },
|
|
1453
2807
|
);
|
|
1454
2808
|
await mkdir(join(root, ".agents", "config"), { recursive: true });
|
|
1455
2809
|
await writeFile(
|
|
1456
2810
|
join(root, ".agents", "config", "project.yaml"),
|
|
1457
|
-
|
|
2811
|
+
"schema_version: 1\nzaip:\n enabled: true\nproject:\n id: sqlite-test\n name: sqlite-test\n timezone: UTC\nstack:\n id: zaip-aios-stack\n overrides: {}\nclients:\n codex: true\n claude: true\ntracking:\n enabled: true\n currency: BRL\n storage_mode: tracked_sanitized\n",
|
|
1458
2812
|
"utf8",
|
|
1459
2813
|
);
|
|
1460
2814
|
await writeFile(
|
|
1461
2815
|
join(root, ".agents", "config", "framework.lock.yaml"),
|
|
1462
|
-
"lock_version: 1\nframework:\n version: 1.0
|
|
2816
|
+
"lock_version: 1\nframework:\n version: 1.3.0\n distribution_sha256: null\nlayout:\n version: 3\nresolved_profile:\n id: null\n sha256: null\nmanaged_files: {}\n",
|
|
1463
2817
|
"utf8",
|
|
1464
2818
|
);
|
|
1465
2819
|
const run = (
|
|
@@ -1553,9 +2907,18 @@ created_at: 2026-08-10T11:01:00.000Z
|
|
|
1553
2907
|
},
|
|
1554
2908
|
];
|
|
1555
2909
|
for (const [id, records] of [
|
|
1556
|
-
[
|
|
1557
|
-
|
|
1558
|
-
|
|
2910
|
+
[
|
|
2911
|
+
"RUN-R1",
|
|
2912
|
+
run("RUN-R1", "2026-08-01", "TASK-A", 600_000, "12:00:00.000Z", "SPEC-A", "PRD-A"),
|
|
2913
|
+
],
|
|
2914
|
+
[
|
|
2915
|
+
"RUN-R2",
|
|
2916
|
+
run("RUN-R2", "2026-08-02", "TASK-B", 1_200_000, "12:00:00.000Z", "SPEC-B", "PRD-A"),
|
|
2917
|
+
],
|
|
2918
|
+
[
|
|
2919
|
+
"RUN-R3",
|
|
2920
|
+
run("RUN-R3", "2026-08-02", "TASK-B", 1_200_000, "12:10:00.000Z", "SPEC-B", "PRD-A"),
|
|
2921
|
+
],
|
|
1559
2922
|
] as const) {
|
|
1560
2923
|
await writeFile(
|
|
1561
2924
|
join(root, ".agents", "records", "runs", "2026", "08", `${id}.jsonl`),
|
|
@@ -1564,16 +2927,42 @@ created_at: 2026-08-10T11:01:00.000Z
|
|
|
1564
2927
|
);
|
|
1565
2928
|
}
|
|
1566
2929
|
await writeFile(
|
|
1567
|
-
join(
|
|
2930
|
+
join(
|
|
2931
|
+
root,
|
|
2932
|
+
".agents",
|
|
2933
|
+
"records",
|
|
2934
|
+
"changes",
|
|
2935
|
+
"2026",
|
|
2936
|
+
"08",
|
|
2937
|
+
"CHG-ART",
|
|
2938
|
+
"artifacts",
|
|
2939
|
+
"evidence",
|
|
2940
|
+
"EVD-1.md",
|
|
2941
|
+
),
|
|
1568
2942
|
"---\nid: EVD-1\nobserved_at: 2026-08-01T12:00:00.000Z\n---\n# Evidence\n",
|
|
1569
2943
|
"utf8",
|
|
1570
2944
|
);
|
|
1571
2945
|
await writeFile(
|
|
1572
|
-
join(
|
|
2946
|
+
join(
|
|
2947
|
+
root,
|
|
2948
|
+
".agents",
|
|
2949
|
+
"records",
|
|
2950
|
+
"changes",
|
|
2951
|
+
"2026",
|
|
2952
|
+
"08",
|
|
2953
|
+
"CHG-ART",
|
|
2954
|
+
"artifacts",
|
|
2955
|
+
"validations",
|
|
2956
|
+
"VAL-1.md",
|
|
2957
|
+
),
|
|
1573
2958
|
"---\nid: VAL-1\nexecuted_at: 2026-08-02T12:00:00.000Z\n---\n# Validation\n",
|
|
1574
2959
|
"utf8",
|
|
1575
2960
|
);
|
|
1576
|
-
for (const [kind, id] of [
|
|
2961
|
+
for (const [kind, id] of [
|
|
2962
|
+
["tasks", "TASK-NO-RUN"],
|
|
2963
|
+
["specs", "SPEC-NO-RUN"],
|
|
2964
|
+
["prds", "PRD-NO-RUN"],
|
|
2965
|
+
] as const)
|
|
1577
2966
|
await writeFile(
|
|
1578
2967
|
join(root, ".agents", "records", kind, "2026", "08", `${id}.md`),
|
|
1579
2968
|
`---\nid: ${id}\ntitle: ${id}\nstatus: draft\ncreated_at: 2026-08-03T12:00:00.000Z\n---\n# ${id}\n`,
|
|
@@ -1710,7 +3099,11 @@ created_at: 2026-08-10T11:01:00.000Z
|
|
|
1710
3099
|
{ headers: { "x-zaip-session": "test-session" } },
|
|
1711
3100
|
);
|
|
1712
3101
|
const nextMonth = (await nextMonthQuick.json()) as {
|
|
1713
|
-
summary: {
|
|
3102
|
+
summary: {
|
|
3103
|
+
run_count: number;
|
|
3104
|
+
task_count: number;
|
|
3105
|
+
overview_metrics: { tokens: number | null; duration_ms: number | null };
|
|
3106
|
+
};
|
|
1714
3107
|
};
|
|
1715
3108
|
expect(nextMonth.summary).toMatchObject({
|
|
1716
3109
|
run_count: 0,
|
|
@@ -1808,9 +3201,21 @@ created_at: 2026-08-10T11:01:00.000Z
|
|
|
1808
3201
|
]);
|
|
1809
3202
|
}
|
|
1810
3203
|
for (const [view, key, counts] of [
|
|
1811
|
-
[
|
|
1812
|
-
|
|
1813
|
-
|
|
3204
|
+
[
|
|
3205
|
+
"cost_monitor_daily",
|
|
3206
|
+
"2026-08-02",
|
|
3207
|
+
{ prd_count: 0, spec_count: 1, task_count: 1, validation_count: 1, evidence_count: 0 },
|
|
3208
|
+
],
|
|
3209
|
+
[
|
|
3210
|
+
"cost_monitor_monthly",
|
|
3211
|
+
"2026-08",
|
|
3212
|
+
{ prd_count: 2, spec_count: 3, task_count: 3, validation_count: 1, evidence_count: 1 },
|
|
3213
|
+
],
|
|
3214
|
+
[
|
|
3215
|
+
"cost_monitor_annual",
|
|
3216
|
+
"2026",
|
|
3217
|
+
{ prd_count: 2, spec_count: 3, task_count: 3, validation_count: 1, evidence_count: 1 },
|
|
3218
|
+
],
|
|
1814
3219
|
] as const) {
|
|
1815
3220
|
expect(filesystem.viewPage(view, { limit: 50 }).rows).toContainEqual(
|
|
1816
3221
|
expect.objectContaining({ key, ...counts }),
|
|
@@ -1828,7 +3233,10 @@ created_at: 2026-08-10T11:01:00.000Z
|
|
|
1828
3233
|
const annualCostPage = filesystem.viewPage("cost_monitor_annual", { limit: 50 });
|
|
1829
3234
|
const dailyCostRows = filesystem.viewPage("cost_monitor_daily", { limit: 50 }).rows;
|
|
1830
3235
|
const pagedDailyCostPage = filesystem.viewPage("cost_monitor_daily", { limit: 1 });
|
|
1831
|
-
expect(pagedDailyCostPage).toMatchObject({
|
|
3236
|
+
expect(pagedDailyCostPage).toMatchObject({
|
|
3237
|
+
total_count: dailyCostRows.length,
|
|
3238
|
+
rows: [expect.any(Object)],
|
|
3239
|
+
});
|
|
1832
3240
|
expect(pagedDailyCostPage.totals).toMatchObject({
|
|
1833
3241
|
total_tokens: dailyCostRows.reduce((sum, row) => sum + Number(row.total_tokens ?? 0), 0),
|
|
1834
3242
|
total_cost_brl: dailyCostRows.reduce((sum, row) => sum + Number(row.total_cost_brl ?? 0), 0),
|
|
@@ -1841,9 +3249,17 @@ created_at: 2026-08-10T11:01:00.000Z
|
|
|
1841
3249
|
const annualCostRow = annualCostPage.rows[0];
|
|
1842
3250
|
if (annualCostRow === undefined) throw new Error("Expected the consolidated 2026 Cost row");
|
|
1843
3251
|
for (const metric of [
|
|
1844
|
-
"prd_count",
|
|
1845
|
-
"
|
|
1846
|
-
"
|
|
3252
|
+
"prd_count",
|
|
3253
|
+
"spec_count",
|
|
3254
|
+
"task_count",
|
|
3255
|
+
"validation_count",
|
|
3256
|
+
"evidence_count",
|
|
3257
|
+
"total_run_count",
|
|
3258
|
+
"total_duration",
|
|
3259
|
+
"duration_known",
|
|
3260
|
+
"total_tokens",
|
|
3261
|
+
"total_cost_usd",
|
|
3262
|
+
"total_cost_brl",
|
|
1847
3263
|
] as const) {
|
|
1848
3264
|
const observed = dailyCostRows
|
|
1849
3265
|
.map((row) => row[metric])
|
|
@@ -1883,7 +3299,14 @@ created_at: 2026-08-10T11:01:00.000Z
|
|
|
1883
3299
|
total_cost_brl: 15,
|
|
1884
3300
|
});
|
|
1885
3301
|
}
|
|
1886
|
-
expect(
|
|
3302
|
+
expect(
|
|
3303
|
+
filesystem.viewPage("cost_monitor_tasks", {
|
|
3304
|
+
from: "2026-08-02",
|
|
3305
|
+
to: "2026-08-02",
|
|
3306
|
+
query: "TASK-B",
|
|
3307
|
+
limit: 1,
|
|
3308
|
+
}).totals,
|
|
3309
|
+
).toEqual({
|
|
1887
3310
|
entity_count: 1,
|
|
1888
3311
|
invocation_count: 2,
|
|
1889
3312
|
total_duration: 1_800_000,
|
|
@@ -1894,24 +3317,75 @@ created_at: 2026-08-10T11:01:00.000Z
|
|
|
1894
3317
|
// The compact Cost Monitor tables share the canonical macro population
|
|
1895
3318
|
// with their big numbers. A macro with no direct invocation must remain
|
|
1896
3319
|
// paginable and retain unavailable financial facts as null.
|
|
1897
|
-
expect(
|
|
3320
|
+
expect(
|
|
3321
|
+
filesystem.viewPage("cost_monitor_specs", { query: "SPEC-NO-RUN", limit: 1 }),
|
|
3322
|
+
).toMatchObject({
|
|
1898
3323
|
total_count: 1,
|
|
1899
|
-
totals: {
|
|
1900
|
-
|
|
3324
|
+
totals: {
|
|
3325
|
+
entity_count: 1,
|
|
3326
|
+
invocation_count: 0,
|
|
3327
|
+
total_duration: null,
|
|
3328
|
+
total_tokens: null,
|
|
3329
|
+
total_cost_brl: null,
|
|
3330
|
+
},
|
|
3331
|
+
rows: [
|
|
3332
|
+
expect.objectContaining({
|
|
3333
|
+
id: "SPEC-NO-RUN",
|
|
3334
|
+
title: "SPEC-NO-RUN",
|
|
3335
|
+
invocation_count: 0,
|
|
3336
|
+
total_duration: null,
|
|
3337
|
+
total_tokens: null,
|
|
3338
|
+
total_cost_brl: null,
|
|
3339
|
+
}),
|
|
3340
|
+
],
|
|
1901
3341
|
});
|
|
1902
|
-
expect(
|
|
3342
|
+
expect(
|
|
3343
|
+
filesystem.viewPage("cost_monitor_prds", { query: "PRD-NO-RUN", limit: 1 }),
|
|
3344
|
+
).toMatchObject({
|
|
1903
3345
|
total_count: 1,
|
|
1904
|
-
totals: {
|
|
1905
|
-
|
|
3346
|
+
totals: {
|
|
3347
|
+
entity_count: 1,
|
|
3348
|
+
invocation_count: 0,
|
|
3349
|
+
total_duration: null,
|
|
3350
|
+
total_tokens: null,
|
|
3351
|
+
total_cost_brl: null,
|
|
3352
|
+
},
|
|
3353
|
+
rows: [
|
|
3354
|
+
expect.objectContaining({
|
|
3355
|
+
id: "PRD-NO-RUN",
|
|
3356
|
+
title: "PRD-NO-RUN",
|
|
3357
|
+
invocation_count: 0,
|
|
3358
|
+
total_duration: null,
|
|
3359
|
+
total_tokens: null,
|
|
3360
|
+
total_cost_brl: null,
|
|
3361
|
+
}),
|
|
3362
|
+
],
|
|
1906
3363
|
});
|
|
1907
|
-
for (const view of [
|
|
1908
|
-
|
|
3364
|
+
for (const view of [
|
|
3365
|
+
"cost_monitor_tasks",
|
|
3366
|
+
"cost_monitor_specs",
|
|
3367
|
+
"cost_monitor_prds",
|
|
3368
|
+
"cost_monitor_conversations",
|
|
3369
|
+
] as const) {
|
|
3370
|
+
const filtered = filesystem.viewPage(view, {
|
|
3371
|
+
phase: "execution",
|
|
3372
|
+
provider: "openai",
|
|
3373
|
+
model: "gpt-5",
|
|
3374
|
+
limit: 1,
|
|
3375
|
+
});
|
|
1909
3376
|
// Dimensional membership and the subtotal share one pre-pagination
|
|
1910
3377
|
// invocation population for every compact lifecycle view.
|
|
1911
3378
|
expect(filtered.rows).toHaveLength(1);
|
|
1912
|
-
expect(filtered.totals).toMatchObject({
|
|
3379
|
+
expect(filtered.totals).toMatchObject({
|
|
3380
|
+
invocation_count: 3,
|
|
3381
|
+
total_tokens: 6,
|
|
3382
|
+
total_cost_brl: 15,
|
|
3383
|
+
});
|
|
1913
3384
|
}
|
|
1914
|
-
expect(filesystem.viewPage("cost_monitor_tasks", { workType: "new", limit: 1 })).toMatchObject({
|
|
3385
|
+
expect(filesystem.viewPage("cost_monitor_tasks", { workType: "new", limit: 1 })).toMatchObject({
|
|
3386
|
+
total_count: 0,
|
|
3387
|
+
rows: [],
|
|
3388
|
+
});
|
|
1915
3389
|
expect(filesystem.firstFoldAllTime()).toBe(allTime);
|
|
1916
3390
|
filesystem.close();
|
|
1917
3391
|
|
|
@@ -1925,26 +3399,61 @@ created_at: 2026-08-10T11:01:00.000Z
|
|
|
1925
3399
|
);
|
|
1926
3400
|
await writeFile(
|
|
1927
3401
|
join(root, ".agents", "records", "runs", "2026", "08", "RUN-CANONICAL-DAY.jsonl"),
|
|
1928
|
-
`${run(
|
|
3402
|
+
`${run(
|
|
3403
|
+
"RUN-CANONICAL-DAY",
|
|
3404
|
+
"2026-08-02",
|
|
3405
|
+
"TASK-CANONICAL-DAY",
|
|
3406
|
+
1_000,
|
|
3407
|
+
"12:30:00.000Z",
|
|
3408
|
+
"SPEC-CANONICAL-DAY",
|
|
3409
|
+
)
|
|
3410
|
+
.map((record) => JSON.stringify(record))
|
|
3411
|
+
.join("\n")}\n`,
|
|
1929
3412
|
"utf8",
|
|
1930
3413
|
);
|
|
1931
3414
|
await writeFile(
|
|
1932
3415
|
join(root, ".agents", "records", "runs", "2026", "08", "RUN-CANONICAL-DAY-LATE.jsonl"),
|
|
1933
|
-
`${run(
|
|
3416
|
+
`${run(
|
|
3417
|
+
"RUN-CANONICAL-DAY-LATE",
|
|
3418
|
+
"2026-08-04",
|
|
3419
|
+
"TASK-CANONICAL-DAY-LATE",
|
|
3420
|
+
1_000,
|
|
3421
|
+
"12:30:00.000Z",
|
|
3422
|
+
"SPEC-CANONICAL-DAY",
|
|
3423
|
+
)
|
|
3424
|
+
.map((record) => JSON.stringify(record))
|
|
3425
|
+
.join("\n")}\n`,
|
|
1934
3426
|
"utf8",
|
|
1935
3427
|
);
|
|
1936
3428
|
await rebuildSqliteReadModel(root);
|
|
1937
3429
|
const canonicalDayFilesystem = new SqliteReadModelFileSystem(root);
|
|
1938
|
-
expect(
|
|
1939
|
-
|
|
1940
|
-
|
|
3430
|
+
expect(
|
|
3431
|
+
canonicalDayFilesystem.viewPage("cost_monitor_specs", {
|
|
3432
|
+
from: "2026-08-03",
|
|
3433
|
+
to: "2026-08-03",
|
|
3434
|
+
query: "canonical title",
|
|
3435
|
+
limit: 1,
|
|
3436
|
+
}),
|
|
3437
|
+
).toMatchObject({
|
|
1941
3438
|
total_count: 1,
|
|
1942
3439
|
totals: { entity_count: 1, invocation_count: 0, total_tokens: null, total_cost_brl: null },
|
|
1943
|
-
rows: [
|
|
3440
|
+
rows: [
|
|
3441
|
+
expect.objectContaining({
|
|
3442
|
+
id: "SPEC-CANONICAL-DAY",
|
|
3443
|
+
invocation_count: 0,
|
|
3444
|
+
total_tokens: null,
|
|
3445
|
+
total_cost_brl: null,
|
|
3446
|
+
}),
|
|
3447
|
+
],
|
|
1944
3448
|
});
|
|
1945
|
-
expect(
|
|
1946
|
-
|
|
1947
|
-
|
|
3449
|
+
expect(
|
|
3450
|
+
canonicalDayFilesystem.viewPage("cost_monitor_specs", {
|
|
3451
|
+
from: "2026-08-02",
|
|
3452
|
+
to: "2026-08-02",
|
|
3453
|
+
query: "SPEC-CANONICAL-DAY",
|
|
3454
|
+
limit: 1,
|
|
3455
|
+
}),
|
|
3456
|
+
).toMatchObject({ total_count: 0, rows: [] });
|
|
1948
3457
|
canonicalDayFilesystem.close();
|
|
1949
3458
|
|
|
1950
3459
|
// A large result set keeps its subtotal for all 270 matching Tasks while
|
|
@@ -1953,7 +3462,9 @@ created_at: 2026-08-10T11:01:00.000Z
|
|
|
1953
3462
|
const id = `RUN-PAGE-${index}`;
|
|
1954
3463
|
await writeFile(
|
|
1955
3464
|
join(root, ".agents", "records", "runs", "2026", "08", `${id}.jsonl`),
|
|
1956
|
-
`${run(id, "2026-08-04", `TASK-PAGE-${index}`, 1_000)
|
|
3465
|
+
`${run(id, "2026-08-04", `TASK-PAGE-${index}`, 1_000)
|
|
3466
|
+
.map((record) => JSON.stringify(record))
|
|
3467
|
+
.join("\n")}\n`,
|
|
1957
3468
|
"utf8",
|
|
1958
3469
|
);
|
|
1959
3470
|
}
|