avorelo 0.3.8 → 0.4.0-rc.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 (394) hide show
  1. package/LICENSE +16 -23
  2. package/README.md +62 -72
  3. package/bin/avorelo +9 -0
  4. package/package.json +147 -139
  5. package/scripts/README.md +40 -0
  6. package/scripts/avorelo-session-collision-guard.js +540 -0
  7. package/scripts/avorelo-workstream-preflight.js +918 -0
  8. package/scripts/cco-dashboard.js +346 -0
  9. package/scripts/cco-posttooluse.js +504 -0
  10. package/scripts/cco-pretooluse.js +381 -0
  11. package/scripts/cco-status.js +540 -0
  12. package/scripts/cco-stop.js +77 -0
  13. package/scripts/cco-userprompt-submit.js +83 -0
  14. package/scripts/lib/activation/account-state.js +37 -0
  15. package/scripts/lib/activation/activate-command.js +114 -0
  16. package/scripts/lib/activation/activation-runner.js +607 -0
  17. package/scripts/lib/activation/activation-self-healing.js +481 -0
  18. package/scripts/lib/activation/activation-state.js +96 -0
  19. package/scripts/lib/activation/activation-summary.js +241 -0
  20. package/scripts/lib/activation/adapters/claude-code.js +77 -0
  21. package/scripts/lib/activation/adapters/codex-cli.js +52 -0
  22. package/scripts/lib/activation/adapters/cursor.js +37 -0
  23. package/scripts/lib/activation/adapters/github-agent.js +39 -0
  24. package/scripts/lib/activation/adapters/terminal.js +42 -0
  25. package/scripts/lib/activation/adapters/vscode.js +39 -0
  26. package/scripts/lib/activation/adapters/windsurf.js +37 -0
  27. package/scripts/lib/activation/ai-surface-detector.js +151 -0
  28. package/scripts/lib/activation/connect-account.js +145 -0
  29. package/scripts/lib/activation/detect-environment.js +75 -0
  30. package/scripts/lib/activation/detect-hosts.js +62 -0
  31. package/scripts/lib/activation/format-activation-output.js +109 -0
  32. package/scripts/lib/activation/next-action.js +43 -0
  33. package/scripts/lib/activation/repair-engine.js +219 -0
  34. package/scripts/lib/activation/run-entry.js +346 -0
  35. package/scripts/lib/activation-distribution-readiness.js +507 -0
  36. package/scripts/lib/adapter-conformance.js +176 -0
  37. package/scripts/lib/adapter-readiness.js +428 -0
  38. package/scripts/lib/adapter-safety-boundaries.js +335 -0
  39. package/scripts/lib/adapter-technical-readiness-gate.js +205 -0
  40. package/scripts/lib/agent-access-governance.js +455 -0
  41. package/scripts/lib/agent-activation-readiness.js +878 -0
  42. package/scripts/lib/agent-enforcement.js +765 -0
  43. package/scripts/lib/agent-evolution-loop.js +479 -0
  44. package/scripts/lib/agent-policy-profile.js +210 -0
  45. package/scripts/lib/agent-security/action-evaluator.js +507 -0
  46. package/scripts/lib/agent-security/adapter-registry.js +98 -0
  47. package/scripts/lib/agent-security/auto-policy.js +139 -0
  48. package/scripts/lib/agent-security/bounded-scan.js +93 -0
  49. package/scripts/lib/agent-security/enforcement-adapter.js +174 -0
  50. package/scripts/lib/agent-security/enforcement-engine.js +1129 -0
  51. package/scripts/lib/agent-security/file-write-adapter.js +183 -0
  52. package/scripts/lib/agent-security/file-write-rules.js +178 -0
  53. package/scripts/lib/agent-security/index.js +3342 -0
  54. package/scripts/lib/agent-security/instruction-risk.js +181 -0
  55. package/scripts/lib/agent-security/mcp-action-adapter.js +185 -0
  56. package/scripts/lib/agent-security/mcp-action-rules.js +184 -0
  57. package/scripts/lib/agent-security/package-action-adapter.js +175 -0
  58. package/scripts/lib/agent-security/package-action-rules.js +233 -0
  59. package/scripts/lib/agent-security/performance.js +148 -0
  60. package/scripts/lib/agent-security/permission-minimizer.js +403 -0
  61. package/scripts/lib/agent-security/scan-cache.js +74 -0
  62. package/scripts/lib/agent-security/source-trust.js +146 -0
  63. package/scripts/lib/ai-efficiency-dogfood-pack.js +437 -0
  64. package/scripts/lib/ai-efficiency-eval.js +207 -0
  65. package/scripts/lib/ai-efficiency-guard-contract.js +209 -0
  66. package/scripts/lib/ai-efficiency-measured-value.js +106 -0
  67. package/scripts/lib/ai-install-prompt.js +293 -0
  68. package/scripts/lib/ai-task-inference.js +155 -0
  69. package/scripts/lib/ai-value-ledger.js +121 -0
  70. package/scripts/lib/ai-value-proof-table.js +151 -0
  71. package/scripts/lib/ai-work-efficiency-routing.js +623 -0
  72. package/scripts/lib/ai-workspace-hygiene.js +1499 -0
  73. package/scripts/lib/alpha-activation.js +520 -0
  74. package/scripts/lib/alpha-feedback.js +263 -0
  75. package/scripts/lib/alpha-readiness-gate.js +332 -0
  76. package/scripts/lib/anti-gaming.js +169 -0
  77. package/scripts/lib/artifact-health.js +431 -0
  78. package/scripts/lib/artifact-receipt-hygiene.js +619 -0
  79. package/scripts/lib/attribution.js +180 -0
  80. package/scripts/lib/audit.js +289 -0
  81. package/scripts/lib/avorelo-skill-registry.js +810 -0
  82. package/scripts/lib/batch-jobs.js +71 -0
  83. package/scripts/lib/brain-pack.js +578 -0
  84. package/scripts/lib/brand-boundary.js +424 -0
  85. package/scripts/lib/brand.js +74 -0
  86. package/scripts/lib/browser-capability.js +1048 -0
  87. package/scripts/lib/browser-proof-governed-workflow.js +1020 -0
  88. package/scripts/lib/browser-proof-preflight.js +321 -0
  89. package/scripts/lib/cache-readiness.js +296 -0
  90. package/scripts/lib/canonical-reentry.js +162 -0
  91. package/scripts/lib/capability-contract-validator.js +177 -0
  92. package/scripts/lib/capability-hygiene.js +504 -0
  93. package/scripts/lib/capability-intake-quarantine.js +789 -0
  94. package/scripts/lib/capability-kernel-registry.js +566 -0
  95. package/scripts/lib/capability-kernel.js +202 -0
  96. package/scripts/lib/capability-manifest.js +255 -0
  97. package/scripts/lib/capability-outcome-normalizer.js +104 -0
  98. package/scripts/lib/capability-packs.js +314 -0
  99. package/scripts/lib/capability-recommender.js +513 -0
  100. package/scripts/lib/capability-registry.js +1062 -0
  101. package/scripts/lib/carry-forward-surfacing.js +194 -0
  102. package/scripts/lib/ccusage-adapter.js +188 -0
  103. package/scripts/lib/claude-session-evidence/index.js +1027 -0
  104. package/scripts/lib/cli-output-sanitizer.js +118 -0
  105. package/scripts/lib/company-loop.js +1149 -0
  106. package/scripts/lib/config.js +641 -0
  107. package/scripts/lib/context-acquisition-plan.js +359 -0
  108. package/scripts/lib/context-authority-rules.js +138 -0
  109. package/scripts/lib/context-budget-guard.js +170 -0
  110. package/scripts/lib/context-budget-scanner.js +257 -0
  111. package/scripts/lib/context-budget.js +167 -0
  112. package/scripts/lib/context-claim-safety.js +116 -0
  113. package/scripts/lib/context-compiler.js +236 -0
  114. package/scripts/lib/context-optimizer.js +715 -0
  115. package/scripts/lib/context-packet.js +121 -0
  116. package/scripts/lib/context-receipt.js +57 -0
  117. package/scripts/lib/context-reduction-plan.js +179 -0
  118. package/scripts/lib/context-safety.js +88 -0
  119. package/scripts/lib/context-savings-engine.js +158 -0
  120. package/scripts/lib/context-source-registry.js +393 -0
  121. package/scripts/lib/context-task-profiles.js +147 -0
  122. package/scripts/lib/cost-abuse-guard.js +975 -0
  123. package/scripts/lib/cost-evidence.js +287 -0
  124. package/scripts/lib/cost-to-outcome-signals.js +639 -0
  125. package/scripts/lib/cross-host-install-plan.js +308 -0
  126. package/scripts/lib/cross-host-install-readiness.js +242 -0
  127. package/scripts/lib/cross-host-value-flow.js +268 -0
  128. package/scripts/lib/dashboard.js +1056 -0
  129. package/scripts/lib/data-permissions-guard.js +1187 -0
  130. package/scripts/lib/deployment-environment-guard.js +1236 -0
  131. package/scripts/lib/design-partner-feedback.js +346 -0
  132. package/scripts/lib/dogfood-evidence-freshness.js +567 -0
  133. package/scripts/lib/efficiency-receipt.js +354 -0
  134. package/scripts/lib/entitlements.js +100 -0
  135. package/scripts/lib/execution-packet.js +559 -0
  136. package/scripts/lib/execution-route-governor.js +179 -0
  137. package/scripts/lib/experimentation-events.js +547 -0
  138. package/scripts/lib/external-capability-compliance.js +107 -0
  139. package/scripts/lib/external-readiness/ai-visibility/ai-visibility-runner.js +322 -0
  140. package/scripts/lib/external-readiness/calibration/benchmark-site-catalog.js +121 -0
  141. package/scripts/lib/external-readiness/calibration/completion-gate.js +112 -0
  142. package/scripts/lib/external-readiness/calibration/real-site-benchmark-runner.js +284 -0
  143. package/scripts/lib/external-readiness/drift-detector.js +100 -0
  144. package/scripts/lib/external-readiness/endpoint-prober.js +332 -0
  145. package/scripts/lib/external-readiness/external-readiness-runner.js +112 -0
  146. package/scripts/lib/external-readiness/full-agent-readiness-scorer.js +220 -0
  147. package/scripts/lib/external-readiness/golden-path-runner.js +333 -0
  148. package/scripts/lib/external-readiness/inside-out-runner.js +118 -0
  149. package/scripts/lib/external-readiness/proof-receipt-writer.js +112 -0
  150. package/scripts/lib/external-readiness/safe-fix-executor.js +117 -0
  151. package/scripts/lib/external-readiness/skills/category-boundary-guard.js +30 -0
  152. package/scripts/lib/external-readiness/skills/pmm-positioning-guard.js +69 -0
  153. package/scripts/lib/external-readiness/skills/safe-fix-policy.js +35 -0
  154. package/scripts/lib/external-user-simulation.js +166 -0
  155. package/scripts/lib/failure-recovery-readiness.js +81 -0
  156. package/scripts/lib/failure-recovery.js +419 -0
  157. package/scripts/lib/feedback-intelligence.js +537 -0
  158. package/scripts/lib/feedback-signals.js +205 -0
  159. package/scripts/lib/file-integrity.js +68 -0
  160. package/scripts/lib/fsx.js +129 -0
  161. package/scripts/lib/full-readiness-gate.js +451 -0
  162. package/scripts/lib/governed-action-exposure-primitives.js +1514 -0
  163. package/scripts/lib/governed-exposure-planner.js +186 -0
  164. package/scripts/lib/governed-workspace-hygiene.js +946 -0
  165. package/scripts/lib/guard-suite-common.js +412 -0
  166. package/scripts/lib/guidance-builder.js +174 -0
  167. package/scripts/lib/hook-apply.js +1075 -0
  168. package/scripts/lib/hook-baseline.js +310 -0
  169. package/scripts/lib/hook-config-preview.js +275 -0
  170. package/scripts/lib/hook-contracts.js +290 -0
  171. package/scripts/lib/hook-safety-boundary-readiness.js +80 -0
  172. package/scripts/lib/host-capability-matrix.js +351 -0
  173. package/scripts/lib/host-support-context.js +254 -0
  174. package/scripts/lib/http-hook-action.js +538 -0
  175. package/scripts/lib/install-ai-readiness.js +84 -0
  176. package/scripts/lib/install-intake-risk.js +1051 -0
  177. package/scripts/lib/install-journey-intelligence.js +329 -0
  178. package/scripts/lib/intervention-guidance.js +57 -0
  179. package/scripts/lib/known-limitations.js +115 -0
  180. package/scripts/lib/l8-path-truth.js +146 -0
  181. package/scripts/lib/launch-hardening-gate.js +436 -0
  182. package/scripts/lib/launch-readiness.js +635 -0
  183. package/scripts/lib/learning-experimentation-foundation.js +1484 -0
  184. package/scripts/lib/learning-memory.js +686 -0
  185. package/scripts/lib/lifecycle-hooks.js +982 -0
  186. package/scripts/lib/local-package-smoke.js +436 -0
  187. package/scripts/lib/local-pricing.js +299 -0
  188. package/scripts/lib/mcp-enforcement.js +311 -0
  189. package/scripts/lib/mcp-least-privilege-policy.js +303 -0
  190. package/scripts/lib/mcp-tool-inventory.js +388 -0
  191. package/scripts/lib/mcp-tool-risk.js +0 -0
  192. package/scripts/lib/memory.js +335 -0
  193. package/scripts/lib/metrics.js +699 -0
  194. package/scripts/lib/micro-proof.js +133 -0
  195. package/scripts/lib/model-work-class-routing.js +79 -0
  196. package/scripts/lib/next-run-context.js +436 -0
  197. package/scripts/lib/next-run-continuity.js +1207 -0
  198. package/scripts/lib/observability-recovery-guard.js +1030 -0
  199. package/scripts/lib/operating-value.js +1662 -0
  200. package/scripts/lib/optimization-v3.js +122 -0
  201. package/scripts/lib/orchestration/adapters/_shared.js +49 -0
  202. package/scripts/lib/orchestration/adapters/aider.js +18 -0
  203. package/scripts/lib/orchestration/adapters/claude-code.js +35 -0
  204. package/scripts/lib/orchestration/adapters/codex.js +35 -0
  205. package/scripts/lib/orchestration/adapters/gemini-cli.js +18 -0
  206. package/scripts/lib/orchestration/adapters/git.js +25 -0
  207. package/scripts/lib/orchestration/adapters/index.js +31 -0
  208. package/scripts/lib/orchestration/adapters/lm-studio.js +18 -0
  209. package/scripts/lib/orchestration/adapters/ollama.js +18 -0
  210. package/scripts/lib/orchestration/adapters/opencode.js +18 -0
  211. package/scripts/lib/orchestration/adapters/openrouter.js +18 -0
  212. package/scripts/lib/orchestration/adapters/test-runner.js +25 -0
  213. package/scripts/lib/orchestration/cli.js +438 -0
  214. package/scripts/lib/orchestration/execution-manager.js +279 -0
  215. package/scripts/lib/orchestration/handoff.js +314 -0
  216. package/scripts/lib/orchestration/index.js +456 -0
  217. package/scripts/lib/orchestration/inventory.js +47 -0
  218. package/scripts/lib/orchestration/model-discovery.js +498 -0
  219. package/scripts/lib/orchestration/model-profiler.js +170 -0
  220. package/scripts/lib/orchestration/model-profiles.js +252 -0
  221. package/scripts/lib/orchestration/model-refresh-policy.js +72 -0
  222. package/scripts/lib/orchestration/proof-writer.js +349 -0
  223. package/scripts/lib/orchestration/provider-discovery/aider.js +49 -0
  224. package/scripts/lib/orchestration/provider-discovery/claude-code.js +56 -0
  225. package/scripts/lib/orchestration/provider-discovery/codex.js +49 -0
  226. package/scripts/lib/orchestration/provider-discovery/common.js +186 -0
  227. package/scripts/lib/orchestration/provider-discovery/gemini.js +106 -0
  228. package/scripts/lib/orchestration/provider-discovery/lm-studio.js +118 -0
  229. package/scripts/lib/orchestration/provider-discovery/models-dev.js +12 -0
  230. package/scripts/lib/orchestration/provider-discovery/ollama.js +100 -0
  231. package/scripts/lib/orchestration/provider-discovery/opencode.js +47 -0
  232. package/scripts/lib/orchestration/provider-discovery/openrouter.js +44 -0
  233. package/scripts/lib/orchestration/risk-classifier.js +130 -0
  234. package/scripts/lib/orchestration/routing-policy.js +486 -0
  235. package/scripts/lib/orchestration/settings.js +95 -0
  236. package/scripts/lib/orchestration/state.js +165 -0
  237. package/scripts/lib/orchestration/verification-manager.js +138 -0
  238. package/scripts/lib/outcome-evidence-stack.js +1083 -0
  239. package/scripts/lib/output-profiles.js +146 -0
  240. package/scripts/lib/package-content-audit.js +368 -0
  241. package/scripts/lib/package-runtime.js +278 -0
  242. package/scripts/lib/plan-surface.js +53 -0
  243. package/scripts/lib/plans.js +2327 -0
  244. package/scripts/lib/policy-provider.js +27 -0
  245. package/scripts/lib/prelaunch-activation-readiness.js +409 -0
  246. package/scripts/lib/prelaunch-evidence-store.js +816 -0
  247. package/scripts/lib/prelaunch-intelligence.js +869 -0
  248. package/scripts/lib/pricing-experiment.js +118 -0
  249. package/scripts/lib/pro-moment-events.js +77 -0
  250. package/scripts/lib/pro-moment-state.js +227 -0
  251. package/scripts/lib/pro-moments.js +1216 -0
  252. package/scripts/lib/product-home-receipt.js +1790 -0
  253. package/scripts/lib/product-learning-events.js +696 -0
  254. package/scripts/lib/production-confidence-control-tower.js +1209 -0
  255. package/scripts/lib/production-confidence.js +1858 -0
  256. package/scripts/lib/project-profile.js +555 -0
  257. package/scripts/lib/prompt-compiler-plan.js +94 -0
  258. package/scripts/lib/prompt-compiler.js +280 -0
  259. package/scripts/lib/prompt-lint.js +32 -0
  260. package/scripts/lib/prompt-suggestions.js +52 -0
  261. package/scripts/lib/proof-canonical.js +398 -0
  262. package/scripts/lib/proof-drilldown.js +383 -0
  263. package/scripts/lib/proof-e2e/promise-completion.js +141 -0
  264. package/scripts/lib/proof-e2e/promise-dashboard-claims.js +135 -0
  265. package/scripts/lib/proof-e2e/promise-local-proof.js +156 -0
  266. package/scripts/lib/proof-e2e/promise-provider-neutral.js +136 -0
  267. package/scripts/lib/proof-e2e/promise-registry.js +219 -0
  268. package/scripts/lib/proof-e2e/promise-security-trust.js +141 -0
  269. package/scripts/lib/proof-e2e/promise-skills-risk.js +163 -0
  270. package/scripts/lib/proof-e2e/promise-token-savings.js +112 -0
  271. package/scripts/lib/proof-e2e/promise-work-management.js +126 -0
  272. package/scripts/lib/proof-events.js +342 -0
  273. package/scripts/lib/proof-history.js +243 -0
  274. package/scripts/lib/proof-metrics.js +296 -0
  275. package/scripts/lib/proof-outcome-evidence.js +134 -0
  276. package/scripts/lib/proof-receipt.js +335 -0
  277. package/scripts/lib/proof-record.js +461 -0
  278. package/scripts/lib/proof-savings-report.js +1549 -0
  279. package/scripts/lib/public-activation-distribution-gate.js +266 -0
  280. package/scripts/lib/public-cli.js +5631 -0
  281. package/scripts/lib/public-distribution-truth.js +211 -0
  282. package/scripts/lib/public-distribution.js +73 -0
  283. package/scripts/lib/public-install-claim-checker.js +300 -0
  284. package/scripts/lib/publish-provenance-readiness.js +287 -0
  285. package/scripts/lib/readiness-delta.js +218 -0
  286. package/scripts/lib/readiness-evidence-closure.js +196 -0
  287. package/scripts/lib/reentry-memory-capture.js +241 -0
  288. package/scripts/lib/reentry-memory-retrieval.js +302 -0
  289. package/scripts/lib/reentry-memory-status.js +147 -0
  290. package/scripts/lib/reentry-memory-store.js +183 -0
  291. package/scripts/lib/reentry-state.js +66 -0
  292. package/scripts/lib/release-candidate-bundle.js +166 -0
  293. package/scripts/lib/remediation.js +81 -0
  294. package/scripts/lib/repo-map.js +391 -0
  295. package/scripts/lib/run-action-policy.js +104 -0
  296. package/scripts/lib/run-contract-receipt.js +48 -0
  297. package/scripts/lib/run-contract.js +288 -0
  298. package/scripts/lib/run-cost-to-verified-outcome.js +87 -0
  299. package/scripts/lib/run-improvements-lifecycle.js +330 -0
  300. package/scripts/lib/run-improvements.js +789 -0
  301. package/scripts/lib/run-proof-contract.js +116 -0
  302. package/scripts/lib/run-risk-classifier.js +131 -0
  303. package/scripts/lib/run-task-classifier.js +216 -0
  304. package/scripts/lib/runtime-decision-policy.js +387 -0
  305. package/scripts/lib/safe-path-engine.js +705 -0
  306. package/scripts/lib/safe-repair.js +877 -0
  307. package/scripts/lib/safe-run-controller.js +887 -0
  308. package/scripts/lib/scope-repair-before-approval.js +865 -0
  309. package/scripts/lib/score.js +262 -0
  310. package/scripts/lib/seamless-enforcement.js +329 -0
  311. package/scripts/lib/seamless-outcome.js +689 -0
  312. package/scripts/lib/seamless-reality-gate.js +5053 -0
  313. package/scripts/lib/security-confidence/activation-safety.js +78 -0
  314. package/scripts/lib/security-confidence/adapters/adapter-contract.js +125 -0
  315. package/scripts/lib/security-confidence/adapters/mock-claude-bughunter-adapter.js +36 -0
  316. package/scripts/lib/security-confidence/adapters/mock-decepticon-adapter.js +34 -0
  317. package/scripts/lib/security-confidence/adapters/mock-mcp-scan-adapter.js +35 -0
  318. package/scripts/lib/security-confidence/adapters/mock-snyk-agent-scan-adapter.js +35 -0
  319. package/scripts/lib/security-confidence/adapters/mock-tank-adapter.js +34 -0
  320. package/scripts/lib/security-confidence/adapters/reference-registry.js +63 -0
  321. package/scripts/lib/security-confidence/auth-rbac-plan.js +39 -0
  322. package/scripts/lib/security-confidence/component-inventory.js +151 -0
  323. package/scripts/lib/security-confidence/constants.js +191 -0
  324. package/scripts/lib/security-confidence/dependency-script-risk.js +95 -0
  325. package/scripts/lib/security-confidence/evidence-hygiene.js +127 -0
  326. package/scripts/lib/security-confidence/feature-impact-classifier.js +80 -0
  327. package/scripts/lib/security-confidence/file-utils.js +161 -0
  328. package/scripts/lib/security-confidence/finding-triage.js +90 -0
  329. package/scripts/lib/security-confidence/findings.js +115 -0
  330. package/scripts/lib/security-confidence/index.js +29 -0
  331. package/scripts/lib/security-confidence/permission-budget.js +93 -0
  332. package/scripts/lib/security-confidence/redaction.js +82 -0
  333. package/scripts/lib/security-confidence/redteam-fixtures.js +53 -0
  334. package/scripts/lib/security-confidence/reference-adoption.js +229 -0
  335. package/scripts/lib/security-confidence/reference-taxonomy.js +155 -0
  336. package/scripts/lib/security-confidence/report-quality.js +99 -0
  337. package/scripts/lib/security-confidence/report-writer.js +79 -0
  338. package/scripts/lib/security-confidence/risk-classifier.js +187 -0
  339. package/scripts/lib/security-confidence/runner.js +179 -0
  340. package/scripts/lib/security-confidence/schema.js +188 -0
  341. package/scripts/lib/security-confidence/secret-safety.js +74 -0
  342. package/scripts/lib/security-confidence/security-capability-router.js +98 -0
  343. package/scripts/lib/security-confidence/web-security-smoke-plan.js +46 -0
  344. package/scripts/lib/security-risk-classifier.js +511 -0
  345. package/scripts/lib/security-scan.js +396 -0
  346. package/scripts/lib/session-context-optimizer.js +1211 -0
  347. package/scripts/lib/session-timing.js +322 -0
  348. package/scripts/lib/skill-hygiene.js +805 -0
  349. package/scripts/lib/skill-packs.js +161 -0
  350. package/scripts/lib/skills-operating-layer-v1.js +1023 -0
  351. package/scripts/lib/skills-operating-layer.js +629 -0
  352. package/scripts/lib/smallest-safe-plan.js +214 -0
  353. package/scripts/lib/smart-routing-plan.js +115 -0
  354. package/scripts/lib/smart-work-routing.js +768 -0
  355. package/scripts/lib/source-catalog.js +1022 -0
  356. package/scripts/lib/status-value-summary.js +32 -0
  357. package/scripts/lib/supply-chain-dependency-guard.js +1333 -0
  358. package/scripts/lib/supply-chain-guard.js +219 -0
  359. package/scripts/lib/support-bundle.js +561 -0
  360. package/scripts/lib/support-redaction.js +66 -0
  361. package/scripts/lib/task-continuation.js +440 -0
  362. package/scripts/lib/test-helpers.js +15 -0
  363. package/scripts/lib/tier.js +38 -0
  364. package/scripts/lib/token-context-quality-gate.js +370 -0
  365. package/scripts/lib/token-cost-capture.js +187 -0
  366. package/scripts/lib/token-cost-evidence.js +862 -0
  367. package/scripts/lib/token-cost-intelligence.js +358 -0
  368. package/scripts/lib/token-efficiency-evidence.js +213 -0
  369. package/scripts/lib/token-efficiency-map.js +110 -0
  370. package/scripts/lib/token-evidence.js +703 -0
  371. package/scripts/lib/tokenish.js +17 -0
  372. package/scripts/lib/tool-output-sandbox.js +559 -0
  373. package/scripts/lib/trust-audit.js +136 -0
  374. package/scripts/lib/unified-events.js +396 -0
  375. package/scripts/lib/upgrade-interruption-recovery.js +407 -0
  376. package/scripts/lib/usage-ledger.js +201 -0
  377. package/scripts/lib/value-ledger.js +130 -0
  378. package/scripts/lib/value-proof-calibration.js +531 -0
  379. package/scripts/lib/visual-qa.js +231 -0
  380. package/scripts/lib/voice-alpha.js +29 -0
  381. package/scripts/lib/webhook-idempotency-guard.js +990 -0
  382. package/scripts/lib/work-aware-orchestration.js +976 -0
  383. package/scripts/lib/work-control-receipts.js +577 -0
  384. package/scripts/lib/work-ledger.js +1123 -0
  385. package/scripts/lib/work-panel-preview.js +352 -0
  386. package/scripts/lib/workflow-discipline.js +280 -0
  387. package/scripts/lib/workflow-intelligence-radar.js +804 -0
  388. package/scripts/lib/workflow-signals.js +419 -0
  389. package/scripts/lib/workspace-map.js +281 -0
  390. package/scripts/lib/workspace-registry.js +1367 -0
  391. package/scripts/lib/workspace-resolver.js +542 -0
  392. package/scripts/wuz-doctor.js +315 -0
  393. package/bin/avorelo.mjs +0 -7
  394. package/dist/avorelo.mjs +0 -24678
