@zaip-ai/cli 1.3.0 → 1.3.2

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 (258) hide show
  1. package/README.md +3 -2
  2. package/dist/services/agent-adapters.js +1 -1
  3. package/dist/services/agent-adapters.js.map +1 -1
  4. package/dist/services/agent-adapters.test.js +2 -1
  5. package/dist/services/agent-adapters.test.js.map +1 -1
  6. package/dist/services/codex-pre-tool-hook-template.d.ts.map +1 -1
  7. package/dist/services/codex-pre-tool-hook-template.js +89 -7
  8. package/dist/services/codex-pre-tool-hook-template.js.map +1 -1
  9. package/dist/services/codex-rules.d.ts +1 -1
  10. package/dist/services/codex-rules.d.ts.map +1 -1
  11. package/dist/services/codex-rules.js +7 -0
  12. package/dist/services/codex-rules.js.map +1 -1
  13. package/dist/services/install-agents-template.d.ts.map +1 -1
  14. package/dist/services/install-agents-template.js +1 -0
  15. package/dist/services/install-agents-template.js.map +1 -1
  16. package/dist/services/runtime-template.test.js +31 -7
  17. package/dist/services/runtime-template.test.js.map +1 -1
  18. package/dist/services/template-manifest.d.ts.map +1 -1
  19. package/dist/services/template-manifest.js +7 -3
  20. package/dist/services/template-manifest.js.map +1 -1
  21. package/package.json +1 -1
  22. package/templates/.agents/config/agents/catalog.yaml +7 -7
  23. package/templates/.agents/config/clients/codex/agents/zaip-agent-backend.toml +2 -2
  24. package/templates/.agents/config/clients/codex/agents/zaip-agent-designer.toml +2 -2
  25. package/templates/.agents/config/clients/codex/agents/zaip-agent-frontend.toml +8 -8
  26. package/templates/.agents/dashboard/.zaip-managed.json +373 -205
  27. package/templates/.agents/dashboard/apps/frontend/dist/assets/{CostCalculationGuidePage-DxR_pgSV.js → CostCalculationGuidePage-ovxurkIk.js} +1 -1
  28. package/templates/.agents/dashboard/apps/frontend/dist/assets/{DashboardHelpDialog-4jZLTWE_.js → DashboardHelpDialog-BXy6nti1.js} +268 -86
  29. package/templates/.agents/dashboard/apps/frontend/dist/assets/{PricingSettingsDialog-CKcsqb-r.js → PricingSettingsDialog-vSvvOHQp.js} +1 -1
  30. package/templates/.agents/dashboard/apps/frontend/dist/assets/{ProjectSettingsPage-DmmJD2Th.js → ProjectSettingsPage-zH758vfs.js} +1 -1
  31. package/templates/.agents/dashboard/apps/frontend/dist/assets/TraceabilityWorkspace-CTH2wDs5.js +1 -0
  32. package/templates/.agents/dashboard/apps/frontend/dist/assets/{TraceabilityWorkspace-CaKwQP43.css → TraceabilityWorkspace-DvvavDLY.css} +1 -1
  33. package/templates/.agents/dashboard/apps/frontend/dist/assets/cost-monitor-DKwP1stV.js +68 -0
  34. package/templates/.agents/dashboard/apps/frontend/dist/assets/cost-monitor-PoJA2PI1.css +1 -0
  35. package/templates/.agents/dashboard/apps/frontend/dist/assets/{icons-vendor-C0fj2uU9.js → icons-vendor-B_lDDHn1.js} +1 -1
  36. package/templates/.agents/dashboard/apps/frontend/dist/assets/index-B31GMG5O.css +1 -0
  37. package/templates/.agents/dashboard/apps/frontend/dist/assets/index-CuMcoUni.js +2 -0
  38. package/templates/.agents/dashboard/apps/frontend/dist/assets/{react-vendor-BEsJ-FYH.js → react-vendor-B3TJrD4O.js} +1 -1
  39. package/templates/.agents/dashboard/apps/frontend/dist/assets/{traceability-B6y6Gw12.js → traceability-7f1j5wx3.js} +1 -1
  40. package/templates/.agents/dashboard/apps/frontend/dist/index.html +7 -7
  41. package/templates/.agents/dashboard/apps/frontend/playwright.dom.config.ts +32 -0
  42. package/templates/.agents/dashboard/apps/frontend/src/App.tsx +132 -245
  43. package/templates/.agents/dashboard/apps/frontend/src/AppOverlays.tsx +0 -21
  44. package/templates/.agents/dashboard/apps/frontend/src/DashboardAlternateContent.tsx +9 -0
  45. package/templates/.agents/dashboard/apps/frontend/src/TraceabilityWorkspace.dom.e2e.ts +56 -0
  46. package/templates/.agents/dashboard/apps/frontend/src/TraceabilityWorkspace.test.ts +18 -1
  47. package/templates/.agents/dashboard/apps/frontend/src/TraceabilityWorkspace.tsx +75 -8
  48. package/templates/.agents/dashboard/apps/frontend/src/dashboard-api.test.ts +25 -1
  49. package/templates/.agents/dashboard/apps/frontend/src/dashboard-api.ts +7 -9
  50. package/templates/.agents/dashboard/apps/frontend/src/operations-period-render.test.ts +4 -4
  51. package/templates/.agents/dashboard/apps/frontend/src/overview-status-page.test.ts +1 -1
  52. package/templates/.agents/dashboard/apps/frontend/src/snapshot-banner-semantics.test.ts +7 -0
  53. package/templates/.agents/dashboard/apps/frontend/src/snapshot-coherence.test.ts +20 -8
  54. package/templates/.agents/dashboard/apps/frontend/src/sqlite-page-export.test.ts +32 -0
  55. package/templates/.agents/dashboard/apps/frontend/src/sqlite-page-export.ts +21 -0
  56. package/templates/.agents/dashboard/apps/frontend/src/styles.css +19 -0
  57. package/templates/.agents/dashboard/apps/frontend/src/traceability-task-pagination.test.ts +32 -0
  58. package/templates/.agents/dashboard/apps/frontend/src/traceability-task-pagination.ts +36 -0
  59. package/templates/.agents/dashboard/apps/frontend/src/traceability-workspace.css +6 -2
  60. package/templates/.agents/dashboard/apps/frontend/src/use-app-cost-loaders.test.ts +48 -0
  61. package/templates/.agents/dashboard/apps/frontend/src/use-app-cost-loaders.ts +31 -27
  62. package/templates/.agents/dashboard/apps/frontend/src/use-app-trace-documents.ts +7 -1
  63. package/templates/.agents/dashboard/apps/frontend/src/use-app-work-list-page.test.ts +163 -0
  64. package/templates/.agents/dashboard/apps/frontend/src/use-app-work-list-page.ts +136 -0
  65. package/templates/.agents/dashboard/apps/frontend/src/use-operations-detail-export.ts +76 -0
  66. package/templates/.agents/dashboard/apps/frontend/src/work-list-load-dedup.test.ts +23 -0
  67. package/templates/.agents/dashboard/apps/frontend/src/work-list-load-dedup.ts +27 -0
  68. package/templates/.agents/dashboard/apps/frontend/src/work-list-pagination.test.ts +38 -14
  69. package/templates/.agents/dashboard/modules/cost-monitor/src/react/CostDeveloperAttributionPanel.tsx +60 -0
  70. package/templates/.agents/dashboard/modules/cost-monitor/src/react/CostDeveloperAttributionTable.tsx +191 -0
  71. package/templates/.agents/dashboard/modules/cost-monitor/src/react/CostFilters.loading.test.ts +14 -0
  72. package/templates/.agents/dashboard/modules/cost-monitor/src/react/CostFilters.run-page.test.ts +18 -0
  73. package/templates/.agents/dashboard/modules/cost-monitor/src/react/CostFilters.tsx +18 -3
  74. package/templates/.agents/dashboard/modules/cost-monitor/src/react/CostMonitorContent.tsx +8 -2
  75. package/templates/.agents/dashboard/modules/cost-monitor/src/react/CostMonitorLoadErrors.tsx +35 -0
  76. package/templates/.agents/dashboard/modules/cost-monitor/src/react/CostMonitorPage.test.ts +47 -1
  77. package/templates/.agents/dashboard/modules/cost-monitor/src/react/CostMonitorPage.tsx +50 -58
  78. package/templates/.agents/dashboard/modules/cost-monitor/src/react/CostTableLoading.test.ts +132 -0
  79. package/templates/.agents/dashboard/modules/cost-monitor/src/react/CostTableLoading.tsx +70 -0
  80. package/templates/.agents/dashboard/modules/cost-monitor/src/react/CostTables.test.ts +128 -138
  81. package/templates/.agents/dashboard/modules/cost-monitor/src/react/CostTables.tsx +17 -67
  82. package/templates/.agents/dashboard/modules/cost-monitor/src/react/cost-monitor-copy.ts +2 -0
  83. package/templates/.agents/dashboard/modules/cost-monitor/src/react/cost-monitor-views.ts +3 -1
  84. package/templates/.agents/dashboard/modules/cost-monitor/src/react/cost-page-range.ts +35 -0
  85. package/templates/.agents/dashboard/modules/cost-monitor/src/react/use-compact-cost-page.ts +16 -4
  86. package/templates/.agents/dashboard/modules/cost-monitor/src/react/use-cost-group-page.test.ts +37 -2
  87. package/templates/.agents/dashboard/modules/cost-monitor/src/react/use-cost-group-page.ts +44 -8
  88. package/templates/.agents/dashboard/modules/cost-monitor/src/react/use-cost-run-page.ts +6 -1
  89. package/templates/.agents/dashboard/modules/operations/src/contracts.ts +20 -3
  90. package/templates/.agents/dashboard/modules/operations/src/react/DeveloperAttributionPanel.test.ts +54 -0
  91. package/templates/.agents/dashboard/modules/operations/src/react/DeveloperAttributionPanel.tsx +247 -0
  92. package/templates/.agents/dashboard/modules/operations/src/react/OperationsMainContent.tsx +39 -13
  93. package/templates/.agents/dashboard/modules/operations/src/react/OperationsOverview.helpers.tsx +107 -2
  94. package/templates/.agents/dashboard/modules/operations/src/react/OperationsOverview.macro-metrics.test.ts +55 -0
  95. package/templates/.agents/dashboard/modules/operations/src/react/OperationsOverview.test.ts +20 -28
  96. package/templates/.agents/dashboard/modules/operations/src/react/OperationsOverview.tsx +162 -165
  97. package/templates/.agents/dashboard/modules/operations/src/react/OperationsOverviewTopPanel.tsx +127 -0
  98. package/templates/.agents/dashboard/modules/operations/src/react/OperationsPage.tsx +13 -46
  99. package/templates/.agents/dashboard/modules/operations/src/react/OperationsPageOverview.tsx +3 -0
  100. package/templates/.agents/dashboard/modules/operations/src/react/PagedWorkList.test.tsx +43 -0
  101. package/templates/.agents/dashboard/modules/operations/src/react/PagedWorkList.tsx +181 -0
  102. package/templates/.agents/dashboard/modules/operations/src/react/UnifiedWorkList.test.ts +4 -2
  103. package/templates/.agents/dashboard/modules/operations/src/react/UnifiedWorkList.tsx +13 -0
  104. package/templates/.agents/dashboard/modules/operations/src/react/developer-identities.test.ts +18 -0
  105. package/templates/.agents/dashboard/modules/operations/src/react/developer-identities.ts +30 -0
  106. package/templates/.agents/dashboard/modules/operations/src/react/execution-metrics.ts +1 -0
  107. package/templates/.agents/dashboard/modules/operations/src/react/export/ExcelExportAction.test.ts +8 -0
  108. package/templates/.agents/dashboard/modules/operations/src/react/export/ExcelExportAction.tsx +3 -0
  109. package/templates/.agents/dashboard/modules/operations/src/react/export/export-layout.test.ts +14 -5
  110. package/templates/.agents/dashboard/modules/operations/src/react/index.ts +1 -0
  111. package/templates/.agents/dashboard/modules/operations/src/react/operations-coverage-toast.test.ts +4 -3
  112. package/templates/.agents/dashboard/modules/operations/src/react/operations-date-filters.css +1 -1
  113. package/templates/.agents/dashboard/modules/operations/src/react/operations-overview-period-filter.test.ts +21 -11
  114. package/templates/.agents/dashboard/modules/operations/src/react/operations-overview.css +4 -0
  115. package/templates/.agents/dashboard/modules/operations/src/react/operations-page-contract.ts +8 -1
  116. package/templates/.agents/dashboard/modules/operations/src/react/operations-view-order.test.ts +1 -0
  117. package/templates/.agents/dashboard/modules/operations/src/react/period-summary.ts +1 -0
  118. package/templates/.agents/dashboard/modules/operations/src/server/metric-coverage.ts +1 -0
  119. package/templates/.agents/dashboard/packages/local-runtime/dist/server.cjs +527 -335
  120. package/templates/.agents/dashboard/packages/local-runtime/dist/sqlite-read-model.cjs +501 -309
  121. package/templates/.agents/dashboard/packages/local-runtime/gitignore.template +2 -0
  122. package/templates/.agents/dashboard/packages/local-runtime/scripts/rebuild-sqlite-read-model.mjs +3 -1
  123. package/templates/.agents/dashboard/packages/local-runtime/scripts/test-sqlite-read-model.mjs +3 -3
  124. package/templates/.agents/dashboard/packages/local-runtime/scripts/validate-sqlite-read-model.mjs +25 -15
  125. package/templates/.agents/dashboard/packages/local-runtime/server.mjs +527 -335
  126. package/templates/.agents/dashboard/packages/local-runtime/src/server-board.test.ts +34 -0
  127. package/templates/.agents/dashboard/packages/local-runtime/src/server-board.ts +15 -8
  128. package/templates/.agents/dashboard/packages/local-runtime/src/server-classification-page.test.ts +87 -0
  129. package/templates/.agents/dashboard/packages/local-runtime/src/server-period-macro-metric.test.ts +44 -0
  130. package/templates/.agents/dashboard/packages/local-runtime/src/server-period-macro-metric.ts +125 -0
  131. package/templates/.agents/dashboard/packages/local-runtime/src/server-reconciliation-refresh.test.ts +66 -0
  132. package/templates/.agents/dashboard/packages/local-runtime/src/server-request-authority.test.ts +61 -0
  133. package/templates/.agents/dashboard/packages/local-runtime/src/server-request-authority.ts +18 -0
  134. package/templates/.agents/dashboard/packages/local-runtime/src/server-run-projections.test.ts +42 -0
  135. package/templates/.agents/dashboard/packages/local-runtime/src/server-snapshot-refresh.ts +97 -0
  136. package/templates/.agents/dashboard/packages/local-runtime/src/server-snapshot.test.ts +3 -1
  137. package/templates/.agents/dashboard/packages/local-runtime/src/server-sqlite-task-trace.ts +91 -0
  138. package/templates/.agents/dashboard/packages/local-runtime/src/server.test-fixtures.ts +36 -0
  139. package/templates/.agents/dashboard/packages/local-runtime/src/server.test.ts +98 -123
  140. package/templates/.agents/dashboard/packages/local-runtime/src/server.ts +111 -135
  141. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-artifact-counts.ts +28 -0
  142. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-cost-agent-page.test.ts +63 -0
  143. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-cost-agent-page.ts +109 -0
  144. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-cost-aggregates.ts +497 -0
  145. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-cost-fast-page-parity.test-support.ts +65 -0
  146. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-cost-group-page.test.ts +176 -0
  147. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-cost-group-page.ts +119 -0
  148. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-cost-group-projection.ts +41 -0
  149. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-cost-invocation-page.test.ts +16 -0
  150. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-cost-invocation-page.ts +29 -0
  151. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-first-fold-cache.ts +355 -0
  152. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-first-fold-persistence.ts +121 -0
  153. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-first-fold-timing.ts +27 -0
  154. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-operations-projection.ts +15 -0
  155. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-operations-work-list.test.ts +293 -0
  156. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-operations-work-list.ts +371 -0
  157. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-read-model-cache.test-support.ts +23 -0
  158. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-read-model-first-fold-types.ts +89 -0
  159. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-read-model-multi-provider-fixture.ts +227 -0
  160. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-read-model-multi-provider.test.ts +691 -0
  161. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-read-model-source-fingerprint.ts +81 -0
  162. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-read-model.test.ts +440 -863
  163. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-read-model.ts +1120 -1086
  164. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-snapshot-cache.ts +129 -0
  165. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-snapshot-install.test.ts +26 -0
  166. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-snapshot-install.ts +28 -0
  167. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-snapshot-seed.test.ts +116 -0
  168. package/templates/.agents/dashboard/packages/local-runtime/start-dashboard-launch-page.mjs +146 -0
  169. package/templates/.agents/dashboard/packages/local-runtime/start-dashboard-launch-page.test.mjs +165 -0
  170. package/templates/.agents/dashboard/packages/local-runtime/start-dashboard-refresh.mjs +140 -0
  171. package/templates/.agents/dashboard/packages/local-runtime/start-dashboard.mjs +188 -299
  172. package/templates/.agents/dashboard/packages/local-runtime/start-dashboard.test.mjs +51 -70
  173. package/templates/.agents/dashboard/packages/windows-launcher/Program.cs +5 -2
  174. package/templates/.agents/dashboard/tests/e2e/playwright.config.ts +4 -1
  175. package/templates/.agents/dashboard/tests/e2e/specs/cost-monitor-loading.spec.ts +142 -0
  176. package/templates/.agents/dashboard/tests/e2e/specs/cost-monitor-pagination.spec.ts +232 -0
  177. package/templates/.agents/dashboard/tests/e2e/specs/dashboard-performance-matrix.spec.ts +743 -0
  178. package/templates/.agents/dashboard/tests/e2e/specs/dashboard.spec.ts +183 -210
  179. package/templates/.agents/dashboard/zaip-dashboard-windows.exe +0 -0
  180. package/templates/.agents/requirements/autonomous-assurance.md +6 -6
  181. package/templates/.agents/requirements/comparative-audit.md +1 -1
  182. package/templates/.agents/requirements/context-engine.md +1 -1
  183. package/templates/.agents/requirements/cost-observability.md +1 -1
  184. package/templates/.agents/requirements/dashboard-launch.md +1 -1
  185. package/templates/.agents/requirements/data-export.md +1 -1
  186. package/templates/.agents/requirements/design-system.md +1 -1
  187. package/templates/.agents/requirements/execution-engine.md +3 -3
  188. package/templates/.agents/requirements/kanban-dashboard.md +10 -2
  189. package/templates/.agents/requirements/model-orchestration.md +1 -1
  190. package/templates/.agents/requirements/public-distribution.md +1 -1
  191. package/templates/.agents/requirements/software-architecture.md +1 -1
  192. package/templates/.agents/requirements/strategic-improvements.md +1 -1
  193. package/templates/.agents/requirements/work-lifecycle.md +4 -4
  194. package/templates/.agents/requirements/zaip-strategic-95.md +1 -1
  195. package/templates/.agents/rules/dashboard-ui-consistency.md +14 -0
  196. package/templates/.agents/rules/frontend-lite.md +4 -4
  197. package/templates/.agents/rules/run-lifecycle-closure.md +4 -4
  198. package/templates/.agents/runtime/bin/zaip.mjs +1137 -1037
  199. package/templates/.agents/runtime/checksums.sha256 +2 -2
  200. package/templates/.agents/runtime/provenance.json +2 -2
  201. package/templates/.agents/skills/criar-pasta-obsidian/scripts/generate-obsidian-vault.test.mjs +20 -16
  202. package/templates/.agents/skills/zaip-skill-agent-catalog/SKILL.md +22 -0
  203. package/templates/.agents/skills/zaip-skill-agent-catalog/agents/openai.yaml +4 -0
  204. package/templates/.agents/skills/zaip-skill-author-skills/SKILL.md +3 -2
  205. package/templates/.agents/skills/zaip-skill-author-skills/scripts/audit-skill-catalog.mjs +49 -0
  206. package/templates/.agents/skills/zaip-skill-author-skills/scripts/author-skill-scripts.test.mjs +27 -0
  207. package/templates/.agents/skills/zaip-skill-author-skills/scripts/run-skill-tests.mjs +37 -0
  208. package/templates/.agents/skills/zaip-skill-backend/SKILL.md +1 -0
  209. package/templates/.agents/skills/zaip-skill-change/SKILL.md +1 -1
  210. package/templates/.agents/skills/zaip-skill-change/references/observable-evidence.md +83 -0
  211. package/templates/.agents/skills/zaip-skill-dashboard-diagnostics/SKILL.md +22 -0
  212. package/templates/.agents/skills/zaip-skill-dashboard-diagnostics/agents/openai.yaml +4 -0
  213. package/templates/.agents/skills/zaip-skill-execution/SKILL.md +1 -1
  214. package/templates/.agents/skills/zaip-skill-frontend/SKILL.md +4 -3
  215. package/templates/.agents/skills/zaip-skill-frontend/agents/openai.yaml +2 -2
  216. package/templates/.agents/skills/zaip-skill-github-deploy/SKILL.md +10 -10
  217. package/templates/.agents/skills/zaip-skill-lifecycle-closure/SKILL.md +27 -0
  218. package/templates/.agents/skills/zaip-skill-lifecycle-closure/agents/openai.yaml +4 -0
  219. package/templates/.agents/skills/zaip-skill-prd/SKILL.md +4 -0
  220. package/templates/.agents/skills/zaip-skill-reconcile-telemetry/scripts/reconcile-local-telemetry.mjs +72 -22
  221. package/templates/.agents/skills/zaip-skill-reconcile-telemetry/scripts/reconcile-telemetry-explicit-recovery.mjs +223 -0
  222. package/templates/.agents/skills/zaip-skill-reconcile-telemetry/scripts/reconcile-telemetry-lib.mjs +42 -1
  223. package/templates/.agents/skills/zaip-skill-reconcile-telemetry/scripts/reconcile-telemetry-lib.test.mjs +101 -0
  224. package/templates/.agents/skills/zaip-skill-reconcile-telemetry/scripts/reconcile-telemetry-remeasurement.test.mjs +53 -0
  225. package/templates/.agents/skills/zaip-skill-release-qualification/SKILL.md +20 -0
  226. package/templates/.agents/skills/zaip-skill-release-qualification/agents/openai.yaml +4 -0
  227. package/templates/.agents/skills/zaip-skill-review/SKILL.md +5 -0
  228. package/templates/.agents/skills/zaip-skill-rules/SKILL.md +1 -1
  229. package/templates/.agents/skills/zaip-skill-spec/SKILL.md +4 -0
  230. package/templates/.agents/skills/zaip-skill-sqlite-read-model/SKILL.md +22 -90
  231. package/templates/.agents/zaip-aios/INDEX.md +57 -32
  232. package/templates/.agents/zaip-aios/README.md +22 -12
  233. package/templates/.agents/zaip-aios/guides/02-requirements.md +5 -0
  234. package/templates/.agents/zaip-aios/guides/06-execucao.md +13 -4
  235. package/templates/.agents/zaip-aios/guides/07-revisao-e-validacao.md +7 -0
  236. package/templates/.agents/zaip-aios/guides/10-seguranca.md +23 -0
  237. package/templates/.agents/zaip-aios/guides/11-observabilidade-e-custos.md +6 -6
  238. package/templates/.agents/zaip-aios/guides/13-boas-praticas.md +3 -0
  239. package/templates/.agents/zaip-aios/guides/16-lifecycle-e-reconciliacao.md +12 -3
  240. package/templates/.agents/zaip-aios/guides/17-como-o-custo-e-calculado.md +5 -5
  241. package/templates/.agents/zaip-aios/guides/19-assurance-e-autonomia.md +23 -0
  242. package/templates/.agents/zaip-aios/guides/20-instalacao-detalhada.md +44 -8
  243. package/templates/.agents/zaip-aios/guides/21-telemetria-monitor-custos.md +8 -14
  244. package/templates/.agents/zaip-aios/guides/22-fluxos-e-roteamento.md +5 -0
  245. package/templates/.agents/zaip-aios/guides/23-orquestracao-de-modelos.md +6 -6
  246. package/templates/.agents/zaip-aios/guides/24-calculo-de-custos-openai.md +8 -8
  247. package/templates/.agents/zaip-aios/guides/25-fontes-de-precos-openai.md +3 -2
  248. package/templates/.agents/zaip-aios/guides/26-qualidade-e-release.md +92 -10
  249. package/templates/.agents/zaip-aios/guides/27-telemetria-git-native.md +8 -3
  250. package/templates/.agents/zaip-aios/guides/28-lifecycle-completo.md +5 -0
  251. package/templates/template-manifest.json +555 -170
  252. package/templates/.agents/dashboard/apps/frontend/dist/assets/TraceabilityWorkspace-BwtitWa_.js +0 -1
  253. package/templates/.agents/dashboard/apps/frontend/dist/assets/cost-monitor-BZ5WdaMN.css +0 -1
  254. package/templates/.agents/dashboard/apps/frontend/dist/assets/cost-monitor-N5Csr0RP.js +0 -68
  255. package/templates/.agents/dashboard/apps/frontend/dist/assets/index-C4aIB1PV.js +0 -2
  256. package/templates/.agents/dashboard/apps/frontend/dist/assets/index-DK_enB5Z.css +0 -1
  257. package/templates/.agents/dashboard/apps/frontend/src/use-idle-cost-prefetch.ts +0 -45
  258. package/templates/.agents/dashboard/packages/local-runtime/dist/server.cjs.metafile.json +0 -7333
