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.
- package/LICENSE +16 -23
- package/README.md +62 -72
- package/bin/avorelo +9 -0
- package/package.json +147 -139
- package/scripts/README.md +40 -0
- package/scripts/avorelo-session-collision-guard.js +540 -0
- package/scripts/avorelo-workstream-preflight.js +918 -0
- package/scripts/cco-dashboard.js +346 -0
- package/scripts/cco-posttooluse.js +504 -0
- package/scripts/cco-pretooluse.js +381 -0
- package/scripts/cco-status.js +540 -0
- package/scripts/cco-stop.js +77 -0
- package/scripts/cco-userprompt-submit.js +83 -0
- package/scripts/lib/activation/account-state.js +37 -0
- package/scripts/lib/activation/activate-command.js +114 -0
- package/scripts/lib/activation/activation-runner.js +607 -0
- package/scripts/lib/activation/activation-self-healing.js +481 -0
- package/scripts/lib/activation/activation-state.js +96 -0
- package/scripts/lib/activation/activation-summary.js +241 -0
- package/scripts/lib/activation/adapters/claude-code.js +77 -0
- package/scripts/lib/activation/adapters/codex-cli.js +52 -0
- package/scripts/lib/activation/adapters/cursor.js +37 -0
- package/scripts/lib/activation/adapters/github-agent.js +39 -0
- package/scripts/lib/activation/adapters/terminal.js +42 -0
- package/scripts/lib/activation/adapters/vscode.js +39 -0
- package/scripts/lib/activation/adapters/windsurf.js +37 -0
- package/scripts/lib/activation/ai-surface-detector.js +151 -0
- package/scripts/lib/activation/connect-account.js +145 -0
- package/scripts/lib/activation/detect-environment.js +75 -0
- package/scripts/lib/activation/detect-hosts.js +62 -0
- package/scripts/lib/activation/format-activation-output.js +109 -0
- package/scripts/lib/activation/next-action.js +43 -0
- package/scripts/lib/activation/repair-engine.js +219 -0
- package/scripts/lib/activation/run-entry.js +346 -0
- package/scripts/lib/activation-distribution-readiness.js +507 -0
- package/scripts/lib/adapter-conformance.js +176 -0
- package/scripts/lib/adapter-readiness.js +428 -0
- package/scripts/lib/adapter-safety-boundaries.js +335 -0
- package/scripts/lib/adapter-technical-readiness-gate.js +205 -0
- package/scripts/lib/agent-access-governance.js +455 -0
- package/scripts/lib/agent-activation-readiness.js +878 -0
- package/scripts/lib/agent-enforcement.js +765 -0
- package/scripts/lib/agent-evolution-loop.js +479 -0
- package/scripts/lib/agent-policy-profile.js +210 -0
- package/scripts/lib/agent-security/action-evaluator.js +507 -0
- package/scripts/lib/agent-security/adapter-registry.js +98 -0
- package/scripts/lib/agent-security/auto-policy.js +139 -0
- package/scripts/lib/agent-security/bounded-scan.js +93 -0
- package/scripts/lib/agent-security/enforcement-adapter.js +174 -0
- package/scripts/lib/agent-security/enforcement-engine.js +1129 -0
- package/scripts/lib/agent-security/file-write-adapter.js +183 -0
- package/scripts/lib/agent-security/file-write-rules.js +178 -0
- package/scripts/lib/agent-security/index.js +3342 -0
- package/scripts/lib/agent-security/instruction-risk.js +181 -0
- package/scripts/lib/agent-security/mcp-action-adapter.js +185 -0
- package/scripts/lib/agent-security/mcp-action-rules.js +184 -0
- package/scripts/lib/agent-security/package-action-adapter.js +175 -0
- package/scripts/lib/agent-security/package-action-rules.js +233 -0
- package/scripts/lib/agent-security/performance.js +148 -0
- package/scripts/lib/agent-security/permission-minimizer.js +403 -0
- package/scripts/lib/agent-security/scan-cache.js +74 -0
- package/scripts/lib/agent-security/source-trust.js +146 -0
- package/scripts/lib/ai-efficiency-dogfood-pack.js +437 -0
- package/scripts/lib/ai-efficiency-eval.js +207 -0
- package/scripts/lib/ai-efficiency-guard-contract.js +209 -0
- package/scripts/lib/ai-efficiency-measured-value.js +106 -0
- package/scripts/lib/ai-install-prompt.js +293 -0
- package/scripts/lib/ai-task-inference.js +155 -0
- package/scripts/lib/ai-value-ledger.js +121 -0
- package/scripts/lib/ai-value-proof-table.js +151 -0
- package/scripts/lib/ai-work-efficiency-routing.js +623 -0
- package/scripts/lib/ai-workspace-hygiene.js +1499 -0
- package/scripts/lib/alpha-activation.js +520 -0
- package/scripts/lib/alpha-feedback.js +263 -0
- package/scripts/lib/alpha-readiness-gate.js +332 -0
- package/scripts/lib/anti-gaming.js +169 -0
- package/scripts/lib/artifact-health.js +431 -0
- package/scripts/lib/artifact-receipt-hygiene.js +619 -0
- package/scripts/lib/attribution.js +180 -0
- package/scripts/lib/audit.js +289 -0
- package/scripts/lib/avorelo-skill-registry.js +810 -0
- package/scripts/lib/batch-jobs.js +71 -0
- package/scripts/lib/brain-pack.js +578 -0
- package/scripts/lib/brand-boundary.js +424 -0
- package/scripts/lib/brand.js +74 -0
- package/scripts/lib/browser-capability.js +1048 -0
- package/scripts/lib/browser-proof-governed-workflow.js +1020 -0
- package/scripts/lib/browser-proof-preflight.js +321 -0
- package/scripts/lib/cache-readiness.js +296 -0
- package/scripts/lib/canonical-reentry.js +162 -0
- package/scripts/lib/capability-contract-validator.js +177 -0
- package/scripts/lib/capability-hygiene.js +504 -0
- package/scripts/lib/capability-intake-quarantine.js +789 -0
- package/scripts/lib/capability-kernel-registry.js +566 -0
- package/scripts/lib/capability-kernel.js +202 -0
- package/scripts/lib/capability-manifest.js +255 -0
- package/scripts/lib/capability-outcome-normalizer.js +104 -0
- package/scripts/lib/capability-packs.js +314 -0
- package/scripts/lib/capability-recommender.js +513 -0
- package/scripts/lib/capability-registry.js +1062 -0
- package/scripts/lib/carry-forward-surfacing.js +194 -0
- package/scripts/lib/ccusage-adapter.js +188 -0
- package/scripts/lib/claude-session-evidence/index.js +1027 -0
- package/scripts/lib/cli-output-sanitizer.js +118 -0
- package/scripts/lib/company-loop.js +1149 -0
- package/scripts/lib/config.js +641 -0
- package/scripts/lib/context-acquisition-plan.js +359 -0
- package/scripts/lib/context-authority-rules.js +138 -0
- package/scripts/lib/context-budget-guard.js +170 -0
- package/scripts/lib/context-budget-scanner.js +257 -0
- package/scripts/lib/context-budget.js +167 -0
- package/scripts/lib/context-claim-safety.js +116 -0
- package/scripts/lib/context-compiler.js +236 -0
- package/scripts/lib/context-optimizer.js +715 -0
- package/scripts/lib/context-packet.js +121 -0
- package/scripts/lib/context-receipt.js +57 -0
- package/scripts/lib/context-reduction-plan.js +179 -0
- package/scripts/lib/context-safety.js +88 -0
- package/scripts/lib/context-savings-engine.js +158 -0
- package/scripts/lib/context-source-registry.js +393 -0
- package/scripts/lib/context-task-profiles.js +147 -0
- package/scripts/lib/cost-abuse-guard.js +975 -0
- package/scripts/lib/cost-evidence.js +287 -0
- package/scripts/lib/cost-to-outcome-signals.js +639 -0
- package/scripts/lib/cross-host-install-plan.js +308 -0
- package/scripts/lib/cross-host-install-readiness.js +242 -0
- package/scripts/lib/cross-host-value-flow.js +268 -0
- package/scripts/lib/dashboard.js +1056 -0
- package/scripts/lib/data-permissions-guard.js +1187 -0
- package/scripts/lib/deployment-environment-guard.js +1236 -0
- package/scripts/lib/design-partner-feedback.js +346 -0
- package/scripts/lib/dogfood-evidence-freshness.js +567 -0
- package/scripts/lib/efficiency-receipt.js +354 -0
- package/scripts/lib/entitlements.js +100 -0
- package/scripts/lib/execution-packet.js +559 -0
- package/scripts/lib/execution-route-governor.js +179 -0
- package/scripts/lib/experimentation-events.js +547 -0
- package/scripts/lib/external-capability-compliance.js +107 -0
- package/scripts/lib/external-readiness/ai-visibility/ai-visibility-runner.js +322 -0
- package/scripts/lib/external-readiness/calibration/benchmark-site-catalog.js +121 -0
- package/scripts/lib/external-readiness/calibration/completion-gate.js +112 -0
- package/scripts/lib/external-readiness/calibration/real-site-benchmark-runner.js +284 -0
- package/scripts/lib/external-readiness/drift-detector.js +100 -0
- package/scripts/lib/external-readiness/endpoint-prober.js +332 -0
- package/scripts/lib/external-readiness/external-readiness-runner.js +112 -0
- package/scripts/lib/external-readiness/full-agent-readiness-scorer.js +220 -0
- package/scripts/lib/external-readiness/golden-path-runner.js +333 -0
- package/scripts/lib/external-readiness/inside-out-runner.js +118 -0
- package/scripts/lib/external-readiness/proof-receipt-writer.js +112 -0
- package/scripts/lib/external-readiness/safe-fix-executor.js +117 -0
- package/scripts/lib/external-readiness/skills/category-boundary-guard.js +30 -0
- package/scripts/lib/external-readiness/skills/pmm-positioning-guard.js +69 -0
- package/scripts/lib/external-readiness/skills/safe-fix-policy.js +35 -0
- package/scripts/lib/external-user-simulation.js +166 -0
- package/scripts/lib/failure-recovery-readiness.js +81 -0
- package/scripts/lib/failure-recovery.js +419 -0
- package/scripts/lib/feedback-intelligence.js +537 -0
- package/scripts/lib/feedback-signals.js +205 -0
- package/scripts/lib/file-integrity.js +68 -0
- package/scripts/lib/fsx.js +129 -0
- package/scripts/lib/full-readiness-gate.js +451 -0
- package/scripts/lib/governed-action-exposure-primitives.js +1514 -0
- package/scripts/lib/governed-exposure-planner.js +186 -0
- package/scripts/lib/governed-workspace-hygiene.js +946 -0
- package/scripts/lib/guard-suite-common.js +412 -0
- package/scripts/lib/guidance-builder.js +174 -0
- package/scripts/lib/hook-apply.js +1075 -0
- package/scripts/lib/hook-baseline.js +310 -0
- package/scripts/lib/hook-config-preview.js +275 -0
- package/scripts/lib/hook-contracts.js +290 -0
- package/scripts/lib/hook-safety-boundary-readiness.js +80 -0
- package/scripts/lib/host-capability-matrix.js +351 -0
- package/scripts/lib/host-support-context.js +254 -0
- package/scripts/lib/http-hook-action.js +538 -0
- package/scripts/lib/install-ai-readiness.js +84 -0
- package/scripts/lib/install-intake-risk.js +1051 -0
- package/scripts/lib/install-journey-intelligence.js +329 -0
- package/scripts/lib/intervention-guidance.js +57 -0
- package/scripts/lib/known-limitations.js +115 -0
- package/scripts/lib/l8-path-truth.js +146 -0
- package/scripts/lib/launch-hardening-gate.js +436 -0
- package/scripts/lib/launch-readiness.js +635 -0
- package/scripts/lib/learning-experimentation-foundation.js +1484 -0
- package/scripts/lib/learning-memory.js +686 -0
- package/scripts/lib/lifecycle-hooks.js +982 -0
- package/scripts/lib/local-package-smoke.js +436 -0
- package/scripts/lib/local-pricing.js +299 -0
- package/scripts/lib/mcp-enforcement.js +311 -0
- package/scripts/lib/mcp-least-privilege-policy.js +303 -0
- package/scripts/lib/mcp-tool-inventory.js +388 -0
- package/scripts/lib/mcp-tool-risk.js +0 -0
- package/scripts/lib/memory.js +335 -0
- package/scripts/lib/metrics.js +699 -0
- package/scripts/lib/micro-proof.js +133 -0
- package/scripts/lib/model-work-class-routing.js +79 -0
- package/scripts/lib/next-run-context.js +436 -0
- package/scripts/lib/next-run-continuity.js +1207 -0
- package/scripts/lib/observability-recovery-guard.js +1030 -0
- package/scripts/lib/operating-value.js +1662 -0
- package/scripts/lib/optimization-v3.js +122 -0
- package/scripts/lib/orchestration/adapters/_shared.js +49 -0
- package/scripts/lib/orchestration/adapters/aider.js +18 -0
- package/scripts/lib/orchestration/adapters/claude-code.js +35 -0
- package/scripts/lib/orchestration/adapters/codex.js +35 -0
- package/scripts/lib/orchestration/adapters/gemini-cli.js +18 -0
- package/scripts/lib/orchestration/adapters/git.js +25 -0
- package/scripts/lib/orchestration/adapters/index.js +31 -0
- package/scripts/lib/orchestration/adapters/lm-studio.js +18 -0
- package/scripts/lib/orchestration/adapters/ollama.js +18 -0
- package/scripts/lib/orchestration/adapters/opencode.js +18 -0
- package/scripts/lib/orchestration/adapters/openrouter.js +18 -0
- package/scripts/lib/orchestration/adapters/test-runner.js +25 -0
- package/scripts/lib/orchestration/cli.js +438 -0
- package/scripts/lib/orchestration/execution-manager.js +279 -0
- package/scripts/lib/orchestration/handoff.js +314 -0
- package/scripts/lib/orchestration/index.js +456 -0
- package/scripts/lib/orchestration/inventory.js +47 -0
- package/scripts/lib/orchestration/model-discovery.js +498 -0
- package/scripts/lib/orchestration/model-profiler.js +170 -0
- package/scripts/lib/orchestration/model-profiles.js +252 -0
- package/scripts/lib/orchestration/model-refresh-policy.js +72 -0
- package/scripts/lib/orchestration/proof-writer.js +349 -0
- package/scripts/lib/orchestration/provider-discovery/aider.js +49 -0
- package/scripts/lib/orchestration/provider-discovery/claude-code.js +56 -0
- package/scripts/lib/orchestration/provider-discovery/codex.js +49 -0
- package/scripts/lib/orchestration/provider-discovery/common.js +186 -0
- package/scripts/lib/orchestration/provider-discovery/gemini.js +106 -0
- package/scripts/lib/orchestration/provider-discovery/lm-studio.js +118 -0
- package/scripts/lib/orchestration/provider-discovery/models-dev.js +12 -0
- package/scripts/lib/orchestration/provider-discovery/ollama.js +100 -0
- package/scripts/lib/orchestration/provider-discovery/opencode.js +47 -0
- package/scripts/lib/orchestration/provider-discovery/openrouter.js +44 -0
- package/scripts/lib/orchestration/risk-classifier.js +130 -0
- package/scripts/lib/orchestration/routing-policy.js +486 -0
- package/scripts/lib/orchestration/settings.js +95 -0
- package/scripts/lib/orchestration/state.js +165 -0
- package/scripts/lib/orchestration/verification-manager.js +138 -0
- package/scripts/lib/outcome-evidence-stack.js +1083 -0
- package/scripts/lib/output-profiles.js +146 -0
- package/scripts/lib/package-content-audit.js +368 -0
- package/scripts/lib/package-runtime.js +278 -0
- package/scripts/lib/plan-surface.js +53 -0
- package/scripts/lib/plans.js +2327 -0
- package/scripts/lib/policy-provider.js +27 -0
- package/scripts/lib/prelaunch-activation-readiness.js +409 -0
- package/scripts/lib/prelaunch-evidence-store.js +816 -0
- package/scripts/lib/prelaunch-intelligence.js +869 -0
- package/scripts/lib/pricing-experiment.js +118 -0
- package/scripts/lib/pro-moment-events.js +77 -0
- package/scripts/lib/pro-moment-state.js +227 -0
- package/scripts/lib/pro-moments.js +1216 -0
- package/scripts/lib/product-home-receipt.js +1790 -0
- package/scripts/lib/product-learning-events.js +696 -0
- package/scripts/lib/production-confidence-control-tower.js +1209 -0
- package/scripts/lib/production-confidence.js +1858 -0
- package/scripts/lib/project-profile.js +555 -0
- package/scripts/lib/prompt-compiler-plan.js +94 -0
- package/scripts/lib/prompt-compiler.js +280 -0
- package/scripts/lib/prompt-lint.js +32 -0
- package/scripts/lib/prompt-suggestions.js +52 -0
- package/scripts/lib/proof-canonical.js +398 -0
- package/scripts/lib/proof-drilldown.js +383 -0
- package/scripts/lib/proof-e2e/promise-completion.js +141 -0
- package/scripts/lib/proof-e2e/promise-dashboard-claims.js +135 -0
- package/scripts/lib/proof-e2e/promise-local-proof.js +156 -0
- package/scripts/lib/proof-e2e/promise-provider-neutral.js +136 -0
- package/scripts/lib/proof-e2e/promise-registry.js +219 -0
- package/scripts/lib/proof-e2e/promise-security-trust.js +141 -0
- package/scripts/lib/proof-e2e/promise-skills-risk.js +163 -0
- package/scripts/lib/proof-e2e/promise-token-savings.js +112 -0
- package/scripts/lib/proof-e2e/promise-work-management.js +126 -0
- package/scripts/lib/proof-events.js +342 -0
- package/scripts/lib/proof-history.js +243 -0
- package/scripts/lib/proof-metrics.js +296 -0
- package/scripts/lib/proof-outcome-evidence.js +134 -0
- package/scripts/lib/proof-receipt.js +335 -0
- package/scripts/lib/proof-record.js +461 -0
- package/scripts/lib/proof-savings-report.js +1549 -0
- package/scripts/lib/public-activation-distribution-gate.js +266 -0
- package/scripts/lib/public-cli.js +5631 -0
- package/scripts/lib/public-distribution-truth.js +211 -0
- package/scripts/lib/public-distribution.js +73 -0
- package/scripts/lib/public-install-claim-checker.js +300 -0
- package/scripts/lib/publish-provenance-readiness.js +287 -0
- package/scripts/lib/readiness-delta.js +218 -0
- package/scripts/lib/readiness-evidence-closure.js +196 -0
- package/scripts/lib/reentry-memory-capture.js +241 -0
- package/scripts/lib/reentry-memory-retrieval.js +302 -0
- package/scripts/lib/reentry-memory-status.js +147 -0
- package/scripts/lib/reentry-memory-store.js +183 -0
- package/scripts/lib/reentry-state.js +66 -0
- package/scripts/lib/release-candidate-bundle.js +166 -0
- package/scripts/lib/remediation.js +81 -0
- package/scripts/lib/repo-map.js +391 -0
- package/scripts/lib/run-action-policy.js +104 -0
- package/scripts/lib/run-contract-receipt.js +48 -0
- package/scripts/lib/run-contract.js +288 -0
- package/scripts/lib/run-cost-to-verified-outcome.js +87 -0
- package/scripts/lib/run-improvements-lifecycle.js +330 -0
- package/scripts/lib/run-improvements.js +789 -0
- package/scripts/lib/run-proof-contract.js +116 -0
- package/scripts/lib/run-risk-classifier.js +131 -0
- package/scripts/lib/run-task-classifier.js +216 -0
- package/scripts/lib/runtime-decision-policy.js +387 -0
- package/scripts/lib/safe-path-engine.js +705 -0
- package/scripts/lib/safe-repair.js +877 -0
- package/scripts/lib/safe-run-controller.js +887 -0
- package/scripts/lib/scope-repair-before-approval.js +865 -0
- package/scripts/lib/score.js +262 -0
- package/scripts/lib/seamless-enforcement.js +329 -0
- package/scripts/lib/seamless-outcome.js +689 -0
- package/scripts/lib/seamless-reality-gate.js +5053 -0
- package/scripts/lib/security-confidence/activation-safety.js +78 -0
- package/scripts/lib/security-confidence/adapters/adapter-contract.js +125 -0
- package/scripts/lib/security-confidence/adapters/mock-claude-bughunter-adapter.js +36 -0
- package/scripts/lib/security-confidence/adapters/mock-decepticon-adapter.js +34 -0
- package/scripts/lib/security-confidence/adapters/mock-mcp-scan-adapter.js +35 -0
- package/scripts/lib/security-confidence/adapters/mock-snyk-agent-scan-adapter.js +35 -0
- package/scripts/lib/security-confidence/adapters/mock-tank-adapter.js +34 -0
- package/scripts/lib/security-confidence/adapters/reference-registry.js +63 -0
- package/scripts/lib/security-confidence/auth-rbac-plan.js +39 -0
- package/scripts/lib/security-confidence/component-inventory.js +151 -0
- package/scripts/lib/security-confidence/constants.js +191 -0
- package/scripts/lib/security-confidence/dependency-script-risk.js +95 -0
- package/scripts/lib/security-confidence/evidence-hygiene.js +127 -0
- package/scripts/lib/security-confidence/feature-impact-classifier.js +80 -0
- package/scripts/lib/security-confidence/file-utils.js +161 -0
- package/scripts/lib/security-confidence/finding-triage.js +90 -0
- package/scripts/lib/security-confidence/findings.js +115 -0
- package/scripts/lib/security-confidence/index.js +29 -0
- package/scripts/lib/security-confidence/permission-budget.js +93 -0
- package/scripts/lib/security-confidence/redaction.js +82 -0
- package/scripts/lib/security-confidence/redteam-fixtures.js +53 -0
- package/scripts/lib/security-confidence/reference-adoption.js +229 -0
- package/scripts/lib/security-confidence/reference-taxonomy.js +155 -0
- package/scripts/lib/security-confidence/report-quality.js +99 -0
- package/scripts/lib/security-confidence/report-writer.js +79 -0
- package/scripts/lib/security-confidence/risk-classifier.js +187 -0
- package/scripts/lib/security-confidence/runner.js +179 -0
- package/scripts/lib/security-confidence/schema.js +188 -0
- package/scripts/lib/security-confidence/secret-safety.js +74 -0
- package/scripts/lib/security-confidence/security-capability-router.js +98 -0
- package/scripts/lib/security-confidence/web-security-smoke-plan.js +46 -0
- package/scripts/lib/security-risk-classifier.js +511 -0
- package/scripts/lib/security-scan.js +396 -0
- package/scripts/lib/session-context-optimizer.js +1211 -0
- package/scripts/lib/session-timing.js +322 -0
- package/scripts/lib/skill-hygiene.js +805 -0
- package/scripts/lib/skill-packs.js +161 -0
- package/scripts/lib/skills-operating-layer-v1.js +1023 -0
- package/scripts/lib/skills-operating-layer.js +629 -0
- package/scripts/lib/smallest-safe-plan.js +214 -0
- package/scripts/lib/smart-routing-plan.js +115 -0
- package/scripts/lib/smart-work-routing.js +768 -0
- package/scripts/lib/source-catalog.js +1022 -0
- package/scripts/lib/status-value-summary.js +32 -0
- package/scripts/lib/supply-chain-dependency-guard.js +1333 -0
- package/scripts/lib/supply-chain-guard.js +219 -0
- package/scripts/lib/support-bundle.js +561 -0
- package/scripts/lib/support-redaction.js +66 -0
- package/scripts/lib/task-continuation.js +440 -0
- package/scripts/lib/test-helpers.js +15 -0
- package/scripts/lib/tier.js +38 -0
- package/scripts/lib/token-context-quality-gate.js +370 -0
- package/scripts/lib/token-cost-capture.js +187 -0
- package/scripts/lib/token-cost-evidence.js +862 -0
- package/scripts/lib/token-cost-intelligence.js +358 -0
- package/scripts/lib/token-efficiency-evidence.js +213 -0
- package/scripts/lib/token-efficiency-map.js +110 -0
- package/scripts/lib/token-evidence.js +703 -0
- package/scripts/lib/tokenish.js +17 -0
- package/scripts/lib/tool-output-sandbox.js +559 -0
- package/scripts/lib/trust-audit.js +136 -0
- package/scripts/lib/unified-events.js +396 -0
- package/scripts/lib/upgrade-interruption-recovery.js +407 -0
- package/scripts/lib/usage-ledger.js +201 -0
- package/scripts/lib/value-ledger.js +130 -0
- package/scripts/lib/value-proof-calibration.js +531 -0
- package/scripts/lib/visual-qa.js +231 -0
- package/scripts/lib/voice-alpha.js +29 -0
- package/scripts/lib/webhook-idempotency-guard.js +990 -0
- package/scripts/lib/work-aware-orchestration.js +976 -0
- package/scripts/lib/work-control-receipts.js +577 -0
- package/scripts/lib/work-ledger.js +1123 -0
- package/scripts/lib/work-panel-preview.js +352 -0
- package/scripts/lib/workflow-discipline.js +280 -0
- package/scripts/lib/workflow-intelligence-radar.js +804 -0
- package/scripts/lib/workflow-signals.js +419 -0
- package/scripts/lib/workspace-map.js +281 -0
- package/scripts/lib/workspace-registry.js +1367 -0
- package/scripts/lib/workspace-resolver.js +542 -0
- package/scripts/wuz-doctor.js +315 -0
- package/bin/avorelo.mjs +0 -7
- 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
|
+
};
|