@@ -0,0 +1,1549 @@
1
+ "use strict";
2
+
3
+ // Proof & Savings Report — local evidence-backed report explaining what improved,
4
+ // what was validated, what was saved or avoided, what risks remain, and the next best action.
5
+ //
6
+ // No cloud calls, no LLM, no daemon, no marketing copy.
7
+ // Evidence-backed. Conservative estimates. Honest limitations.
8
+ //
9
+ // Report artifacts:
10
+ // .claude/cco/reports/proof-savings-report.json — avorelo.proofSavingsReport.v1
11
+ // .claude/cco/reports/proof-savings-report.md — Markdown report
12
+ //
13
+ // Evidence quality values:
14
+ // sufficient — multiple validated signals from real artifacts
15
+ // candidate — some signals, partial coverage
16
+ // insufficient — few or weak signals
17
+ // stale — artifacts exist but TTL exceeded or fingerprint mismatch
18
+ // fixture_only — only test fixture artifacts found
19
+ // error — unexpected error during collection
20
+
21
+ const fs = require("fs");
22
+ const path = require("path");
23
+ const crypto = require("crypto");
24
+
25
+ const REPORT_JSON_REL = ".claude/cco/reports/proof-savings-report.json";
26
+ const REPORT_MD_REL = ".claude/cco/reports/proof-savings-report.md";
27
+ const SCHEMA_VERSION = "avorelo.proofSavingsReport.v1";
28
+
29
+ const EVIDENCE_QUALITY_VALUES = [
30
+ "sufficient",
31
+ "candidate",
32
+ "insufficient",
33
+ "stale",
34
+ "fixture_only",
35
+ "error",
36
+ ];
37
+
38
+ const PROOF_TYPES = ["real", "dogfood", "fixture", "insufficient"];
39
+
40
+ const SAVINGS_CATEGORIES = [
41
+ "avoided_repeated_setup",
42
+ "avoided_validation_rework",
43
+ "avoided_context_waste",
44
+ "avoided_risky_action",
45
+ "avoided_public_claim_rework",
46
+ "token_or_cost_waste_avoided",
47
+ "manual_investigation_avoided",
48
+ ];
49
+
50
+ const RISK_CATEGORIES = [
51
+ "missing_proof",
52
+ "stale_context",
53
+ "fake_applied_claim",
54
+ "unsupported_host_assumption",
55
+ "unsafe_public_claim",
56
+ "prompt_or_instruction_risk",
57
+ "token_cost_gap",
58
+ "repo_state_risk",
59
+ "unresolved_validation_gap",
60
+ "production_orchestration_missing",
61
+ ];
62
+
63
+ // Conservative time heuristics (min, max) in minutes per confidence tier.
64
+ // These are heuristics, not measured values. Always mark as estimate.
65
+ const MINUTE_HEURISTICS = {
66
+ avoided_repeated_setup: { low: [3, 5], medium: [6, 12], high: [12, 20] },
67
+ avoided_validation_rework: { low: [5, 10], medium: [10, 20], high: [20, 40] },
68
+ avoided_context_waste: { low: [2, 5], medium: [5, 12], high: [12, 25] },
69
+ avoided_risky_action: { low: [2, 5], medium: [5, 15], high: [15, 30] },
70
+ avoided_public_claim_rework: { low: [3, 8], medium: [8, 18], high: [18, 35] },
71
+ token_or_cost_waste_avoided: { low: [2, 5], medium: [5, 12], high: [12, 25] },
72
+ manual_investigation_avoided: { low: [5, 10], medium: [10, 25], high: [25, 45] },
73
+ };
74
+
75
+ function nowIso() {
76
+ return new Date().toISOString();
77
+ }
78
+
79
+ function buildFingerprint(data) {
80
+ return crypto
81
+ .createHash("sha256")
82
+ .update(JSON.stringify(data))
83
+ .digest("hex")
84
+ .slice(0, 16);
85
+ }
86
+
87
+ // ── Evidence collection ───────────────────────────────────────────────────────
88
+
89
+ function collectEvidence(cwd) {
90
+ const ev = {
91
+ runImprovements: null,
92
+ lifecycleReceipt: null,
93
+ nextRunContext: null,
94
+ learningSummary: null,
95
+ decisionRegister: null,
96
+ riskRegister: null,
97
+ adapterReadiness: null,
98
+ outcomeEvents: null,
99
+ tokenEvidence: null,
100
+ costEvidence: null,
101
+ tokenCostEvidence: null,
102
+ fullReadinessGate: null,
103
+ proofReceipts: null,
104
+ };
105
+
106
+ // Run improvements artifact
107
+ try {
108
+ const { loadRunImprovements } = require("./run-improvements");
109
+ ev.runImprovements = loadRunImprovements(cwd);
110
+ } catch {}
111
+
112
+ // Lifecycle receipt
113
+ try {
114
+ const { loadLifecycleReceipt } = require("./run-improvements-lifecycle");
115
+ ev.lifecycleReceipt = loadLifecycleReceipt(cwd);
116
+ } catch {}
117
+
118
+ // Next-run context
119
+ try {
120
+ const { loadNextRunContext } = require("./next-run-context");
121
+ ev.nextRunContext = loadNextRunContext(cwd);
122
+ } catch {}
123
+
124
+ // Learning artifacts
125
+ try {
126
+ const { loadLearningSummary, loadDecisionRegister, loadRiskRegister } = require("./learning-memory");
127
+ ev.learningSummary = loadLearningSummary(cwd);
128
+ ev.decisionRegister = loadDecisionRegister(cwd);
129
+ ev.riskRegister = loadRiskRegister(cwd);
130
+ } catch {}
131
+
132
+ // Adapter readiness
133
+ try {
134
+ const { buildAdapterReadinessSurface } = require("./adapter-readiness");
135
+ ev.adapterReadiness = buildAdapterReadinessSurface(cwd);
136
+ } catch {}
137
+
138
+ // Outcome events (last 7 days, exclude run_improvements audit category)
139
+ try {
140
+ const { readOutcomeEvents, aggregateOutcomeEvents } = require("./unified-events");
141
+ const raw = readOutcomeEvents(cwd);
142
+ const events = raw.filter((e) => e.category !== "run_improvements");
143
+ if (events.length > 0) {
144
+ ev.outcomeEvents = aggregateOutcomeEvents(events, { days: 7 });
145
+ }
146
+ } catch {}
147
+
148
+ // Proof receipts — latest from .claude/cco/receipts/
149
+ try {
150
+ const receiptsDir = path.join(cwd, ".claude", "cco", "receipts");
151
+ if (fs.existsSync(receiptsDir)) {
152
+ const files = fs.readdirSync(receiptsDir).filter((f) => f.endsWith(".json"));
153
+ if (files.length > 0) {
154
+ const sorted = files
155
+ .map((n) => ({ n, mt: fs.statSync(path.join(receiptsDir, n)).mtimeMs }))
156
+ .sort((a, b) => b.mt - a.mt);
157
+ const latest = JSON.parse(
158
+ fs.readFileSync(path.join(receiptsDir, sorted[0].n), "utf8")
159
+ );
160
+ ev.proofReceipts = {
161
+ count: files.length,
162
+ latest: {
163
+ completionStatus: latest.result?.status || "unknown",
164
+ material: latest.material || false,
165
+ antiGamingValid: latest.anti_gaming?.valid !== false,
166
+ },
167
+ };
168
+ }
169
+ }
170
+ } catch {}
171
+
172
+ // Token evidence — absent unless artifact exists
173
+ try {
174
+ const te = require("./token-evidence");
175
+ if (typeof te.loadTokenEvidence === "function") {
176
+ ev.tokenEvidence = te.loadTokenEvidence(cwd);
177
+ }
178
+ } catch {}
179
+
180
+ // Cost evidence — absent unless artifact exists
181
+ try {
182
+ const ce = require("./cost-evidence");
183
+ if (typeof ce.loadCostEvidence === "function") {
184
+ ev.costEvidence = ce.loadCostEvidence(cwd);
185
+ }
186
+ } catch {}
187
+
188
+ // Unified token/cost evidence — absent unless artifact exists
189
+ try {
190
+ const tce = require("./token-cost-evidence");
191
+ if (typeof tce.loadTokenCostEvidence === "function") {
192
+ const raw = tce.loadTokenCostEvidence({ cwd });
193
+ if (raw) {
194
+ const validation = tce.validateTokenCostEvidence(raw);
195
+ // Only use evidence that is valid and not a test fixture
196
+ if (validation.valid && !validation.isFixture) {
197
+ ev.tokenCostEvidence = raw;
198
+ }
199
+ }
200
+ }
201
+ } catch {}
202
+
203
+ // Full-readiness gate — optional
204
+ try {
205
+ const frg = require("./full-readiness-gate");
206
+ if (typeof frg.loadFullReadinessGate === "function") {
207
+ ev.fullReadinessGate = frg.loadFullReadinessGate(cwd);
208
+ } else if (typeof frg.buildFullReadinessGate === "function") {
209
+ ev.fullReadinessGate = frg.buildFullReadinessGate(cwd);
210
+ }
211
+ } catch {}
212
+
213
+ return ev;
214
+ }
215
+
216
+ // ── Evidence quality classification ──────────────────────────────────────────
217
+
218
+ function classifyEvidenceQuality(ev) {
219
+ const populated = Object.values(ev).filter((v) => v !== null).length;
220
+ if (populated === 0) return "error";
221
+
222
+ const ri = ev.runImprovements;
223
+ const riExpired =
224
+ ri &&
225
+ (ri.status === "expired" || ri.status === "stale" || ri.status === "not_available");
226
+ const nrc = ev.nextRunContext;
227
+ const nrcExpired =
228
+ nrc && (nrc.status === "expired" || nrc.status === "stale" || nrc.status === "not_available");
229
+
230
+ // Stale: main artifact is expired and no other live signals
231
+ if (
232
+ ri &&
233
+ riExpired &&
234
+ (!nrc || nrcExpired) &&
235
+ !ev.lifecycleReceipt &&
236
+ !ev.learningSummary
237
+ ) {
238
+ return "stale";
239
+ }
240
+
241
+ // Count live, real signal sources
242
+ let signalCount = 0;
243
+ if (ri && !riExpired) signalCount++;
244
+ if (ev.lifecycleReceipt) signalCount++;
245
+ if (nrc && !nrcExpired) signalCount++;
246
+ if (ev.learningSummary) signalCount++;
247
+ if (ev.proofReceipts) signalCount++;
248
+ if (ev.adapterReadiness && ev.adapterReadiness.readiness?.verdict !== "adapter_not_ready") signalCount++;
249
+ if (ev.fullReadinessGate && ev.fullReadinessGate.status === "ok") signalCount++;
250
+
251
+ if (signalCount >= 3) return "sufficient";
252
+ if (signalCount >= 1) return "candidate";
253
+ return "insufficient";
254
+ }
255
+
256
+ // ── Proof section ─────────────────────────────────────────────────────────────
257
+
258
+ function buildProofSection(ev) {
259
+ const validatedSignals = [];
260
+ const limitations = [];
261
+
262
+ // Run improvements artifact
263
+ const ri = ev.runImprovements;
264
+ if (ri) {
265
+ if (ri.status === "expired" || ri.status === "stale") {
266
+ limitations.push(
267
+ "Run improvements artifact is expired or stale — proof signal degraded."
268
+ );
269
+ } else if (
270
+ ri.status === "not_available" ||
271
+ ri.status === "insufficient_evidence"
272
+ ) {
273
+ limitations.push(
274
+ "Run improvements: insufficient evidence — no validated improvement signals."
275
+ );
276
+ } else {
277
+ validatedSignals.push({
278
+ signal: "run_improvements_prepared",
279
+ description: `Run improvements ${ri.status}: ${
280
+ (ri.topImprovements || []).length
281
+ } improvement(s), ${(ri.nextRunDefaults || []).length} next-run default(s).`,
282
+ proofType: "real",
283
+ source: "run_improvements_artifact",
284
+ reasonCodes: ri.reasonCodes || [],
285
+ });
286
+ }
287
+ } else {
288
+ limitations.push("No run improvements artifact found.");
289
+ }
290
+
291
+ // Lifecycle receipt
292
+ const lc = ev.lifecycleReceipt;
293
+ if (lc) {
294
+ validatedSignals.push({
295
+ signal: "lifecycle_receipt_exists",
296
+ description: `Lifecycle receipt: ${lc.lifecycleState} (surface: ${
297
+ lc.surface || "unknown"
298
+ }).`,
299
+ proofType: "real",
300
+ source: "lifecycle_receipt",
301
+ reasonCodes: lc.reasonCodes || [],
302
+ });
303
+ if (lc.lifecycleState === "applied") {
304
+ validatedSignals.push({
305
+ signal: "run_improvements_applied",
306
+ description: `Run improvements applied via ${lc.surface || "unknown"} at ${
307
+ lc.appliedAt || "unknown"
308
+ }.`,
309
+ proofType: "real",
310
+ source: "lifecycle_receipt",
311
+ reasonCodes: ["LIFECYCLE_HONEST_CLAIM"],
312
+ });
313
+ }
314
+ } else {
315
+ limitations.push(
316
+ "No lifecycle receipt found — applied state cannot be confirmed."
317
+ );
318
+ }
319
+
320
+ // Next-run context
321
+ const nrc = ev.nextRunContext;
322
+ if (nrc) {
323
+ if (nrc.status === "expired") {
324
+ limitations.push("Next-run context artifact is expired.");
325
+ } else if (
326
+ nrc.status !== "not_available" &&
327
+ nrc.status !== "insufficient_evidence"
328
+ ) {
329
+ validatedSignals.push({
330
+ signal: "next_run_context_exists",
331
+ description: `Next-run context: ${nrc.status}, ${
332
+ (nrc.appliedDefaults || []).length
333
+ } default(s), ${nrc.activeDecisionCount || 0} decision(s).`,
334
+ proofType: "real",
335
+ source: "next_run_context",
336
+ reasonCodes: nrc.reasonCodes || [],
337
+ });
338
+ }
339
+ } else {
340
+ limitations.push("No next-run context artifact found.");
341
+ }
342
+
343
+ // Learning summary
344
+ if (ev.learningSummary) {
345
+ const ls = ev.learningSummary;
346
+ validatedSignals.push({
347
+ signal: "learning_summary_exists",
348
+ description: `Learning summary: ${ls.activeDecisionCount} decision(s), ${ls.activeRiskCount} risk(s), ${ls.capabilityCount} capability(ies).`,
349
+ proofType: "real",
350
+ source: "learning_summary",
351
+ reasonCodes: [],
352
+ });
353
+ } else {
354
+ limitations.push("No learning summary found.");
355
+ }
356
+
357
+ // Proof receipts
358
+ if (ev.proofReceipts) {
359
+ const pr = ev.proofReceipts;
360
+ const completed = pr.latest.completionStatus === "completed";
361
+ validatedSignals.push({
362
+ signal: "proof_receipt_exists",
363
+ description: `Proof receipt found (${pr.count} total). Latest: status=${pr.latest.completionStatus}, material=${pr.latest.material}.`,
364
+ proofType: completed ? "real" : "dogfood",
365
+ source: "proof_receipts",
366
+ reasonCodes: completed ? [] : ["INCOMPLETE_PROOF_RECEIPT"],
367
+ });
368
+ if (!completed) {
369
+ limitations.push("Latest proof receipt is not 'completed' — proof is partial.");
370
+ }
371
+ } else {
372
+ limitations.push("No proof receipts found in .claude/cco/receipts/.");
373
+ }
374
+
375
+ // Adapter readiness — only a validated signal when adapter is actually ready
376
+ if (
377
+ ev.adapterReadiness &&
378
+ ev.adapterReadiness.readiness?.verdict !== "adapter_not_ready"
379
+ ) {
380
+ validatedSignals.push({
381
+ signal: "adapter_readiness_available",
382
+ description: `Adapter readiness: ${
383
+ ev.adapterReadiness.readiness?.status || "checked"
384
+ }.`,
385
+ proofType: "real",
386
+ source: "adapter_readiness",
387
+ reasonCodes: [],
388
+ });
389
+ }
390
+
391
+ // Full readiness gate
392
+ if (ev.fullReadinessGate) {
393
+ const fg = ev.fullReadinessGate;
394
+ validatedSignals.push({
395
+ signal: "full_readiness_gate_run",
396
+ description: `Full readiness gate: ${fg.status || "available"}.`,
397
+ proofType: "real",
398
+ source: "full_readiness_gate",
399
+ reasonCodes: [],
400
+ });
401
+ }
402
+
403
+ // Token/cost evidence — only counts as validated signal when it is real, non-fixture
404
+ if (ev.tokenCostEvidence) {
405
+ try {
406
+ const { summarizeTokenCostEvidence } = require("./token-cost-evidence");
407
+ const tceSum = summarizeTokenCostEvidence(ev.tokenCostEvidence);
408
+ if (tceSum.available && !tceSum.isFixture) {
409
+ const tokenStr = tceSum.totalTokens !== null
410
+ ? `${(tceSum.totalTokens / 1000).toFixed(1)}k tokens`
411
+ : "tokens: unknown";
412
+ const costStr = tceSum.totalCost !== null
413
+ ? `, ~$${tceSum.totalCost.toFixed(4)}`
414
+ : ", cost: not estimated";
415
+ validatedSignals.push({
416
+ signal: "token_cost_evidence_valid",
417
+ description: `Token/cost evidence: ${tokenStr}${costStr}, ${tceSum.confidence} confidence.`,
418
+ proofType: tceSum.isDogfood ? "dogfood" : "real",
419
+ source: "token_cost_evidence",
420
+ reasonCodes: (tceSum.reasonCodes || []).slice(0, 3),
421
+ });
422
+ }
423
+ } catch {}
424
+ }
425
+
426
+ const proofType =
427
+ validatedSignals.length >= 3
428
+ ? "real"
429
+ : validatedSignals.length >= 1
430
+ ? "dogfood"
431
+ : "insufficient";
432
+
433
+ const proofCoverage =
434
+ validatedSignals.length === 0
435
+ ? "none"
436
+ : validatedSignals.length <= 2
437
+ ? "partial"
438
+ : "sufficient";
439
+
440
+ return {
441
+ validatedSignals,
442
+ validatedSignalCount: validatedSignals.length,
443
+ proofType,
444
+ proofCoverage,
445
+ limitations,
446
+ };
447
+ }
448
+
449
+ // ── Savings section ───────────────────────────────────────────────────────────
450
+
451
+ function makeSavingsEstimate(
452
+ category,
453
+ confidence,
454
+ basis,
455
+ evidenceRefs,
456
+ limitations = [],
457
+ reasonCodes = []
458
+ ) {
459
+ const heuristic = MINUTE_HEURISTICS[category];
460
+ const range = heuristic
461
+ ? heuristic[confidence] || heuristic.low
462
+ : null;
463
+ return {
464
+ category,
465
+ estimateType: "conservative_heuristic",
466
+ estimatedMinutesRange: range ? { min: range[0], max: range[1] } : null,
467
+ tokenSavings: null, // Only set when token evidence exists
468
+ costSavings: null, // Only set when cost evidence exists
469
+ confidence,
470
+ basis,
471
+ evidenceRefs,
472
+ limitations: [
473
+ "This is a conservative heuristic estimate, not a measured value.",
474
+ ...limitations,
475
+ ],
476
+ reasonCodes,
477
+ };
478
+ }
479
+
480
+ function buildSavingsSection(ev) {
481
+ const estimates = [];
482
+
483
+ // avoided_repeated_setup: run improvements prepared with improvements
484
+ const ri = ev.runImprovements;
485
+ if (
486
+ ri &&
487
+ ri.status !== "not_available" &&
488
+ ri.status !== "expired" &&
489
+ ri.status !== "stale" &&
490
+ ri.status !== "insufficient_evidence" &&
491
+ Array.isArray(ri.topImprovements) &&
492
+ ri.topImprovements.length > 0
493
+ ) {
494
+ const improvCount = ri.topImprovements.length;
495
+ const confidence =
496
+ improvCount >= 3 ? "medium" : improvCount >= 1 ? "low" : "insufficient";
497
+ if (confidence !== "insufficient") {
498
+ estimates.push(
499
+ makeSavingsEstimate(
500
+ "avoided_repeated_setup",
501
+ confidence,
502
+ `${improvCount} run improvement(s) prepared — next-run defaults reduce redundant context setup.`,
503
+ ["run_improvements_artifact"],
504
+ [
505
+ "Estimate assumes defaults would have been discovered manually in a follow-up session.",
506
+ ],
507
+ (ri.reasonCodes || []).slice(0, 3)
508
+ )
509
+ );
510
+ }
511
+ }
512
+
513
+ // avoided_validation_rework: lifecycle applied + proof receipt
514
+ const lc = ev.lifecycleReceipt;
515
+ if (lc && lc.lifecycleState === "applied" && ev.proofReceipts) {
516
+ estimates.push(
517
+ makeSavingsEstimate(
518
+ "avoided_validation_rework",
519
+ "medium",
520
+ "Lifecycle applied + proof receipt exists — validation state was captured, avoiding re-validation in next session.",
521
+ ["lifecycle_receipt", "proof_receipts"],
522
+ [
523
+ "Assumes validation would be repeated without this artifact.",
524
+ "Estimate is conservative.",
525
+ ],
526
+ ["LIFECYCLE_HONEST_CLAIM"]
527
+ )
528
+ );
529
+ } else if (lc && lc.lifecycleState === "applied") {
530
+ estimates.push(
531
+ makeSavingsEstimate(
532
+ "avoided_validation_rework",
533
+ "low",
534
+ "Lifecycle applied — defaults injected into next run via next-run context.",
535
+ ["lifecycle_receipt"],
536
+ ["No proof receipt to corroborate. Lower confidence."],
537
+ ["LIFECYCLE_HONEST_CLAIM"]
538
+ )
539
+ );
540
+ }
541
+
542
+ // avoided_context_waste: next-run context with defaults
543
+ const nrc = ev.nextRunContext;
544
+ if (
545
+ nrc &&
546
+ nrc.status !== "not_available" &&
547
+ nrc.status !== "expired" &&
548
+ nrc.status !== "insufficient_evidence" &&
549
+ (nrc.appliedDefaults || []).length > 0
550
+ ) {
551
+ estimates.push(
552
+ makeSavingsEstimate(
553
+ "avoided_context_waste",
554
+ "medium",
555
+ `Next-run context with ${nrc.appliedDefaults.length} default(s) and ${
556
+ nrc.activeDecisionCount || 0
557
+ } decision(s) prepared — reduces context re-discovery in next session.`,
558
+ ["next_run_context"],
559
+ [
560
+ "Assumes context would be rediscovered manually without this artifact.",
561
+ ],
562
+ (nrc.reasonCodes || []).slice(0, 3)
563
+ )
564
+ );
565
+ }
566
+
567
+ // avoided_risky_action: learning risks + lifecycle receipt
568
+ if (ev.learningSummary && ev.learningSummary.activeRiskCount > 0 && lc) {
569
+ const riskCount = ev.learningSummary.activeRiskCount;
570
+ estimates.push(
571
+ makeSavingsEstimate(
572
+ "avoided_risky_action",
573
+ riskCount >= 2 ? "medium" : "low",
574
+ `${riskCount} active risk(s) tracked in learning memory — risk awareness carried forward reduces risky action probability.`,
575
+ ["learning_summary", "lifecycle_receipt"],
576
+ [
577
+ "Risk reduction is probabilistic, not guaranteed.",
578
+ "Minutes are not directly measurable.",
579
+ ],
580
+ ["LIFECYCLE_HONEST_CLAIM"]
581
+ )
582
+ );
583
+ }
584
+
585
+ // manual_investigation_avoided: learning decisions active
586
+ if (ev.learningSummary && ev.learningSummary.activeDecisionCount > 0) {
587
+ const decCount = ev.learningSummary.activeDecisionCount;
588
+ estimates.push(
589
+ makeSavingsEstimate(
590
+ "manual_investigation_avoided",
591
+ decCount >= 3 ? "medium" : "low",
592
+ `${decCount} active decision(s) in learning register — decisions carried forward avoid re-investigation.`,
593
+ ["learning_summary"],
594
+ [
595
+ "Assumes decisions would need to be re-derived without learning memory.",
596
+ ],
597
+ []
598
+ )
599
+ );
600
+ }
601
+
602
+ // ── Token/cost evidence integration ──────────────────────────────────────
603
+ // Use unified token-cost-evidence artifact if available.
604
+ // Fall back to legacy tokenEvidence/costEvidence artifacts if present.
605
+
606
+ let tceSummary = null;
607
+ try {
608
+ const { summarizeTokenCostEvidence } = require("./token-cost-evidence");
609
+ if (ev.tokenCostEvidence) {
610
+ tceSummary = summarizeTokenCostEvidence(ev.tokenCostEvidence);
611
+ }
612
+ } catch {}
613
+
614
+ // token_or_cost_waste_avoided: only when valid token evidence present
615
+ const hasRealTokenCost = tceSummary && tceSummary.available && !tceSummary.isFixture;
616
+ const legacyTokenEvidence = ev.tokenEvidence && ev.tokenEvidence.measurements &&
617
+ (ev.tokenEvidence.measurements.totalProviderTokens ||
618
+ ev.tokenEvidence.measurements.candidateTokenReduction);
619
+
620
+ if (hasRealTokenCost && tceSummary.totalTokens) {
621
+ const tokenK = Math.round(tceSummary.totalTokens / 1000);
622
+ const isDogfood = tceSummary.isDogfood;
623
+ estimates.push(
624
+ makeSavingsEstimate(
625
+ "token_or_cost_waste_avoided",
626
+ isDogfood ? "low" : "low",
627
+ isDogfood
628
+ ? `Token usage tracked via dogfood evidence: ~${tokenK}k tokens. Candidate only — not high-confidence real evidence.`
629
+ : `Token usage tracked: ~${tokenK}k tokens from safe local evidence.`,
630
+ ["token_cost_evidence"],
631
+ [
632
+ "Token savings require a measured baseline for accurate estimation.",
633
+ isDogfood ? "Dogfood evidence: candidate signal, not high-confidence real evidence." : null,
634
+ tceSummary.totalCost === null ? "Cost estimate not available — no explicit cost data in evidence." : null,
635
+ ].filter(Boolean),
636
+ tceSummary.reasonCodes || []
637
+ )
638
+ );
639
+ } else if (legacyTokenEvidence) {
640
+ // Legacy fallback
641
+ estimates.push(
642
+ makeSavingsEstimate(
643
+ "token_or_cost_waste_avoided",
644
+ "low",
645
+ "Token evidence present — token usage is being tracked.",
646
+ ["token_evidence"],
647
+ ["Token savings require baseline measurement for accurate estimation."],
648
+ []
649
+ )
650
+ );
651
+ }
652
+
653
+ const totalMinSaved = estimates.reduce(
654
+ (sum, e) => sum + (e.estimatedMinutesRange?.min || 0),
655
+ 0
656
+ );
657
+ const totalMaxSaved = estimates.reduce(
658
+ (sum, e) => sum + (e.estimatedMinutesRange?.max || 0),
659
+ 0
660
+ );
661
+
662
+ const overallConfidence =
663
+ estimates.length >= 3
664
+ ? "medium"
665
+ : estimates.length >= 1
666
+ ? "low"
667
+ : "insufficient";
668
+
669
+ // Determine token/cost evidence summary for report fields
670
+ const hasTokenEvidence = (tceSummary && tceSummary.totalTokens !== null && !tceSummary.isFixture) ||
671
+ legacyTokenEvidence;
672
+ const hasCostEvidence = (tceSummary && tceSummary.totalCost !== null && !tceSummary.isFixture) ||
673
+ (ev.costEvidence && ev.costEvidence.preferredMeasuredCost && ev.costEvidence.preferredMeasuredCost > 0);
674
+
675
+ const tokenCostLimitations = [
676
+ ...(!hasTokenEvidence ? ["No token evidence found — token savings not estimated."] : []),
677
+ ...(!hasCostEvidence ? ["No cost evidence found — cost savings not estimated."] : []),
678
+ ...(tceSummary?.limitations || []).slice(0, 2),
679
+ ];
680
+
681
+ const limitations = [
682
+ "All estimates are conservative heuristics, not measured values.",
683
+ "Prefer 'estimated X–Y minutes avoided' over 'saved X minutes'.",
684
+ ...tokenCostLimitations.slice(0, 2),
685
+ ];
686
+
687
+ // Build token savings block — only when token evidence is real
688
+ const tokenSavingsBlock = (() => {
689
+ if (tceSummary && tceSummary.totalTokens !== null && !tceSummary.isFixture) {
690
+ return {
691
+ available: true,
692
+ totalTokens: tceSummary.totalTokens,
693
+ confidence: tceSummary.confidence,
694
+ isDogfood: tceSummary.isDogfood,
695
+ evidence: "token_cost_evidence artifact",
696
+ limitations: tceSummary.limitations.slice(0, 2),
697
+ note: tceSummary.isDogfood
698
+ ? "Dogfood evidence: candidate signal only."
699
+ : "Token evidence from safe local sources.",
700
+ };
701
+ }
702
+ if (legacyTokenEvidence) {
703
+ return {
704
+ available: true,
705
+ evidence: "token_evidence artifact",
706
+ note: "Token evidence present. See token-evidence module for details.",
707
+ };
708
+ }
709
+ return null;
710
+ })();
711
+
712
+ // Build cost savings block — only when explicit cost evidence exists
713
+ const costSavingsBlock = (() => {
714
+ if (tceSummary && tceSummary.totalCost !== null && !tceSummary.isFixture) {
715
+ return {
716
+ available: true,
717
+ totalCost: tceSummary.totalCost,
718
+ currency: tceSummary.currency || "USD",
719
+ confidence: tceSummary.confidence,
720
+ isDogfood: tceSummary.isDogfood,
721
+ evidence: "token_cost_evidence artifact",
722
+ note: "Cost from safe local evidence. Not suitable for billing reconciliation.",
723
+ };
724
+ }
725
+ if (ev.costEvidence && ev.costEvidence.preferredMeasuredCost && ev.costEvidence.preferredMeasuredCost > 0) {
726
+ return {
727
+ available: true,
728
+ evidence: "cost_evidence artifact",
729
+ note: "Cost evidence present. See cost-evidence module for details.",
730
+ };
731
+ }
732
+ return null;
733
+ })();
734
+
735
+ return {
736
+ estimates,
737
+ tokenCostEvidence: tceSummary
738
+ ? {
739
+ sourceType: tceSummary.sourceType,
740
+ available: tceSummary.available,
741
+ totalTokens: tceSummary.totalTokens,
742
+ totalCost: tceSummary.totalCost,
743
+ currency: tceSummary.currency,
744
+ confidence: tceSummary.confidence,
745
+ isFixture: tceSummary.isFixture,
746
+ isDogfood: tceSummary.isDogfood,
747
+ recordCount: tceSummary.recordCount,
748
+ limitations: tceSummary.limitations,
749
+ }
750
+ : null,
751
+ estimatedTokenSavings: tokenSavingsBlock ? tokenSavingsBlock.totalTokens ?? null : null,
752
+ estimatedCostSavings: costSavingsBlock ? costSavingsBlock.totalCost ?? null : null,
753
+ tokenCostConfidence: tceSummary?.confidence ?? "unavailable",
754
+ tokenCostLimitations,
755
+ tokenSavings: tokenSavingsBlock,
756
+ costSavings: costSavingsBlock,
757
+ conservativeTotalMinutesRange:
758
+ estimates.length > 0 ? { min: totalMinSaved, max: totalMaxSaved } : null,
759
+ overallConfidence,
760
+ limitations,
761
+ };
762
+ }
763
+
764
+ // ── Risk section ──────────────────────────────────────────────────────────────
765
+
766
+ function buildRiskSection(ev) {
767
+ const openRisks = [];
768
+ const reducedRisks = [];
769
+ const blockedClaims = [];
770
+
771
+ // Missing proof
772
+ if (!ev.proofReceipts) {
773
+ openRisks.push({
774
+ category: "missing_proof",
775
+ title: "No proof receipts found",
776
+ severity: "medium",
777
+ nextMitigation:
778
+ "Run an Avorelo session with proof capture enabled.",
779
+ evidenceRefs: [],
780
+ reasonCodes: ["NO_PROOF_RECEIPT"],
781
+ });
782
+ }
783
+
784
+ // Fake applied claim: run improvements says applied but no receipt
785
+ const ri = ev.runImprovements;
786
+ const lc = ev.lifecycleReceipt;
787
+ if (ri && ri.status === "applied" && !lc) {
788
+ blockedClaims.push({
789
+ category: "fake_applied_claim",
790
+ title:
791
+ "Run improvements shows 'applied' but no lifecycle receipt exists",
792
+ severity: "high",
793
+ nextMitigation:
794
+ "Re-apply via `avorelo run-improvements --apply` to generate a legitimate receipt.",
795
+ evidenceRefs: ["run_improvements_artifact"],
796
+ reasonCodes: ["LIFECYCLE_HONEST_CLAIM"],
797
+ });
798
+ } else if (lc && lc.lifecycleState === "applied") {
799
+ reducedRisks.push({
800
+ category: "fake_applied_claim",
801
+ title: "Applied claim is backed by lifecycle receipt",
802
+ severity: "none",
803
+ evidenceRefs: ["lifecycle_receipt"],
804
+ reasonCodes: ["LIFECYCLE_HONEST_CLAIM"],
805
+ });
806
+ }
807
+
808
+ // Stale context
809
+ if (ri && (ri.status === "expired" || ri.status === "stale")) {
810
+ openRisks.push({
811
+ category: "stale_context",
812
+ title: "Run improvements artifact is expired or stale",
813
+ severity: "medium",
814
+ nextMitigation:
815
+ "Regenerate via `avorelo run-improvements --generate`.",
816
+ evidenceRefs: ["run_improvements_artifact"],
817
+ reasonCodes: ["STALE_ARTIFACT_RISK"],
818
+ });
819
+ }
820
+
821
+ // Production orchestration missing — always note; local-only limitation
822
+ openRisks.push({
823
+ category: "production_orchestration_missing",
824
+ title: "No production orchestration receipt in this workspace",
825
+ severity: "low",
826
+ nextMitigation:
827
+ "Expected in local development. Production receipts are generated during real sessions.",
828
+ evidenceRefs: [],
829
+ reasonCodes: ["LOCAL_WORKSPACE_ONLY"],
830
+ note: "This is a local-workspace limitation, not a product failure.",
831
+ });
832
+
833
+ // Unsupported host assumption — adapter readiness always runs but may return not_ready
834
+ if (!ev.adapterReadiness || ev.adapterReadiness.readiness?.verdict === "adapter_not_ready") {
835
+ openRisks.push({
836
+ category: "unsupported_host_assumption",
837
+ title: "Adapter readiness not checked — host capabilities unknown",
838
+ severity: "low",
839
+ nextMitigation:
840
+ "Run `avorelo adapter-readiness` to verify host support.",
841
+ evidenceRefs: [],
842
+ reasonCodes: ["HOST_SUPPORT_HOST_SPECIFIC"],
843
+ });
844
+ } else {
845
+ reducedRisks.push({
846
+ category: "unsupported_host_assumption",
847
+ title: "Adapter readiness checked — host capabilities known",
848
+ severity: "none",
849
+ evidenceRefs: ["adapter_readiness"],
850
+ reasonCodes: ["HOST_SUPPORT_HOST_SPECIFIC"],
851
+ });
852
+ }
853
+
854
+ // Token/cost gap — check unified evidence first, then legacy
855
+ const hasTCE = ev.tokenCostEvidence !== null;
856
+ const hasLegacyToken = ev.tokenEvidence !== null;
857
+ const hasLegacyCost = ev.costEvidence !== null;
858
+ const hasSufficientTokenCost = hasTCE || (hasLegacyToken && hasLegacyCost);
859
+
860
+ if (!hasSufficientTokenCost) {
861
+ if (hasTCE) {
862
+ // Has unified evidence but no cost — lower severity
863
+ openRisks.push({
864
+ category: "token_cost_gap",
865
+ title: "Token evidence available but cost evidence absent — cost savings not estimated",
866
+ severity: "low",
867
+ nextMitigation:
868
+ "Import redacted cost evidence via `avorelo token-evidence --import <path>` to enable cost estimates.",
869
+ evidenceRefs: ["token_cost_evidence"],
870
+ reasonCodes: ["NO_COST_EVIDENCE"],
871
+ });
872
+ } else {
873
+ openRisks.push({
874
+ category: "token_cost_gap",
875
+ title: "Token or cost evidence absent — savings cannot include cost estimates",
876
+ severity: "low",
877
+ nextMitigation:
878
+ "Capture token usage via `avorelo token-evidence --generate` to enable cost estimates.",
879
+ evidenceRefs: [],
880
+ reasonCodes: ["NO_TOKEN_COST_EVIDENCE"],
881
+ });
882
+ }
883
+ } else if (hasTCE) {
884
+ reducedRisks.push({
885
+ category: "token_cost_gap",
886
+ title: "Token/cost evidence present — token savings estimates available",
887
+ severity: "none",
888
+ evidenceRefs: ["token_cost_evidence"],
889
+ reasonCodes: ["TOKEN_COST_EVIDENCE_PRESENT"],
890
+ });
891
+ }
892
+
893
+ // Active risks from learning risk register (bounded to top 3)
894
+ if (ev.riskRegister && Array.isArray(ev.riskRegister.risks)) {
895
+ const active = ev.riskRegister.risks.filter((r) => r.status === "active");
896
+ for (const r of active.slice(0, 3)) {
897
+ openRisks.push({
898
+ category: r.category || "unresolved_validation_gap",
899
+ title: r.title,
900
+ severity: r.severity || "medium",
901
+ nextMitigation: r.mitigation || "See risk register for details.",
902
+ evidenceRefs: r.evidenceRefs || ["risk_register"],
903
+ reasonCodes: r.reasonCodes || [],
904
+ });
905
+ }
906
+ }
907
+
908
+ // Production confidence risks — consume from artifact if current and not fixture
909
+ try {
910
+ const { extractProductionConfidenceRisks } = require("./production-confidence");
911
+ const pcRisks = extractProductionConfidenceRisks(cwd);
912
+ if (pcRisks && pcRisks.blockerCount > 0) {
913
+ for (const b of (pcRisks.blockers || []).slice(0, 2)) {
914
+ openRisks.push({
915
+ category: "production_orchestration_missing",
916
+ title: `Production confidence blocker: ${b.title}`,
917
+ severity: b.severity === "critical" ? "high" : b.severity || "medium",
918
+ nextMitigation: b.recommendation || "Resolve production confidence blocker before shipping.",
919
+ evidenceRefs: ["production_confidence_report"],
920
+ reasonCodes: (b.reasonCodes || ["PRODUCTION_CONFIDENCE_BLOCKER"]).slice(0, 3),
921
+ note: "From production confidence scan — local read-only.",
922
+ });
923
+ }
924
+ }
925
+ } catch {}
926
+
927
+ return {
928
+ openRisks,
929
+ reducedRisks,
930
+ blockedClaims,
931
+ openRiskCount: openRisks.length,
932
+ reducedRiskCount: reducedRisks.length,
933
+ blockedClaimCount: blockedClaims.length,
934
+ limitations: [
935
+ "Risk register is evidence-backed but bounded — not exhaustive.",
936
+ "Production orchestration limitation is local-workspace-only.",
937
+ ],
938
+ };
939
+ }
940
+
941
+ // ── Run Improvements outcome section ─────────────────────────────────────────
942
+
943
+ function buildRunImprovementsSection(ev) {
944
+ if (!ev.runImprovements) {
945
+ return {
946
+ status: "not_available",
947
+ prepared: false,
948
+ consumed: false,
949
+ applied: false,
950
+ injected: false,
951
+ expired: false,
952
+ categories: [],
953
+ defaultsCount: 0,
954
+ lifecycleReceipt: null,
955
+ nextRunContextArtifact: null,
956
+ limitations: ["No run improvements artifact found."],
957
+ };
958
+ }
959
+
960
+ const ri = ev.runImprovements;
961
+ const lc = ev.lifecycleReceipt;
962
+ const nrc = ev.nextRunContext;
963
+
964
+ // Only trust lifecycle receipt for applied/consumed state
965
+ const isApplied = lc !== null && lc.lifecycleState === "applied";
966
+ const isConsumed =
967
+ lc !== null &&
968
+ (lc.lifecycleState === "consumed" || lc.lifecycleState === "applied");
969
+ const isInjected =
970
+ nrc !== null &&
971
+ (nrc.status === "applied" || nrc.status === "injected");
972
+
973
+ return {
974
+ status: ri.status,
975
+ prepared:
976
+ ri.status === "prepared" ||
977
+ ri.status === "applied" ||
978
+ ri.status === "consumed",
979
+ consumed: isConsumed,
980
+ applied: isApplied,
981
+ injected: isInjected,
982
+ expired: ri.status === "expired" || ri.status === "stale",
983
+ categories: [
984
+ ...new Set((ri.topImprovements || []).map((i) => i.category)),
985
+ ],
986
+ defaultsCount: (ri.nextRunDefaults || []).length,
987
+ lifecycleReceipt: lc
988
+ ? {
989
+ lifecycleState: lc.lifecycleState,
990
+ surface: lc.surface,
991
+ consumedAt: lc.consumedAt,
992
+ appliedAt: lc.appliedAt,
993
+ }
994
+ : null,
995
+ nextRunContextArtifact: nrc
996
+ ? {
997
+ status: nrc.status,
998
+ appliedDefaultsCount: (nrc.appliedDefaults || []).length,
999
+ activeDecisionCount: nrc.activeDecisionCount || 0,
1000
+ }
1001
+ : null,
1002
+ limitations: [
1003
+ ...(!isApplied && ri.status !== "not_available"
1004
+ ? [
1005
+ "applied=true requires a lifecycle receipt via `avorelo run-improvements --apply`.",
1006
+ ]
1007
+ : []),
1008
+ ...(!isInjected
1009
+ ? [
1010
+ "injected requires session-start hook to consume next-run context artifact.",
1011
+ ]
1012
+ : []),
1013
+ ],
1014
+ };
1015
+ }
1016
+
1017
+ // ── Learning section ──────────────────────────────────────────────────────────
1018
+
1019
+ function buildLearningSection(ev) {
1020
+ if (!ev.learningSummary) {
1021
+ return {
1022
+ available: false,
1023
+ activeDecisionCount: 0,
1024
+ activeRiskCount: 0,
1025
+ capabilityCount: 0,
1026
+ staleItemCount: 0,
1027
+ topLearningSignals: [],
1028
+ nextRunInfluence: [],
1029
+ limitations: [
1030
+ "No learning summary found. Run `avorelo learning --generate` to build.",
1031
+ ],
1032
+ };
1033
+ }
1034
+
1035
+ const ls = ev.learningSummary;
1036
+
1037
+ // Bounded top signals — no raw register dump
1038
+ const rawSignals = ls.topLearningSignals || ls.topSignals || [];
1039
+ const topSignals = rawSignals.slice(0, 3).map((s) => ({
1040
+ type: s.type,
1041
+ summary: (s.summary || "").slice(0, 120),
1042
+ confidence: s.confidence,
1043
+ reasonCodes: (s.reasonCodes || []).slice(0, 3),
1044
+ }));
1045
+
1046
+ // Bounded next-run influence
1047
+ const nextRunInfluence = (ls.nextRunInfluence || []).slice(0, 3).map((inf) => ({
1048
+ type: inf.type,
1049
+ text: inf.text,
1050
+ reasonCodes: (inf.reasonCodes || []).slice(0, 3),
1051
+ }));
1052
+
1053
+ return {
1054
+ available: true,
1055
+ activeDecisionCount: ls.activeDecisionCount || 0,
1056
+ activeRiskCount: ls.activeRiskCount || 0,
1057
+ capabilityCount: ls.capabilityCount || 0,
1058
+ staleItemCount: ls.staleItemCount || 0,
1059
+ topLearningSignals: topSignals,
1060
+ nextRunInfluence,
1061
+ limitations: (ls.limitations || []).slice(0, 2),
1062
+ };
1063
+ }
1064
+
1065
+ // ── Next best action ──────────────────────────────────────────────────────────
1066
+
1067
+ function buildNextBestAction(ev, proof, savings, risk, runImprovementsSection) {
1068
+ // Priority 1: blocked claim — fix this first
1069
+ if (risk.blockedClaims.length > 0) {
1070
+ const blocked = risk.blockedClaims[0];
1071
+ return {
1072
+ title: "Fix blocked claim before sharing report",
1073
+ reason: blocked.title,
1074
+ source: "risk_section",
1075
+ priority: "critical",
1076
+ evidenceRefs: blocked.evidenceRefs,
1077
+ };
1078
+ }
1079
+
1080
+ // Priority 2: no run improvements artifact
1081
+ if (!ev.runImprovements || ev.runImprovements.status === "not_available") {
1082
+ return {
1083
+ title: "Generate run improvements to enable proof and savings",
1084
+ reason:
1085
+ "No run improvements artifact found. Run `avorelo run-improvements --generate`.",
1086
+ source: "evidence_collection",
1087
+ priority: "high",
1088
+ evidenceRefs: [],
1089
+ };
1090
+ }
1091
+
1092
+ // Priority 3: prepared but not applied
1093
+ if (runImprovementsSection.prepared && !runImprovementsSection.applied) {
1094
+ return {
1095
+ title: "Apply run improvements to next-run context",
1096
+ reason:
1097
+ "Run improvements prepared but not yet applied. Run `avorelo run-improvements --apply`.",
1098
+ source: "run_improvements_lifecycle",
1099
+ priority: "high",
1100
+ evidenceRefs: ["run_improvements_artifact"],
1101
+ };
1102
+ }
1103
+
1104
+ // Priority 4: no learning summary
1105
+ if (!ev.learningSummary) {
1106
+ return {
1107
+ title: "Generate learning memory to improve next-run influence",
1108
+ reason:
1109
+ "No learning summary found. Run `avorelo learning --generate` to build decisions and risks.",
1110
+ source: "learning_section",
1111
+ priority: "medium",
1112
+ evidenceRefs: [],
1113
+ };
1114
+ }
1115
+
1116
+ // Priority 5: applied but no proof receipts
1117
+ if (runImprovementsSection.applied && !ev.proofReceipts) {
1118
+ return {
1119
+ title: "Run a session with proof capture to build validation evidence",
1120
+ reason:
1121
+ "Run improvements applied but no proof receipts found — savings estimates remain low confidence.",
1122
+ source: "proof_section",
1123
+ priority: "medium",
1124
+ evidenceRefs: ["run_improvements_artifact", "lifecycle_receipt"],
1125
+ };
1126
+ }
1127
+
1128
+ // Default: good state — keep evidence fresh
1129
+ return {
1130
+ title: "Rerun proof validation to keep evidence fresh",
1131
+ reason:
1132
+ "Evidence is available. Keep artifacts fresh by regenerating after each session.",
1133
+ source: "report_summary",
1134
+ priority: "low",
1135
+ evidenceRefs: Object.keys(ev).filter((k) => ev[k] !== null),
1136
+ };
1137
+ }
1138
+
1139
+ // ── Source fingerprint ────────────────────────────────────────────────────────
1140
+
1141
+ function buildSourceFingerprint(ev) {
1142
+ return buildFingerprint({
1143
+ riStatus: ev.runImprovements?.status || "none",
1144
+ riFingerprint: ev.runImprovements?.sourceRunFingerprint || "none",
1145
+ lcState: ev.lifecycleReceipt?.lifecycleState || "none",
1146
+ nrcStatus: ev.nextRunContext?.status || "none",
1147
+ lsFingerprint: ev.learningSummary?.sourceFingerprint || "none",
1148
+ proofReceiptCount: ev.proofReceipts?.count || 0,
1149
+ });
1150
+ }
1151
+
1152
+ // ── Main report builder ───────────────────────────────────────────────────────
1153
+
1154
+ function buildProofSavingsReport(cwd) {
1155
+ const generatedAt = nowIso();
1156
+ const ev = collectEvidence(cwd);
1157
+ const evidenceQuality = classifyEvidenceQuality(ev);
1158
+ const fingerprint = buildSourceFingerprint(ev);
1159
+
1160
+ const proof = buildProofSection(ev);
1161
+ const savings = buildSavingsSection(ev);
1162
+ const risk = buildRiskSection(ev);
1163
+ const runImprovementsSection = buildRunImprovementsSection(ev);
1164
+ const learningSection = buildLearningSection(ev);
1165
+ const nextBestAction = buildNextBestAction(
1166
+ ev,
1167
+ proof,
1168
+ savings,
1169
+ risk,
1170
+ runImprovementsSection
1171
+ );
1172
+
1173
+ const reasonCodes = [
1174
+ ...new Set([
1175
+ ...proof.validatedSignals.flatMap((s) => s.reasonCodes),
1176
+ ...savings.estimates.flatMap((e) => e.reasonCodes),
1177
+ ...risk.openRisks.flatMap((r) => r.reasonCodes),
1178
+ ]),
1179
+ ].slice(0, 10);
1180
+
1181
+ const allLimitations = [
1182
+ ...proof.limitations.slice(0, 3),
1183
+ ...savings.limitations.slice(0, 2),
1184
+ ...risk.limitations.slice(0, 2),
1185
+ "This report is local-only. No cloud sync, no external services.",
1186
+ "Token and cost savings are omitted unless token/cost evidence artifacts exist.",
1187
+ ];
1188
+
1189
+ const nrc = ev.nextRunContext;
1190
+
1191
+ return {
1192
+ schemaVersion: SCHEMA_VERSION,
1193
+ generatedAt,
1194
+ sourceFingerprint: fingerprint,
1195
+ reportScope: "local_workspace",
1196
+ evidenceQuality,
1197
+ proof,
1198
+ savings,
1199
+ risk,
1200
+ runImprovements: runImprovementsSection,
1201
+ learning: learningSection,
1202
+ nextRunContext: nrc
1203
+ ? {
1204
+ status: nrc.status,
1205
+ appliedDefaultsCount: (nrc.appliedDefaults || []).length,
1206
+ activeDecisionCount: nrc.activeDecisionCount || 0,
1207
+ activeRiskCount: nrc.activeRiskCount || 0,
1208
+ }
1209
+ : null,
1210
+ nextBestAction,
1211
+ redactionStatus: "redacted",
1212
+ reasonCodes,
1213
+ limitations: [...new Set(allLimitations)].slice(0, 10),
1214
+ };
1215
+ }
1216
+
1217
+ // ── Write artifacts ───────────────────────────────────────────────────────────
1218
+
1219
+ function generateProofSavingsReport(cwd) {
1220
+ const report = buildProofSavingsReport(cwd);
1221
+
1222
+ const jsonPath = path.join(cwd, REPORT_JSON_REL);
1223
+ fs.mkdirSync(path.dirname(jsonPath), { recursive: true });
1224
+ fs.writeFileSync(jsonPath, JSON.stringify(report, null, 2), "utf8");
1225
+
1226
+ const md = formatReportMarkdown(report);
1227
+ const mdPath = path.join(cwd, REPORT_MD_REL);
1228
+ fs.writeFileSync(mdPath, md, "utf8");
1229
+
1230
+ try {
1231
+ _emitAuditEvent(cwd, report);
1232
+ } catch {}
1233
+
1234
+ return {
1235
+ report,
1236
+ written: true,
1237
+ jsonPath: REPORT_JSON_REL,
1238
+ mdPath: REPORT_MD_REL,
1239
+ };
1240
+ }
1241
+
1242
+ function loadProofSavingsReport(cwd) {
1243
+ try {
1244
+ const absPath = path.join(cwd, REPORT_JSON_REL);
1245
+ const raw = JSON.parse(fs.readFileSync(absPath, "utf8"));
1246
+ if (raw.schemaVersion !== SCHEMA_VERSION) return null;
1247
+ return raw;
1248
+ } catch {
1249
+ return null;
1250
+ }
1251
+ }
1252
+
1253
+ // ── Markdown report ───────────────────────────────────────────────────────────
1254
+
1255
+ function formatReportMarkdown(report) {
1256
+ const r = report;
1257
+ const lines = [];
1258
+
1259
+ lines.push(`# Avorelo Proof & Savings Report`);
1260
+ lines.push(``);
1261
+ lines.push(`Generated: ${r.generatedAt}`);
1262
+ lines.push(`Evidence quality: **${r.evidenceQuality}**`);
1263
+ lines.push(`Validated signals: ${r.proof.validatedSignalCount}`);
1264
+ lines.push(``);
1265
+
1266
+ // Summary
1267
+ lines.push(`## Summary`);
1268
+ lines.push(``);
1269
+ const sv = r.savings;
1270
+ const totalMin = sv.conservativeTotalMinutesRange;
1271
+ if (totalMin) {
1272
+ lines.push(
1273
+ `Estimated savings: **${totalMin.min}–${totalMin.max} minutes avoided**, ${sv.overallConfidence} confidence.`
1274
+ );
1275
+ } else {
1276
+ lines.push(`Estimated savings: insufficient evidence to estimate.`);
1277
+ }
1278
+ lines.push(`Open risks: ${r.risk.openRiskCount}.`);
1279
+ lines.push(`Next action: ${r.nextBestAction.title}.`);
1280
+ lines.push(``);
1281
+
1282
+ // What improved
1283
+ lines.push(`## What Improved`);
1284
+ lines.push(``);
1285
+ const ri = r.runImprovements;
1286
+ if (ri.prepared) {
1287
+ lines.push(
1288
+ `- Run improvements prepared: ${ri.defaultsCount} next-run default(s) across ${ri.categories.length} category(ies).`
1289
+ );
1290
+ if (ri.applied)
1291
+ lines.push(
1292
+ `- Applied via lifecycle receipt (surface: ${ri.lifecycleReceipt?.surface || "unknown"}).`
1293
+ );
1294
+ if (ri.injected)
1295
+ lines.push(
1296
+ `- Injected into next-run context: ${ri.nextRunContextArtifact?.appliedDefaultsCount || 0} default(s).`
1297
+ );
1298
+ } else {
1299
+ lines.push(`- No run improvements prepared.`);
1300
+ }
1301
+ if (r.learning.available) {
1302
+ lines.push(
1303
+ `- Learning memory: ${r.learning.activeDecisionCount} active decision(s), ${r.learning.activeRiskCount} active risk(s).`
1304
+ );
1305
+ }
1306
+ lines.push(``);
1307
+
1308
+ // What was proven
1309
+ lines.push(`## What Was Proven`);
1310
+ lines.push(``);
1311
+ if (r.proof.validatedSignals.length > 0) {
1312
+ for (const s of r.proof.validatedSignals) {
1313
+ lines.push(`- **${s.signal}** [${s.proofType}]: ${s.description}`);
1314
+ }
1315
+ } else {
1316
+ lines.push(
1317
+ `No validated signals. Run an Avorelo session to generate evidence.`
1318
+ );
1319
+ }
1320
+ lines.push(``);
1321
+ if (r.proof.limitations.length > 0) {
1322
+ lines.push(`**Proof limitations:**`);
1323
+ for (const l of r.proof.limitations) lines.push(`- ${l}`);
1324
+ lines.push(``);
1325
+ }
1326
+
1327
+ // Estimated savings
1328
+ lines.push(`## Estimated Savings`);
1329
+ lines.push(``);
1330
+ if (sv.estimates.length > 0) {
1331
+ for (const e of sv.estimates) {
1332
+ const range = e.estimatedMinutesRange
1333
+ ? `${e.estimatedMinutesRange.min}–${e.estimatedMinutesRange.max} min`
1334
+ : "n/a";
1335
+ lines.push(`- **${e.category}**: estimated ${range}, ${e.confidence} confidence.`);
1336
+ lines.push(` Basis: ${e.basis}`);
1337
+ if (e.limitations.length > 1)
1338
+ lines.push(` Limitation: ${e.limitations[1]}`);
1339
+ }
1340
+ } else {
1341
+ lines.push(`No savings estimates. Insufficient evidence.`);
1342
+ }
1343
+ lines.push(``);
1344
+ for (const l of sv.limitations.slice(0, 3)) lines.push(`> ${l}`);
1345
+ lines.push(``);
1346
+
1347
+ // Risks and limitations
1348
+ lines.push(`## Risks and Limitations`);
1349
+ lines.push(``);
1350
+ if (r.risk.openRisks.length > 0) {
1351
+ lines.push(`**Open risks:**`);
1352
+ for (const rk of r.risk.openRisks) {
1353
+ lines.push(`- [${rk.severity}] **${rk.category}**: ${rk.title}`);
1354
+ lines.push(` Mitigation: ${rk.nextMitigation}`);
1355
+ }
1356
+ lines.push(``);
1357
+ }
1358
+ if (r.risk.reducedRisks.length > 0) {
1359
+ lines.push(`**Risks reduced:**`);
1360
+ for (const rk of r.risk.reducedRisks) {
1361
+ lines.push(`- ~~${rk.category}~~: ${rk.title}`);
1362
+ }
1363
+ lines.push(``);
1364
+ }
1365
+ if (r.risk.blockedClaims.length > 0) {
1366
+ lines.push(`**Blocked claims:**`);
1367
+ for (const bc of r.risk.blockedClaims) {
1368
+ lines.push(`- [${bc.severity}] ${bc.title}`);
1369
+ lines.push(` Fix: ${bc.nextMitigation}`);
1370
+ }
1371
+ lines.push(``);
1372
+ }
1373
+
1374
+ // Run Improvements outcome
1375
+ lines.push(`## Run Improvements Outcome`);
1376
+ lines.push(``);
1377
+ lines.push(`Status: \`${ri.status}\``);
1378
+ lines.push(`- Prepared: ${ri.prepared}`);
1379
+ lines.push(`- Consumed: ${ri.consumed}`);
1380
+ lines.push(
1381
+ `- Applied: ${ri.applied}${
1382
+ ri.applied ? ` (receipt confirmed)` : ` (requires lifecycle receipt)`
1383
+ }`
1384
+ );
1385
+ lines.push(`- Injected: ${ri.injected}`);
1386
+ if (ri.categories.length > 0)
1387
+ lines.push(`- Categories: ${ri.categories.join(", ")}`);
1388
+ lines.push(``);
1389
+ for (const l of ri.limitations) lines.push(`> ${l}`);
1390
+ lines.push(``);
1391
+
1392
+ // Learning influence
1393
+ lines.push(`## Learning Influence`);
1394
+ lines.push(``);
1395
+ if (r.learning.available) {
1396
+ lines.push(`- Active decisions: ${r.learning.activeDecisionCount}`);
1397
+ lines.push(`- Active risks: ${r.learning.activeRiskCount}`);
1398
+ lines.push(`- Capabilities: ${r.learning.capabilityCount}`);
1399
+ lines.push(`- Stale items: ${r.learning.staleItemCount}`);
1400
+ if (r.learning.topLearningSignals.length > 0) {
1401
+ lines.push(``);
1402
+ lines.push(`**Top learning signals:**`);
1403
+ for (const s of r.learning.topLearningSignals) {
1404
+ lines.push(`- [${s.type}, conf=${s.confidence}] ${s.summary}`);
1405
+ }
1406
+ }
1407
+ if (r.learning.nextRunInfluence.length > 0) {
1408
+ lines.push(``);
1409
+ lines.push(`**Next-run influence:**`);
1410
+ for (const inf of r.learning.nextRunInfluence) {
1411
+ lines.push(`- ${inf.text}`);
1412
+ }
1413
+ }
1414
+ } else {
1415
+ lines.push(
1416
+ `Learning memory not available. ${r.learning.limitations[0] || ""}`
1417
+ );
1418
+ }
1419
+ lines.push(``);
1420
+
1421
+ // Next action
1422
+ lines.push(`## Next Action`);
1423
+ lines.push(``);
1424
+ lines.push(`**${r.nextBestAction.title}**`);
1425
+ lines.push(``);
1426
+ lines.push(r.nextBestAction.reason);
1427
+ lines.push(`Priority: ${r.nextBestAction.priority}`);
1428
+ lines.push(``);
1429
+
1430
+ // Evidence quality
1431
+ lines.push(`## Evidence Quality`);
1432
+ lines.push(``);
1433
+ lines.push(`Quality: **${r.evidenceQuality}**`);
1434
+ lines.push(`Proof type: ${r.proof.proofType}`);
1435
+ lines.push(`Coverage: ${r.proof.proofCoverage}`);
1436
+ lines.push(``);
1437
+ if (r.limitations.length > 0) {
1438
+ lines.push(`**Report limitations:**`);
1439
+ for (const l of r.limitations) lines.push(`- ${l}`);
1440
+ }
1441
+
1442
+ return lines.join("\n") + "\n";
1443
+ }
1444
+
1445
+ // ── Compact status/dashboard surface ─────────────────────────────────────────
1446
+
1447
+ function buildProofSavingsSurface(cwd) {
1448
+ const ev = collectEvidence(cwd);
1449
+ const evidenceQuality = classifyEvidenceQuality(ev);
1450
+ const proof = buildProofSection(ev);
1451
+ const savings = buildSavingsSection(ev);
1452
+ const risk = buildRiskSection(ev);
1453
+ const riSection = buildRunImprovementsSection(ev);
1454
+
1455
+ const totalMin = savings.conservativeTotalMinutesRange;
1456
+ const rangeText = totalMin
1457
+ ? `${totalMin.min}–${totalMin.max} min estimated`
1458
+ : "no estimate";
1459
+
1460
+ const statusLine = `Proof & Savings: ${proof.validatedSignalCount} validated signal(s), ${rangeText}, ${savings.overallConfidence} confidence, ${risk.openRiskCount} limitation(s).`;
1461
+
1462
+ const shouldShow =
1463
+ proof.validatedSignalCount > 0 || ev.runImprovements !== null;
1464
+
1465
+ // Compact token/cost evidence line
1466
+ let tokenCostLine = null;
1467
+ try {
1468
+ const { formatTokenCostEvidenceStatusLine } = require("./token-cost-evidence");
1469
+ tokenCostLine = formatTokenCostEvidenceStatusLine(ev.tokenCostEvidence);
1470
+ } catch {}
1471
+
1472
+ return {
1473
+ showInStatus: shouldShow,
1474
+ statusLine,
1475
+ evidenceQuality,
1476
+ estimatedSavings: totalMin,
1477
+ openRisks: risk.openRiskCount,
1478
+ nextBestAction: buildNextBestAction(ev, proof, savings, risk, riSection).title,
1479
+ validatedSignalCount: proof.validatedSignalCount,
1480
+ savingsConfidence: savings.overallConfidence,
1481
+ tokenCostEvidence: {
1482
+ available: !!ev.tokenCostEvidence,
1483
+ statusLine: tokenCostLine,
1484
+ totalTokens: savings.tokenCostEvidence?.totalTokens ?? null,
1485
+ totalCost: savings.tokenCostEvidence?.totalCost ?? null,
1486
+ confidence: savings.tokenCostConfidence,
1487
+ limitations: savings.tokenCostLimitations,
1488
+ },
1489
+ };
1490
+ }
1491
+
1492
+ function formatProofSavingsStatusLine(cwd) {
1493
+ const surface = buildProofSavingsSurface(cwd);
1494
+ if (!surface.showInStatus) return null;
1495
+ return surface.statusLine;
1496
+ }
1497
+
1498
+ // ── Audit event ───────────────────────────────────────────────────────────────
1499
+
1500
+ function _emitAuditEvent(cwd, report) {
1501
+ const eventsPath = path.join(cwd, ".claude/cco/events/outcome-events.jsonl");
1502
+ fs.mkdirSync(path.dirname(eventsPath), { recursive: true });
1503
+ const event = JSON.stringify({
1504
+ event_id: `psr_generated_${report.sourceFingerprint}`,
1505
+ session_id: "avorelo-proof-savings-report",
1506
+ timestamp: report.generatedAt,
1507
+ category: "proof_savings_report",
1508
+ event_name: "proof_savings_report_generated",
1509
+ reason_code: "PROOF_SAVINGS_REPORT_GENERATED",
1510
+ confidence_score: 1.0,
1511
+ platform: "avorelo",
1512
+ metadata: {
1513
+ schemaVersion: report.schemaVersion,
1514
+ evidenceQuality: report.evidenceQuality,
1515
+ validatedSignalCount: report.proof.validatedSignalCount,
1516
+ savingsConfidence: report.savings.overallConfidence,
1517
+ openRiskCount: report.risk.openRiskCount,
1518
+ reportPaths: [REPORT_JSON_REL, REPORT_MD_REL],
1519
+ redactionStatus: report.redactionStatus,
1520
+ reasonCodes: report.reasonCodes.slice(0, 5),
1521
+ },
1522
+ });
1523
+ fs.appendFileSync(eventsPath, event + "\n", "utf8");
1524
+ }
1525
+
1526
+ module.exports = {
1527
+ SCHEMA_VERSION,
1528
+ REPORT_JSON_REL,
1529
+ REPORT_MD_REL,
1530
+ EVIDENCE_QUALITY_VALUES,
1531
+ PROOF_TYPES,
1532
+ SAVINGS_CATEGORIES,
1533
+ RISK_CATEGORIES,
1534
+ MINUTE_HEURISTICS,
1535
+ collectEvidence,
1536
+ classifyEvidenceQuality,
1537
+ buildProofSection,
1538
+ buildSavingsSection,
1539
+ buildRiskSection,
1540
+ buildRunImprovementsSection,
1541
+ buildLearningSection,
1542
+ buildNextBestAction,
1543
+ buildProofSavingsReport,
1544
+ generateProofSavingsReport,
1545
+ loadProofSavingsReport,
1546
+ formatReportMarkdown,
1547
+ buildProofSavingsSurface,
1548
+ formatProofSavingsStatusLine,
1549
+ };