@@ -1,5 +1,11 @@
1
1
  import { readFile, rename, writeFile } from "node:fs/promises";
2
2
  import { join, resolve } from "node:path";
3
+ import {
4
+ applyExplicitTurnRecovery,
5
+ normalizeExplicitTurnRecoverySchema,
6
+ parseExplicitTurnMappings,
7
+ planExplicitTurnRecovery,
8
+ } from "./reconcile-telemetry-explicit-recovery.mjs";
3
9
  import {
4
10
  aggregate,
5
11
  duplicateUsageAssignments,
@@ -32,6 +38,7 @@ const reprice = process.argv.includes("--reprice");
32
38
  const deduplicate = process.argv.includes("--deduplicate");
33
39
  const remeasure = process.argv.includes("--remeasure");
34
40
  const timingOnly = process.argv.includes("--timing-only");
41
+ const explicitRecovery = process.argv.includes("--explicit-turn-recovery");
35
42
  if (timingOnly && !remeasure) {
36
43
  throw new Error("--timing-only requires --remeasure");
37
44
  }
@@ -55,13 +62,19 @@ const selectedSessionFiles = process.argv
55
62
  : [],
56
63
  )
57
64
  .filter(Boolean);
65
+ const explicitMappings = parseExplicitTurnMappings(
66
+ process.argv,
67
+ explicitRecovery,
68
+ selectedRunIds,
69
+ selectedSessionFiles,
70
+ );
58
71
  if (remeasure && selectedRunIds.size === 0) {
59
72
  throw new Error("--remeasure requires at least one explicit --run <RUN-ID>");
60
73
  }
