@zaip-ai/cli 1.3.2 → 1.3.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (98) hide show
  1. package/LICENSE +6 -3
  2. package/README.md +8 -2
  3. package/dist/services/codex-pre-tool-hook-template.js +1 -1
  4. package/dist/services/runtime-template.test.js +9 -8
  5. package/dist/services/runtime-template.test.js.map +1 -1
  6. package/package.json +2 -2
  7. package/templates/.agents/dashboard/.zaip-managed.json +414 -394
  8. package/templates/.agents/dashboard/apps/frontend/dist/assets/{CostCalculationGuidePage-ovxurkIk.js → CostCalculationGuidePage-D1mpyYwh.js} +1 -1
  9. package/templates/.agents/dashboard/apps/frontend/dist/assets/{DashboardHelpDialog-BXy6nti1.js → DashboardHelpDialog-CKO47D5s.js} +30 -1
  10. package/templates/.agents/dashboard/apps/frontend/dist/assets/{PricingSettingsDialog-vSvvOHQp.js → PricingSettingsDialog-BuSlCbyZ.js} +1 -1
  11. package/templates/.agents/dashboard/apps/frontend/dist/assets/{ProjectSettingsPage-zH758vfs.js → ProjectSettingsPage-CUHFkAhZ.js} +1 -1
  12. package/templates/.agents/dashboard/apps/frontend/dist/assets/{TraceabilityWorkspace-CTH2wDs5.js → TraceabilityWorkspace-BmASq2gW.js} +1 -1
  13. package/templates/.agents/dashboard/apps/frontend/dist/assets/cost-monitor-Csj6LiAt.js +68 -0
  14. package/templates/.agents/dashboard/apps/frontend/dist/assets/{icons-vendor-B_lDDHn1.js → icons-vendor-VyTTl_ph.js} +1 -1
  15. package/templates/.agents/dashboard/apps/frontend/dist/assets/index-DIwDvCu5.js +2 -0
  16. package/templates/.agents/dashboard/apps/frontend/dist/assets/index-hPPfVGQv.css +1 -0
  17. package/templates/.agents/dashboard/apps/frontend/dist/assets/{react-vendor-B3TJrD4O.js → react-vendor-CTC6vtln.js} +1 -1
  18. package/templates/.agents/dashboard/apps/frontend/dist/assets/{traceability-7f1j5wx3.js → traceability-9Mtvbwrg.js} +1 -1
  19. package/templates/.agents/dashboard/apps/frontend/dist/index.html +6 -6
  20. package/templates/.agents/dashboard/apps/frontend/src/App.tsx +74 -10
  21. package/templates/.agents/dashboard/apps/frontend/src/AppRequestGuards.tsx +44 -0
  22. package/templates/.agents/dashboard/apps/frontend/src/cost-period-refresh.test.ts +103 -2
  23. package/templates/.agents/dashboard/apps/frontend/src/dashboard-capability-nav.css +11 -0
  24. package/templates/.agents/dashboard/apps/frontend/src/operations-period-contract.test.ts +14 -0
  25. package/templates/.agents/dashboard/apps/frontend/src/operations-period.test.ts +3 -6
  26. package/templates/.agents/dashboard/apps/frontend/src/operations-period.ts +3 -2
  27. package/templates/.agents/dashboard/apps/frontend/src/snapshot-coherence.test.ts +2 -2
  28. package/templates/.agents/dashboard/modules/cost-monitor/src/react/CostDeveloperAttributionPanel.test.ts +60 -0
  29. package/templates/.agents/dashboard/modules/cost-monitor/src/react/CostDeveloperAttributionPanel.tsx +26 -9
  30. package/templates/.agents/dashboard/modules/cost-monitor/src/react/CostMonitorNavigation.tsx +189 -0
  31. package/templates/.agents/dashboard/modules/cost-monitor/src/react/CostMonitorPage.test.ts +122 -2
  32. package/templates/.agents/dashboard/modules/cost-monitor/src/react/CostMonitorPage.tsx +70 -155
  33. package/templates/.agents/dashboard/modules/operations/src/react/OperationsOverview.helpers.tsx +2 -1
  34. package/templates/.agents/dashboard/modules/operations/src/react/OperationsOverview.test.ts +12 -4
  35. package/templates/.agents/dashboard/modules/operations/src/react/OperationsOverview.tsx +67 -24
  36. package/templates/.agents/dashboard/modules/operations/src/react/OperationsPage.tsx +19 -4
  37. package/templates/.agents/dashboard/modules/operations/src/react/export/ExcelExportAction.test.ts +59 -0
  38. package/templates/.agents/dashboard/modules/operations/src/react/export/ExcelExportAction.tsx +55 -2
  39. package/templates/.agents/dashboard/modules/operations/src/react/operation-date-range.test.ts +25 -0
  40. package/templates/.agents/dashboard/modules/operations/src/react/operation-date-range.ts +29 -0
  41. package/templates/.agents/dashboard/modules/operations/src/react/operations-coverage-toast.test.ts +3 -2
  42. package/templates/.agents/dashboard/modules/operations/src/react/operations-overview-period-filter.test.ts +12 -2
  43. package/templates/.agents/dashboard/packages/local-runtime/dist/server.cjs +274 -246
  44. package/templates/.agents/dashboard/packages/local-runtime/dist/sqlite-read-model.cjs +255 -227
  45. package/templates/.agents/dashboard/packages/local-runtime/server.mjs +263 -235
  46. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-cost-dimension-facts.test.ts +282 -0
  47. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-cost-dimension-facts.ts +71 -0
  48. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-read-model-launch-progress.ts +18 -0
  49. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-read-model-stale-seed.ts +50 -0
  50. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-read-model.test.ts +9 -6
  51. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-read-model.ts +45 -73
  52. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-snapshot-seed.test.ts +79 -2
  53. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-work-item-index.test.ts +56 -0
  54. package/templates/.agents/dashboard/packages/local-runtime/start-dashboard-launch-page.mjs +26 -8
  55. package/templates/.agents/dashboard/packages/local-runtime/start-dashboard-launch-page.test.mjs +45 -4
  56. package/templates/.agents/dashboard/packages/local-runtime/start-dashboard-lifecycle.mjs +58 -0
  57. package/templates/.agents/dashboard/packages/local-runtime/start-dashboard-lifecycle.test.mjs +81 -0
  58. package/templates/.agents/dashboard/packages/local-runtime/start-dashboard.mjs +171 -71
  59. package/templates/.agents/dashboard/packages/local-runtime/start-dashboard.test.mjs +152 -11
  60. package/templates/.agents/dashboard/packages/windows-launcher/Program.cs +4 -9
  61. package/templates/.agents/dashboard/tests/e2e/playwright.config.ts +9 -1
  62. package/templates/.agents/dashboard/tests/e2e/specs/cost-monitor-loading.spec.ts +1 -1
  63. package/templates/.agents/dashboard/tests/e2e/specs/cost-monitor-pagination.spec.ts +4 -0
  64. package/templates/.agents/dashboard/tests/e2e/specs/cost-monitor-period-transition.spec.ts +238 -0
  65. package/templates/.agents/dashboard/tests/e2e/specs/dashboard-performance-matrix.spec.ts +4 -0
  66. package/templates/.agents/dashboard/tests/e2e/specs/dashboard.spec.ts +60 -17
  67. package/templates/.agents/requirements/autonomous-assurance.md +1 -1
  68. package/templates/.agents/requirements/comparative-audit.md +1 -1
  69. package/templates/.agents/requirements/context-engine.md +1 -1
  70. package/templates/.agents/requirements/cost-observability.md +1 -1
  71. package/templates/.agents/requirements/dashboard-launch.md +1 -1
  72. package/templates/.agents/requirements/data-export.md +1 -1
  73. package/templates/.agents/requirements/design-system.md +1 -1
  74. package/templates/.agents/requirements/execution-engine.md +1 -1
  75. package/templates/.agents/requirements/kanban-dashboard.md +1 -1
  76. package/templates/.agents/requirements/model-orchestration.md +1 -1
  77. package/templates/.agents/requirements/public-distribution.md +1 -1
  78. package/templates/.agents/requirements/software-architecture.md +1 -1
  79. package/templates/.agents/requirements/strategic-improvements.md +1 -1
  80. package/templates/.agents/requirements/work-lifecycle.md +1 -1
  81. package/templates/.agents/requirements/zaip-strategic-95.md +1 -1
  82. package/templates/.agents/runtime/bin/zaip.mjs +7 -7
  83. package/templates/.agents/runtime/checksums.sha256 +3 -3
  84. package/templates/.agents/runtime/provenance.json +3 -3
  85. package/templates/.agents/runtime/sbom.cdx.json +1595 -3491
  86. package/templates/.agents/skills/zaip-skill-lifecycle-closure/SKILL.md +16 -0
  87. package/templates/.agents/skills/zaip-skill-reconcile-telemetry/scripts/reconcile-local-telemetry.mjs +19 -20
  88. package/templates/.agents/skills/zaip-skill-reconcile-telemetry/scripts/reconcile-local-telemetry.test.mjs +143 -0
  89. package/templates/.agents/skills/zaip-skill-reconcile-telemetry/scripts/reconcile-telemetry-lib.mjs +14 -0
  90. package/templates/.agents/skills/zaip-skill-reconcile-telemetry/scripts/reconcile-telemetry-remeasurement.mjs +3 -1
  91. package/templates/.agents/skills/zaip-skill-reconcile-telemetry/scripts/reconcile-telemetry-remeasurement.test.mjs +21 -0
  92. package/templates/.agents/skills/zaip-skill-reconcile-telemetry/scripts/source-size-telemetry/model-identity-reconciliation.mjs +3 -0
  93. package/templates/.agents/zaip-aios/guides/26-qualidade-e-release.md +29 -0
  94. package/templates/template-manifest.json +539 -935
  95. package/templates/.agents/dashboard/.tmp-run-list.json +0 -254
  96. package/templates/.agents/dashboard/apps/frontend/dist/assets/cost-monitor-DKwP1stV.js +0 -68
  97. package/templates/.agents/dashboard/apps/frontend/dist/assets/index-B31GMG5O.css +0 -1
  98. package/templates/.agents/dashboard/apps/frontend/dist/assets/index-CuMcoUni.js +0 -2
