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,1030 @@
1
+ "use strict";
2
+
3
+ const fs = require("fs");
4
+ const path = require("path");
5
+
6
+ const { ensureCcoDirs, nowIso, safeReadJson, safeWriteJson } = require("./fsx");
7
+
8
+ const CONTRACT = "avorelo.observabilityRecoveryGuard.v1";
9
+ const REPORT_DIR_REL = ".claude/cco/reports/observability-recovery-guard";
10
+ const REPORT_JSON_REL = `${REPORT_DIR_REL}/latest-report.json`;
11
+
12
+ const TEXT_FILE_RE = /\.(cjs|cts|env|ini|js|json|jsx|md|mjs|mts|prisma|sql|toml|ts|tsx|txt|yaml|yml)$/i;
13
+ const SKIP_DIRS = new Set([
14
+ ".claude",
15
+ ".git",
16
+ ".next",
17
+ ".nuxt",
18
+ ".turbo",
19
+ ".wasp",
20
+ "build",
21
+ "coverage",
22
+ "dist",
23
+ "node_modules",
24
+ ]);
25
+
26
+ // --- Detection patterns ---
27
+
28
+ const LOGGING_RE = /\b(winston|pino|bunyan|log4js?|morgan|logger|logging|console\.(log|error|warn|info|debug)|createLogger|getLogger|log\.info|log\.error|log\.warn|log\.debug)\b/i;
29
+ const METRICS_RE = /\b(prometheus|prom-client|statsd|datadog|dd-trace|metrics|collectDefaultMetrics|Counter|Histogram|Gauge|Summary|register\.metrics)\b/i;
30
+ const TRACING_RE = /\b(opentelemetry|otel|@opentelemetry|tracing|jaeger|zipkin|TracerProvider|trace\.getTracer|SpanKind|startSpan|endSpan|W3CTraceContextPropagator)\b/i;
31
+ const ERROR_HANDLING_RE = /\b(ErrorBoundary|error[_-]?boundary|errorHandler|error[_-]?handler|Sentry|captureException|captureMessage|reportError|onError|handleError|process\.on\s*\(\s*["']uncaughtException|process\.on\s*\(\s*["']unhandledRejection)\b/i;
32
+ const HEALTHCHECK_RE = /\b(\/health|\/healthz|\/healthcheck|health[_-]?check|healthCheck|healthEndpoint)\b/i;
33
+ const READINESS_RE = /\b(\/ready|\/readyz|\/readiness|\/liveness|\/livez|readiness[_-]?check|liveness[_-]?check|readinessProbe|livenessProbe)\b/i;
34
+ const ROLLBACK_DOC_RE = /\b(rollback|roll[_-]?back)\b/i;
35
+ const RECOVERY_DOC_RE = /\b(recovery|runbook|incident[_-]?response|disaster[_-]?recovery|backup[_-]?plan)\b/i;
36
+ const AUDIT_EVENT_RE = /\b(audit|audit[_-]?log|audit[_-]?event|audit[_-]?trail|auditLog|auditEvent)\b/i;
37
+ const RETRY_RECOVERY_RE = /\b(retry|retries|exponential[_-]?backoff|circuit[_-]?breaker|fallback|graceful[_-]?degradation|dead[_-]?letter|dlq|compensating[_-]?transaction)\b/i;
38
+
39
+ const SUPPORT_BUNDLE_PATH_RE = /(^|\/)\.claude\/cco\/support\b/i;
40
+ const RECEIPT_PATH_RE = /(^|\/)\.claude\/cco\/receipts?\b/i;
41
+ const VALIDATION_ARTIFACT_PATH_RE = /(^|\/)\.claude\/cco\/reports\b/i;
42
+ const CI_WORKFLOW_PATH_RE = /(^|\/)\.github\/workflows\/.+\.(yml|yaml)$/i;
43
+ const TEST_FILE_PATH_RE = /(^|\/)(test|tests|__tests__|spec|__spec__|\.test\.|\.spec\.)\b/i;
44
+
45
+ // --- Utility functions (same pattern as existing guards) ---
46
+
47
+ function unique(values) {
48
+ return [...new Set((values || []).filter(Boolean))];
49
+ }
50
+
51
+ function toPosix(value) {
52
+ return String(value || "").replace(/\\/g, "/");
53
+ }
54
+
55
+ function sanitizeText(value, max = 220) {
56
+ const text = String(value || "")
57
+ .replace(/\s+/g, " ")
58
+ .replace(/(?:sk-[A-Za-z0-9_-]{16,}|gh[ps]_[A-Za-z0-9]{12,}|npm_[A-Za-z0-9]{12,}|AKIA[0-9A-Z]{16})/g, "[redacted-token]")
59
+ .replace(/(bearer\s+)[A-Za-z0-9._-]{8,}/ig, "$1[redacted]")
60
+ .replace(/((?:api[_ -]?key|token|password|secret|authorization)\s*[:=]\s*)([^\s'"]+)/ig, "$1[redacted]")
61
+ .trim();
62
+ if (!text) return null;
63
+ return text.length > max ? `${text.slice(0, max - 3).trimEnd()}...` : text;
64
+ }
65
+
66
+ function sanitizeRef(ref) {
67
+ const text = String(ref || "").trim().replace(/\\/g, "/");
68
+ if (!text || text.startsWith("..")) return null;
69
+ return text;
70
+ }
71
+
72
+ function makeEvidenceRef(relPath, lineNumber, label) {
73
+ const base = sanitizeRef(relPath);
74
+ if (!base) return null;
75
+ const suffix = Number.isFinite(lineNumber) && lineNumber > 0 ? `:${lineNumber}` : "";
76
+ const note = label ? ` (${sanitizeText(label, 80)})` : "";
77
+ return `${base}${suffix}${note}`;
78
+ }
79
+
80
+ // --- Workspace walking ---
81
+
82
+ function walkWorkspace(cwd) {
83
+ const files = [];
84
+
85
+ function visit(current, depth) {
86
+ if (depth > 8 || files.length >= 2200) return;
87
+ let entries = [];
88
+ try {
89
+ entries = fs.readdirSync(current, { withFileTypes: true });
90
+ } catch {
91
+ return;
92
+ }
93
+
94
+ for (const entry of entries) {
95
+ if (files.length >= 2200) return;
96
+ const absPath = path.join(current, entry.name);
97
+ const relPath = toPosix(path.relative(cwd, absPath));
98
+ if (entry.isDirectory()) {
99
+ if (SKIP_DIRS.has(entry.name)) continue;
100
+ visit(absPath, depth + 1);
101
+ continue;
102
+ }
103
+ if (!entry.isFile()) continue;
104
+ files.push({
105
+ absPath,
106
+ relPath,
107
+ text: undefined,
108
+ });
109
+ }
110
+ }
111
+
112
+ visit(cwd, 0);
113
+ return files;
114
+ }
115
+
116
+ function readText(file) {
117
+ if (file.text !== undefined) return file.text;
118
+ if (!TEXT_FILE_RE.test(file.relPath)) {
119
+ file.text = null;
120
+ return file.text;
121
+ }
122
+ try {
123
+ const stat = fs.statSync(file.absPath);
124
+ if (stat.size > 256 * 1024) {
125
+ file.text = null;
126
+ return file.text;
127
+ }
128
+ file.text = fs.readFileSync(file.absPath, "utf8");
129
+ return file.text;
130
+ } catch {
131
+ file.text = null;
132
+ return file.text;
133
+ }
134
+ }
135
+
136
+ function findLineNumber(text, index) {
137
+ const prefix = text.slice(0, index);
138
+ return prefix.split(/\r?\n/).length;
139
+ }
140
+
141
+ function collectPatternRefs(file, regex, options = {}) {
142
+ const text = readText(file);
143
+ if (!text) return [];
144
+ const limit = options.limit || 5;
145
+ const refs = [];
146
+ const flags = regex.flags.includes("g") ? regex.flags : `${regex.flags}g`;
147
+ const matcher = new RegExp(regex.source, flags);
148
+ let match;
149
+ while ((match = matcher.exec(text)) && refs.length < limit) {
150
+ const lineNumber = findLineNumber(text, match.index);
151
+ refs.push(makeEvidenceRef(file.relPath, lineNumber, options.label ? options.label(match) : null));
152
+ if (match.index === matcher.lastIndex) matcher.lastIndex += 1;
153
+ }
154
+ return refs.filter(Boolean);
155
+ }
156
+
157
+ function collectLineRefs(file, matcher, options = {}) {
158
+ const text = readText(file);
159
+ if (!text) return [];
160
+ const limit = options.limit || 5;
161
+ const refs = [];
162
+ const lines = text.split(/\r?\n/);
163
+ for (let index = 0; index < lines.length && refs.length < limit; index += 1) {
164
+ const line = lines[index];
165
+ const value = typeof matcher === "function" ? matcher(line, index + 1) : (matcher.test(line) ? true : false);
166
+ if (!value) continue;
167
+ const label = typeof value === "string"
168
+ ? value
169
+ : options.label
170
+ ? options.label(line, index + 1)
171
+ : null;
172
+ refs.push(makeEvidenceRef(file.relPath, index + 1, label));
173
+ }
174
+ return refs.filter(Boolean);
175
+ }
176
+
177
+ // --- Severity helpers ---
178
+
179
+ function severityRank(severity) {
180
+ if (severity === "block") return 3;
181
+ if (severity === "warn") return 2;
182
+ return 1;
183
+ }
184
+
185
+ // --- Finding counter ---
186
+
187
+ let findingCounter = 0;
188
+
189
+ function nextFindingId() {
190
+ findingCounter += 1;
191
+ return `obs-rec-${String(findingCounter).padStart(3, "0")}`;
192
+ }
193
+
194
+ function resetFindingCounter() {
195
+ findingCounter = 0;
196
+ }
197
+
198
+ // --- Report builder ---
199
+
200
+ function buildEmptyReport() {
201
+ return {
202
+ schemaVersion: CONTRACT,
203
+ generatedAt: nowIso(),
204
+ status: "no_data",
205
+ redacted: true,
206
+ summary: {
207
+ title: "Observability & Recovery Guard",
208
+ text: "No observability or recovery evidence detected.",
209
+ findingCounts: { info: 0, warn: 0, block: 0 },
210
+ safeNextAction: "Add observability or recovery evidence before trusting this change.",
211
+ },
212
+ surfaceEvidence: {
213
+ filesInspected: 0,
214
+ artifactsInspected: 0,
215
+ changedFilesConsidered: 0,
216
+ surfacesDetected: [],
217
+ limitsApplied: [],
218
+ },
219
+ findings: [],
220
+ productHome: {
221
+ cardSource: "observabilityRecoveryGuard",
222
+ status: "no_data",
223
+ found: [],
224
+ fixedOrPrepared: [],
225
+ savedOrProved: [],
226
+ forReview: [],
227
+ safeNextAction: "Add observability or recovery evidence before trusting this change.",
228
+ },
229
+ valueProof: {
230
+ implemented: true,
231
+ dogfooded: false,
232
+ measured: false,
233
+ measurementType: "heuristic",
234
+ publicClaimAllowed: false,
235
+ evidenceRefs: [],
236
+ caveat: "Local static scan only. No external observability API calls.",
237
+ },
238
+ limits: {
239
+ localFirst: true,
240
+ deterministicFirst: true,
241
+ modelCalls: false,
242
+ networkCalls: false,
243
+ providerCalls: false,
244
+ rawLogDump: false,
245
+ rawPromptDump: false,
246
+ rawCodeDump: false,
247
+ secretDump: false,
248
+ autoFix: false,
249
+ },
250
+ overhead: {
251
+ durationMs: 0,
252
+ filesInspected: 0,
253
+ artifactsInspected: 0,
254
+ limitsApplied: [],
255
+ },
256
+ };
257
+ }
258
+
259
+ function addFinding(report, finding) {
260
+ report.findings.push({
261
+ id: finding.id,
262
+ severity: finding.severity,
263
+ reasonCode: finding.reasonCode,
264
+ title: sanitizeText(finding.title, 120),
265
+ message: sanitizeText(finding.message, 220),
266
+ evidenceRefs: (finding.evidenceRefs || []).map((ref) => ({
267
+ path: sanitizeRef(ref.path),
268
+ kind: ref.kind || "file",
269
+ selector: sanitizeText(ref.selector, 120) || null,
270
+ redacted: true,
271
+ })).filter((ref) => ref.path),
272
+ safeNextAction: sanitizeText(finding.safeNextAction, 220) || "Review the evidence before shipping.",
273
+ });
274
+ }
275
+
276
+ // --- Detection surfaces ---
277
+
278
+ function detectLogging(files) {
279
+ const refs = [];
280
+ for (const file of files) {
281
+ const found = collectPatternRefs(file, LOGGING_RE, { limit: 2 });
282
+ refs.push(...found);
283
+ if (refs.length >= 8) break;
284
+ }
285
+ return refs.slice(0, 8);
286
+ }
287
+
288
+ function detectMetrics(files) {
289
+ const refs = [];
290
+ for (const file of files) {
291
+ const found = collectPatternRefs(file, METRICS_RE, { limit: 2 });
292
+ refs.push(...found);
293
+ if (refs.length >= 8) break;
294
+ }
295
+ return refs.slice(0, 8);
296
+ }
297
+
298
+ function detectTracing(files) {
299
+ const refs = [];
300
+ for (const file of files) {
301
+ const found = collectPatternRefs(file, TRACING_RE, { limit: 2 });
302
+ refs.push(...found);
303
+ if (refs.length >= 8) break;
304
+ }
305
+ return refs.slice(0, 8);
306
+ }
307
+
308
+ function detectErrorHandling(files) {
309
+ const refs = [];
310
+ for (const file of files) {
311
+ const found = collectPatternRefs(file, ERROR_HANDLING_RE, { limit: 2 });
312
+ refs.push(...found);
313
+ if (refs.length >= 8) break;
314
+ }
315
+ return refs.slice(0, 8);
316
+ }
317
+
318
+ function detectHealthChecks(files) {
319
+ const refs = [];
320
+ for (const file of files) {
321
+ const found = collectPatternRefs(file, HEALTHCHECK_RE, { limit: 2 });
322
+ refs.push(...found);
323
+ if (refs.length >= 8) break;
324
+ }
325
+ return refs.slice(0, 8);
326
+ }
327
+
328
+ function detectReadinessLiveness(files) {
329
+ const refs = [];
330
+ for (const file of files) {
331
+ const found = collectPatternRefs(file, READINESS_RE, { limit: 2 });
332
+ refs.push(...found);
333
+ if (refs.length >= 8) break;
334
+ }
335
+ return refs.slice(0, 8);
336
+ }
337
+
338
+ function detectRollbackDocs(files) {
339
+ const refs = [];
340
+ for (const file of files) {
341
+ if (ROLLBACK_DOC_RE.test(file.relPath)) {
342
+ refs.push(makeEvidenceRef(file.relPath, null, "rollback doc"));
343
+ if (refs.length >= 8) break;
344
+ continue;
345
+ }
346
+ const text = readText(file);
347
+ if (!text) continue;
348
+ if (/\.md$/i.test(file.relPath) && ROLLBACK_DOC_RE.test(text)) {
349
+ const found = collectPatternRefs(file, ROLLBACK_DOC_RE, { limit: 1 });
350
+ refs.push(...found);
351
+ if (refs.length >= 8) break;
352
+ }
353
+ }
354
+ return refs.filter(Boolean).slice(0, 8);
355
+ }
356
+
357
+ function detectRecoveryDocs(files) {
358
+ const refs = [];
359
+ for (const file of files) {
360
+ if (RECOVERY_DOC_RE.test(file.relPath)) {
361
+ refs.push(makeEvidenceRef(file.relPath, null, "recovery doc"));
362
+ if (refs.length >= 8) break;
363
+ continue;
364
+ }
365
+ const text = readText(file);
366
+ if (!text) continue;
367
+ if (/\.md$/i.test(file.relPath) && RECOVERY_DOC_RE.test(text)) {
368
+ const found = collectPatternRefs(file, RECOVERY_DOC_RE, { limit: 1 });
369
+ refs.push(...found);
370
+ if (refs.length >= 8) break;
371
+ }
372
+ }
373
+ return refs.filter(Boolean).slice(0, 8);
374
+ }
375
+
376
+ function detectSupportBundle(files) {
377
+ const refs = [];
378
+ for (const file of files) {
379
+ if (SUPPORT_BUNDLE_PATH_RE.test(file.relPath)) {
380
+ refs.push(makeEvidenceRef(file.relPath, null, "support bundle"));
381
+ if (refs.length >= 8) break;
382
+ }
383
+ }
384
+ return refs.slice(0, 8);
385
+ }
386
+
387
+ function detectReceipts(files) {
388
+ const refs = [];
389
+ for (const file of files) {
390
+ if (RECEIPT_PATH_RE.test(file.relPath)) {
391
+ refs.push(makeEvidenceRef(file.relPath, null, "receipt"));
392
+ if (refs.length >= 8) break;
393
+ }
394
+ }
395
+ return refs.slice(0, 8);
396
+ }
397
+
398
+ function detectAuditEvents(files) {
399
+ const refs = [];
400
+ for (const file of files) {
401
+ const found = collectPatternRefs(file, AUDIT_EVENT_RE, { limit: 2 });
402
+ refs.push(...found);
403
+ if (refs.length >= 8) break;
404
+ }
405
+ return refs.slice(0, 8);
406
+ }
407
+
408
+ function detectValidationArtifacts(files) {
409
+ const refs = [];
410
+ for (const file of files) {
411
+ if (VALIDATION_ARTIFACT_PATH_RE.test(file.relPath)) {
412
+ refs.push(makeEvidenceRef(file.relPath, null, "validation artifact"));
413
+ if (refs.length >= 8) break;
414
+ }
415
+ }
416
+ return refs.slice(0, 8);
417
+ }
418
+
419
+ function detectCiEvidence(files) {
420
+ const refs = [];
421
+ for (const file of files) {
422
+ if (CI_WORKFLOW_PATH_RE.test(file.relPath)) {
423
+ refs.push(makeEvidenceRef(file.relPath, null, "CI workflow"));
424
+ if (refs.length >= 8) break;
425
+ }
426
+ }
427
+ return refs.slice(0, 8);
428
+ }
429
+
430
+ function detectTestEvidence(files) {
431
+ const refs = [];
432
+ for (const file of files) {
433
+ if (TEST_FILE_PATH_RE.test(file.relPath)) {
434
+ refs.push(makeEvidenceRef(file.relPath, null, "test file"));
435
+ if (refs.length >= 6) break;
436
+ }
437
+ }
438
+ return refs.slice(0, 6);
439
+ }
440
+
441
+ function detectErrorBoundaries(files) {
442
+ const refs = [];
443
+ for (const file of files) {
444
+ const found = collectPatternRefs(file, /\b(ErrorBoundary|error[_-]?boundary)\b/i, { limit: 2 });
445
+ refs.push(...found);
446
+ if (refs.length >= 8) break;
447
+ }
448
+ return refs.slice(0, 8);
449
+ }
450
+
451
+ function detectRetryRecovery(files) {
452
+ const refs = [];
453
+ for (const file of files) {
454
+ const found = collectPatternRefs(file, RETRY_RECOVERY_RE, { limit: 2 });
455
+ refs.push(...found);
456
+ if (refs.length >= 8) break;
457
+ }
458
+ return refs.slice(0, 8);
459
+ }
460
+
461
+ // --- Main builder ---
462
+
463
+ function buildObservabilityRecoveryGuard(cwd = process.cwd(), options = {}) {
464
+ const startTime = Date.now();
465
+ resetFindingCounter();
466
+
467
+ const report = buildEmptyReport();
468
+ const files = walkWorkspace(cwd);
469
+ const limitsApplied = [];
470
+
471
+ if (files.length >= 2200) {
472
+ limitsApplied.push("file-count-limit-2200");
473
+ }
474
+
475
+ // Source files for content-based detection
476
+ const sourceFiles = files.filter((file) => /\.(cjs|cts|js|jsx|mjs|mts|ts|tsx)$/i.test(file.relPath));
477
+ // All text files including md, yaml, etc. for doc-based detection
478
+ const allTextFiles = files.filter((file) => TEXT_FILE_RE.test(file.relPath));
479
+
480
+ // Run detection surfaces
481
+ const loggingRefs = detectLogging(sourceFiles);
482
+ const metricsRefs = detectMetrics(sourceFiles);
483
+ const tracingRefs = detectTracing(sourceFiles);
484
+ const errorHandlingRefs = detectErrorHandling(sourceFiles);
485
+ const healthCheckRefs = detectHealthChecks(allTextFiles);
486
+ const readinessRefs = detectReadinessLiveness(allTextFiles);
487
+ const rollbackDocRefs = detectRollbackDocs(allTextFiles);
488
+ const recoveryDocRefs = detectRecoveryDocs(allTextFiles);
489
+ const supportBundleRefs = detectSupportBundle(files);
490
+ const receiptRefs = detectReceipts(files);
491
+ const auditEventRefs = detectAuditEvents(sourceFiles);
492
+ const validationArtifactRefs = detectValidationArtifacts(files);
493
+ const ciEvidenceRefs = detectCiEvidence(files);
494
+ const testEvidenceRefs = detectTestEvidence(files);
495
+ const errorBoundaryRefs = detectErrorBoundaries(sourceFiles);
496
+ const retryRecoveryRefs = detectRetryRecovery(sourceFiles);
497
+
498
+ // Track detected surfaces
499
+ const surfacesDetected = [];
500
+ let artifactsInspected = 0;
501
+
502
+ // --- Emit findings for each detected surface ---
503
+
504
+ if (loggingRefs.length > 0) {
505
+ surfacesDetected.push("logging");
506
+ artifactsInspected += loggingRefs.length;
507
+ addFinding(report, {
508
+ id: nextFindingId(),
509
+ severity: "info",
510
+ reasonCode: "OBS_REC_LOGGING_FOUND",
511
+ title: "Logging setup detected",
512
+ message: `Found ${loggingRefs.length} logging reference(s) in the workspace.`,
513
+ evidenceRefs: loggingRefs.slice(0, 3).map((ref) => ({ path: ref, kind: "pattern-match" })),
514
+ safeNextAction: "Keep logging configuration current as the codebase evolves.",
515
+ });
516
+ }
517
+
518
+ if (metricsRefs.length > 0) {
519
+ surfacesDetected.push("metrics");
520
+ artifactsInspected += metricsRefs.length;
521
+ addFinding(report, {
522
+ id: nextFindingId(),
523
+ severity: "info",
524
+ reasonCode: "OBS_REC_METRICS_FOUND",
525
+ title: "Metrics setup detected",
526
+ message: `Found ${metricsRefs.length} metrics reference(s) in the workspace.`,
527
+ evidenceRefs: metricsRefs.slice(0, 3).map((ref) => ({ path: ref, kind: "pattern-match" })),
528
+ safeNextAction: "Keep metrics instrumentation aligned with production surfaces.",
529
+ });
530
+ }
531
+
532
+ if (tracingRefs.length > 0) {
533
+ surfacesDetected.push("tracing");
534
+ artifactsInspected += tracingRefs.length;
535
+ addFinding(report, {
536
+ id: nextFindingId(),
537
+ severity: "info",
538
+ reasonCode: "OBS_REC_TRACING_FOUND",
539
+ title: "Tracing or OpenTelemetry setup detected",
540
+ message: `Found ${tracingRefs.length} tracing reference(s) in the workspace.`,
541
+ evidenceRefs: tracingRefs.slice(0, 3).map((ref) => ({ path: ref, kind: "pattern-match" })),
542
+ safeNextAction: "Keep tracing configuration aligned with deployed service boundaries.",
543
+ });
544
+ }
545
+
546
+ if (errorHandlingRefs.length > 0) {
547
+ surfacesDetected.push("error-handling");
548
+ artifactsInspected += errorHandlingRefs.length;
549
+ addFinding(report, {
550
+ id: nextFindingId(),
551
+ severity: "info",
552
+ reasonCode: "OBS_REC_ERROR_BOUNDARY_FOUND",
553
+ title: "Error handling patterns detected",
554
+ message: `Found ${errorHandlingRefs.length} error handling reference(s) in the workspace.`,
555
+ evidenceRefs: errorHandlingRefs.slice(0, 3).map((ref) => ({ path: ref, kind: "pattern-match" })),
556
+ safeNextAction: "Keep error handling coverage aligned with critical code paths.",
557
+ });
558
+ }
559
+
560
+ if (healthCheckRefs.length > 0) {
561
+ surfacesDetected.push("health-checks");
562
+ artifactsInspected += healthCheckRefs.length;
563
+ addFinding(report, {
564
+ id: nextFindingId(),
565
+ severity: "info",
566
+ reasonCode: "OBS_REC_HEALTHCHECK_FOUND",
567
+ title: "Health check endpoint detected",
568
+ message: `Found ${healthCheckRefs.length} health check reference(s) in the workspace.`,
569
+ evidenceRefs: healthCheckRefs.slice(0, 3).map((ref) => ({ path: ref, kind: "pattern-match" })),
570
+ safeNextAction: "Keep health check endpoints exercised and monitored in production.",
571
+ });
572
+ }
573
+
574
+ if (readinessRefs.length > 0) {
575
+ surfacesDetected.push("readiness-liveness");
576
+ artifactsInspected += readinessRefs.length;
577
+ addFinding(report, {
578
+ id: nextFindingId(),
579
+ severity: "info",
580
+ reasonCode: "OBS_REC_READINESS_FOUND",
581
+ title: "Readiness or liveness check detected",
582
+ message: `Found ${readinessRefs.length} readiness/liveness reference(s) in the workspace.`,
583
+ evidenceRefs: readinessRefs.slice(0, 3).map((ref) => ({ path: ref, kind: "pattern-match" })),
584
+ safeNextAction: "Keep readiness and liveness probes aligned with deployment configuration.",
585
+ });
586
+ }
587
+
588
+ if (rollbackDocRefs.length > 0) {
589
+ surfacesDetected.push("rollback-docs");
590
+ artifactsInspected += rollbackDocRefs.length;
591
+ addFinding(report, {
592
+ id: nextFindingId(),
593
+ severity: "info",
594
+ reasonCode: "OBS_REC_ROLLBACK_DOC_FOUND",
595
+ title: "Rollback documentation detected",
596
+ message: `Found ${rollbackDocRefs.length} rollback doc reference(s) in the workspace.`,
597
+ evidenceRefs: rollbackDocRefs.slice(0, 3).map((ref) => ({ path: ref, kind: "doc" })),
598
+ safeNextAction: "Keep rollback documentation current with the latest deployment path.",
599
+ });
600
+ }
601
+
602
+ if (recoveryDocRefs.length > 0) {
603
+ surfacesDetected.push("recovery-docs");
604
+ artifactsInspected += recoveryDocRefs.length;
605
+ addFinding(report, {
606
+ id: nextFindingId(),
607
+ severity: "info",
608
+ reasonCode: "OBS_REC_RECOVERY_DOC_FOUND",
609
+ title: "Recovery documentation detected",
610
+ message: `Found ${recoveryDocRefs.length} recovery doc reference(s) in the workspace.`,
611
+ evidenceRefs: recoveryDocRefs.slice(0, 3).map((ref) => ({ path: ref, kind: "doc" })),
612
+ safeNextAction: "Keep recovery runbooks current with the latest architecture.",
613
+ });
614
+ }
615
+
616
+ if (supportBundleRefs.length > 0) {
617
+ surfacesDetected.push("support-bundle");
618
+ artifactsInspected += supportBundleRefs.length;
619
+ addFinding(report, {
620
+ id: nextFindingId(),
621
+ severity: "info",
622
+ reasonCode: "OBS_REC_SUPPORT_BUNDLE_FOUND",
623
+ title: "Support bundle detected",
624
+ message: `Found ${supportBundleRefs.length} support bundle artifact(s).`,
625
+ evidenceRefs: supportBundleRefs.slice(0, 3).map((ref) => ({ path: ref, kind: "artifact" })),
626
+ safeNextAction: "Keep the support bundle generation process exercised.",
627
+ });
628
+ }
629
+
630
+ if (receiptRefs.length > 0) {
631
+ surfacesDetected.push("receipts");
632
+ artifactsInspected += receiptRefs.length;
633
+ addFinding(report, {
634
+ id: nextFindingId(),
635
+ severity: "info",
636
+ reasonCode: "OBS_REC_RECEIPT_FOUND",
637
+ title: "Receipts detected",
638
+ message: `Found ${receiptRefs.length} receipt artifact(s).`,
639
+ evidenceRefs: receiptRefs.slice(0, 3).map((ref) => ({ path: ref, kind: "artifact" })),
640
+ safeNextAction: "Keep receipt generation aligned with deployment and guard runs.",
641
+ });
642
+ }
643
+
644
+ if (auditEventRefs.length > 0) {
645
+ surfacesDetected.push("audit-events");
646
+ artifactsInspected += auditEventRefs.length;
647
+ addFinding(report, {
648
+ id: nextFindingId(),
649
+ severity: "info",
650
+ reasonCode: "OBS_REC_AUDIT_EVENT_FOUND",
651
+ title: "Audit event patterns detected",
652
+ message: `Found ${auditEventRefs.length} audit event reference(s).`,
653
+ evidenceRefs: auditEventRefs.slice(0, 3).map((ref) => ({ path: ref, kind: "pattern-match" })),
654
+ safeNextAction: "Keep audit event coverage aligned with sensitive operations.",
655
+ });
656
+ }
657
+
658
+ if (validationArtifactRefs.length > 0) {
659
+ surfacesDetected.push("validation-artifacts");
660
+ artifactsInspected += validationArtifactRefs.length;
661
+ addFinding(report, {
662
+ id: nextFindingId(),
663
+ severity: "info",
664
+ reasonCode: "OBS_REC_VALIDATION_ARTIFACT_FOUND",
665
+ title: "Validation artifacts detected",
666
+ message: `Found ${validationArtifactRefs.length} validation artifact(s) in .claude/cco/reports.`,
667
+ evidenceRefs: validationArtifactRefs.slice(0, 3).map((ref) => ({ path: ref, kind: "artifact" })),
668
+ safeNextAction: "Keep validation artifacts current with the latest guard runs.",
669
+ });
670
+ }
671
+
672
+ const ciAndTestRefs = [...ciEvidenceRefs, ...testEvidenceRefs];
673
+ if (ciAndTestRefs.length > 0) {
674
+ surfacesDetected.push("ci-test-evidence");
675
+ artifactsInspected += ciAndTestRefs.length;
676
+ addFinding(report, {
677
+ id: nextFindingId(),
678
+ severity: "info",
679
+ reasonCode: "OBS_REC_CI_EVIDENCE_FOUND",
680
+ title: "CI and test evidence detected",
681
+ message: `Found ${ciEvidenceRefs.length} CI workflow(s) and ${testEvidenceRefs.length} test file(s).`,
682
+ evidenceRefs: ciAndTestRefs.slice(0, 3).map((ref) => ({ path: ref, kind: "artifact" })),
683
+ safeNextAction: "Keep CI workflows and test coverage aligned with deployment confidence.",
684
+ });
685
+ }
686
+
687
+ if (errorBoundaryRefs.length > 0 && !surfacesDetected.includes("error-handling")) {
688
+ surfacesDetected.push("error-boundaries");
689
+ artifactsInspected += errorBoundaryRefs.length;
690
+ addFinding(report, {
691
+ id: nextFindingId(),
692
+ severity: "info",
693
+ reasonCode: "OBS_REC_ERROR_BOUNDARY_FOUND",
694
+ title: "Error boundary components detected",
695
+ message: `Found ${errorBoundaryRefs.length} error boundary reference(s).`,
696
+ evidenceRefs: errorBoundaryRefs.slice(0, 3).map((ref) => ({ path: ref, kind: "pattern-match" })),
697
+ safeNextAction: "Keep error boundaries covering critical user-facing routes.",
698
+ });
699
+ }
700
+
701
+ if (retryRecoveryRefs.length > 0) {
702
+ surfacesDetected.push("retry-recovery");
703
+ artifactsInspected += retryRecoveryRefs.length;
704
+ addFinding(report, {
705
+ id: nextFindingId(),
706
+ severity: "info",
707
+ reasonCode: "OBS_REC_RETRY_RECOVERY_FOUND",
708
+ title: "Retry and recovery patterns detected",
709
+ message: `Found ${retryRecoveryRefs.length} retry/recovery reference(s).`,
710
+ evidenceRefs: retryRecoveryRefs.slice(0, 3).map((ref) => ({ path: ref, kind: "pattern-match" })),
711
+ safeNextAction: "Keep retry and recovery patterns aligned with external dependency boundaries.",
712
+ });
713
+ }
714
+
715
+ // --- Warn/block findings for missing surfaces ---
716
+
717
+ const hasDeploymentEvidence = ciEvidenceRefs.length > 0
718
+ || files.some((file) => /(^|\/)vercel\.json$/i.test(file.relPath)
719
+ || /(^|\/)netlify\.toml$/i.test(file.relPath)
720
+ || /(^|\/)fly\.toml$/i.test(file.relPath)
721
+ || /(^|\/)railway\.json$/i.test(file.relPath)
722
+ || /(^|\/)(dockerfile|docker-compose\.ya?ml)$/i.test(file.relPath));
723
+
724
+ if (hasDeploymentEvidence && rollbackDocRefs.length === 0 && recoveryDocRefs.length === 0) {
725
+ addFinding(report, {
726
+ id: nextFindingId(),
727
+ severity: "warn",
728
+ reasonCode: "OBS_REC_MISSING_RECOVERY_PATH",
729
+ title: "Missing recovery documentation for deployment-facing change",
730
+ message: "Deployment configuration exists but no rollback or recovery documentation was found.",
731
+ evidenceRefs: ciEvidenceRefs.slice(0, 1).map((ref) => ({ path: ref, kind: "artifact" })),
732
+ safeNextAction: "Add recovery or rollback documentation before trusting this deployment path.",
733
+ });
734
+ }
735
+
736
+ if (hasDeploymentEvidence && supportBundleRefs.length === 0) {
737
+ addFinding(report, {
738
+ id: nextFindingId(),
739
+ severity: "warn",
740
+ reasonCode: "OBS_REC_MISSING_SUPPORT_BUNDLE",
741
+ title: "Missing support bundle for deployment-facing workspace",
742
+ message: "Deployment configuration exists but no .claude/cco/support bundle was found.",
743
+ evidenceRefs: [],
744
+ safeNextAction: "Generate a support bundle to improve recovery confidence.",
745
+ });
746
+ }
747
+
748
+ if (hasDeploymentEvidence && receiptRefs.length === 0) {
749
+ addFinding(report, {
750
+ id: nextFindingId(),
751
+ severity: "warn",
752
+ reasonCode: "OBS_REC_MISSING_RECEIPT",
753
+ title: "Missing receipts for deployment-facing workspace",
754
+ message: "Deployment configuration exists but no .claude/cco/receipts were found.",
755
+ evidenceRefs: [],
756
+ safeNextAction: "Generate guard receipts to create audit trail for deployment confidence.",
757
+ });
758
+ }
759
+
760
+ // Check for stale validation artifacts
761
+ for (const file of files.filter((f) => VALIDATION_ARTIFACT_PATH_RE.test(f.relPath) && /\.json$/i.test(f.relPath))) {
762
+ try {
763
+ const stat = fs.statSync(file.absPath);
764
+ const ageMs = Date.now() - stat.mtimeMs;
765
+ const ageDays = ageMs / (1000 * 60 * 60 * 24);
766
+ if (ageDays > 7) {
767
+ addFinding(report, {
768
+ id: nextFindingId(),
769
+ severity: "warn",
770
+ reasonCode: "OBS_REC_STALE_VALIDATION",
771
+ title: "Stale validation artifact detected",
772
+ message: `Validation artifact ${toPosix(path.relative(cwd, file.absPath))} is ${Math.floor(ageDays)} days old.`,
773
+ evidenceRefs: [{ path: makeEvidenceRef(file.relPath, null, "stale artifact"), kind: "artifact" }],
774
+ safeNextAction: "Re-run guards to refresh stale validation artifacts.",
775
+ });
776
+ break; // Only report one stale finding
777
+ }
778
+ } catch {
779
+ // Skip files we can't stat
780
+ }
781
+ }
782
+
783
+ // Check for corrupt state artifacts
784
+ for (const file of files.filter((f) => VALIDATION_ARTIFACT_PATH_RE.test(f.relPath) && /\.json$/i.test(f.relPath))) {
785
+ const text = readText(file);
786
+ if (text === null) continue;
787
+ if (text.trim().length > 0) {
788
+ try {
789
+ JSON.parse(text);
790
+ } catch {
791
+ addFinding(report, {
792
+ id: nextFindingId(),
793
+ severity: "block",
794
+ reasonCode: "OBS_REC_CORRUPT_STATE_ARTIFACT",
795
+ title: "Corrupt state artifact detected",
796
+ message: `Validation artifact ${toPosix(path.relative(cwd, file.absPath))} contains invalid JSON.`,
797
+ evidenceRefs: [{ path: makeEvidenceRef(file.relPath, null, "corrupt artifact"), kind: "artifact" }],
798
+ safeNextAction: "Delete and regenerate the corrupt validation artifact before trusting guard results.",
799
+ });
800
+ break; // Only report one corrupt finding
801
+ }
802
+ }
803
+ }
804
+
805
+ // High-risk change with no recovery path
806
+ if (hasDeploymentEvidence
807
+ && loggingRefs.length === 0
808
+ && metricsRefs.length === 0
809
+ && tracingRefs.length === 0
810
+ && errorHandlingRefs.length === 0
811
+ && healthCheckRefs.length === 0
812
+ && rollbackDocRefs.length === 0
813
+ && recoveryDocRefs.length === 0) {
814
+ addFinding(report, {
815
+ id: nextFindingId(),
816
+ severity: "block",
817
+ reasonCode: "OBS_REC_HIGH_RISK_NO_RECOVERY",
818
+ title: "Deployment-facing workspace with no observability or recovery evidence",
819
+ message: "Deployment configuration exists but no logging, metrics, tracing, error handling, health checks, or recovery docs were found.",
820
+ evidenceRefs: ciEvidenceRefs.slice(0, 1).map((ref) => ({ path: ref, kind: "artifact" })),
821
+ safeNextAction: "Add observability and recovery evidence before trusting this deployment path.",
822
+ });
823
+ }
824
+
825
+ // No evidence at all
826
+ if (surfacesDetected.length === 0) {
827
+ addFinding(report, {
828
+ id: nextFindingId(),
829
+ severity: "info",
830
+ reasonCode: "OBS_REC_NO_EVIDENCE",
831
+ title: "No observability or recovery evidence found",
832
+ message: "No logging, metrics, tracing, error handling, health checks, recovery docs, or deployment artifacts detected.",
833
+ evidenceRefs: [],
834
+ safeNextAction: "Add observability or recovery evidence as the project matures.",
835
+ });
836
+ }
837
+
838
+ // --- Finalize report ---
839
+
840
+ const infos = report.findings.filter((f) => f.severity === "info");
841
+ const warns = report.findings.filter((f) => f.severity === "warn");
842
+ const blocks = report.findings.filter((f) => f.severity === "block");
843
+
844
+ report.findings.sort((a, b) => severityRank(b.severity) - severityRank(a.severity));
845
+
846
+ // Determine status
847
+ if (surfacesDetected.length === 0) {
848
+ report.status = "no_data";
849
+ } else if (blocks.length > 0) {
850
+ report.status = "blocked";
851
+ } else if (warns.length > 0) {
852
+ report.status = "warn";
853
+ } else {
854
+ report.status = "pass";
855
+ }
856
+
857
+ // Determine safeNextAction
858
+ let safeNextAction = "Keep observability and recovery evidence current as the codebase evolves.";
859
+ if (blocks.length > 0) {
860
+ safeNextAction = blocks[0].safeNextAction;
861
+ } else if (warns.length > 0) {
862
+ safeNextAction = warns[0].safeNextAction;
863
+ } else if (surfacesDetected.length === 0) {
864
+ safeNextAction = "Add observability or recovery evidence before trusting this change.";
865
+ }
866
+
867
+ // Summary text
868
+ const summaryParts = [];
869
+ if (surfacesDetected.length > 0) {
870
+ summaryParts.push(`${surfacesDetected.length} surface(s) detected`);
871
+ }
872
+ if (infos.length > 0) summaryParts.push(`${infos.length} info`);
873
+ if (warns.length > 0) summaryParts.push(`${warns.length} warn`);
874
+ if (blocks.length > 0) summaryParts.push(`${blocks.length} block`);
875
+ if (summaryParts.length === 0) summaryParts.push("no evidence found");
876
+
877
+ report.summary = {
878
+ title: "Observability & Recovery Guard",
879
+ text: summaryParts.join(" · "),
880
+ findingCounts: { info: infos.length, warn: warns.length, block: blocks.length },
881
+ safeNextAction,
882
+ };
883
+
884
+ report.surfaceEvidence = {
885
+ filesInspected: files.length,
886
+ artifactsInspected,
887
+ changedFilesConsidered: 0,
888
+ surfacesDetected: unique(surfacesDetected),
889
+ limitsApplied,
890
+ };
891
+
892
+ // productHome
893
+ report.productHome = {
894
+ cardSource: "observabilityRecoveryGuard",
895
+ status: report.status,
896
+ found: unique(surfacesDetected),
897
+ fixedOrPrepared: [],
898
+ savedOrProved: infos.map((f) => f.title).slice(0, 6),
899
+ forReview: [...warns, ...blocks].map((f) => f.title).slice(0, 6),
900
+ safeNextAction,
901
+ };
902
+
903
+ // valueProof
904
+ report.valueProof.evidenceRefs = unique(surfacesDetected.map((s) => `surface:${s}`));
905
+
906
+ // overhead
907
+ const durationMs = Date.now() - startTime;
908
+ report.overhead = {
909
+ durationMs,
910
+ filesInspected: files.length,
911
+ artifactsInspected,
912
+ limitsApplied,
913
+ };
914
+
915
+ report.generatedAt = nowIso();
916
+
917
+ if (options.write === true) {
918
+ ensureCcoDirs(cwd);
919
+ safeWriteJson(cwd, REPORT_JSON_REL, report);
920
+ }
921
+
922
+ return report;
923
+ }
924
+
925
+ function generateObservabilityRecoveryGuard(cwd = process.cwd(), options = {}) {
926
+ const report = buildObservabilityRecoveryGuard(cwd, { ...options, write: options.write !== false });
927
+ return {
928
+ report,
929
+ reportPath: path.join(cwd, REPORT_JSON_REL),
930
+ };
931
+ }
932
+
933
+ function loadObservabilityRecoveryGuard(cwd = process.cwd()) {
934
+ return safeReadJson(cwd, REPORT_JSON_REL, null);
935
+ }
936
+
937
+ function formatObservabilityRecoveryGuardText(report) {
938
+ if (!report || report.schemaVersion !== CONTRACT) {
939
+ return [
940
+ "Avorelo Observability & Recovery Guard",
941
+ "Status: NO DATA",
942
+ "No observability or recovery evidence was detected yet.",
943
+ "Safe next action: Re-run after adding observability or recovery configuration.",
944
+ ].join("\n");
945
+ }
946
+
947
+ const counts = report.summary?.findingCounts || { info: 0, warn: 0, block: 0 };
948
+ const surfaces = report.surfaceEvidence?.surfacesDetected?.length || 0;
949
+
950
+ const lines = [
951
+ "Avorelo Observability & Recovery Guard",
952
+ `Status: ${String(report.status || "no_data").replace(/_/g, " ").toUpperCase()} · redacted=${report.redacted === true ? "yes" : "no"}`,
953
+ `Surfaces: ${surfaces} · info=${counts.info} · warn=${counts.warn} · block=${counts.block}`,
954
+ "Notes: local static scan only · no external observability API calls",
955
+ ];
956
+
957
+ const findings = Array.isArray(report.findings) ? report.findings.slice(0, 6) : [];
958
+ if (findings.length > 0) {
959
+ lines.push("");
960
+ lines.push("Findings:");
961
+ for (const finding of findings) {
962
+ const refPath = finding.evidenceRefs?.[0]?.path || "";
963
+ lines.push(`- [${finding.severity}] ${finding.title}${refPath ? ` · ${refPath}` : ""}`);
964
+ }
965
+ }
966
+
967
+ lines.push("");
968
+ lines.push(`Safe next action: ${report.summary?.safeNextAction || "Review the evidence before shipping."}`);
969
+ return lines.join("\n");
970
+ }
971
+
972
+ function formatObservabilityRecoveryGuardStatusLineFromReport(report) {
973
+ if (!report || report.schemaVersion !== CONTRACT) {
974
+ return "Observability guard: NOT RUN · run observability-recovery-guard";
975
+ }
976
+ const counts = report.summary?.findingCounts || { info: 0, warn: 0, block: 0 };
977
+ return `Observability guard: ${String(report.status || "no_data").replace(/_/g, " ").toUpperCase()}`
978
+ + ` · warn=${counts.warn}`
979
+ + ` · block=${counts.block}`
980
+ + ` · next: ${sanitizeText(report.summary?.safeNextAction, 140) || "Review observability evidence."}`;
981
+ }
982
+
983
+ function buildObservabilityRecoveryGuardSurface(cwd = process.cwd(), options = {}) {
984
+ const report = loadObservabilityRecoveryGuard(cwd) || (options.buildIfMissing ? buildObservabilityRecoveryGuard(cwd, { write: false }) : null);
985
+ if (!report) {
986
+ return {
987
+ status: "not_run",
988
+ blockerCount: 0,
989
+ needsReviewCount: 0,
990
+ surfacesInspected: 0,
991
+ nextBestAction: "Run the observability-recovery-guard before trusting deployment confidence.",
992
+ statusLine: "Observability guard: NOT RUN · run observability-recovery-guard",
993
+ showInStatus: true,
994
+ showInDashboard: true,
995
+ evidenceRef: null,
996
+ limitations: [
997
+ "Local static scan only. No external observability API calls.",
998
+ ],
999
+ };
1000
+ }
1001
+
1002
+ const counts = report.summary?.findingCounts || { info: 0, warn: 0, block: 0 };
1003
+
1004
+ return {
1005
+ status: report.status,
1006
+ blockerCount: counts.block,
1007
+ needsReviewCount: counts.warn,
1008
+ surfacesInspected: report.surfaceEvidence?.surfacesDetected?.length || 0,
1009
+ nextBestAction: report.summary?.safeNextAction,
1010
+ statusLine: formatObservabilityRecoveryGuardStatusLineFromReport(report),
1011
+ showInStatus: true,
1012
+ showInDashboard: true,
1013
+ evidenceRef: REPORT_JSON_REL,
1014
+ limitations: [
1015
+ "Local static scan only. No external observability API calls.",
1016
+ "Absence of evidence stays bounded and reason-coded.",
1017
+ ],
1018
+ };
1019
+ }
1020
+
1021
+ module.exports = {
1022
+ CONTRACT,
1023
+ REPORT_JSON_REL,
1024
+ buildObservabilityRecoveryGuard,
1025
+ generateObservabilityRecoveryGuard,
1026
+ loadObservabilityRecoveryGuard,
1027
+ formatObservabilityRecoveryGuardText,
1028
+ formatObservabilityRecoveryGuardStatusLineFromReport,
1029
+ buildObservabilityRecoveryGuardSurface,
1030
+ };