61
74
  if (apply && deduplicate && selectedRunIds.size === 0) {
62
75
  throw new Error("--apply --deduplicate requires at least one explicit --run <RUN-ID>");
63
76
  }
64
- const applyBackfill = apply && !deduplicate && !remeasure;
77
+ const applyBackfill = apply && !deduplicate && !remeasure && !explicitRecovery;
65
78
 
66
79
  const runFiles = await filesUnder(join(workspace, ".agents", "records", "runs"), ".jsonl");
67
80
  const runs = [];
@@ -192,9 +205,38 @@ const allSegments = await loadSegments(
192
205
  workspace,
193
206
  selectedSessionFiles.length === 0 ? null : selectedSessionFiles,
194
207
  );
195
- // Native usage can be captured before the Codex session emits task_complete.
196
- // A normal backfill must not replace those observed tokens or costs, but it can
197
- // append an exact, timing-only correction once that terminal boundary appears.
208
+ let explicitSchemaNormalized = false;
209
+ if (apply && explicitRecovery) {
210
+ const run = runs.find((candidate) => candidate.started.run_id === [...selectedRunIds][0]);
211
+ if (run) {
212
+ const normalized = await normalizeExplicitTurnRecoverySchema(
213
+ run.file,
214
+ run.records,
215
+ explicitMappings,
216
+ );
217
+ if (normalized !== run.records) {
218
+ run.records = normalized;
219
+ run.usage = normalized
220
+ .filter((record) => recordType(record) === "usage.recorded")
221
+ .map(usageView);
222
+ explicitSchemaNormalized = true;
223
+ }
224
+ }
225
+ }
226
+ const explicitRecoveryPlan = explicitRecovery
227
+ ? (() => {
228
+ const runId = [...selectedRunIds][0];
229
+ const run = runs.find((candidate) => candidate.started.run_id === runId);
230
+ return run
231
+ ? planExplicitTurnRecovery({ run, segments: allSegments, mappings: explicitMappings })
232
+ : { run_id: runId, eligible: false, reasons: ["run-not-found"], turns: [], recovered: [] };
233
+ })()
234
+ : null;
235
+ if (apply && explicitRecovery && explicitRecoveryPlan.eligible) {
236
+ const run = runs.find((candidate) => candidate.started.run_id === explicitRecoveryPlan.run_id);
237
+ await applyExplicitTurnRecovery({ run, plan: explicitRecoveryPlan });
238
+ explicitRecoveryPlan.applied = true;
239
+ }
198
240
  const timingRunIds = timingEnrichmentRunIds({
199
241
  remeasure,
200
242
  applyBackfill,
@@ -208,8 +250,6 @@ const remeasurement =
208
250
  allSegments,
209
251
  runs,
210
252
  selectedRunIds: timingRunIds,
211
- // Automatic backfill is intentionally timing-only. Explicit remeasurement
212
- // retains its existing token/cost correction behavior unless requested.
213
253
  timingOnly: remeasure ? timingOnly : true,
214
254
  workspace,
215
255
  })