@@ -79,14 +79,10 @@ namespace ZaipDashboardLauncher
79
79
 
80
80
  private static int WaitForLaunchStatus(Process process, string statusPath, string workspaceRoot)
81
81
  {
82
- // The Node launcher coalesces concurrent clicks and may wait for a
83
- // healthy build/handoff. Keep this wrapper alive for that bounded
84
- // handoff instead of showing a second failure dialog.
85
- // A waiting click can spend the Node lock window (210 s) behind
86
- // the current leader, then still needs the bounded 180 s server
87
- // startup window if that leader fails before publishing a session.
88
- var deadline = DateTime.UtcNow.AddSeconds(420);
89
- while (DateTime.UtcNow < deadline)
82
+ // A cold local read model has no useful fixed wall-clock limit.
83
+ // Keep this wrapper attached until Node publishes a real result;
84
+ // errors still surface when Node reports them or exits.
85
+ while (true)
90
86
  {
91
87
  try
92
88
  {
@@ -125,7 +121,6 @@ namespace ZaipDashboardLauncher
125
121
  }
126
122
  Thread.Sleep(100);
127
123
  }
128
- return ReportFailure("O dashboard ainda não publicou uma sessão pronta após 420 segundos. O processo local pode continuar registrando detalhes no log temporário; feche esta mensagem e tente novamente após verificar o log.");
129
124
  }
