@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
|
@@ -2,9 +2,9 @@ import { mkdir, mkdtemp, readFile, rm, writeFile } from "node:fs/promises";
|
|
|
2
2
|
import { tmpdir } from "node:os";
|
|
3
3
|
import { join } from "node:path";
|
|
4
4
|
import {
|
|
5
|
+
PROJECT_CONFIG_PATH,
|
|
5
6
|
parseProjectConfig,
|
|
6
7
|
parseYaml,
|
|
7
|
-
PROJECT_CONFIG_PATH,
|
|
8
8
|
serializeYaml,
|
|
9
9
|
WorkspaceFileSystem,
|
|
10
10
|
} from "@zaip-ai/core";
|
|
@@ -123,6 +123,10 @@ async function fixtureProject() {
|
|
|
123
123
|
}
|
|
124
124
|
|
|
125
125
|
describe("project settings persistence", () => {
|
|
126
|
+
it("uses the canonical lowercase architecture artifact path", () => {
|
|
127
|
+
expect(SOFTWARE_ARCHITECTURE_PATH).toBe(".agents/architecture/software-architecture.md");
|
|
128
|
+
});
|
|
129
|
+
|
|
126
130
|
it("reads, validates and atomically persists the complete project config", async () => {
|
|
127
131
|
const { configPath, filesystem } = await fixtureProject();
|
|
128
132
|
const current = await readProjectSettings(filesystem);
|
|
@@ -385,7 +389,7 @@ describe("project settings persistence", () => {
|
|
|
385
389
|
}),
|
|
386
390
|
expect.objectContaining({
|
|
387
391
|
id: "brandbook",
|
|
388
|
-
artifact: ".agents/
|
|
392
|
+
artifact: ".agents/branding/brandbook.md",
|
|
389
393
|
available: false,
|
|
390
394
|
}),
|
|
391
395
|
]),
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import {
|
|
2
2
|
PROJECT_CONFIG_PATH,
|
|
3
3
|
type ProjectConfig,
|
|
4
|
-
parseProjectConfig,
|
|
5
4
|
parseAgentCatalog,
|
|
5
|
+
parseProjectConfig,
|
|
6
6
|
parseYaml,
|
|
7
7
|
serializeYaml,
|
|
8
8
|
type WorkspaceFileSystem,
|
|
@@ -12,7 +12,7 @@ const AGENT_CATALOG_PATH = ".agents/config/agents/catalog.yaml";
|
|
|
12
12
|
const CODEX_CONFIG_PATH = ".codex/config.toml";
|
|
13
13
|
const FRAMEWORK_LOCK_PATH = ".agents/config/framework.lock.yaml";
|
|
14
14
|
const SQLITE_READ_MODEL_PATH = ".local/dashboard-sqlite/read-model.sqlite";
|
|
15
|
-
export const SOFTWARE_ARCHITECTURE_PATH = "
|
|
15
|
+
export const SOFTWARE_ARCHITECTURE_PATH = ".agents/architecture/software-architecture.md";
|
|
16
16
|
|
|
17
17
|
export type ProjectOverview = {
|
|
18
18
|
framework_version: string | null;
|
|
@@ -48,7 +48,7 @@ const projectOverviewArtifacts: Array<Omit<ProjectOverview["areas"][number], "av
|
|
|
48
48
|
artifact: SOFTWARE_ARCHITECTURE_PATH,
|
|
49
49
|
},
|
|
50
50
|
{ id: "design_system", label: "Design system", artifact: ".agents/design/DESIGN.md" },
|
|
51
|
-
{ id: "brandbook", label: "Brandbook", artifact: ".agents/
|
|
51
|
+
{ id: "brandbook", label: "Brandbook", artifact: ".agents/branding/brandbook.md" },
|
|
52
52
|
{
|
|
53
53
|
id: "marketing_strategy",
|
|
54
54
|
label: "Estratégia de Marketing",
|
|
@@ -17,14 +17,13 @@ describe("boardPage", () => {
|
|
|
17
17
|
prds: [prd],
|
|
18
18
|
specs: [spec],
|
|
19
19
|
} as unknown as Parameters<typeof boardPage>[0];
|
|
20
|
-
const page = boardPage(
|
|
21
|
-
|
|
22
|
-
"
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
);
|
|
20
|
+
const page = boardPage(projection, "executing", 0, 10, [], {
|
|
21
|
+
query: "",
|
|
22
|
+
status: "",
|
|
23
|
+
risk: "",
|
|
24
|
+
origin: "",
|
|
25
|
+
kind: "",
|
|
26
|
+
});
|
|
28
27
|
|
|
29
28
|
expect(page.tasks[0]).toBe(task);
|
|
30
29
|
expect(page.prds[0]).toBe(prd);
|
|
@@ -42,17 +41,57 @@ describe("boardPage", () => {
|
|
|
42
41
|
const projection = { changes: [], tasks: [task], prds: [], specs: [] } as unknown as Parameters<
|
|
43
42
|
typeof boardPage
|
|
44
43
|
>[0];
|
|
45
|
-
const page = boardPage(
|
|
46
|
-
|
|
47
|
-
"
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
);
|
|
44
|
+
const page = boardPage(projection, "executing", 0, 10, [], {
|
|
45
|
+
query: "",
|
|
46
|
+
status: "",
|
|
47
|
+
risk: "",
|
|
48
|
+
origin: "",
|
|
49
|
+
kind: "",
|
|
50
|
+
});
|
|
53
51
|
expect(page.tasks[0]).toBe(task);
|
|
54
52
|
});
|
|
55
53
|
|
|
54
|
+
it("separates standalone Tasks from Tasks linked to a SPEC", () => {
|
|
55
|
+
const standalone = {
|
|
56
|
+
id: "TASK-STANDALONE",
|
|
57
|
+
title: "Standalone",
|
|
58
|
+
status: "executing",
|
|
59
|
+
spec_id: null,
|
|
60
|
+
updated_at: "2026-08-08T10:00:00Z",
|
|
61
|
+
};
|
|
62
|
+
const linked = {
|
|
63
|
+
id: "TASK-LINKED",
|
|
64
|
+
title: "Linked",
|
|
65
|
+
status: "executing",
|
|
66
|
+
spec_id: "SPEC-1",
|
|
67
|
+
updated_at: "2026-08-08T10:00:00Z",
|
|
68
|
+
};
|
|
69
|
+
const projection = {
|
|
70
|
+
changes: [],
|
|
71
|
+
tasks: [standalone, linked],
|
|
72
|
+
prds: [],
|
|
73
|
+
specs: [],
|
|
74
|
+
} as unknown as Parameters<typeof boardPage>[0];
|
|
75
|
+
|
|
76
|
+
const standalonePage = boardPage(projection, "executing", 0, 10, [], {
|
|
77
|
+
query: "",
|
|
78
|
+
status: "",
|
|
79
|
+
risk: "",
|
|
80
|
+
origin: "",
|
|
81
|
+
kind: "standalone-task",
|
|
82
|
+
});
|
|
83
|
+
const linkedPage = boardPage(projection, "executing", 0, 10, [], {
|
|
84
|
+
query: "",
|
|
85
|
+
status: "",
|
|
86
|
+
risk: "",
|
|
87
|
+
origin: "",
|
|
88
|
+
kind: "task",
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
expect(standalonePage.tasks).toEqual([standalone]);
|
|
92
|
+
expect(linkedPage.tasks).toEqual([linked]);
|
|
93
|
+
expect(standalonePage.totals_by_kind).toMatchObject({ task: 1, "standalone-task": 1 });
|
|
94
|
+
});
|
|
56
95
|
});
|
|
57
96
|
|
|
58
97
|
function macro(id: string, kind: "prd" | "spec", taskIds: string[]) {
|
|
@@ -7,7 +7,13 @@ import type { Context } from "hono";
|
|
|
7
7
|
import type { buildCanonicalOperationsProjection } from "./server-projections.js";
|
|
8
8
|
|
|
9
9
|
type BoardStage = WorkStage;
|
|
10
|
-
export type BoardClassification =
|
|
10
|
+
export type BoardClassification =
|
|
11
|
+
| "lite"
|
|
12
|
+
| "standard"
|
|
13
|
+
| "critical"
|
|
14
|
+
| "empty"
|
|
15
|
+
| "structured"
|
|
16
|
+
| "rework";
|
|
11
17
|
|
|
12
18
|
interface BoardFilters {
|
|
13
19
|
query: string;
|
|
@@ -110,7 +116,11 @@ export function boardPage(
|
|
|
110
116
|
const stageItems =
|
|
111
117
|
filters.kind === ""
|
|
112
118
|
? allStageItems
|
|
113
|
-
:
|
|
119
|
+
: filters.kind === "standalone-task"
|
|
120
|
+
? allStageItems.filter((item) => item.kind === "task" && item.row.spec_id === null)
|
|
121
|
+
: filters.kind === "task"
|
|
122
|
+
? allStageItems.filter((item) => item.kind === "task" && item.row.spec_id !== null)
|
|
123
|
+
: allStageItems.filter((item) => item.kind === filters.kind);
|
|
114
124
|
const page = stageItems.slice(offset, offset + limit);
|
|
115
125
|
const ids = new Set(page.map((item) => item.row.id));
|
|
116
126
|
return {
|
|
@@ -119,19 +129,17 @@ export function boardPage(
|
|
|
119
129
|
total: stageItems.length,
|
|
120
130
|
totals_by_kind: {
|
|
121
131
|
all: allStageItems.length,
|
|
122
|
-
task: allStageItems.filter((item) => item.kind === "task")
|
|
132
|
+
task: allStageItems.filter((item) => item.kind === "task" && item.row.spec_id !== null)
|
|
133
|
+
.length,
|
|
134
|
+
"standalone-task": allStageItems.filter(
|
|
135
|
+
(item) => item.kind === "task" && item.row.spec_id === null,
|
|
136
|
+
).length,
|
|
123
137
|
prd: allStageItems.filter((item) => item.kind === "prd").length,
|
|
124
138
|
spec: allStageItems.filter((item) => item.kind === "spec").length,
|
|
125
139
|
},
|
|
126
|
-
prds: page
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
specs: page
|
|
130
|
-
.filter((item) => item.kind === "spec")
|
|
131
|
-
.map((item) => item.row),
|
|
132
|
-
tasks: page
|
|
133
|
-
.filter((item) => item.kind === "task")
|
|
134
|
-
.map((item) => item.row),
|
|
140
|
+
prds: page.filter((item) => item.kind === "prd").map((item) => item.row),
|
|
141
|
+
specs: page.filter((item) => item.kind === "spec").map((item) => item.row),
|
|
142
|
+
tasks: page.filter((item) => item.kind === "task").map((item) => item.row),
|
|
135
143
|
changes: projection.changes.filter((change) =>
|
|
136
144
|
change.task_ids.some((taskId) => ids.has(taskId)),
|
|
137
145
|
),
|
|
@@ -173,7 +181,9 @@ export function classificationPage(
|
|
|
173
181
|
tasks: kind === "task" ? page : [],
|
|
174
182
|
changes:
|
|
175
183
|
kind === "task"
|
|
176
|
-
? projection.changes.filter((change) =>
|
|
184
|
+
? projection.changes.filter((change) =>
|
|
185
|
+
page.some((task) => change.task_ids.includes(task.id)),
|
|
186
|
+
)
|
|
177
187
|
: [],
|
|
178
188
|
};
|
|
179
189
|
}
|
|
@@ -45,7 +45,7 @@ describe("dashboard backend snapshot", () => {
|
|
|
45
45
|
[
|
|
46
46
|
"lock_version: 1",
|
|
47
47
|
"framework:",
|
|
48
|
-
" version: 1.0
|
|
48
|
+
" version: 1.3.0",
|
|
49
49
|
" distribution_sha256: null",
|
|
50
50
|
"layout:",
|
|
51
51
|
" version: 3",
|
|
@@ -593,12 +593,27 @@ describe("Cost Monitor daily summary route", () => {
|
|
|
593
593
|
it("keeps the Daily first-fold response to its displayed-column allowlist", () => {
|
|
594
594
|
const source = readFileSync(new URL("./sqlite-read-model.ts", import.meta.url), "utf8");
|
|
595
595
|
const dailyBranch = source.slice(
|
|
596
|
-
source.indexOf(
|
|
597
|
-
|
|
596
|
+
source.indexOf(
|
|
597
|
+
"if (filteredCostGroup !== undefined && temporalCostGroup && !hasDimensionalCostFilter)",
|
|
598
|
+
),
|
|
599
|
+
source.indexOf(
|
|
600
|
+
"if (filteredCostGroup !== undefined && (!temporalCostGroup || hasDimensionalCostFilter))",
|
|
601
|
+
),
|
|
598
602
|
);
|
|
599
603
|
expect(dailyBranch).not.toContain("costMonitorFactualDurationByDay(");
|
|
600
604
|
expect(dailyBranch).toContain("Daily first fold is an allowlisted table contract");
|
|
601
|
-
for (const field of [
|
|
605
|
+
for (const field of [
|
|
606
|
+
"prd_count",
|
|
607
|
+
"spec_count",
|
|
608
|
+
"task_count",
|
|
609
|
+
"total_run_count",
|
|
610
|
+
"validation_count",
|
|
611
|
+
"evidence_count",
|
|
612
|
+
"total_duration",
|
|
613
|
+
"duration_known",
|
|
614
|
+
"total_tokens",
|
|
615
|
+
"total_cost_brl",
|
|
616
|
+
])
|
|
602
617
|
expect(dailyBranch).toContain(`${field}:`);
|
|
603
618
|
expect(dailyBranch).not.toContain("...row,");
|
|
604
619
|
});
|
|
@@ -51,7 +51,10 @@ export function githubRepositoryFromRemote(remote: string): string | null {
|
|
|
51
51
|
}
|
|
52
52
|
|
|
53
53
|
export function dashboardWorkspaceKey(workspaceRoot: string): string {
|
|
54
|
-
return createHash("sha256")
|
|
54
|
+
return createHash("sha256")
|
|
55
|
+
.update(`${resolve(workspaceRoot)}:dashboard-sqlite`)
|
|
56
|
+
.digest("hex")
|
|
57
|
+
.slice(0, 16);
|
|
55
58
|
}
|
|
56
59
|
|
|
57
60
|
export interface ReconciliationItem {
|
|
@@ -104,11 +107,12 @@ export function reconciliationResult(value: unknown): ReconciliationResult {
|
|
|
104
107
|
const record = entity as Record<string, unknown>;
|
|
105
108
|
if (
|
|
106
109
|
item.status === "closed" &&
|
|
107
|
-
record.status
|
|
110
|
+
["completed", "blocked", "cancelled", "failed"].includes(record.status as string) &&
|
|
108
111
|
typeof record.id === "string"
|
|
109
112
|
) {
|
|
110
113
|
reconciled.add(record.id);
|
|
111
|
-
}
|
|
114
|
+
}
|
|
115
|
+
if (record.status === "blocked") {
|
|
112
116
|
remember(blocked, record.id, record.status_reason ?? reason);
|
|
113
117
|
} else if (item.status === "deferred") {
|
|
114
118
|
remember(notReconciled, record.id, reason);
|
|
@@ -12,6 +12,7 @@ import {
|
|
|
12
12
|
openWorkIds,
|
|
13
13
|
projectionPeriodFilter,
|
|
14
14
|
reconciliationResult,
|
|
15
|
+
SqliteReadModelFileSystem,
|
|
15
16
|
} from "./server.js";
|
|
16
17
|
import { invocationSummary } from "./server.test-fixtures.js";
|
|
17
18
|
import { classificationPage } from "./server-board.js";
|
|
@@ -21,6 +22,7 @@ import {
|
|
|
21
22
|
mergeLifecycleRunPage,
|
|
22
23
|
runTimestampInRange,
|
|
23
24
|
} from "./server-projections.js";
|
|
25
|
+
import { rebuildSqliteReadModel } from "./sqlite-read-model.js";
|
|
24
26
|
|
|
25
27
|
const workspaceRoot = resolve(import.meta.dirname, "../../../../..");
|
|
26
28
|
describe("dashboard backend", () => {
|
|
@@ -252,7 +254,11 @@ describe("dashboard backend", () => {
|
|
|
252
254
|
});
|
|
253
255
|
});
|
|
254
256
|
it("permits canonical open-work reconciliation while serving a read-only SQLite snapshot", async () => {
|
|
255
|
-
const reconcile = vi.fn(async () => ({
|
|
257
|
+
const reconcile = vi.fn(async () => ({
|
|
258
|
+
reconciled_ids: ["TASK-RECONCILED"],
|
|
259
|
+
blocked: [],
|
|
260
|
+
not_reconciled: [],
|
|
261
|
+
}));
|
|
256
262
|
const refresh = vi.fn(async () => undefined);
|
|
257
263
|
const canonicalFilesystem = new WorkspaceFileSystem(workspaceRoot);
|
|
258
264
|
const app = createDashboardApp(workspaceRoot, "test-session", undefined, {
|
|
@@ -275,6 +281,106 @@ describe("dashboard backend", () => {
|
|
|
275
281
|
const rejected = await app.request("/api/v2/reconcile-open-work", { method: "POST" });
|
|
276
282
|
expect(rejected.status).toBe(401);
|
|
277
283
|
}, 130_000);
|
|
284
|
+
it("rebuilds a stale immutable projection without reconciling lifecycle work", async () => {
|
|
285
|
+
const fixtureRoot = await mkdtemp(join(tmpdir(), "zaip-dashboard-stale-projection-"));
|
|
286
|
+
const taskIndexPath = join(
|
|
287
|
+
fixtureRoot,
|
|
288
|
+
".agents",
|
|
289
|
+
"records",
|
|
290
|
+
"lifecycle",
|
|
291
|
+
"indexes",
|
|
292
|
+
"task.json",
|
|
293
|
+
);
|
|
294
|
+
const taskRecordPath = join(
|
|
295
|
+
fixtureRoot,
|
|
296
|
+
".agents",
|
|
297
|
+
"records",
|
|
298
|
+
"tasks",
|
|
299
|
+
"2026",
|
|
300
|
+
"08",
|
|
301
|
+
"TASK-STALE-PROJECTION.md",
|
|
302
|
+
);
|
|
303
|
+
await mkdir(join(fixtureRoot, ".agents", "config"), { recursive: true });
|
|
304
|
+
await mkdir(join(fixtureRoot, ".agents", "records", "lifecycle", "indexes"), {
|
|
305
|
+
recursive: true,
|
|
306
|
+
});
|
|
307
|
+
await mkdir(join(fixtureRoot, ".agents", "records", "tasks", "2026", "08"), {
|
|
308
|
+
recursive: true,
|
|
309
|
+
});
|
|
310
|
+
await writeFile(
|
|
311
|
+
join(fixtureRoot, ".agents", "config", "project.yaml"),
|
|
312
|
+
"schema_version: 1\nproject:\n id: stale-projection\n name: stale-projection\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",
|
|
313
|
+
);
|
|
314
|
+
await writeFile(
|
|
315
|
+
join(fixtureRoot, ".agents", "config", "framework.lock.yaml"),
|
|
316
|
+
"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",
|
|
317
|
+
);
|
|
318
|
+
const task = (status: "executing" | "completed") => ({
|
|
319
|
+
schema_version: 1,
|
|
320
|
+
entities: {
|
|
321
|
+
"TASK-STALE-PROJECTION": {
|
|
322
|
+
kind: "task",
|
|
323
|
+
id: "TASK-STALE-PROJECTION",
|
|
324
|
+
title: "Stale projection",
|
|
325
|
+
status,
|
|
326
|
+
risk: "standard",
|
|
327
|
+
priority: "medium",
|
|
328
|
+
updated_at: "2026-08-22T12:00:00.000Z",
|
|
329
|
+
relations: [],
|
|
330
|
+
usage: null,
|
|
331
|
+
data: { created_at: "2026-08-22T12:00:00.000Z" },
|
|
332
|
+
},
|
|
333
|
+
},
|
|
334
|
+
});
|
|
335
|
+
await writeFile(taskIndexPath, `${JSON.stringify(task("executing"))}\n`);
|
|
336
|
+
const taskRecord = (status: "executing" | "completed") =>
|
|
337
|
+
`---\nid: TASK-STALE-PROJECTION\ntitle: Stale projection\nstatus: ${status}\nrisk: standard\ncreated_at: 2026-08-22T12:00:00.000Z\n---\n# Stale projection\n`;
|
|
338
|
+
await writeFile(taskRecordPath, taskRecord("executing"));
|
|
339
|
+
await rebuildSqliteReadModel(fixtureRoot);
|
|
340
|
+
const filesystem = new SqliteReadModelFileSystem(fixtureRoot);
|
|
341
|
+
const reconcile = vi.fn(async () => ({ reconciled_ids: [], blocked: [], not_reconciled: [] }));
|
|
342
|
+
try {
|
|
343
|
+
const app = createDashboardApp(fixtureRoot, "test-session", undefined, {
|
|
344
|
+
canonicalFilesystem: new WorkspaceFileSystem(fixtureRoot),
|
|
345
|
+
filesystem,
|
|
346
|
+
reconcileOpenWork: reconcile,
|
|
347
|
+
});
|
|
348
|
+
const before = await app.request("/api/v2/operations?scope=quick", {
|
|
349
|
+
headers: { "x-zaip-session": "test-session" },
|
|
350
|
+
});
|
|
351
|
+
const beforePayload = (await before.json()) as {
|
|
352
|
+
summary: { overview_metrics: { task_status_counts: Record<string, number> } };
|
|
353
|
+
};
|
|
354
|
+
expect(beforePayload.summary.overview_metrics.task_status_counts.executing).toBe(1);
|
|
355
|
+
|
|
356
|
+
await writeFile(taskIndexPath, `${JSON.stringify(task("completed"))}\n`);
|
|
357
|
+
await writeFile(taskRecordPath, taskRecord("completed"));
|
|
358
|
+
const previousSeedPreference = process.env.ZAIP_SQLITE_PREFER_LAST_VALID_SEED;
|
|
359
|
+
process.env.ZAIP_SQLITE_PREFER_LAST_VALID_SEED = "1";
|
|
360
|
+
const refreshed = await app.request("/api/v2/refresh-projection", {
|
|
361
|
+
method: "POST",
|
|
362
|
+
headers: { "x-zaip-session": "test-session" },
|
|
363
|
+
});
|
|
364
|
+
if (previousSeedPreference === undefined)
|
|
365
|
+
delete process.env.ZAIP_SQLITE_PREFER_LAST_VALID_SEED;
|
|
366
|
+
else process.env.ZAIP_SQLITE_PREFER_LAST_VALID_SEED = previousSeedPreference;
|
|
367
|
+
|
|
368
|
+
expect(refreshed.status, await refreshed.clone().text()).toBe(200);
|
|
369
|
+
const payload = (await refreshed.json()) as {
|
|
370
|
+
operations: {
|
|
371
|
+
summary: { overview_metrics: { task_status_counts: Record<string, number> } };
|
|
372
|
+
};
|
|
373
|
+
};
|
|
374
|
+
expect(payload.operations.summary.overview_metrics.task_status_counts.executing ?? 0).toBe(0);
|
|
375
|
+
expect(payload.operations.summary.overview_metrics.task_status_counts.completed).toBe(1);
|
|
376
|
+
expect(reconcile).not.toHaveBeenCalled();
|
|
377
|
+
const rejected = await app.request("/api/v2/refresh-projection", { method: "POST" });
|
|
378
|
+
expect(rejected.status).toBe(401);
|
|
379
|
+
} finally {
|
|
380
|
+
filesystem.close();
|
|
381
|
+
await rm(fixtureRoot, { recursive: true, force: true });
|
|
382
|
+
}
|
|
383
|
+
}, 130_000);
|
|
278
384
|
it("persists Kanban priority canonically while a SQLite snapshot blocks other settings writes", async () => {
|
|
279
385
|
const canonicalRoot = await mkdtemp(join(tmpdir(), "zaip-dashboard-priority-"));
|
|
280
386
|
try {
|
|
@@ -298,11 +404,21 @@ describe("dashboard backend", () => {
|
|
|
298
404
|
};
|
|
299
405
|
expect(beforeBoard.tasks.length).toBeGreaterThan(1);
|
|
300
406
|
const concurrent = await Promise.all([
|
|
301
|
-
app.request(
|
|
302
|
-
|
|
407
|
+
app.request(
|
|
408
|
+
"/api/v2/operations?scope=board&stage=completed&from=2000-01-01&to=2099-12-31&offset=0&limit=10",
|
|
409
|
+
{ headers: { "x-zaip-session": "test-session" } },
|
|
410
|
+
),
|
|
411
|
+
app.request(
|
|
412
|
+
"/api/v2/operations?scope=board&stage=blocked&from=2000-01-01&to=2099-12-31&offset=0&limit=10",
|
|
413
|
+
{ headers: { "x-zaip-session": "test-session" } },
|
|
414
|
+
),
|
|
303
415
|
]);
|
|
304
416
|
expect(concurrent.every((response) => response.status === 200)).toBe(true);
|
|
305
|
-
expect(
|
|
417
|
+
expect(
|
|
418
|
+
priorityReads.mock.calls.filter(
|
|
419
|
+
([path]) => path === ".agents/dashboard/work-priority.json",
|
|
420
|
+
),
|
|
421
|
+
).toHaveLength(1);
|
|
306
422
|
const priority = { item_ids: [beforeBoard.tasks.at(-1)!.id], updated_at: null };
|
|
307
423
|
const persisted = await app.request("/api/v2/work-priority", {
|
|
308
424
|
method: "PUT",
|
|
@@ -327,7 +443,10 @@ describe("dashboard backend", () => {
|
|
|
327
443
|
expect(after.status, await after.clone().text()).toBe(200);
|
|
328
444
|
const afterBoard = (await after.json()) as typeof beforeBoard;
|
|
329
445
|
expect(afterBoard.tasks[0]?.id).toBe(priority.item_ids[0]);
|
|
330
|
-
expect(
|
|
446
|
+
expect(
|
|
447
|
+
priorityReads.mock.calls.filter(([path]) => path === ".agents/dashboard/work-priority.json")
|
|
448
|
+
.length,
|
|
449
|
+
).toBe(readsAfterPut + 1);
|
|
331
450
|
const blocked = await app.request("/api/v2/pricing", {
|
|
332
451
|
method: "PUT",
|
|
333
452
|
headers: { "content-type": "application/json", "x-zaip-session": "test-session" },
|
|
@@ -414,7 +533,9 @@ describe("dashboard backend", () => {
|
|
|
414
533
|
};
|
|
415
534
|
expect(payload.tasks).toEqual([]);
|
|
416
535
|
expect(payload.prds).toEqual([]);
|
|
417
|
-
expect(
|
|
536
|
+
expect(
|
|
537
|
+
payload.specs.every((spec) => spec.task_count === 0 && spec.rework_run_count === 0),
|
|
538
|
+
).toBe(true);
|
|
418
539
|
});
|
|
419
540
|
it("serves a compact cost summary and paginated Run metrics from the manifest", async () => {
|
|
420
541
|
const app = createDashboardApp(workspaceRoot, "test-session");
|
|
@@ -721,7 +842,7 @@ describe("dashboard backend", () => {
|
|
|
721
842
|
unresolved_running_run_ids: ["RUN-ACTIVE"],
|
|
722
843
|
}),
|
|
723
844
|
).toEqual({
|
|
724
|
-
reconciled_ids: ["CHG-COMPLETED", "TASK-COMPLETED"],
|
|
845
|
+
reconciled_ids: ["CHG-COMPLETED", "TASK-BLOCKED", "TASK-COMPLETED"],
|
|
725
846
|
blocked: [
|
|
726
847
|
{
|
|
727
848
|
id: "EXEC-ORPHANED",
|
|
@@ -830,8 +951,10 @@ describe("dashboard backend", () => {
|
|
|
830
951
|
source.indexOf("function buildSqliteOperationsProjection"),
|
|
831
952
|
source.indexOf("function nullableMetric"),
|
|
832
953
|
);
|
|
833
|
-
expect(projection).toContain(
|
|
834
|
-
|
|
954
|
+
expect(projection).toContain(
|
|
955
|
+
"options.includePeriods === true ? filesystem.dailyPeriods(filter) : {}",
|
|
956
|
+
);
|
|
957
|
+
expect(source).toContain('includePeriods: scope === "detail" || scope === "overview"');
|
|
835
958
|
});
|
|
836
959
|
it("rebuilds a fresh aggregate after an in-flight normal read instead of sharing its payload", async () => {
|
|
837
960
|
const source = await import("node:fs/promises").then(({ readFile }) =>
|