@zaip-ai/cli 1.3.1 → 1.3.4
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/LICENSE +6 -3
- package/README.md +11 -4
- package/dist/services/codex-pre-tool-hook-template.js +1 -1
- package/dist/services/runtime-template.test.js +9 -8
- package/dist/services/runtime-template.test.js.map +1 -1
- package/package.json +2 -2
- package/templates/.agents/dashboard/.zaip-managed.json +403 -383
- package/templates/.agents/dashboard/apps/frontend/dist/assets/{CostCalculationGuidePage-ovxurkIk.js → CostCalculationGuidePage-BZWjXQB-.js} +1 -1
- package/templates/.agents/dashboard/apps/frontend/dist/assets/{DashboardHelpDialog-BgVgrfhQ.js → DashboardHelpDialog-D8qqeIPE.js} +58 -1
- package/templates/.agents/dashboard/apps/frontend/dist/assets/{PricingSettingsDialog-vSvvOHQp.js → PricingSettingsDialog-Cm12_A0v.js} +1 -1
- package/templates/.agents/dashboard/apps/frontend/dist/assets/{ProjectSettingsPage-zH758vfs.js → ProjectSettingsPage-DxO9F8B4.js} +1 -1
- package/templates/.agents/dashboard/apps/frontend/dist/assets/{TraceabilityWorkspace-DLn-Mz2M.js → TraceabilityWorkspace-_x0twOcS.js} +1 -1
- package/templates/.agents/dashboard/apps/frontend/dist/assets/cost-monitor-Cpp8xFij.js +68 -0
- package/templates/.agents/dashboard/apps/frontend/dist/assets/{icons-vendor-B_lDDHn1.js → icons-vendor-CR4Fbf3g.js} +1 -1
- package/templates/.agents/dashboard/apps/frontend/dist/assets/index-ncC1rxap.js +2 -0
- package/templates/.agents/dashboard/apps/frontend/dist/assets/{react-vendor-B3TJrD4O.js → react-vendor-DRJQbKnp.js} +1 -1
- package/templates/.agents/dashboard/apps/frontend/dist/assets/{traceability-7f1j5wx3.js → traceability-CMrDYqjR.js} +1 -1
- package/templates/.agents/dashboard/apps/frontend/dist/index.html +5 -5
- package/templates/.agents/dashboard/apps/frontend/src/App.tsx +48 -3
- package/templates/.agents/dashboard/apps/frontend/src/AppRequestGuards.tsx +44 -0
- package/templates/.agents/dashboard/apps/frontend/src/cost-period-refresh.test.ts +92 -1
- package/templates/.agents/dashboard/apps/frontend/src/snapshot-coherence.test.ts +2 -2
- package/templates/.agents/dashboard/modules/cost-monitor/src/react/CostDeveloperAttributionPanel.test.ts +60 -0
- package/templates/.agents/dashboard/modules/cost-monitor/src/react/CostDeveloperAttributionPanel.tsx +26 -9
- package/templates/.agents/dashboard/modules/cost-monitor/src/react/CostMonitorNavigation.tsx +189 -0
- package/templates/.agents/dashboard/modules/cost-monitor/src/react/CostMonitorPage.test.ts +122 -2
- package/templates/.agents/dashboard/modules/cost-monitor/src/react/CostMonitorPage.tsx +70 -155
- package/templates/.agents/dashboard/modules/operations/src/react/export/ExcelExportAction.test.ts +59 -0
- package/templates/.agents/dashboard/modules/operations/src/react/export/ExcelExportAction.tsx +55 -2
- package/templates/.agents/dashboard/packages/local-runtime/dist/server.cjs +274 -246
- package/templates/.agents/dashboard/packages/local-runtime/dist/sqlite-read-model.cjs +255 -227
- package/templates/.agents/dashboard/packages/local-runtime/server.mjs +263 -235
- package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-cost-dimension-facts.test.ts +282 -0
- package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-cost-dimension-facts.ts +71 -0
- package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-operations-work-list.test.ts +70 -0
- package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-operations-work-list.ts +74 -7
- package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-read-model-launch-progress.ts +18 -0
- package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-read-model-stale-seed.ts +50 -0
- package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-read-model.test.ts +9 -6
- package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-read-model.ts +45 -73
- package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-snapshot-seed.test.ts +79 -2
- package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-work-item-index.test.ts +56 -0
- package/templates/.agents/dashboard/packages/local-runtime/start-dashboard-launch-page.mjs +26 -8
- package/templates/.agents/dashboard/packages/local-runtime/start-dashboard-launch-page.test.mjs +45 -4
- package/templates/.agents/dashboard/packages/local-runtime/start-dashboard-lifecycle.mjs +58 -0
- package/templates/.agents/dashboard/packages/local-runtime/start-dashboard-lifecycle.test.mjs +81 -0
- package/templates/.agents/dashboard/packages/local-runtime/start-dashboard.mjs +171 -71
- package/templates/.agents/dashboard/packages/local-runtime/start-dashboard.test.mjs +152 -11
- package/templates/.agents/dashboard/packages/windows-launcher/Program.cs +4 -9
- package/templates/.agents/dashboard/tests/e2e/playwright.config.ts +9 -1
- package/templates/.agents/dashboard/tests/e2e/specs/cost-monitor-period-transition.spec.ts +232 -0
- package/templates/.agents/dashboard/tests/e2e/specs/dashboard.spec.ts +26 -5
- 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/bin/zaip.mjs +7 -7
- package/templates/.agents/runtime/checksums.sha256 +3 -3
- package/templates/.agents/runtime/provenance.json +3 -3
- package/templates/.agents/runtime/sbom.cdx.json +1595 -3491
- package/templates/.agents/skills/zaip-skill-lifecycle-closure/SKILL.md +16 -0
- package/templates/.agents/skills/zaip-skill-reconcile-telemetry/scripts/reconcile-local-telemetry.mjs +19 -20
- package/templates/.agents/skills/zaip-skill-reconcile-telemetry/scripts/reconcile-local-telemetry.test.mjs +143 -0
- package/templates/.agents/skills/zaip-skill-reconcile-telemetry/scripts/reconcile-telemetry-lib.mjs +14 -0
- package/templates/.agents/skills/zaip-skill-reconcile-telemetry/scripts/reconcile-telemetry-remeasurement.mjs +3 -1
- package/templates/.agents/skills/zaip-skill-reconcile-telemetry/scripts/reconcile-telemetry-remeasurement.test.mjs +21 -0
- package/templates/.agents/skills/zaip-skill-reconcile-telemetry/scripts/source-size-telemetry/model-identity-reconciliation.mjs +3 -0
- package/templates/.agents/zaip-aios/guides/26-qualidade-e-release.md +44 -0
- package/templates/template-manifest.json +536 -932
- package/templates/.agents/dashboard/.tmp-run-list.json +0 -254
- package/templates/.agents/dashboard/apps/frontend/dist/assets/cost-monitor-DKwP1stV.js +0 -68
- package/templates/.agents/dashboard/apps/frontend/dist/assets/index-CZQlsLV9.js +0 -2
|
@@ -22,6 +22,22 @@ the supplied ID and canonical record; never scan ordinary history to guess a tar
|
|
|
22
22
|
5. Persist observed evidence before terminal Task, Change, and Execution state; refresh
|
|
23
23
|
manifests before the root Run outcome. Report technical success and formal closure
|
|
24
24
|
separately.
|
|
25
|
+
6. Inventory every affected ID, including prerequisites, failed preparations and retries.
|
|
26
|
+
Before the last finalizer, verify their canonical states, not only the current root.
|
|
27
|
+
After failed creation or missing manifest entries, rebuild the manifest and compare
|
|
28
|
+
it with the canonical records. A finished Run is not proof that its Task, Change,
|
|
29
|
+
Execution, or sibling work has closed.
|
|
30
|
+
7. Explicit recovery of confirmed inactive legacy work uses `run reconcile --open`
|
|
31
|
+
with `--orphan-reason inactive_terminal_without_host_identity` and
|
|
32
|
+
`--orphan-scope` containing the reviewed Run/Task/Execution IDs. Preserve the current
|
|
33
|
+
delivery and other active work. Do not widen an ID list to `all`, infer inactivity
|
|
34
|
+
from missing metadata alone, or invent host identity. Persist the reason for blocking
|
|
35
|
+
work without completion evidence. Re-run the same scope to verify idempotence.
|
|
36
|
+
8. Check source, generated files, framework lock, and evidence scopes before starting
|
|
37
|
+
an implementation. Reuse the current delivery for its own recovery; do not create
|
|
38
|
+
a chain of cleanup Tasks to compensate for an incomplete scope or preparation error.
|
|
39
|
+
Await every delegated result, make the finalizer the last child, and only report
|
|
40
|
+
closure after all owned work is terminal. A progress handoff is not completion.
|
|
25
41
|
|
|
26
42
|
Use `$zaip-skill-reconcile-telemetry` only for missing observed usage after lifecycle
|
|
27
43
|
identity is correct; it is not a substitute for closure.
|
|
@@ -20,6 +20,7 @@ import {
|
|
|
20
20
|
recordSequence,
|
|
21
21
|
recordType,
|
|
22
22
|
sameCost,
|
|
23
|
+
selectedRunIdsFromArgs,
|
|
23
24
|
supersedableUsageBeforeTerminal,
|
|
24
25
|
usageStatus,
|
|
25
26
|
usageView,
|
|
@@ -42,17 +43,7 @@ const explicitRecovery = process.argv.includes("--explicit-turn-recovery");
|
|
|
42
43
|
if (timingOnly && !remeasure) {
|
|
43
44
|
throw new Error("--timing-only requires --remeasure");
|
|
44
45
|
}
|
|
45
|
-
const selectedRunIds =
|
|
46
|
-
process.argv.flatMap((argument, index, values) =>
|
|
47
|
-
argument === "--run"
|
|
48
|
-
? String(values[index + 1] ?? "")
|
|
49
|
-
.split(",")
|
|
50
|
-
.filter(Boolean)
|
|
51
|
-
: argument.startsWith("--run=")
|
|
52
|
-
? argument.slice("--run=".length).split(",").filter(Boolean)
|
|
53
|
-
: [],
|
|
54
|
-
),
|
|
55
|
-
);
|
|
46
|
+
const selectedRunIds = selectedRunIdsFromArgs(process.argv);
|
|
56
47
|
const selectedSessionFiles = process.argv
|
|
57
48
|
.flatMap((argument, index, values) =>
|
|
58
49
|
argument === "--session-file"
|
|
@@ -75,6 +66,7 @@ if (apply && deduplicate && selectedRunIds.size === 0) {
|
|
|
75
66
|
throw new Error("--apply --deduplicate requires at least one explicit --run <RUN-ID>");
|
|
76
67
|
}
|
|
77
68
|
const applyBackfill = apply && !deduplicate && !remeasure && !explicitRecovery;
|
|
69
|
+
const appliesToRun = (runId) => selectedRunIds.size === 0 || selectedRunIds.has(runId);
|
|
78
70
|
|
|
79
71
|
const runFiles = await filesUnder(join(workspace, ".agents", "records", "runs"), ".jsonl");
|
|
80
72
|
const runs = [];
|
|
@@ -82,6 +74,8 @@ const usedKeys = new Set();
|
|
|
82
74
|
let danglingSupersessionRepairs = 0;
|
|
83
75
|
for (const file of runFiles) {
|
|
84
76
|
let records = jsonLines(await readFile(file, "utf8"));
|
|
77
|
+
const started = records.find((record) => recordType(record) === "run.started");
|
|
78
|
+
const applyToCurrentRun = appliesToRun(started?.run_id);
|
|
85
79
|
const finishedRecord = records.find((record) => recordType(record) === "run.finished");
|
|
86
80
|
const canonicalCorrectionTime = finishedRecord
|
|
87
81
|
? new Date(Date.parse(recordOccurredAt(finishedRecord)) - 1).toISOString()
|
|
@@ -93,7 +87,7 @@ for (const file of runFiles) {
|
|
|
93
87
|
usageView(record)?.activity_kind === "retrospective_local_reconciliation" &&
|
|
94
88
|
recordOccurredAt(record) !== canonicalCorrectionTime,
|
|
95
89
|
);
|
|
96
|
-
if (applyBackfill && staleCorrectionTime) {
|
|
90
|
+
if (applyBackfill && applyToCurrentRun && staleCorrectionTime) {
|
|
97
91
|
records = records.map((record) =>
|
|
98
92
|
usageView(record)?.activity_kind === "retrospective_local_reconciliation"
|
|
99
93
|
? { ...record, occurred_at: canonicalCorrectionTime }
|
|
@@ -116,7 +110,7 @@ for (const file of runFiles) {
|
|
|
116
110
|
.map((usage) => usage.supersedes_event_id)
|
|
117
111
|
.filter(Boolean),
|
|
118
112
|
);
|
|
119
|
-
if (applyBackfill && nativeMeasured)
|
|
113
|
+
if (applyBackfill && applyToCurrentRun && nativeMeasured)
|
|
120
114
|
records = records.filter((record) => {
|
|
121
115
|
const usage = usageView(record);
|
|
122
116
|
return (
|
|
@@ -132,7 +126,7 @@ for (const file of runFiles) {
|
|
|
132
126
|
let next = record;
|
|
133
127
|
if (usage.supersedes_event_id !== null && !priorUsageIds.includes(usage.supersedes_event_id)) {
|
|
134
128
|
danglingSupersessionRepairs += 1;
|
|
135
|
-
if (applyBackfill) {
|
|
129
|
+
if (applyBackfill && applyToCurrentRun) {
|
|
136
130
|
repairedDangling = true;
|
|
137
131
|
const replacement = priorUsageIds.at(-1) ?? null;
|
|
138
132
|
next = Array.isArray(record)
|
|
@@ -147,7 +141,7 @@ for (const file of runFiles) {
|
|
|
147
141
|
priorUsageIds.push(usage.event_id);
|
|
148
142
|
return next;
|
|
149
143
|
});
|
|
150
|
-
if (applyBackfill && repairedDangling) {
|
|
144
|
+
if (applyBackfill && applyToCurrentRun && repairedDangling) {
|
|
151
145
|
const temporary = `${file}.supersession.tmp`;
|
|
152
146
|
await writeFile(
|
|
153
147
|
temporary,
|
|
@@ -163,7 +157,7 @@ for (const file of runFiles) {
|
|
|
163
157
|
index > finishIndex &&
|
|
164
158
|
finishIndex >= 0,
|
|
165
159
|
);
|
|
166
|
-
if (applyBackfill && (misplaced.length || staleCorrectionTime)) {
|
|
160
|
+
if (applyBackfill && applyToCurrentRun && (misplaced.length || staleCorrectionTime)) {
|
|
167
161
|
const retained = records.filter((record) => !misplaced.includes(record));
|
|
168
162
|
const insertAt = retained.findIndex((record) => recordType(record) === "run.finished");
|
|
169
163
|
records = [...retained.slice(0, insertAt), ...misplaced, ...retained.slice(insertAt)];
|
|
@@ -180,6 +174,7 @@ for (const file of runFiles) {
|
|
|
180
174
|
);
|
|
181
175
|
if (
|
|
182
176
|
applyBackfill &&
|
|
177
|
+
applyToCurrentRun &&
|
|
183
178
|
(hasCorrection || nativeMeasured) &&
|
|
184
179
|
records.some((record, index) => recordSequence(record) !== index + 1)
|
|
185
180
|
) {
|
|
@@ -192,7 +187,6 @@ for (const file of runFiles) {
|
|
|
192
187
|
);
|
|
193
188
|
await rename(temporary, file);
|
|
194
189
|
}
|
|
195
|
-
const started = records.find((record) => recordType(record) === "run.started");
|
|
196
190
|
const usage = records.filter((record) => recordType(record) === "usage.recorded").map(usageView);
|
|
197
191
|
for (const event of usage)
|
|
198
192
|
if (event.source_segment_key && event.tokens?.total !== null)
|
|
@@ -264,7 +258,9 @@ const unfinishedMatches = unfinished.map((run) => ({
|
|
|
264
258
|
const finishEligible = unfinishedMatches.filter(({ segment }) => segment !== null);
|
|
265
259
|
const finishAmbiguous = unfinishedMatches.filter(({ ambiguous }) => ambiguous);
|
|
266
260
|
if (applyBackfill) {
|
|
267
|
-
for (const { run, segment } of finishEligible)
|
|
261
|
+
for (const { run, segment } of finishEligible.filter(({ run }) =>
|
|
262
|
+
appliesToRun(run.started.run_id),
|
|
263
|
+
)) {
|
|
268
264
|
const sequence = Math.max(...run.records.map((record) => recordSequence(record) ?? 0)) + 1;
|
|
269
265
|
const finished = {
|
|
270
266
|
schema_version: 2,
|
|
@@ -300,6 +296,7 @@ let repricedEvents = 0;
|
|
|
300
296
|
let repricedRuns = 0;
|
|
301
297
|
if (reprice) {
|
|
302
298
|
for (const run of runs) {
|
|
299
|
+
if (applyBackfill && !appliesToRun(run.started.run_id)) continue;
|
|
303
300
|
const superseded = new Set(run.usage.map((usage) => usage.supersedes_event_id).filter(Boolean));
|
|
304
301
|
const effective = run.usage.filter((usage) => !superseded.has(usage.event_id));
|
|
305
302
|
const corrections = [];
|
|
@@ -361,6 +358,7 @@ if (reprice) {
|
|
|
361
358
|
|
|
362
359
|
const modelIdentityCorrections = await reconcileGenericModelIdentities({
|
|
363
360
|
applyBackfill,
|
|
361
|
+
selectedRunIds,
|
|
364
362
|
pricingFor,
|
|
365
363
|
runs,
|
|
366
364
|
segments: allSegments,
|
|
@@ -703,6 +701,7 @@ const ambiguousRunIds = [
|
|
|
703
701
|
]),
|
|
704
702
|
];
|
|
705
703
|
const matchedIds = new Set(eligible.map(({ run }) => run.started.run_id));
|
|
704
|
+
const scopedFinishEligible = finishEligible.filter(({ run }) => appliesToRun(run.started.run_id));
|
|
706
705
|
const corrections = runs.flatMap((run) =>
|
|
707
706
|
run.usage.filter((usage) => usage.activity_kind === "retrospective_local_reconciliation"),
|
|
708
707
|
);
|
|
@@ -749,7 +748,7 @@ console.log(
|
|
|
749
748
|
missing_before: missing.length,
|
|
750
749
|
unfinished_before: unfinished.length,
|
|
751
750
|
unfinished_finish_eligible: finishEligible.length,
|
|
752
|
-
unfinished_finish_applied: applyBackfill ?
|
|
751
|
+
unfinished_finish_applied: applyBackfill ? scopedFinishEligible.length : 0,
|
|
753
752
|
unfinished_finish_ambiguous: finishAmbiguous.length,
|
|
754
753
|
eligible: eligible.length,
|
|
755
754
|
applied: applyBackfill ? eligible.length : 0,
|
|
@@ -789,7 +788,7 @@ console.log(
|
|
|
789
788
|
model_identity_corrections: modelIdentityCorrections,
|
|
790
789
|
dangling_supersession_repairs: danglingSupersessionRepairs,
|
|
791
790
|
eligible_run_ids: eligible.map(({ run }) => run.started.run_id),
|
|
792
|
-
finish_eligible_run_ids:
|
|
791
|
+
finish_eligible_run_ids: scopedFinishEligible.map(({ run }) => run.started.run_id),
|
|
793
792
|
confidence: Object.fromEntries(
|
|
794
793
|
eligible.map(({ run, confidence }) => [run.started.run_id, confidence]),
|
|
795
794
|
),
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
import assert from "node:assert/strict";
|
|
2
|
+
import { execFile } from "node:child_process";
|
|
3
|
+
import { mkdir, mkdtemp, readFile, rm, writeFile } from "node:fs/promises";
|
|
4
|
+
import { tmpdir } from "node:os";
|
|
5
|
+
import { join } from "node:path";
|
|
6
|
+
import { after, test } from "node:test";
|
|
7
|
+
import { fileURLToPath } from "node:url";
|
|
8
|
+
import { promisify } from "node:util";
|
|
9
|
+
|
|
10
|
+
const roots = [];
|
|
11
|
+
const run = promisify(execFile);
|
|
12
|
+
const script = fileURLToPath(new URL("./reconcile-local-telemetry.mjs", import.meta.url));
|
|
13
|
+
|
|
14
|
+
after(async () => Promise.all(roots.map((root) => rm(root, { recursive: true, force: true }))));
|
|
15
|
+
|
|
16
|
+
test("apply with --run leaves unselected historical corrections byte-identical", async () => {
|
|
17
|
+
const root = await mkdtemp(join(tmpdir(), "zaip-reconcile-scope-"));
|
|
18
|
+
roots.push(root);
|
|
19
|
+
const records = join(root, ".agents", "records", "runs", "2026", "08");
|
|
20
|
+
const selectedFile = join(records, "RUN-SELECTED.jsonl");
|
|
21
|
+
const unselectedFile = join(records, "RUN-UNSELECTED.jsonl");
|
|
22
|
+
const sessionFile = join(root, "selected-session.jsonl");
|
|
23
|
+
|
|
24
|
+
await mkdir(records, { recursive: true });
|
|
25
|
+
|
|
26
|
+
await writeFile(
|
|
27
|
+
selectedFile,
|
|
28
|
+
`${[
|
|
29
|
+
started("RUN-SELECTED", "turn-selected"),
|
|
30
|
+
finished("RUN-SELECTED", "2026-08-31T12:01:00.000Z"),
|
|
31
|
+
]
|
|
32
|
+
.map(JSON.stringify)
|
|
33
|
+
.join("\n")}\n`,
|
|
34
|
+
);
|
|
35
|
+
const unselected = `${[
|
|
36
|
+
started("RUN-UNSELECTED", "turn-unselected"),
|
|
37
|
+
usage("RUN-UNSELECTED:000002", "2026-08-31T12:00:20.000Z", null),
|
|
38
|
+
usage("RUN-UNSELECTED:reconcile:000003", "2026-08-31T12:00:30.000Z", "RUN-UNSELECTED:000002"),
|
|
39
|
+
finished("RUN-UNSELECTED", "2026-08-31T12:01:00.000Z"),
|
|
40
|
+
]
|
|
41
|
+
.map(JSON.stringify)
|
|
42
|
+
.join("\n")}\n`;
|
|
43
|
+
await writeFile(unselectedFile, unselected);
|
|
44
|
+
await writeFile(
|
|
45
|
+
sessionFile,
|
|
46
|
+
`${[
|
|
47
|
+
{
|
|
48
|
+
timestamp: "2026-08-31T12:00:00.000Z",
|
|
49
|
+
type: "session_meta",
|
|
50
|
+
payload: { id: "session", cwd: root },
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
timestamp: "2026-08-31T12:00:01.000Z",
|
|
54
|
+
type: "event_msg",
|
|
55
|
+
payload: { type: "task_started", turn_id: "turn-selected" },
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
timestamp: "2026-08-31T12:00:20.000Z",
|
|
59
|
+
type: "event_msg",
|
|
60
|
+
payload: {
|
|
61
|
+
type: "token_count",
|
|
62
|
+
info: {
|
|
63
|
+
last_token_usage: {
|
|
64
|
+
input_tokens: 10,
|
|
65
|
+
cached_input_tokens: 2,
|
|
66
|
+
output_tokens: 4,
|
|
67
|
+
reasoning_output_tokens: 1,
|
|
68
|
+
total_tokens: 14,
|
|
69
|
+
},
|
|
70
|
+
},
|
|
71
|
+
},
|
|
72
|
+
},
|
|
73
|
+
{
|
|
74
|
+
timestamp: "2026-08-31T12:00:30.000Z",
|
|
75
|
+
type: "event_msg",
|
|
76
|
+
payload: { type: "task_complete", turn_id: "turn-selected" },
|
|
77
|
+
},
|
|
78
|
+
]
|
|
79
|
+
.map(JSON.stringify)
|
|
80
|
+
.join("\n")}\n`,
|
|
81
|
+
);
|
|
82
|
+
|
|
83
|
+
await run(
|
|
84
|
+
process.execPath,
|
|
85
|
+
[script, "--apply", "--run", "RUN-SELECTED", "--session-file", sessionFile],
|
|
86
|
+
{
|
|
87
|
+
cwd: root,
|
|
88
|
+
},
|
|
89
|
+
);
|
|
90
|
+
|
|
91
|
+
assert.equal(await readFile(unselectedFile, "utf8"), unselected);
|
|
92
|
+
const selected = await readFile(selectedFile, "utf8");
|
|
93
|
+
assert.match(selected, /retrospective_local_reconciliation/);
|
|
94
|
+
assert.match(selected, /"total":14/);
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
function started(runId, turnId) {
|
|
98
|
+
return {
|
|
99
|
+
schema_version: 2,
|
|
100
|
+
event_id: `${runId}:000001`,
|
|
101
|
+
run_id: runId,
|
|
102
|
+
sequence: 1,
|
|
103
|
+
occurred_at: "2026-08-31T12:00:00.000Z",
|
|
104
|
+
type: "run.started",
|
|
105
|
+
phase: "execution",
|
|
106
|
+
client_turn_id: turnId,
|
|
107
|
+
model: "gpt-5.6-terra",
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
function usage(eventId, occurredAt, supersedes) {
|
|
112
|
+
return {
|
|
113
|
+
schema_version: 2,
|
|
114
|
+
event_id: eventId,
|
|
115
|
+
run_id: "RUN-UNSELECTED",
|
|
116
|
+
sequence: eventId.endsWith("000002") ? 2 : 3,
|
|
117
|
+
occurred_at: occurredAt,
|
|
118
|
+
type: "usage.recorded",
|
|
119
|
+
phase: "execution",
|
|
120
|
+
activity_kind: eventId.includes("reconcile")
|
|
121
|
+
? "retrospective_local_reconciliation"
|
|
122
|
+
: "implementation",
|
|
123
|
+
tokens: { input: 1, cached_input: 0, output: 1, reasoning: 0, total: 2 },
|
|
124
|
+
cost: { usd: 0.001, brl: 0.005 },
|
|
125
|
+
provider: "openai",
|
|
126
|
+
model: "gpt-5.6-terra",
|
|
127
|
+
source_segment_key: null,
|
|
128
|
+
supersedes_event_id: supersedes,
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
function finished(runId, occurredAt) {
|
|
133
|
+
return {
|
|
134
|
+
schema_version: 2,
|
|
135
|
+
event_id: `${runId}:000004`,
|
|
136
|
+
run_id: runId,
|
|
137
|
+
sequence: runId === "RUN-SELECTED" ? 2 : 4,
|
|
138
|
+
occurred_at: occurredAt,
|
|
139
|
+
type: "run.finished",
|
|
140
|
+
phase: "execution",
|
|
141
|
+
status: "completed",
|
|
142
|
+
};
|
|
143
|
+
}
|
package/templates/.agents/skills/zaip-skill-reconcile-telemetry/scripts/reconcile-telemetry-lib.mjs
CHANGED
|
@@ -48,6 +48,20 @@ export function jsonLines(text) {
|
|
|
48
48
|
});
|
|
49
49
|
}
|
|
50
50
|
|
|
51
|
+
export function selectedRunIdsFromArgs(args) {
|
|
52
|
+
return new Set(
|
|
53
|
+
args.flatMap((argument, index, values) =>
|
|
54
|
+
argument === "--run"
|
|
55
|
+
? String(values[index + 1] ?? "")
|
|
56
|
+
.split(",")
|
|
57
|
+
.filter(Boolean)
|
|
58
|
+
: argument.startsWith("--run=")
|
|
59
|
+
? argument.slice("--run=".length).split(",").filter(Boolean)
|
|
60
|
+
: [],
|
|
61
|
+
),
|
|
62
|
+
);
|
|
63
|
+
}
|
|
64
|
+
|
|
51
65
|
export function recordType(record) {
|
|
52
66
|
if (!Array.isArray(record)) return record.type;
|
|
53
67
|
return record[1] === "u"
|
|
@@ -146,7 +146,9 @@ export function timingEnrichmentRunIds({ remeasure, applyBackfill, selectedRunId
|
|
|
146
146
|
runs
|
|
147
147
|
.filter(
|
|
148
148
|
(run) =>
|
|
149
|
-
|
|
149
|
+
(selectedRunIds.size === 0 || selectedRunIds.has(run.started.run_id)) &&
|
|
150
|
+
run.nativeMeasured &&
|
|
151
|
+
run.records.some((record) => recordType(record) === "run.finished"),
|
|
150
152
|
)
|
|
151
153
|
.map((run) => run.started.run_id),
|
|
152
154
|
);
|
|
@@ -37,6 +37,27 @@ test("selects completed native Runs for default timing-only backfill", () => {
|
|
|
37
37
|
assert.deepEqual([...selected], ["RUN-NATIVE"]);
|
|
38
38
|
});
|
|
39
39
|
|
|
40
|
+
test("limits automatic timing enrichment to explicit Run selection", () => {
|
|
41
|
+
const selected = timingEnrichmentRunIds({
|
|
42
|
+
remeasure: false,
|
|
43
|
+
applyBackfill: true,
|
|
44
|
+
selectedRunIds: new Set(["RUN-SELECTED"]),
|
|
45
|
+
runs: [
|
|
46
|
+
{
|
|
47
|
+
nativeMeasured: true,
|
|
48
|
+
started: { run_id: "RUN-SELECTED" },
|
|
49
|
+
records: [{ type: "run.started" }, { type: "run.finished" }],
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
nativeMeasured: true,
|
|
53
|
+
started: { run_id: "RUN-UNSELECTED" },
|
|
54
|
+
records: [{ type: "run.started" }, { type: "run.finished" }],
|
|
55
|
+
},
|
|
56
|
+
],
|
|
57
|
+
});
|
|
58
|
+
assert.deepEqual([...selected], ["RUN-SELECTED"]);
|
|
59
|
+
});
|
|
60
|
+
|
|
40
61
|
test("explicit recovery requires exact session identity, unused turns, model/effort, and SPEC text", () => {
|
|
41
62
|
const run = {
|
|
42
63
|
started: {
|
|
@@ -2,6 +2,7 @@ import { rename, writeFile } from "node:fs/promises";
|
|
|
2
2
|
|
|
3
3
|
export async function reconcileGenericModelIdentities({
|
|
4
4
|
applyBackfill,
|
|
5
|
+
selectedRunIds = new Set(),
|
|
5
6
|
pricingFor,
|
|
6
7
|
runs,
|
|
7
8
|
segments,
|
|
@@ -13,6 +14,8 @@ export async function reconcileGenericModelIdentities({
|
|
|
13
14
|
const genericModel = (model) => typeof model === "string" && /^gpt-5$/i.test(model.trim());
|
|
14
15
|
let correctionsCount = 0;
|
|
15
16
|
for (const run of runs) {
|
|
17
|
+
if (applyBackfill && selectedRunIds.size > 0 && !selectedRunIds.has(run.started.run_id))
|
|
18
|
+
continue;
|
|
16
19
|
const superseded = new Set(run.usage.map((usage) => usage.supersedes_event_id).filter(Boolean));
|
|
17
20
|
const effective = run.usage.filter((usage) => !superseded.has(usage.event_id));
|
|
18
21
|
const corrections = effective.flatMap((usage) => {
|
|
@@ -50,6 +50,21 @@ sincronize/audite novamente o template público. Execute gates geradores em
|
|
|
50
50
|
checkout/worktree isolado para preservar trabalho concorrente. Gates locais,
|
|
51
51
|
artefato exato, CI terminal e produção continuam sendo provas distintas.
|
|
52
52
|
|
|
53
|
+
### Falhas de desempenho no dashboard
|
|
54
|
+
|
|
55
|
+
Reproduza a rota, período, filtro, offset e tamanho da página que falharam.
|
|
56
|
+
Separe a primeira consulta sem resultado em cache da navegação já aquecida;
|
|
57
|
+
uma página rápida em cache não comprova o custo de exportar páginas distintas.
|
|
58
|
+
Correlacione o clique com a requisição, a espera pelo servidor, o retorno e o
|
|
59
|
+
fechamento do arquivo. Registre a concorrência do teste e do ambiente.
|
|
60
|
+
|
|
61
|
+
Timeout não autoriza aumentar limites nem remover a matriz de performance.
|
|
62
|
+
Primeiro diferencie requisição ausente, cancelada, bloqueada e consulta lenta.
|
|
63
|
+
Uma correção de consulta deve preservar filtros, ordenação, total, IDs únicos,
|
|
64
|
+
offsets contíguos e exportação até `has_more=false`. Reexecute o cenário que
|
|
65
|
+
falhou e o gate correspondente no candidato corrigido. Se o pacote anterior
|
|
66
|
+
já estiver publicado, distribua a correção em nova versão imutável.
|
|
67
|
+
|
|
53
68
|
## Histórico e nova qualificação em 30/08/2026
|
|
54
69
|
|
|
55
70
|
Snapshot bloqueado em 2026-08-30 para o candidato
|
|
@@ -98,6 +113,35 @@ O guard não remove, move, ignora ou adiciona arquivos ao Git; a limpeza deve
|
|
|
98
113
|
ser resolvida pelo responsável autorizado, preservando os artefatos anteriores.
|
|
99
114
|
Use o checkout limpo do candidato exato e não publique TGZs de diagnóstico.
|
|
100
115
|
|
|
116
|
+
## Controles críticos pendentes de prova
|
|
117
|
+
|
|
118
|
+
Para uma Change que altere diagnóstico de pacote, encerramento/recovery,
|
|
119
|
+
filtragem de conteúdo, SBOM, política de empacotamento ou proteção remota,
|
|
120
|
+
documentar e executar cenários negativos no candidato exato. O contrato deve
|
|
121
|
+
incluir, quando aplicável: dual-doctor de TGZ e corrupção controlada; paridade
|
|
122
|
+
entre `finish` e recovery com Evidence de reviewer filho e rejeição cross-root
|
|
123
|
+
e cross-task; variantes de segredo/binário; identidade do SBOM do artefato
|
|
124
|
+
real; e temporário interno rastreado que não deve entrar no TGZ. A projeção
|
|
125
|
+
exclui `.tmp-run-list.json`; se esse arquivo aparecer no inventário empacotado,
|
|
126
|
+
o guard deve bloquear o pacote, sem apagar o arquivo local.
|
|
127
|
+
|
|
128
|
+
Um script local de consulta de proteção não demonstra que a branch está
|
|
129
|
+
protegida. Para `main`, o guard implementado é
|
|
130
|
+
`node scripts/validate-github-protection.mjs --repository zaip-ai/zaip-aios --branch main --json`,
|
|
131
|
+
com alias `validate:github-protection`. Se a consulta retornar 403, registre a
|
|
132
|
+
limitação de acesso e mantenha o controle remoto pendente; não contorne a API
|
|
133
|
+
nem declare proteção aplicada. Configurar/aplicar a proteção depende de duas
|
|
134
|
+
pessoas/contas autorizadas e de decisão humana separada.
|
|
135
|
+
|
|
136
|
+
O alias live é um check manual, separado de CI: restrição de plano ou permissão
|
|
137
|
+
do provedor não deve tornar o CI indiscriminadamente vermelho. Testes locais do
|
|
138
|
+
guard comprovam somente a proposta local; o JSON retornado pela consulta não é
|
|
139
|
+
proteção ativa.
|
|
140
|
+
|
|
141
|
+
Documentação de contrato, presença de testes ou snapshot não substituem output
|
|
142
|
+
executado, SHA candidato, ambiente, horário real e locator sanitizado. Não
|
|
143
|
+
alegar aprovação final, suporte, SLA ou canal comercial a partir desses gates.
|
|
144
|
+
|
|
101
145
|
## Evidência e aprovação
|
|
102
146
|
|
|
103
147
|
Testes passando comprovam validação técnica. Maturidade formal máxima exige ainda:
|