130
125
 
131
126
  private static bool VerifyDashboardLaunch(string workspaceRoot, out string error)
@@ -11,6 +11,9 @@ export default defineConfig({
11
11
  timeout: 180_000,
12
12
  expect: { timeout: 60_000 },
13
13
  retries: process.env.CI ? 1 : 0,
14
+ // CI shares one SQLite runtime across the suite. Serializing browser workers
15
+ // keeps the measured latency gates independent from runner CPU count.
16
+ ...(process.env.CI ? { workers: 1 } : {}),
14
17
  reporter: process.env.CI ? "github" : "list",
15
18
  use: {
16
19
  baseURL: `${baseURL}/?token=e2e-token`,
@@ -22,7 +25,10 @@ export default defineConfig({
22
25
  cwd: workspaceRoot,
23
26
  url: `${baseURL}/api/v2/health`,
24
27
  reuseExistingServer: false,
25
- timeout: 120_000,
28
+ // The canonical SQLite rebuild is intentionally unbounded in production.
29
+ // Keep only a broad test-runner safety envelope so a large clean workspace
30
+ // is not killed by the former two-minute startup deadline.
31
+ timeout: 3_000_000,
26
32
  env: {
27
33
  ZAIP_UI_TOKEN: "e2e-token",
28
34
  ZAIP_SERVER_PORT: serverPort,
@@ -31,6 +37,8 @@ export default defineConfig({
31
37
  // Match the Windows launcher: first paint uses the latest validated
32
38
  // immutable seed while canonical refresh work stays off the served path.
33
39
  ZAIP_SQLITE_PREFER_LAST_VALID_SEED: "1",
40
+ // Keep pre-bind progress observable if the web-server health gate times out.
41
+ ZAIP_DASHBOARD_LAUNCH_PROGRESS: "1",
34
42
  },
35
43
  },
36
44
  });
@@ -126,7 +126,7 @@ test("loads every Cost Monitor tab before returning to Operation", async ({ page
126
126
 
127
127
  async function expectGlobalMonthPreset(page: import("@playwright/test").Page) {
128
128
  await expect(
129
- page.locator(".dashboard-global-controls").getByRole("combobox", { name: "Período" }),
129
+ page.locator(".dashboard-global-controls").getByLabel("Período"),
130
130
  ).toHaveValue("this-month");
131
131
  }
132
132
 
@@ -156,6 +156,10 @@ async function openAllTimeCostMonitor(page: Page) {
156
156
  );
157
157
  await page.goto("/?token=e2e-token");
158
158
  await operations;
159
+ await page
160
+ .getByRole("navigation", { name: "Áreas do dashboard" })
161
+ .getByRole("button", { name: /Operação/ })
162
+ .click();
159
163
  const period = page
160
164
  .locator(".dashboard-global-controls")
161
165
  .getByRole("combobox", { name: "Período" });
@@ -0,0 +1,238 @@
1
+ import { expect, type Page, test } from "@playwright/test";
2
+
3
+ const COST_MONITOR_PATH = "/api/v2/cost-monitor";
4
+ const STALE_SUMMARY_SENTINEL = "SENTINELA-RESPOSTA-ANTIGA";
5
+ const fiveSeconds = 5_000;
6
+
7
+ test("refreshes Cost Monitor within five seconds when Todo o Período is selected in place", async ({
8
+ page,
9
+ }) => {
10
+ await openDashboard(page);
11
+ await openCostMonitor(page);
12
+
13
+ const summary = waitForCostSummary(page, "all");
14
+ const startedAt = Date.now();
15
+ await periodControl(page).selectOption("all");
16
+ await summary;
17
+ await expectCostMonitorReady(page);
18
+
19
+ expect(Date.now() - startedAt).toBeLessThan(fiveSeconds);
20
+ await expect(periodControl(page)).toHaveValue("all");
21
+ });
22
+
23
+ test("loads Cost Monitor within five seconds when the user enters after choosing Todo o Período", async ({
24
+ page,
25
+ }) => {
26
+ await openDashboard(page);
27
+
28
+ await page
29
+ .getByRole("navigation", { name: "Áreas do dashboard" })
30
+ .getByRole("button", { name: /Operação/ })
31
+ .click();
32
+ await expect(periodControl(page)).toBeVisible();
33
+
34
+ await periodControl(page).selectOption("all");
35
+ await expect(page.locator(".period-transition-overlay")).toHaveCount(0, { timeout: 60_000 });
36
+
37
+ const summary = waitForCostSummary(page, "all");
38
+ const startedAt = Date.now();
39
+ await page
40
+ .getByRole("navigation", { name: "Áreas do dashboard" })
41
+ .getByRole("button", { name: /Monitor de Custos/ })
42
+ .click();
43
+ await summary;
44
+ await expectCostMonitorReady(page);
45
+
46
+ expect(Date.now() - startedAt).toBeLessThan(fiveSeconds);
47
+ });
48
+
49
+ test("shows one retry after a summary 503 and does not retry in a loop", async ({ page }) => {
50
+ let summaries = 0;
51
+ await page.route("**/api/v2/cost-monitor**", async (route) => {
52
+ const url = new URL(route.request().url());
53
+ if (url.searchParams.get("scope") !== "summary") return route.continue();
54
+ summaries += 1;
55
+ if (summaries === 1)
56
+ return route.fulfill({
57
+ status: 503,
58
+ contentType: "application/json",
59
+ body: JSON.stringify({ error: "summary temporarily unavailable" }),
60
+ });
61
+ return route.continue();
62
+ });
63
+
64
+ await openDashboard(page);
65
+ await openCostMonitor(page, false);
66
+ const retry = page.locator(".app-loading-panel-error").getByRole("button", {
67
+ name: "Tentar novamente",
68
+ });
69
+ await expect(retry).toBeVisible();
70
+
71
+ await retry.click();
72
+ await expectCostMonitorReady(page);
73
+ await page.waitForTimeout(750);
74
+ expect(summaries).toBe(2);
75
+ });
76
+
77
+ test("does not let a late all-time summary overwrite the newer period", async ({ page }) => {
78
+ let priorPeriodBody: string | null = null;
79
+ page.on("response", (response) => {
80
+ const url = new URL(response.url());
81
+ if (
82
+ response.status() === 200 &&
83
+ url.pathname === COST_MONITOR_PATH &&
84
+ url.searchParams.get("scope") === "summary" &&
85
+ url.searchParams.has("from")
86
+ )
87
+ void response.text().then((body) => {
88
+ priorPeriodBody ??= body;
89
+ });
90
+ });
91
+ await page.addInitScript(() => {
92
+ type Probe = {
93
+ allTimeBody: string | null;
94
+ allTimeFinished: boolean;
95
+ allTimeStarted: boolean;
96
+ releaseAllTime: null | (() => Promise<void>);
97
+ };
98
+ const probe: Probe = {
99
+ allTimeBody: null,
100
+ allTimeFinished: false,
101
+ allTimeStarted: false,
102
+ releaseAllTime: null,
103
+ };
104
+ const originalFetch = window.fetch.bind(window);
105
+ Object.assign(window, { __costSummaryStaleProbe: probe });
106
+ window.fetch = (input, init) => {
107
+ const url = new URL(
108
+ typeof input === "string" ? input : input instanceof URL ? input.href : input.url,
109
+ window.location.href,
110
+ );
111
+ const isAllTimeSummary =
112
+ url.pathname === "/api/v2/cost-monitor" &&
113
+ url.searchParams.get("scope") === "summary" &&
114
+ !url.searchParams.has("from") &&
115
+ !url.searchParams.has("to");
116
+ if (!isAllTimeSummary || probe.allTimeStarted) return originalFetch(input, init);
117
+
118
+ probe.allTimeStarted = true;
119
+ return new Promise<Response>((resolve, reject) => {
120
+ probe.releaseAllTime = async () => {
121
+ try {
122
+ resolve(
123
+ new Response(probe.allTimeBody, {
124
+ headers: { "content-type": "application/json" },
125
+ status: 200,
126
+ }),
127
+ );
128
+ } catch (error) {
129
+ reject(error);
130
+ } finally {
131
+ probe.allTimeFinished = true;
132
+ }
133
+ };
134
+ });
135
+ };
136
+ });
137
+
138
+ await openDashboard(page);
139
+ await openCostMonitor(page);
140
+ await expect.poll(() => priorPeriodBody).not.toBeNull();
141
+ const staleBody = withStaleSummarySentinel(priorPeriodBody!);
142
+ await page.evaluate((body) => {
143
+ window.__costSummaryStaleProbe.allTimeBody = body;
144
+ }, staleBody);
145
+
146
+ await periodControl(page).selectOption("all");
147
+ await expect
148
+ .poll(() => page.evaluate(() => window.__costSummaryStaleProbe.allTimeStarted))
149
+ .toBe(true);
150
+
151
+ const latestSummary = waitForCostSummary(page, "this-month");
152
+ await periodControl(page).selectOption("this-month");
153
+ await page.evaluate(async () => await window.__costSummaryStaleProbe.releaseAllTime?.());
154
+ await expect
155
+ .poll(() => page.evaluate(() => window.__costSummaryStaleProbe.allTimeFinished))
156
+ .toBe(true);
157
+ await latestSummary;
158
+ await expect(periodControl(page)).toHaveValue("this-month");
159
+ await expectCostMonitorReady(page);
160
+ await expect(page.locator(".cost-content-daily")).not.toContainText(STALE_SUMMARY_SENTINEL);
161
+ });
162
+
163
+ declare global {
164
+ interface Window {
165
+ __costSummaryStaleProbe: {
166
+ allTimeBody: string | null;
167
+ allTimeFinished: boolean;
168
+ allTimeStarted: boolean;
169
+ releaseAllTime: null | (() => Promise<void>);
170
+ };
171
+ }
172
+ }
173
+
174
+ async function openDashboard(page: Page) {
175
+ const operations = page.waitForResponse(
176
+ (response) =>
177
+ response.status() === 200 &&
178
+ response.url().includes("/api/v2/operations") &&
179
+ response.url().includes("scope=quick"),
180
+ );
181
+ await page.goto("/?token=e2e-token");
182
+ await operations;
183
+ }
184
+
185
+ async function openCostMonitor(page: Page, expectReady = true) {
186
+ const summary = expectReady ? waitForCostSummary(page, "this-month") : null;
187
+ await page
188
+ .getByRole("navigation", { name: "Áreas do dashboard" })
189
+ .getByRole("button", { name: /Monitor de Custos/ })
190
+ .click();
191
+ if (!expectReady) return;
192
+ await summary;
193
+ await expectCostMonitorReady(page);
194
+ }
195
+
196
+ function periodControl(page: Page) {
197
+ return page.locator(".dashboard-global-controls").getByRole("combobox", { name: "Período" });
198
+ }
199
+
200
+ function waitForCostSummary(page: Page, preset: "all" | "this-month") {
201
+ return page.waitForResponse((response) => {
202
+ if (response.status() !== 200) return false;
203
+ const url = new URL(response.url());
204
+ if (url.pathname !== COST_MONITOR_PATH || url.searchParams.get("scope") !== "summary")
205
+ return false;
206
+ return preset === "all"
207
+ ? !url.searchParams.has("from") && !url.searchParams.has("to")
208
+ : url.searchParams.has("from") && url.searchParams.has("to");
209
+ });
210
+ }
211
+
212
+ async function expectCostMonitorReady(page: Page) {
213
+ await expect(page.locator(".cost-tabs")).toBeVisible({ timeout: fiveSeconds });
214
+ const dailyTable = page.locator(".cost-content-daily table");
215
+ await expect(dailyTable).toBeVisible({ timeout: fiveSeconds });
216
+ await expect(dailyTable).not.toHaveAttribute("aria-busy", "true");
217
+ await expect(page.locator(".cost-content-daily tbody tr").first()).toBeVisible({
218
+ timeout: fiveSeconds,
219
+ });
220
+ await expect(page.locator(".app-loading-panel[aria-busy='true']")).toHaveCount(0);
221
+ await expect(page.locator(".period-transition-overlay")).toHaveCount(0);
222
+ }
223
+
224
+ function withStaleSummarySentinel(body: string) {
225
+ const projection = JSON.parse(body) as {
226
+ groups?: { daily?: Array<{ key: string; label: string }> };
227
+ };
228
+ const firstDailyRow = projection.groups?.daily?.[0];
229
+ if (firstDailyRow === undefined)
230
+ throw new Error(
231
+ "The Cost summary fixture must contain a daily row for stale-response detection.",
232
+ );
233
+ projection.groups!.daily = [
234
+ { ...firstDailyRow, key: STALE_SUMMARY_SENTINEL, label: STALE_SUMMARY_SENTINEL },
235
+ ...projection.groups!.daily!,
236
+ ];
237
+ return JSON.stringify(projection);
238
+ }
@@ -174,6 +174,10 @@ async function openDashboard(page: Page) {
174
174
  }
175
175
 
176
176
  async function selectPeriod(page: Page, period: "this-month" | "all") {
177
+ await page
178
+ .getByRole("navigation", { name: "Áreas do dashboard" })
179
+ .getByRole("button", { name: /Operação/ })
180
+ .click();
177
181
  const control = page
178
182
  .locator(".dashboard-global-controls")
179
183
  .getByRole("combobox", { name: "Período" });
@@ -163,7 +163,12 @@ test("exports Kanban, Lista and Cost Monitor through a save picker while the das
163
163
  });
164
164
 
165
165
  test("renders the modern read-only dashboard and meets accessibility gates", async ({ page }) => {
166
- await openDashboard(page);
166
+ const initialResponse = await openDashboard(page);
167
+ const globalPeriod = page.getByRole("combobox", { name: /Per/ }).first();
168
+ await expect(globalPeriod).toHaveValue("all");
169
+ const initialUrl = new URL(initialResponse.url());
170
+ expect(initialUrl.searchParams.has("from")).toBe(false);
171
+ expect(initialUrl.searchParams.has("to")).toBe(false);
167
172
  await expect(page.getByRole("navigation", { name: "Dashboard Zaip AIOS menu" })).toBeVisible();
168
173
  const capabilityNav = page.getByRole("navigation", { name: "Áreas do dashboard" });
169
174
  const globalControls = page.locator(".dashboard-global-controls");
@@ -179,6 +184,13 @@ test("renders the modern read-only dashboard and meets accessibility gates", asy
179
184
  buttons.map((button) => button.getBoundingClientRect().top),
180
185
  );
181
186
  expect(new Set(buttonBoxes.map((top) => Math.round(top))).size).toBe(1);
187
+ await expect(globalControls.getByRole("textbox", { name: "Busca" })).toBeHidden();
188
+ await expect(globalControls.getByLabel("Data inicial")).toBeHidden();
189
+ await expect(globalControls.getByLabel("Data final")).toBeHidden();
190
+ await expect(globalControls.getByRole("combobox", { name: "Período" })).toBeHidden();
191
+ await expect(page.getByLabel("Kanban de trabalho")).toHaveCount(0);
192
+ await expect(page.locator(".operations-task-card")).toHaveCount(0);
193
+ await selectOperations(page);
182
194
  const searchInput = globalControls.getByRole("textbox", { name: "Busca" });
183
195
  await expect(searchInput).toBeVisible();
184
196
  await expect(globalControls.getByRole("button", { name: "Limpar busca" })).toHaveCount(0);
@@ -204,9 +216,6 @@ test("renders the modern read-only dashboard and meets accessibility gates", asy
204
216
  elements.map((element) => Math.round(element.getBoundingClientRect().bottom)),
205
217
  );
206
218
  expect(new Set(controlRowBottoms).size).toBe(1);
207
- await expect(page.getByLabel("Kanban de trabalho")).toHaveCount(0);
208
- await expect(page.locator(".operations-task-card")).toHaveCount(0);
209
- await selectOperations(page);
210
219
  await expect(page.getByLabel("Kanban de trabalho")).toBeVisible();
211
220
  await expect(page.locator(".operations-risk.is-standard").first()).toBeVisible();
212
221
  const visibleCards = page.locator(".operations-task-card:visible");
@@ -233,7 +242,7 @@ test("renders the modern read-only dashboard and meets accessibility gates", asy
233
242
  const period = globalControls.getByRole("combobox", { name: "Período" });
234
243
  await expect(startDate).toHaveValue(/^\d{4}-\d{2}-\d{2}$/);
235
244
  await expect(endDate).toHaveValue(/^\d{4}-\d{2}-\d{2}$/);
236
- await expect(period).toHaveValue("this-month");
245
+ await expect(period).toHaveValue("all");
237
246
  const initialStart = await startDate.inputValue();
238
247
  const today = await endDate.inputValue();
239
248
  await expect(page.getByLabel("Data inicial nos filtros")).toHaveValue(initialStart);
@@ -263,6 +272,13 @@ test("renders the modern read-only dashboard and meets accessibility gates", asy
263
272
 
264
273
  const results = await new AxeBuilder({ page }).analyze();
265
274
  expect(results.violations).toEqual([]);
275
+
276
+ await capabilityNav.getByRole("button", { name: /Monitor de Custos/ }).click();
277
+ await expect(page.locator(".cost-tabs")).toBeVisible();
278
+ await expect(searchInput).toBeVisible();
279
+ await expect(startDate).toBeVisible();
280
+ await expect(endDate).toBeVisible();
281
+ await expect(period).toBeVisible();
266
282
  });
267
283
 
268
284
  test("loads a quick Operations summary without full snapshot hydration", async ({ page }) => {
@@ -274,6 +290,7 @@ test("loads a quick Operations summary without full snapshot hydration", async (
274
290
  });
275
291
 
276
292
  await openDashboard(page);
293
+ await selectPopulatedAllTime(page);
277
294
  expect(operationsRequests.some((url) => url.includes("scope=quick"))).toBe(true);
278
295
  expect(operationsRequests.some((url) => url.includes("scope=detail"))).toBe(false);
279
296
  expect(operationsRequests.some((url) => url.includes("/snapshot"))).toBe(false);
@@ -403,6 +420,7 @@ test("embeds traceability and keeps global settings and help available", async (
403
420
 
404
421
  test("groups macro work in All and reveals descendant Tasks only in Tasks", async ({ page }) => {
405
422
  await openDashboard(page);
423
+ await selectPopulatedAllTime(page);
406
424
  await selectOperations(page);
407
425
  const board = page.getByLabel("Kanban de trabalho");
408
426
  await expect(board.locator(".operations-task-card").first()).toBeVisible();
@@ -448,10 +466,14 @@ test("groups macro work in All and reveals descendant Tasks only in Tasks", asyn
448
466
  }
449
467
  });
450
468
 
451
- test("shows the observed default-month macro duration consistently for SPEC and PRD", async ({
469
+ test("shows the observed all-time macro duration consistently for SPEC and PRD", async ({
452
470
  page,
453
471
  }) => {
454
472
  const response = await openDashboard(page);
473
+ await expect(page.getByRole("combobox", { name: /Per/ }).first()).toHaveValue("all");
474
+ const responseUrl = new URL(response.url());
475
+ expect(responseUrl.searchParams.has("from")).toBe(false);
476
+ expect(responseUrl.searchParams.has("to")).toBe(false);
455
477
  const projection = (await response.json()) as {
456
478
  summary: {
457
479
  overview_metrics?: {
@@ -466,8 +488,6 @@ test("shows the observed default-month macro duration consistently for SPEC and
466
488
  };
467
489
  };
468
490
  };
469
- await expect(page.getByRole("combobox", { name: /Per/ }).first()).toHaveValue("this-month");
470
-
471
491
  for (const kind of ["SPECs", "PRDs"] as const) {
472
492
  const macroKey = kind === "SPECs" ? "specs" : "prds";
473
493
  const macroMetric = projection.summary.overview_metrics?.macro_metrics?.[macroKey];
@@ -521,20 +541,26 @@ test("loads monthly overview quickly and keeps PRD and SPEC chart totals reconci
521
541
  page,
522
542
  }) => {
523
543
  const openedAt = Date.now();
524
- await openDashboard(page);
544
+ const initialQuickResponse = await openDashboard(page);
525
545
  expect(Date.now() - openedAt).toBeLessThan(3_000);
546
+ await selectOperations(page);
526
547
 
527
548
  const period = page.getByRole("combobox", { name: /Per/ }).first();
528
549
  for (const preset of ["all", "this-month"] as const) {
529
- const response = page.waitForResponse(
530
- (candidate) =>
531
- candidate.status() === 200 &&
532
- candidate.url().includes("/api/v2/operations") &&
533
- candidate.url().includes("scope=quick"),
534
- );
535
550
  const selectedAt = Date.now();
536
- await period.selectOption(preset);
537
- const quickResponse = await response;
551
+ const quickResponse =
552
+ preset === "all"
553
+ ? initialQuickResponse
554
+ : await (async () => {
555
+ const response = page.waitForResponse(
556
+ (candidate) =>
557
+ candidate.status() === 200 &&
558
+ candidate.url().includes("/api/v2/operations") &&
559
+ candidate.url().includes("scope=quick"),
560
+ );
561
+ await period.selectOption(preset);
562
+ return response;
563
+ })();
538
564
  const quickUrl = new URL(quickResponse.url());
539
565
  const dateControls = page.locator(".dashboard-global-controls");
540
566
  const expectedFrom =
@@ -654,6 +680,23 @@ async function openDashboard(page: import("@playwright/test").Page) {
654
680
  return operations;
655
681
  }
656
682
 
683
+ async function selectPopulatedAllTime(page: import("@playwright/test").Page) {
684
+ const response = page.waitForResponse((candidate) => {
685
+ if (
686
+ candidate.status() !== 200 ||
687
+ !candidate.url().includes("/api/v2/operations") ||
688
+ !candidate.url().includes("scope=quick")
689
+ ) {
690
+ return false;
691
+ }
692
+ const url = new URL(candidate.url());
693
+ return !url.searchParams.has("from") && !url.searchParams.has("to");
694
+ });
695
+ await selectOperations(page);
696
+ await page.getByRole("combobox", { name: /Per/ }).first().selectOption("all");
697
+ return response;
698
+ }
699
+
657
700
  async function selectOperations(page: import("@playwright/test").Page) {
658
701
  await page
659
702
  .getByRole("navigation", { name: "Áreas do dashboard" })
@@ -6,7 +6,7 @@ title: Garantia adaptativa e execução autônoma
6
6
  status: active
7
7
  version: 3
8
8
  source_change: null
9
- source_release: "1.3.2"
9
+ source_release: "1.3.5"
10
10
  ---
11
11
 
12
12
  # Garantia adaptativa e execução autônoma
@@ -6,7 +6,7 @@ title: Auditoria comparativa e plano de evolução
6
6
  status: active
7
7
  version: 1
8
8
  source_change: null
9
- source_release: "1.3.2"
9
+ source_release: "1.3.5"
10
10
  ---
11
11
 
12
12
  # Auditoria comparativa e plano de evolução
@@ -6,7 +6,7 @@ title: Contexto mínimo, seguro e navegável
6
6
  status: active
7
7
  version: 8
8
8
  source_change: null
9
- source_release: "1.3.2"
9
+ source_release: "1.3.5"
10
10
  ---
11
11
 
12
12
  # Context engine
@@ -6,7 +6,7 @@ title: Tokens, custos e cobertura
6
6
  status: active
7
7
  version: 10
8
8
  source_change: null
9
- source_release: "1.3.2"
9
+ source_release: "1.3.5"
10
10
  ---
11
11
 
12
12
  # Cost observability
@@ -6,7 +6,7 @@ title: Inicialização e hidratação confiável do dashboard
6
6
  status: active
7
7
  version: 1
8
8
  source_change: null
9
- source_release: "1.3.2"
9
+ source_release: "1.3.5"
10
10
  ---
11
11
 
12
12
  # Inicialização e hidratação confiável do dashboard
@@ -6,7 +6,7 @@ title: Exportação contextual de dados para Excel
6
6
  status: proposed
7
7
  version: 2
8
8
  source_change: null
9
- source_release: "1.3.2"
9
+ source_release: "1.3.5"
10
10
  ---
11
11
 
12
12
  # Exportação contextual de dados
@@ -6,7 +6,7 @@ title: Contrato visual e catálogo executável
6
6
  status: active
7
7
  version: 3
8
8
  source_change: null
9
- source_release: "1.3.2"
9
+ source_release: "1.3.5"
10
10
  ---
11
11
 
12
12
  # Design system
@@ -6,7 +6,7 @@ title: Preparação, materialização e DAG
6
6
  status: active
7
7
  version: 11
8
8
  source_change: null
9
- source_release: "1.3.2"
9
+ source_release: "1.3.5"
10
10
  ---
11
11
 
12
12
  # Execution engine
@@ -6,7 +6,7 @@ title: Projeções operacionais e analíticas
6
6
  status: active
7
7
  version: 14
8
8
  source_change: null
9
- source_release: "1.3.2"
9
+ source_release: "1.3.5"
10
10
  ---
11
11
 
12
12
  # Kanban and dashboard
@@ -6,7 +6,7 @@ title: Seleção automática e observável de modelo e effort
6
6
  status: active
7
7
  version: 7
8
8
  source_change: null
9
- source_release: "1.3.2"
9
+ source_release: "1.3.5"
10
10
  ---
11
11
 
12
12
  # Orquestração de modelos
@@ -6,7 +6,7 @@ title: Distribuição pública e ativação
6
6
  status: active
7
7
  version: 3
8
8
  source_change: null
9
- source_release: "1.3.2"
9
+ source_release: "1.3.5"
10
10
  ---
11
11
 
12
12
  # Distribuição pública e ativação
@@ -6,7 +6,7 @@ title: Layout modular e limites de código-fonte
6
6
  status: active
7
7
  version: 5
8
8
  source_change: null
9
- source_release: "1.3.2"
9
+ source_release: "1.3.5"
10
10
  ---
11
11
 
12
12
  # Software architecture
@@ -6,7 +6,7 @@ title: Melhorias estratégicas de custo, qualidade e resiliência
6
6
  status: active
7
7
  version: 1
8
8
  source_change: null
9
- source_release: "1.3.2"
9
+ source_release: "1.3.5"
10
10
  ---
11
11
 
12
12
  # Melhorias estratégicas de custo, qualidade e resiliência
@@ -6,7 +6,7 @@ title: Ciclo de vida do trabalho
6
6
  status: active
7
7
  version: 24
8
8
  source_change: null
9
- source_release: "1.3.2"
9
+ source_release: "1.3.5"
10
10
  ---
11
11
 
12
12
  # Work lifecycle
@@ -6,7 +6,7 @@ title: Evidências, custo por Task e autonomia por SPEC
6
6
  status: active
7
7
  version: 1
8
8
  source_change: null
9
- source_release: "1.3.2"
9
+ source_release: "1.3.5"
10
10
  ---
11
11
 
12
12
  # Evidências, custo por Task e autonomia por SPEC