@@ -598,8 +638,6 @@ const eligible = candidates.filter(
598
638
 
599
639
  if (applyBackfill) {
600
640
  for (const { run, segment, confidence } of eligible) {
601
- // Re-read each Run under the serial apply loop: a preceding timing repair may
602
- // have reordered or appended a correction after the initial scan.
603
641
  const persistedRecords = jsonLines(await readFile(run.file, "utf8"));
604
642
  const finishIndex = persistedRecords.findIndex(
605
643
  (record) => recordType(record) === "run.finished",
@@ -676,23 +714,35 @@ console.log(
676
714
  ? apply
677
715
  ? "apply-deduplicate"
678
716
  : "dry-run-deduplicate"
679
- : remeasure
717
+ : explicitRecovery
680
718
  ? apply
681
- ? "apply-remeasure"
682
- : "dry-run-remeasure"
683
- : apply
684
- ? reprice
685
- ? "apply-reprice"
686
- : approximate
687
- ? "apply-approximate"
688
- : "apply"
689
- : reprice
690
- ? "dry-run-reprice"
691
- : approximate
692
- ? "dry-run-approximate"
693
- : "dry-run",
719
+ ? "apply-explicit-turn-recovery"
720
+ : "dry-run-explicit-turn-recovery"
721
+ : remeasure
722
+ ? apply
723
+ ? "apply-remeasure"
724
+ : "dry-run-remeasure"
725
+ : apply
726
+ ? reprice
727
+ ? "apply-reprice"
728
+ : approximate
729
+ ? "apply-approximate"
730
+ : "apply"
731
+ : reprice
732
+ ? "dry-run-reprice"
733
+ : approximate
734
+ ? "dry-run-approximate"
735
+ : "dry-run",
694
736
  run_files: runs.length,
695
737
  remeasurement,
738
+ explicit_turn_recovery: explicitRecoveryPlan && {
739
+ run_id: explicitRecoveryPlan.run_id,
740
+ eligible: explicitRecoveryPlan.eligible,
741
+ applied: explicitRecoveryPlan.applied === true,
742
+ reasons: explicitRecoveryPlan.reasons,
743
+ turns: explicitRecoveryPlan.turns,
744
+ schema_normalized: explicitSchemaNormalized,
745
+ },
696
746
  local_session_files: new Set(segments.map((segment) => segment.file)).size,
697
747
  local_segments_available: segments.length,
698
748
  already_measured: runs.filter((run) => run.measured).length,
@@ -0,0 +1,223 @@
1
+ import { open, readFile, rename, rm, writeFile } from "node:fs/promises";
2
+ import {
3
+ aggregate,
4
+ jsonLines,
5
+ recordPhase,
6
+ recordType,
7
+ usageStatus,
8
+ usageView,
9
+ withSequence,
10
+ } from "./reconcile-telemetry-lib.mjs";
11
+
12
+ export function parseExplicitTurnMappings(args, enabled, runIds, sessionFiles) {
13
+ const mappings = args.flatMap((argument, index, values) => {
14
+ if (argument !== "--explicit-turn") return [];
15
+ const [spec_id, turn_id, total, usd, brl] = String(values[index + 1] ?? "").split("|");
16
+ return [{ spec_id, turn_id, total: Number(total), usd: Number(usd), brl: Number(brl) }];
17
+ });
18
+ if (enabled && (runIds.size !== 1 || sessionFiles.length !== 1))
19
+ throw new Error("--explicit-turn-recovery requires exactly one --run and one --session-file");
20
+ if (enabled && mappings.length === 0)
21
+ throw new Error(
22
+ "--explicit-turn-recovery requires one or more --explicit-turn SPEC|TURN|TOTAL|USD|BRL",
23
+ );
24
+ return mappings;
25
+ }
26
+
27
+ // This deliberately accepts no temporal heuristic. A recovery is useful only
28
+ // when a human supplies the expected SPEC-to-turn mapping and every identity
29
+ // boundary independently agrees with the persisted Run.
30
+ export function planExplicitTurnRecovery({ run, segments, mappings }) {
31
+ const runId = run?.started?.run_id;
32
+ const finished = run?.records?.find((record) => recordType(record) === "run.finished");
33
+ const usedKeys = new Set(
34
+ run.usage.filter((usage) => usage.source_segment_key).map((usage) => usage.source_segment_key),
35
+ );
36
+ const problems = [];
37
+ if (!runId || !finished) problems.push("run-not-finished");
38
+ if (!run?.started?.client_thread_id) problems.push("run-client-thread-unavailable");
39
+ if (!Array.isArray(mappings) || mappings.length === 0) problems.push("explicit-mapping-required");
40
+ const turnIds = new Set();
41
+ const recovered = [];
42
+ for (const mapping of mappings ?? []) {
43
+ if (!mapping.spec_id || !mapping.turn_id) {
44
+ problems.push("mapping-spec-and-turn-required");
45
+ continue;
46
+ }
47
+ if (turnIds.has(mapping.turn_id)) {
48
+ problems.push("duplicate-explicit-turn");
49
+ continue;
50
+ }
51
+ turnIds.add(mapping.turn_id);
52
+ const matches = segments.filter(
53
+ (segment) =>
54
+ segment.internal_turn_ids?.includes(mapping.turn_id) || segment.turn_id === mapping.turn_id,
55
+ );
56
+ if (matches.length !== 1) {
57
+ problems.push(
58
+ matches.length === 0
59
+ ? `turn-not-found:${mapping.turn_id}`
60
+ : `turn-ambiguous:${mapping.turn_id}`,
61
+ );
62
+ continue;
63
+ }
64
+ const segment = matches[0];
65
+ if (segment.session_agent_path !== run.started.client_thread_id)
66
+ problems.push(`session-agent-path-mismatch:${mapping.turn_id}`);
67
+ if (segment.model !== run.started.model || segment.effort !== run.started.reasoning_effort)
68
+ problems.push(`model-effort-mismatch:${mapping.turn_id}`);
69
+ if (usedKeys.has(segment.key)) problems.push(`turn-already-used:${mapping.turn_id}`);
70
+ if (!segment.finished_at) problems.push(`turn-not-finished:${mapping.turn_id}`);
71
+ if (!segment.raw?.includes(mapping.spec_id))
72
+ problems.push(`spec-evidence-missing:${mapping.turn_id}`);
73
+ const tokens = aggregate(segment);
74
+ if (mapping.total !== undefined && tokens.total !== mapping.total)
75
+ problems.push(`token-total-mismatch:${mapping.turn_id}`);
76
+ recovered.push({ mapping, segment, tokens });
77
+ }
78
+ return {
79
+ run_id: runId,
80
+ eligible: problems.length === 0 && recovered.length === mappings.length,
81
+ reasons: problems,
82
+ turns: recovered.map(({ mapping, segment, tokens }) => ({
83
+ spec_id: mapping.spec_id,
84
+ turn_id: mapping.turn_id,
85
+ source_segment_key: segment.key,
86
+ source_started_at: segment.started_at,
87
+ source_finished_at: segment.finished_at,
88
+ tokens,
89
+ })),
90
+ recovered,
91
+ };
92
+ }
93
+
94
+ export async function applyExplicitTurnRecovery({ run, plan }) {
95
+ if (!plan.eligible)
96
+ throw new Error(`Explicit recovery is not eligible: ${plan.reasons.join(", ")}`);
97
+ const finished = run.records.find((record) => recordType(record) === "run.finished");
98
+ const superseded = usageStatus(run.usage).effective.at(-1);
99
+ if (!superseded) throw new Error("Explicit recovery needs a supersedable effective usage event");
100
+ const sequence = run.records.length + 1;
101
+ const events = plan.recovered.map(({ mapping, segment, tokens }, index) => ({
102
+ schema_version: 2,
103
+ event_id: `${run.started.run_id}:explicit-turn-recovery:${String(sequence + index).padStart(6, "0")}`,
104
+ run_id: run.started.run_id,
105
+ sequence: sequence + index,
106
+ occurred_at: segment.finished_at,
107
+ type: "usage.recorded",
108
+ phase: recordPhase(finished),
109
+ activity_kind: "retrospective_explicit_turn_recovery",
110
+ classification_source: "explicit",
111
+ tokens: { ...tokens, source: "provider_reported" },
112
+ cost: { usd: mapping.usd, brl: mapping.brl },
113
+ provider: run.started.provider ?? "openai",
114
+ model: segment.model,
115
+ source_segment_key: segment.key,
116
+ attributed_spec_id: mapping.spec_id,
117
+ supersedes_event_id: index === 0 ? superseded.event_id : null,
118
+ retrospective_correction: true,
119
+ source_occurred_at: segment.finished_at,
120
+ source_started_at: segment.started_at,
121
+ source_finished_at: segment.finished_at,
122
+ runtime: { reasoning_effort: segment.effort, service_tier: segment.service_tier },
123
+ }));
124
+ await appendExplicitTurnRecovery(run.file, run.records, events);
125
+ return events;
126
+ }
127
+
128
+ // Kept separate from the general reconcile path: it only normalizes fields
129
+ // emitted by this explicit recovery writer, and only when the same scoped
130
+ // command is being resumed after an interrupted projection check.
131
+ export async function normalizeExplicitTurnRecoverySchema(file, expectedRecords, mappings = []) {
132
+ const specByTurn = new Map(mappings.map((mapping) => [mapping.turn_id, mapping.spec_id]));
133
+ const changed = expectedRecords.some((record) => {
134
+ const usage = usageView(record);
135
+ return (
136
+ usage?.activity_kind === "retrospective_explicit_turn_recovery" &&
137
+ (usage.classification_source !== "explicit" ||
138
+ "explicit_turn_recovery" in usage ||
139
+ "explicit_spec_id" in usage ||
140
+ usage.attributed_spec_id === undefined)
141
+ );
142
+ });
143
+ if (!changed) return expectedRecords;
144
+ const lockPath = `${file}.lock`;
145
+ const handle = await open(lockPath, "wx");
146
+ await handle.close();
147
+ try {
148
+ const persisted = jsonLines(await readFile(file, "utf8"));
149
+ const ids = (records) => records.map((record) => record?.event_id ?? record?.[2]);
150
+ if (
151
+ persisted.length !== expectedRecords.length ||
152
+ ids(persisted).some((id, index) => id !== ids(expectedRecords)[index])
153
+ )
154
+ throw new Error("Run history changed before explicit recovery schema normalization");
155
+ let recoveryIndex = 0;
156
+ const normalized = persisted.map((record) => {
157
+ const usage = usageView(record);
158
+ if (usage?.activity_kind !== "retrospective_explicit_turn_recovery") return record;
159
+ const { explicit_turn_recovery, explicit_spec_id, ...rest } = usage;
160
+ const recoveredTurn = [...specByTurn.keys()].find((turn) =>
161
+ rest.source_segment_key?.includes(turn),
162
+ );
163
+ const mappedSpecId = mappings[recoveryIndex++]?.spec_id;
164
+ return {
165
+ ...rest,
166
+ classification_source: "explicit",
167
+ ...(typeof rest.attributed_spec_id === "string"
168
+ ? {}
169
+ : typeof explicit_spec_id === "string"
170
+ ? { attributed_spec_id: explicit_spec_id }
171
+ : recoveredTurn
172
+ ? { attributed_spec_id: specByTurn.get(recoveredTurn) }
173
+ : typeof mappedSpecId === "string"
174
+ ? { attributed_spec_id: mappedSpecId }
175
+ : {}),
176
+ };
177
+ });
178
+ const temporary = `${file}.explicit-recovery-schema.tmp`;
179
+ await writeFile(
180
+ temporary,
181
+ `${normalized.map((record) => JSON.stringify(record)).join("\n")}\n`,
182
+ "utf8",
183
+ );
184
+ await rename(temporary, file);
185
+ return normalized;
186
+ } finally {
187
+ await rm(lockPath, { force: true });
188
+ }
189
+ }
190
+
191
+ export async function appendExplicitTurnRecovery(file, expectedRecords, events) {
192
+ if (!Array.isArray(events) || events.length === 0)
193
+ throw new Error("Explicit recovery events required");
194
+ const lockPath = `${file}.lock`;
195
+ const handle = await open(lockPath, "wx");
196
+ await handle.close();
197
+ try {
198
+ const persisted = jsonLines(await readFile(file, "utf8"));
199
+ const ids = (records) => records.map((record) => record?.event_id ?? record?.[2]);
200
+ if (
201
+ persisted.length !== expectedRecords.length ||
202
+ ids(persisted).some((id, index) => id !== ids(expectedRecords)[index])
203
+ )
204
+ throw new Error("Run history changed before explicit recovery");
205
+ const finishIndex = persisted.findIndex((record) => recordType(record) === "run.finished");
206
+ if (finishIndex < 0) throw new Error("Explicit recovery requires run.finished");
207
+ const before = persisted.slice(0, finishIndex);
208
+ const finish = persisted[finishIndex];
209
+ const after = persisted.slice(finishIndex + 1);
210
+ const updated = [...before, ...after, ...events, finish].map((record, index) =>
211
+ withSequence(record, index + 1),
212
+ );
213
+ const temporary = `${file}.explicit-recovery.tmp`;
214
+ await writeFile(
215
+ temporary,
216
+ `${updated.map((record) => JSON.stringify(record)).join("\n")}\n`,
217
+ "utf8",
218
+ );
219
+ await rename(temporary, file);
220
+ } finally {
221
+ await rm(lockPath, { force: true });
222
+ }
223
+ }
@@ -243,7 +243,20 @@ export function exactCompletedSegment(started, segments) {
243
243
  if (!started?.client_turn_id) return { segment: null, ambiguous: false };
244
244
  const runStartedAt = Date.parse(started.occurred_at ?? "");
245
245
  const matches = segments.filter((segment) => {
246
- if (segment.turn_id !== started.client_turn_id || !segment.finished_at) return false;
246
+ // Older Codex sub-runs can persist the internal turn id exposed in a
247
+ // response item's metadata instead of the enclosing task_started id. It
248
+ // is an observed identity for this exact local interval, never a token
249
+ // matching heuristic.
250
+ const observedInternalTurnIds = Array.isArray(segment.internal_turn_ids)
251
+ ? segment.internal_turn_ids
252
+ : [];
253
+ if (
254
+ (segment.turn_id !== started.client_turn_id &&
255
+ !observedInternalTurnIds.includes(started.client_turn_id)) ||
256
+ !segment.finished_at
257
+ ) {
258
+ return false;
259
+ }
247
260
  const segmentFinishedAt = Date.parse(segment.finished_at);
248
261
  return (
249
262
  Number.isFinite(runStartedAt) &&
@@ -330,6 +343,7 @@ export async function loadSegments(workspace, sessionFiles = null) {
330
343
  let canonicalSessionMetaSeen = false;
331
344
  let workspaceMatches = false;
332
345
  let sessionId = null;
346
+ let sessionAgentPath = null;
333
347
  let current = null;
334
348
  let index = 0;
335
349
  let model = null;
@@ -365,6 +379,16 @@ export async function loadSegments(workspace, sessionFiles = null) {
365
379
  canonicalSessionMetaSeen = true;
366
380
  workspaceMatches = normalized(payload.cwd) === normalized(workspace);
367
381
  sessionId = nextSessionId;
382
+ const declaredAgentPath =
383
+ typeof payload.agent_path === "string"
384
+ ? payload.agent_path
385
+ : typeof payload?.source?.subagent?.thread_spawn?.agent_path === "string"
386
+ ? payload.source.subagent.thread_spawn.agent_path
387
+ : null;
388
+ // A child rollout may embed its parent session metadata immediately
389
+ // after its own. Retain the child identity rather than downgrading to
390
+ // the parent metadata that cannot identify the subagent.
391
+ sessionAgentPath = declaredAgentPath ?? sessionAgentPath;
368
392
  }
369
393
  if (!workspaceMatches) continue;
370
394
  const settings = payload?.type === "thread_settings_applied" ? payload.thread_settings : null;
@@ -393,12 +417,14 @@ export async function loadSegments(workspace, sessionFiles = null) {
393
417
  key: `${normalized(file)}#${index}`,
394
418
  file,
395
419
  session_id: sessionId,
420
+ session_agent_path: sessionAgentPath,
396
421
  turn_id: typeof payload.turn_id === "string" ? payload.turn_id : null,
397
422
  started_at: record.timestamp ?? null,
398
423
  finished_at: null,
399
424
  model,
400
425
  effort,
401
426
  service_tier: serviceTier,
427
+ internal_turn_ids: [],
402
428
  usage: [],
403
429
  raw: [],
404
430
  };
@@ -422,12 +448,27 @@ export async function loadSegments(workspace, sessionFiles = null) {
422
448
  }
423
449
  }
424
450
  if (!current) continue;
451
+ const internalTurnId = payload?.internal_chat_message_metadata_passthrough?.turn_id;
452
+ if (
453
+ typeof internalTurnId === "string" &&
454
+ !current.internal_turn_ids.includes(internalTurnId)
455
+ ) {
456
+ current.internal_turn_ids.push(internalTurnId);
457
+ }
425
458
  if (line.includes("RUN-") || line.includes("TASK-")) current.raw.push(line);
426
459
  if (payload?.type === "task_complete") {
427
460
  current.finished_at = record.timestamp ?? null;
428
461
  if (current.usage.length) segments.push(current);
429
462
  current = null;
430
463
  }
464
+ if (current && payload?.type === "turn_aborted" && payload.turn_id === current.turn_id) {
465
+ // An interrupted Codex turn is still an observed terminal boundary.
466
+ // Preserve its collected token snapshots, but never fabricate a later
467
+ // finish from the Run history or wall clock.
468
+ current.finished_at = record.timestamp ?? null;
469
+ if (current.usage.length) segments.push(current);
470
+ current = null;
471
+ }
431
472
  }
432
473
  if (current?.usage.length) segments.push(current);
433
474
  }
@@ -13,6 +13,7 @@ import {
13
13
  exactRemeasurementSegment,
14
14
  isExactDuplicateUsageGroup,
15
15
  jsonLines,
16
+ loadSegments,
16
17
  pricingFor,
17
18
  recordSequence,
18
19
  recordType,
@@ -209,6 +210,106 @@ test("selects only one completed local segment for an exact Run turn", () => {
209
210
  );
210
211
  });
211
212
 
213
+ test("matches an observed internal Codex subturn to its enclosing local interval", async () => {
214
+ const root = await mkdtemp(join(tmpdir(), "zaip-reconcile-internal-turn-"));
215
+ roots.push(root);
216
+ const sessionFile = join(root, "internal-subturn.jsonl");
217
+ await writeFile(
218
+ sessionFile,
219
+ [
220
+ {
221
+ timestamp: "2026-08-12T04:30:25.797Z",
222
+ type: "session_meta",
223
+ payload: { id: "session-1", cwd: root },
224
+ },
225
+ {
226
+ timestamp: "2026-08-12T04:30:26.435Z",
227
+ type: "event_msg",
228
+ payload: { type: "task_started", turn_id: "outer-turn" },
229
+ },
230
+ {
231
+ timestamp: "2026-08-12T04:31:00.000Z",
232
+ type: "response_item",
233
+ payload: {
234
+ type: "reasoning",
235
+ internal_chat_message_metadata_passthrough: { turn_id: "internal-subturn" },
236
+ },
237
+ },
238
+ {
239
+ timestamp: "2026-08-12T04:32:00.000Z",
240
+ type: "event_msg",
241
+ payload: {
242
+ type: "token_count",
243
+ info: {
244
+ last_token_usage: {
245
+ input_tokens: 10,
246
+ cached_input_tokens: 0,
247
+ output_tokens: 2,
248
+ reasoning_output_tokens: 0,
249
+ total_tokens: 12,
250
+ },
251
+ },
252
+ },
253
+ },
254
+ {
255
+ timestamp: "2026-08-12T04:33:00.000Z",
256
+ type: "event_msg",
257
+ payload: { type: "task_complete", turn_id: "outer-turn" },
258
+ },
259
+ {
260
+ timestamp: "2026-08-12T04:35:46.804Z",
261
+ type: "event_msg",
262
+ payload: { type: "task_started", turn_id: "enclosing-turn" },
263
+ },
264
+ {
265
+ timestamp: "2026-08-12T04:36:00.000Z",
266
+ type: "response_item",
267
+ payload: {
268
+ type: "reasoning",
269
+ internal_chat_message_metadata_passthrough: { turn_id: "internal-subturn" },
270
+ },
271
+ },
272
+ {
273
+ timestamp: "2026-08-12T04:37:00.000Z",
274
+ type: "event_msg",
275
+ payload: {
276
+ type: "token_count",
277
+ info: {
278
+ last_token_usage: {
279
+ input_tokens: 20,
280
+ cached_input_tokens: 0,
281
+ output_tokens: 4,
282
+ reasoning_output_tokens: 0,
283
+ total_tokens: 24,
284
+ },
285
+ },
286
+ },
287
+ },
288
+ {
289
+ timestamp: "2026-08-12T04:39:10.716Z",
290
+ type: "event_msg",
291
+ payload: { type: "turn_aborted", turn_id: "enclosing-turn", completed_at: 1786509550 },
292
+ },
293
+ ]
294
+ .map((record) => JSON.stringify(record))
295
+ .join("\n") + "\n",
296
+ );
297
+
298
+ const [outerSegment, segment] = await loadSegments(root, [sessionFile]);
299
+ assert.deepEqual(outerSegment.internal_turn_ids, ["internal-subturn"]);
300
+ assert.deepEqual(segment.internal_turn_ids, ["internal-subturn"]);
301
+ assert.equal(outerSegment.finished_at, "2026-08-12T04:33:00.000Z");
302
+ assert.equal(segment.started_at, "2026-08-12T04:35:46.804Z");
303
+ assert.equal(segment.finished_at, "2026-08-12T04:39:10.716Z");
304
+ assert.deepEqual(
305
+ exactCompletedSegment(
306
+ { client_turn_id: "internal-subturn", occurred_at: "2026-08-12T04:39:07.934Z" },
307
+ [outerSegment, segment],
308
+ ),
309
+ { segment, ambiguous: false },
310
+ );
311
+ });
312
+
212
313
  test("remeasurement falls back only to the exact persisted source segment key", () => {
213
314
  const target = {
214
315
  key: "c:/users/test/.codex/sessions/2026/07/25/child.jsonl#1",
@@ -3,6 +3,7 @@ import { mkdir, mkdtemp, readFile, rm, writeFile } from "node:fs/promises";
3
3
  import { tmpdir } from "node:os";
4
4
  import { join } from "node:path";
5
5
  import { after, test } from "node:test";
6
+ import { planExplicitTurnRecovery } from "./reconcile-telemetry-explicit-recovery.mjs";
6
7
  import { jsonLines, usageStatus, usageView } from "./reconcile-telemetry-lib.mjs";
7
8
  import {
8
9
  appendRetrospectiveUsage,
@@ -36,6 +37,58 @@ test("selects completed native Runs for default timing-only backfill", () => {
36
37
  assert.deepEqual([...selected], ["RUN-NATIVE"]);
37
38
  });
38
39
 
40
+ test("explicit recovery requires exact session identity, unused turns, model/effort, and SPEC text", () => {
41
+ const run = {
42
+ started: {
43
+ run_id: "RUN-EXPLICIT",
44
+ client_thread_id: "/root/agent",
45
+ model: "gpt-test",
46
+ reasoning_effort: "medium",
47
+ },
48
+ records: [
49
+ { type: "run.started" },
50
+ { type: "usage.recorded", event_id: "RUN-EXPLICIT:old", source_segment_key: "old" },
51
+ { type: "run.finished" },
52
+ ],
53
+ usage: [{ event_id: "RUN-EXPLICIT:old", source_segment_key: "old", tokens: { total: 1 } }],
54
+ };
55
+ const segment = {
56
+ key: "session#5",
57
+ turn_id: "turn-r7qk",
58
+ internal_turn_ids: ["turn-r7qk"],
59
+ session_agent_path: "/root/agent",
60
+ model: "gpt-test",
61
+ effort: "medium",
62
+ started_at: "2026-08-22T22:56:58.553Z",
63
+ finished_at: "2026-08-22T23:05:26.121Z",
64
+ raw: "SPEC-R7QK observed",
65
+ usage: [
66
+ {
67
+ input_tokens: 8,
68
+ cached_input_tokens: 3,
69
+ output_tokens: 2,
70
+ reasoning_output_tokens: 1,
71
+ total_tokens: 10,
72
+ },
73
+ ],
74
+ };
75
+ const plan = planExplicitTurnRecovery({
76
+ run,
77
+ segments: [segment],
78
+ mappings: [{ spec_id: "SPEC-R7QK", turn_id: "turn-r7qk", total: 10, usd: 1, brl: 5 }],
79
+ });
80
+ assert.equal(plan.eligible, true);
81
+ assert.equal(plan.turns[0].tokens.total, 10);
82
+ assert.equal(
83
+ planExplicitTurnRecovery({
84
+ run,
85
+ segments: [{ ...segment, session_agent_path: "/root/root", key: "old" }],
86
+ mappings: [{ spec_id: "SPEC-R7QK", turn_id: "turn-r7qk", total: 10, usd: 1, brl: 5 }],
87
+ }).eligible,
88
+ false,
89
+ );
90
+ });
91
+
39
92
  test("inserts a correction before the terminal event under an exclusive lock", async () => {
40
93
  const root = await mkdtemp(join(tmpdir(), "zaip-remeasure-append-"));
41
94
  roots.push(root);
@@ -0,0 +1,20 @@
1
+ ---
2
+ name: zaip-skill-release-qualification
3
+ description: Qualify an exact ZAIP release candidate through source-template-package parity, cleanroom, smoke, and candidate-specific evidence; use before a release or publication decision.
4
+ ---
5
+
6
+ # Qualify a release candidate
7
+
8
+ Use before deciding whether a concrete candidate is ready. It does not publish.
9
+
10
+ 1. Identify the exact candidate revision, version, and intended distribution surface.
11
+ Do not substitute current working-tree checks for candidate evidence.
12
+ 2. Validate framework lock, source-to-public-template parity, generated artifacts,
13
+ package contents, and version alignment. Treat any source/template/package drift as
14
+ a failed candidate.
15
+ 3. Run the relevant smoke and cleanroom checks against that candidate and preserve the
16
+ commands, revision, outcomes, and unresolved limits as evidence.
17
+ 4. Separate local qualification, remote GitHub CI, registry publication, and formal
18
+ lifecycle closure. A matching SHA or passing local gate does not prove terminal CI.
19
+ 5. Route an explicit push, deploy, or GitHub publication request to
20
+ `$zaip-skill-github-deploy`; never publish as part of qualification.
@@ -0,0 +1,4 @@
1
+ interface:
2
+ display_name: "ZAIP Release Qualification"
3
+ short_description: "Qualify an exact release candidate without publishing it."
4
+ default_prompt: "Use $zaip-skill-release-qualification to qualify this exact ZAIP release candidate for source-template-package parity, smoke, and cleanroom evidence."
@@ -16,3 +16,8 @@ Esta skill é read-only. Um pedido de revisão não autoriza corrigir, concluir
16
16
  7. Correções aprovadas exigem autorização separada e começam uma nova Task. Inicie seu Run com `--work-type rework`, relacione somente IDs já conhecidos e deixe ancestral desconhecido como `null`; nunca leia todo o histórico para adivinhar vínculos. A revisão original permanece imutável.
17
17
  8. Valide o perfil quantitativo e semântico por mínimos, sem quotas máximas: `lite` exige pelo menos uma validação e uma Evidence, normalmente uma de cada, mas aceita extras legítimos; `standard` exige pelo menos duas validações no perfil base ou três no elevado e ao menos uma Evidence consolidada; `critical` exige três ou mais validações, quality review independente e somente os controles acionados pelos sinais persistidos; SPEC/PRD exigem três ou mais validações e Evidences parentais, matriz, integração e review independente.
18
18
  9. Para cleanroom, ambiente representativo ou produção, confira hash do candidato, identidade do ambiente, reviewer independente e Run observado; teste local não promove esses estados.
19
+ 10. Leia [o contrato de prova observável](../zaip-skill-change/references/observable-evidence.md) e confronte cenário, expectativa e observação por AC. Diferencie prova confirmada, limitada, pendente, reprovada e modalidade não aplicável; observações não substituem Validation/Evidence aprovadas. Não transfira aprovação entre Runs nem conte uma limitação como prova suficiente.
20
+
21
+ # Revisão visual condicional
22
+
23
+ Não aprove UI visual apenas por source ou typecheck: exija render de cada consumidor e bundle servido quando aplicável, além de screenshot real examinado do estado pedido. Após o fallback finito, browser indisponível deixa browser proof como unknown e o AC visual pendente, sem bloquear prova técnica ou trabalho independente. Ausência de impacto visual admite N/A justificado, não ausência de ferramenta.