@event4u/agent-config 9.9.0 → 9.10.0
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/.claude-plugin/marketplace.json +1 -1
- package/CHANGELOG.md +153 -194
- package/README.md +1 -1
- package/dist/agent-src/commands/agent-status.md +12 -11
- package/dist/agent-src/commands/agents/user/accept.md +115 -30
- package/dist/agent-src/commands/agents/user/delete.md +147 -0
- package/dist/agent-src/commands/agents/user/review.md +65 -28
- package/dist/agent-src/commands/agents/user/show.md +82 -29
- package/dist/agent-src/commands/agents/user/update.md +2 -2
- package/dist/agent-src/commands/agents/user.md +16 -3
- package/dist/agent-src/commands/check-current-md.md +0 -10
- package/dist/agent-src/commands/condense.md +28 -97
- package/dist/agent-src/commands/cost/report.md +7 -0
- package/dist/agent-src/commands/fix/portability.md +0 -8
- package/dist/agent-src/commands/fix/refs.md +0 -8
- package/dist/agent-src/commands/humanize.md +2 -2
- package/dist/agent-src/commands/jira-ticket.md +1 -1
- package/dist/agent-src/commands/memory/load.md +11 -0
- package/dist/agent-src/commands/optimize/skills.md +1 -1
- package/dist/agent-src/commands/pr/create.md +4 -4
- package/dist/agent-src/commands/profile/show.md +3 -3
- package/dist/agent-src/commands/rule-compliance-audit.md +5 -4
- package/dist/agent-src/commands/security-audit-config.md +1 -1
- package/dist/agent-src/commands/sync/gitignore/fix.md +1 -1
- package/dist/agent-src/commands/tdd.md +21 -0
- package/dist/agent-src/commands/team/delegate.md +2 -2
- package/dist/agent-src/commands/team-knowledge/bootstrap.md +9 -8
- package/dist/agent-src/commands/team-knowledge/consolidate.md +8 -7
- package/dist/agent-src/commands/team.md +4 -1
- package/dist/agent-src/commands/upstream-contribute.md +0 -1
- package/dist/agent-src/contexts/authority/commit-mechanics.md +7 -0
- package/dist/agent-src/contexts/authority/destructive-mechanics.md +16 -0
- package/dist/agent-src/contexts/authority/scope-mechanics.md +61 -0
- package/dist/agent-src/contexts/communication/rules-auto/reply-close-mechanics.md +20 -18
- package/dist/agent-src/contexts/communication/rules-auto/skill-quality-mechanics.md +1 -1
- package/dist/agent-src/contexts/communication/rules-auto/slash-command-routing-policy-mechanics.md +1 -1
- package/dist/agent-src/contexts/communication/rules-auto/source-of-truth-mechanics.md +9 -10
- package/dist/agent-src/contexts/communication/rules-auto/think-before-action-mechanics.md +1 -1
- package/dist/agent-src/contexts/communication/rules-auto/user-interaction-mechanics.md +11 -0
- package/dist/agent-src/contexts/contracts/artifact-engagement-flow.md +26 -15
- package/dist/agent-src/contexts/contracts/command-suggestion-flow.md +3 -0
- package/dist/agent-src/contexts/execution/auto-dispatch-classification.md +67 -37
- package/dist/agent-src/contexts/execution/auto-orchestration-activation.md +1 -1
- package/dist/agent-src/contexts/execution/autonomy-examples.md +1 -1
- package/dist/agent-src/contexts/execution/autonomy-mechanics.md +7 -6
- package/dist/agent-src/contexts/execution/evidence-discipline.md +92 -77
- package/dist/agent-src/contexts/execution/orchestration-benchmark-gate.md +22 -21
- package/dist/agent-src/contexts/execution/orchestration-telemetry.md +24 -0
- package/dist/agent-src/contexts/execution/project-intelligence.md +122 -103
- package/dist/agent-src/contexts/execution/roadmap-execution-contract.md +23 -21
- package/dist/agent-src/contexts/execution/subagent-response-contract.md +5 -5
- package/dist/agent-src/contexts/execution/subagent-routing.md +11 -0
- package/dist/agent-src/contexts/execution/subagent-spawn-contract.md +13 -13
- package/dist/agent-src/contexts/execution/subagent-steering.md +36 -34
- package/dist/agent-src/contexts/execution/toolchain-resolver.md +1 -1
- package/dist/agent-src/contexts/execution/user-memory-channels.md +189 -0
- package/dist/agent-src/contexts/execution/verification-mechanics.md +9 -0
- package/dist/agent-src/contexts/model-recommendations.md +3 -2
- package/dist/agent-src/contexts/subagent-configuration.md +3 -3
- package/dist/agent-src/ghostwriter/README.md +2 -2
- package/dist/agent-src/packs/README.md +1 -1
- package/dist/agent-src/personas/README.md +5 -5
- package/dist/agent-src/personas/_template-specialist/persona.md +3 -3
- package/dist/agent-src/personas/backend-architect.md +24 -23
- package/dist/agent-src/personas/eloquent-tamer.md +30 -30
- package/dist/agent-src/personas/frontend-engineer.md +30 -30
- package/dist/agent-src/personas/product-owner.md +41 -38
- package/dist/agent-src/personas/qa.md +13 -13
- package/dist/agent-src/personas/security-engineer.md +22 -22
- package/dist/agent-src/presets/README.md +3 -3
- package/dist/agent-src/profiles/README.md +3 -3
- package/dist/agent-src/rules/active-remediation.md +2 -2
- package/dist/agent-src/rules/artifact-engagement-recording.md +4 -4
- package/dist/agent-src/rules/ask-when-uncertain.md +0 -4
- package/dist/agent-src/rules/augment-edit-discipline.md +1 -1
- package/dist/agent-src/rules/broken-access-control.md +4 -4
- package/dist/agent-src/rules/code-comment-discipline.md +1 -1
- package/dist/agent-src/rules/code-provenance.md +2 -2
- package/dist/agent-src/rules/commit-policy.md +4 -9
- package/dist/agent-src/rules/communication-through-line.md +5 -5
- package/dist/agent-src/rules/decision-revisit-gate.md +1 -1
- package/dist/agent-src/rules/doc-screenshot-hygiene.md +1 -1
- package/dist/agent-src/rules/domain-adoption-policy.md +1 -1
- package/dist/agent-src/rules/domain-safety-pii.md +1 -1
- package/dist/agent-src/rules/external-code-graph-interop.md +1 -1
- package/dist/agent-src/rules/fast-path-marker-visibility.md +43 -7
- package/dist/agent-src/rules/finance-safety-floor.md +1 -1
- package/dist/agent-src/rules/framework-neutrality-in-generic-skills.md +3 -3
- package/dist/agent-src/rules/history-discipline.md +1 -1
- package/dist/agent-src/rules/legal-safety-floor.md +1 -1
- package/dist/agent-src/rules/lethal-trifecta-guard.md +5 -5
- package/dist/agent-src/rules/low-impact-corpus-privacy-floor.md +10 -8
- package/dist/agent-src/rules/media-governance-routing.md +13 -13
- package/dist/agent-src/rules/media-sync-ground-truth.md +29 -11
- package/dist/agent-src/rules/no-cheap-questions.md +7 -7
- package/dist/agent-src/rules/no-decorative-emojis-in-git-surfaces.md +29 -18
- package/dist/agent-src/rules/non-destructive-by-default.md +5 -23
- package/dist/agent-src/rules/onboarding-gate.md +14 -4
- package/dist/agent-src/rules/persona-governance.md +2 -2
- package/dist/agent-src/rules/prefer-enums-over-literals.md +9 -9
- package/dist/agent-src/rules/preservation-guard.md +10 -2
- package/dist/agent-src/rules/question-not-instruction.md +1 -1
- package/dist/agent-src/rules/roadmap-progress-sync.md +6 -6
- package/dist/agent-src/rules/rule-type-governance.md +1 -1
- package/dist/agent-src/rules/scale-discipline.md +1 -1
- package/dist/agent-src/rules/scope-control.md +1 -1
- package/dist/agent-src/rules/secret-vcs-guard.md +1 -1
- package/dist/agent-src/rules/security-sensitive-stop.md +17 -11
- package/dist/agent-src/rules/senior-engineering-discipline.md +17 -17
- package/dist/agent-src/rules/session-canary.md +1 -1
- package/dist/agent-src/rules/skill-quality.md +1 -1
- package/dist/agent-src/rules/source-confidentiality.md +21 -19
- package/dist/agent-src/rules/source-of-truth.md +6 -5
- package/dist/agent-src/rules/spreadsheet-source-quality.md +2 -2
- package/dist/agent-src/rules/strategy-safety-floor.md +1 -1
- package/dist/agent-src/rules/think-before-action.md +5 -5
- package/dist/agent-src/rules/token-budget-discipline.md +5 -3
- package/dist/agent-src/rules/token-efficiency.md +2 -2
- package/dist/agent-src/rules/untrusted-input-defense.md +4 -4
- package/dist/agent-src/rules/user-interaction.md +12 -0
- package/dist/agent-src/rules/verify-before-complete.md +4 -24
- package/dist/agent-src/skills/adversarial-review/SKILL.md +2 -2
- package/dist/agent-src/skills/agent-security-review/SKILL.md +52 -45
- package/dist/agent-src/skills/agents-md-thin-root/SKILL.md +2 -2
- package/dist/agent-src/skills/ai-code-blindspots/SKILL.md +20 -20
- package/dist/agent-src/skills/ai-council/SKILL.md +185 -128
- package/dist/agent-src/skills/analysis-skill-router/SKILL.md +3 -3
- package/dist/agent-src/skills/api-endpoint/SKILL.md +2 -2
- package/dist/agent-src/skills/artisan-commands/SKILL.md +2 -2
- package/dist/agent-src/skills/async-python-patterns/SKILL.md +8 -7
- package/dist/agent-src/skills/authz-review/SKILL.md +16 -15
- package/dist/agent-src/skills/aws-infrastructure/SKILL.md +5 -5
- package/dist/agent-src/skills/blade-ui/SKILL.md +1 -1
- package/dist/agent-src/skills/bug-analyzer/SKILL.md +30 -12
- package/dist/agent-src/skills/code-intelligence/SKILL.md +0 -1
- package/dist/agent-src/skills/code-intelligence/evals/triggers.json +52 -0
- package/dist/agent-src/skills/code-review/SKILL.md +6 -6
- package/dist/agent-src/skills/command-routing/SKILL.md +5 -4
- package/dist/agent-src/skills/composer-packages/SKILL.md +2 -2
- package/dist/agent-src/skills/condense-memory/SKILL.md +43 -41
- package/dist/agent-src/skills/context-document/SKILL.md +23 -21
- package/dist/agent-src/skills/copilot-config/SKILL.md +6 -1
- package/dist/agent-src/skills/decision-record/SKILL.md +20 -18
- package/dist/agent-src/skills/design-intelligence/SKILL.md +4 -4
- package/dist/agent-src/skills/design-review/SKILL.md +15 -14
- package/dist/agent-src/skills/design-system-capture/reference/design-system-json.md +28 -25
- package/dist/agent-src/skills/devcontainer/SKILL.md +2 -2
- package/dist/agent-src/skills/docker/SKILL.md +1 -1
- package/dist/agent-src/skills/docx-authoring/evals/triggers.json +52 -0
- package/dist/agent-src/skills/emit-tickets/SKILL.md +2 -2
- package/dist/agent-src/skills/error-handling-patterns/SKILL.md +1 -1
- package/dist/agent-src/skills/estimate-ticket/SKILL.md +2 -2
- package/dist/agent-src/skills/evaluate-llm-feature/SKILL.md +0 -1
- package/dist/agent-src/skills/evaluate-llm-feature/evals/triggers.json +52 -0
- package/dist/agent-src/skills/existing-ui-audit/SKILL.md +6 -5
- package/dist/agent-src/skills/feature-planning/SKILL.md +2 -2
- package/dist/agent-src/skills/finishing-a-development-branch/SKILL.md +3 -3
- package/dist/agent-src/skills/flux/SKILL.md +1 -1
- package/dist/agent-src/skills/frontend-render-security/SKILL.md +13 -13
- package/dist/agent-src/skills/git-workflow/SKILL.md +33 -33
- package/dist/agent-src/skills/grafana/SKILL.md +5 -0
- package/dist/agent-src/skills/humanizer/SKILL.md +83 -66
- package/dist/agent-src/skills/humanizer/data/patterns.md +14 -14
- package/dist/agent-src/skills/humanizer/references/anti-aiisms.md +4 -4
- package/dist/agent-src/skills/judge-artifact-completeness/SKILL.md +82 -37
- package/dist/agent-src/skills/judge-bug-hunter/SKILL.md +17 -5
- package/dist/agent-src/skills/judge-injection-defense/SKILL.md +63 -25
- package/dist/agent-src/skills/judge-security-auditor/SKILL.md +2 -0
- package/dist/agent-src/skills/judge-synthesis/SKILL.md +72 -28
- package/dist/agent-src/skills/laravel-horizon/SKILL.md +5 -0
- package/dist/agent-src/skills/laravel-mail/SKILL.md +5 -4
- package/dist/agent-src/skills/laravel-middleware/SKILL.md +5 -4
- package/dist/agent-src/skills/laravel-notifications/SKILL.md +10 -9
- package/dist/agent-src/skills/laravel-pennant/SKILL.md +1 -1
- package/dist/agent-src/skills/laravel-pulse/SKILL.md +9 -8
- package/dist/agent-src/skills/laravel-reverb/SKILL.md +6 -5
- package/dist/agent-src/skills/laravel-scheduling/SKILL.md +6 -1
- package/dist/agent-src/skills/laravel-validation/SKILL.md +12 -0
- package/dist/agent-src/skills/launch-readiness/SKILL.md +1 -1
- package/dist/agent-src/skills/learning-to-rule-or-skill/SKILL.md +7 -7
- package/dist/agent-src/skills/learning-tutor/SKILL.md +44 -43
- package/dist/agent-src/skills/learning-tutor/evals/triggers.json +52 -0
- package/dist/agent-src/skills/license-compliance-audit/SKILL.md +7 -7
- package/dist/agent-src/skills/license-compliance-borrow-check/SKILL.md +3 -3
- package/dist/agent-src/skills/license-compliance-credits/SKILL.md +4 -4
- package/dist/agent-src/skills/llm-provider-knowledge/SKILL.md +0 -1
- package/dist/agent-src/skills/memory-consolidation/SKILL.md +69 -64
- package/dist/agent-src/skills/motion-choreographer/SKILL.md +6 -6
- package/dist/agent-src/skills/pdf-tools/evals/triggers.json +52 -0
- package/dist/agent-src/skills/performance-analysis/SKILL.md +7 -3
- package/dist/agent-src/skills/persona-improvement/SKILL.md +0 -2
- package/dist/agent-src/skills/persona-improvement/evals/triggers.json +52 -0
- package/dist/agent-src/skills/php-coder/SKILL.md +10 -0
- package/dist/agent-src/skills/prediction-pool-optimizer/SKILL.md +129 -120
- package/dist/agent-src/skills/prediction-pool-optimizer/reference/ev-fixtures.md +36 -35
- package/dist/agent-src/skills/prediction-pool-optimizer/reference/odds-and-bonus.md +45 -41
- package/dist/agent-src/skills/project-analysis-core/SKILL.md +4 -4
- package/dist/agent-src/skills/project-analysis-hypothesis-driven/SKILL.md +3 -3
- package/dist/agent-src/skills/project-analysis-react/SKILL.md +1 -1
- package/dist/agent-src/skills/project-analysis-symfony/SKILL.md +1 -1
- package/dist/agent-src/skills/project-analysis-zend-laminas/SKILL.md +2 -2
- package/dist/agent-src/skills/prompt-engineering-patterns/SKILL.md +1 -1
- package/dist/agent-src/skills/prompt-validator/SKILL.md +39 -39
- package/dist/agent-src/skills/quality-tools/SKILL.md +15 -15
- package/dist/agent-src/skills/react-shadcn-ui/SKILL.md +55 -19
- package/dist/agent-src/skills/react-shadcn-ui/reference/registry.md +29 -27
- package/dist/agent-src/skills/readme-writing-package/SKILL.md +2 -2
- package/dist/agent-src/skills/reasoning-orchestrator/SKILL.md +25 -25
- package/dist/agent-src/skills/recursive-verification/SKILL.md +6 -5
- package/dist/agent-src/skills/refine-prompt/SKILL.md +1 -1
- package/dist/agent-src/skills/refine-ticket/SKILL.md +20 -2
- package/dist/agent-src/skills/repomix-packer/SKILL.md +1 -1
- package/dist/agent-src/skills/requesting-code-review/SKILL.md +2 -2
- package/dist/agent-src/skills/roadmap-management/SKILL.md +80 -66
- package/dist/agent-src/skills/roadmap-writing/SKILL.md +84 -77
- package/dist/agent-src/skills/rule-refactor/SKILL.md +1 -1
- package/dist/agent-src/skills/screenshot-hygiene/evals/triggers.json +52 -0
- package/dist/agent-src/skills/security-audit/SKILL.md +26 -9
- package/dist/agent-src/skills/security-maturity-assessment/SKILL.md +38 -16
- package/dist/agent-src/skills/skill-improvement-pipeline/SKILL.md +14 -11
- package/dist/agent-src/skills/skill-writing/SKILL.md +9 -8
- package/dist/agent-src/skills/song-to-script/SKILL.md +93 -85
- package/dist/agent-src/skills/sql-writing/SKILL.md +2 -2
- package/dist/agent-src/skills/stakeholder-tradeoff/SKILL.md +4 -3
- package/dist/agent-src/skills/standards-from-config/SKILL.md +61 -43
- package/dist/agent-src/skills/subagent-orchestration/SKILL.md +22 -8
- package/dist/agent-src/skills/subagent-orchestration/prompts/README.md +28 -2
- package/dist/agent-src/skills/supply-chain-intake/SKILL.md +13 -13
- package/dist/agent-src/skills/systematic-debugging/SKILL.md +22 -21
- package/dist/agent-src/skills/tailwind-engineer/SKILL.md +1 -1
- package/dist/agent-src/skills/technical-specification/SKILL.md +5 -0
- package/dist/agent-src/skills/terraform/SKILL.md +2 -2
- package/dist/agent-src/skills/terragrunt/SKILL.md +8 -8
- package/dist/agent-src/skills/testing-anti-patterns/process-anti-patterns.md +1 -1
- package/dist/agent-src/skills/threat-modeling/SKILL.md +19 -13
- package/dist/agent-src/skills/universal-project-analysis/SKILL.md +1 -1
- package/dist/agent-src/skills/upstream-contribute/SKILL.md +0 -1
- package/dist/agent-src/skills/using-git-worktrees/SKILL.md +9 -9
- package/dist/agent-src/skills/validate-feature-fit/SKILL.md +3 -1
- package/dist/agent-src/skills/verify-completion-evidence/SKILL.md +4 -6
- package/dist/agent-src/skills/verify-repair-loop/SKILL.md +67 -61
- package/dist/agent-src/skills/video-director/SKILL.md +7 -7
- package/dist/agent-src/skills/worktree-lifecycle/SKILL.md +3 -3
- package/dist/agent-src/templates/agents/agent-project-settings.example.yml +1 -1
- package/dist/agent-src/templates/contexts/knowledge-pages.md +47 -45
- package/dist/agent-src/templates/contexts/lesson-card.md +2 -2
- package/dist/agent-src/templates/contexts/tenant-boundaries.md +2 -2
- package/dist/agent-src/templates/contexts.md +1 -1
- package/dist/agent-src/templates/features.md +1 -1
- package/dist/agent-src/templates/roadmaps.md +125 -116
- package/dist/agent-src/templates/rule.md +2 -1
- package/dist/agent-src/templates/scripts/pr_risk_review.ts +0 -0
- package/dist/agent-src/templates/scripts/telemetry/aggregator.ts +0 -0
- package/dist/agent-src/templates/scripts/tier_usage_report.ts +2 -2
- package/dist/agent-src/templates/scripts/work_engine/directives/ui/polish.ts +2 -2
- package/dist/agent-src/templates/scripts/work_engine/directives/ui/review.ts +1 -1
- package/dist/agent-src/user-types/README.md +8 -8
- package/dist/agent-src/user-types/galabau-field-crew.md +34 -33
- package/dist/agent-src/user-types/metalworking-shop.md +35 -34
- package/dist/agent-src/user-types/truck-driver.md +22 -20
- package/dist/cli/python/workspace_roles.js +2 -2
- package/dist/cli/python/workspace_roles.js.map +1 -1
- package/dist/discovery/deprecation-report.md +1 -1
- package/dist/discovery/discovery-manifest.json +88 -62
- package/dist/discovery/discovery-manifest.json.sha256 +1 -1
- package/dist/discovery/discovery-manifest.summary.md +3 -3
- package/dist/discovery/orphan-report.md +1 -1
- package/dist/discovery/packs.json +6 -5
- package/dist/discovery/trust-report.md +2 -2
- package/dist/discovery/workspaces.json +5 -4
- package/dist/hooks/dispatch.js +186 -12
- package/dist/install/install.mjs +8 -0
- package/dist/mcp/registry-manifest.json +3 -3
- package/dist/mcp/server.json +2 -2
- package/dist/mcp/server.mjs +1199 -857
- package/dist/router.json +1 -1
- package/dist/scripts/_lib/compile_time_toggles.js +48 -0
- package/dist/scripts/_lib/compile_time_toggles.js.map +1 -0
- package/dist/scripts/condense.js +234 -217
- package/dist/scripts/condense.js.map +1 -1
- package/dist/server/schemas/settings.js +4 -0
- package/dist/server/schemas/settings.js.map +1 -1
- package/dist/shared/userMd/utils.js +30 -0
- package/dist/shared/userMd/utils.js.map +1 -1
- package/dist/ui/assets/index-BpSQt5vm.js.map +1 -1
- package/docs/guidelines/agent-infra/api-cost-levers.md +56 -5
- package/docs/guidelines/agent-infra/simplicity-and-goal-demos.md +93 -33
- package/package.json +1 -1
- package/src/agent-src/templates/scripts/pr_risk_review.ts +0 -0
- package/src/agent-src/templates/scripts/telemetry/aggregator.ts +0 -0
- package/src/agent-src/templates/scripts/tier_usage_report.ts +2 -2
- package/src/agent-src/templates/scripts/work_engine/directives/ui/polish.ts +2 -2
- package/src/agent-src/templates/scripts/work_engine/directives/ui/review.ts +1 -1
- package/src/config/agent-settings.template.yml +32 -2
- package/src/config/ci-local-parity.yml +142 -0
- package/src/config/gate-coverage.yml +127 -0
- package/src/config/preamble-payload-budget.json +44 -0
- package/src/scripts/_cli/cmd_doctor.ts +78 -2
- package/src/scripts/_lib/agent_user_profile.ts +381 -0
- package/src/scripts/_lib/agents_overlay.ts +9 -0
- package/src/scripts/_lib/anchor_eval.ts +311 -0
- package/src/scripts/_lib/cc_transcript.ts +316 -0
- package/src/scripts/_lib/compile_time_toggles.ts +79 -0
- package/src/scripts/_lib/confusables.ts +101 -0
- package/src/scripts/_lib/duplicate_scope_census.ts +77 -0
- package/src/scripts/_lib/managed_agents_folder.ts +181 -0
- package/src/scripts/_lib/payload_hash_drift.ts +126 -0
- package/src/scripts/_lib/preservation_migration.ts +291 -0
- package/src/scripts/_lib/retrieval_sanitize.ts +166 -2
- package/src/scripts/_lib/scan_scope.ts +115 -0
- package/src/scripts/_lib/user_global_memory_audit.ts +187 -0
- package/src/scripts/_lib/user_global_observations.ts +830 -0
- package/src/scripts/_lib/user_global_revocations.ts +110 -0
- package/src/scripts/_lib/user_memory_gate_counters.ts +291 -0
- package/src/scripts/ai_council/blind_review.ts +0 -0
- package/src/scripts/ai_council/budget_guard.ts +90 -11
- package/src/scripts/ai_council/bundler.ts +2 -2
- package/src/scripts/ai_council/clients.ts +59 -3
- package/src/scripts/ai_council/config.ts +38 -0
- package/src/scripts/ai_council/orchestrator.ts +54 -9
- package/src/scripts/ai_team/team_dispatch.ts +17 -6
- package/src/scripts/anchor_eval_falsify.ts +198 -0
- package/src/scripts/anchor_scoring_run.ts +239 -0
- package/src/scripts/annotate_discovery.ts +1 -65
- package/src/scripts/bench_quality_run.ts +168 -4
- package/src/scripts/cache_realization_report.ts +782 -0
- package/src/scripts/check_artefact_count_messaging.ts +5 -1
- package/src/scripts/check_augment_description_cap.ts +15 -4
- package/src/scripts/check_ci_local_parity.ts +317 -0
- package/src/scripts/check_condensation.ts +96 -191
- package/src/scripts/check_context_paths.ts +38 -9
- package/src/scripts/check_gate_coverage.ts +299 -0
- package/src/scripts/check_iron_law_prominence.ts +22 -1
- package/src/scripts/check_kernel_prefix_stability.ts +0 -0
- package/src/scripts/check_no_new_legacy_path.ts +16 -6
- package/src/scripts/check_no_roadmap_refs.ts +22 -9
- package/src/scripts/check_originality_freshness.ts +167 -0
- package/src/scripts/check_preamble_payload_budget.ts +130 -0
- package/src/scripts/check_proposal.ts +0 -0
- package/src/scripts/check_references.ts +0 -1
- package/src/scripts/check_safety_floor_untouched.ts +171 -24
- package/src/scripts/check_site_links.ts +62 -3
- package/src/scripts/ci_status.ts +0 -0
- package/src/scripts/cluster_near_miss_patterns.ts +0 -0
- package/src/scripts/code_graph/build.ts +0 -0
- package/src/scripts/command_suggester/types.ts +0 -0
- package/src/scripts/compile_router.ts +10 -14
- package/src/scripts/condense.sh +3 -4
- package/src/scripts/condense.ts +247 -228
- package/src/scripts/cost/track.mjs +168 -33
- package/src/scripts/cost_summary.ts +33 -1
- package/src/scripts/council_cli.ts +45 -3
- package/src/scripts/discovery_graph.ts +0 -0
- package/src/scripts/encoding_corpus.ts +500 -0
- package/src/scripts/encoding_corpus_report.ts +216 -0
- package/src/scripts/generate_index.ts +19 -2
- package/src/scripts/install-hooks.sh +2 -2
- package/src/scripts/learning_sidecar.ts +0 -0
- package/src/scripts/lint_confusables.ts +10 -72
- package/src/scripts/lint_featured_skills.ts +0 -0
- package/src/scripts/lint_hidden_unicode.ts +208 -0
- package/src/scripts/lint_load_context.ts +17 -5
- package/src/scripts/lint_new_skill_gate.ts +9 -3
- package/src/scripts/lint_no_python_twin_rationale.ts +17 -2
- package/src/scripts/lint_originality.ts +1 -1
- package/src/scripts/lint_skill_originality.ts +1 -1
- package/src/scripts/lint_ticket_buildable.ts +1 -1
- package/src/scripts/mcp_server/tools.ts +4 -4
- package/src/scripts/measure_scope_dedup.ts +224 -0
- package/src/scripts/memory_lookup.ts +0 -0
- package/src/scripts/mine_session.ts +98 -0
- package/src/scripts/orchestration_payload_hash_drift.ts +145 -0
- package/src/scripts/preamble_byte_census.ts +574 -0
- package/src/scripts/probe_skill_registration.ts +2 -2
- package/src/scripts/redact_hook_capture.ts +13 -0
- package/src/scripts/release.ts +65 -10
- package/src/scripts/router_telemetry.ts +1 -1
- package/src/scripts/second_brain_retrieval.ts +14 -4
- package/src/scripts/skill_linter.ts +5 -0
- package/src/scripts/surface-tiers.yml +2 -0
- package/src/scripts/validate_pack_yaml.ts +0 -0
- package/src/server/schemas/settings.ts +8 -0
- package/src/shared/userMd/utils.ts +31 -0
- package/dist/agent-src/rules/telegraph-speak.md +0 -87
|
@@ -0,0 +1,782 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Cache-realization report — pre-registers and evaluates the five claims
|
|
4
|
+
* (C-1..C-5) from `road-to-cache-economy.md` Phase 2.
|
|
5
|
+
*
|
|
6
|
+
* Metric definition (load-bearing, restated from `_lib/cc_transcript.ts`):
|
|
7
|
+
*
|
|
8
|
+
* billable_input = input_tokens + cache_read_input_tokens
|
|
9
|
+
* + cache_creation_input_tokens
|
|
10
|
+
*
|
|
11
|
+
* Anthropic's `usage.input_tokens` field EXCLUDES cache tokens — a cost or
|
|
12
|
+
* volume figure built from `input_tokens` alone silently drops the
|
|
13
|
+
* cache-read and cache-write legs. Every number in this report is built
|
|
14
|
+
* from `billable_input`, never from `input_tokens` alone.
|
|
15
|
+
*
|
|
16
|
+
* Class A (per the ADR-124 no-runtime-boundary contract): in-process,
|
|
17
|
+
* per-invocation, no socket, no daemon, no network, no writes outside a
|
|
18
|
+
* stdout/JSON report. Reads local `~/.claude/projects/**\/*.jsonl`
|
|
19
|
+
* transcripts (via `_lib/cc_transcript.ts` — reused, not reimplemented),
|
|
20
|
+
* local rule directories, local council-response artefacts, and shells out
|
|
21
|
+
* to `claude --version` and `git worktree list` (both read-only, no network).
|
|
22
|
+
*
|
|
23
|
+
* Usage:
|
|
24
|
+
* ./scripts-run src/scripts/cache_realization_report [--format text|json]
|
|
25
|
+
* [--root <path>] [--max-age-days <n>] [--repo-root <path>]
|
|
26
|
+
* [--council-root <path>] [--user-rules-dir <path>] [--project-rules-dir <path>]
|
|
27
|
+
*
|
|
28
|
+
* Defaults: `--root` is `~/.claude/projects` (the full tree, matching the
|
|
29
|
+
* roadmap's own "First-party measurement" method — no per-project filter);
|
|
30
|
+
* `--max-age-days 14` matches that measurement's stated window;
|
|
31
|
+
* `--repo-root` / `--council-root` default to this file's own repo checkout.
|
|
32
|
+
*/
|
|
33
|
+
import { execFileSync } from 'node:child_process';
|
|
34
|
+
import * as fs from 'node:fs';
|
|
35
|
+
import { homedir } from 'node:os';
|
|
36
|
+
import * as path from 'node:path';
|
|
37
|
+
import { fileURLToPath, pathToFileURL } from 'node:url';
|
|
38
|
+
|
|
39
|
+
import {
|
|
40
|
+
aggregateByBucket,
|
|
41
|
+
billableInputTokens,
|
|
42
|
+
DEFAULT_PROJECTS_ROOT,
|
|
43
|
+
scanTranscripts,
|
|
44
|
+
type BucketAggregate,
|
|
45
|
+
type TranscriptBucket,
|
|
46
|
+
type TranscriptRecord,
|
|
47
|
+
} from './_lib/cc_transcript.js';
|
|
48
|
+
import { censusDuplicateScope } from './_lib/duplicate_scope_census.js';
|
|
49
|
+
import { load_prices, reprice_with_cache } from './ai_council/pricing.js';
|
|
50
|
+
|
|
51
|
+
const _HERE = fileURLToPath(import.meta.url);
|
|
52
|
+
// src/scripts/cache_realization_report.ts → parents[1] is the repo root
|
|
53
|
+
// (mirrors the same 2-up resolution `cost_summary.ts` uses for a script at
|
|
54
|
+
// the same directory depth).
|
|
55
|
+
const REPO_ROOT = path.resolve(path.dirname(_HERE), '..', '..');
|
|
56
|
+
|
|
57
|
+
const C1_COLD_START_DOMINANCE_THRESHOLD = 0.5;
|
|
58
|
+
const C2_DUPLICATE_SCOPE_THRESHOLD = 0.25;
|
|
59
|
+
const C4_COUNCIL_MISPRICING_THRESHOLD = 0.05;
|
|
60
|
+
const C5_CONFIRM_RATIO = 0.1;
|
|
61
|
+
const C5_FALSIFY_RATIO = 0.5;
|
|
62
|
+
|
|
63
|
+
const DRIFT_READ_SHARE_FLOOR = 0.9;
|
|
64
|
+
const DRIFT_COLD_START_SHARE_FLOOR = 0.5;
|
|
65
|
+
|
|
66
|
+
// ── generic stats helpers ──────────────────────────────────────────────
|
|
67
|
+
|
|
68
|
+
export function median(nums: readonly number[]): number {
|
|
69
|
+
if (nums.length === 0) return 0;
|
|
70
|
+
const sorted = [...nums].sort((a, b) => a - b);
|
|
71
|
+
const mid = Math.floor(sorted.length / 2);
|
|
72
|
+
return sorted.length % 2 === 0 ? ((sorted[mid - 1] as number) + (sorted[mid] as number)) / 2 : (sorted[mid] as number);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
export function mean(nums: readonly number[]): number {
|
|
76
|
+
if (nums.length === 0) return 0;
|
|
77
|
+
return nums.reduce((a, b) => a + b, 0) / nums.length;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// ── cold-start analysis (subagent legs only — a "leg" is one agentId) ──
|
|
81
|
+
|
|
82
|
+
export interface ColdStartStats {
|
|
83
|
+
/** Distinct subagent agentIds observed. */
|
|
84
|
+
legs: number;
|
|
85
|
+
median_first_call_written_or_uncached: number;
|
|
86
|
+
mean_first_call_written_or_uncached: number;
|
|
87
|
+
/** Σ(first-call cache_read) / Σ(first-call billable_input) across ALL legs — an aggregate share, not a per-leg median. */
|
|
88
|
+
first_call_cache_read_share: number;
|
|
89
|
+
/** Σ(first-call cache_creation_input_tokens) / Σ(all subagent cache_creation_input_tokens) — the C-1 metric. */
|
|
90
|
+
cold_start_share_of_write_volume: number;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* The first record per subagent leg (agentId), ordered by the ISO-8601
|
|
95
|
+
* `timestamp` string (lexical order matches chronological order for that
|
|
96
|
+
* format). Records with a missing/tied timestamp fall back to scan order
|
|
97
|
+
* (the array's own push order), which is deterministic within one run.
|
|
98
|
+
*/
|
|
99
|
+
function firstCallsByLeg(records: readonly TranscriptRecord[]): TranscriptRecord[] {
|
|
100
|
+
const byAgent = new Map<string, TranscriptRecord[]>();
|
|
101
|
+
for (const r of records) {
|
|
102
|
+
if (r.bucket !== 'subagent' || r.agentId === null) continue;
|
|
103
|
+
const arr = byAgent.get(r.agentId) ?? [];
|
|
104
|
+
arr.push(r);
|
|
105
|
+
byAgent.set(r.agentId, arr);
|
|
106
|
+
}
|
|
107
|
+
const firstCalls: TranscriptRecord[] = [];
|
|
108
|
+
for (const arr of byAgent.values()) {
|
|
109
|
+
const sorted = arr
|
|
110
|
+
.map((r, idx) => ({ r, idx }))
|
|
111
|
+
.sort((a, b) => {
|
|
112
|
+
const ta = a.r.timestamp;
|
|
113
|
+
const tb = b.r.timestamp;
|
|
114
|
+
if (ta !== null && tb !== null && ta !== tb) return ta < tb ? -1 : 1;
|
|
115
|
+
if (ta !== null && tb === null) return -1;
|
|
116
|
+
if (ta === null && tb !== null) return 1;
|
|
117
|
+
return a.idx - b.idx;
|
|
118
|
+
})
|
|
119
|
+
.map((x) => x.r);
|
|
120
|
+
firstCalls.push(sorted[0] as TranscriptRecord);
|
|
121
|
+
}
|
|
122
|
+
return firstCalls;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
export function computeColdStarts(records: readonly TranscriptRecord[]): ColdStartStats {
|
|
126
|
+
const subagentRecords = records.filter((r) => r.bucket === 'subagent');
|
|
127
|
+
const totalWriteVolume = subagentRecords.reduce((s, r) => s + r.usage.cache_creation_input_tokens, 0);
|
|
128
|
+
const firstCalls = firstCallsByLeg(records);
|
|
129
|
+
|
|
130
|
+
const writtenOrUncached = firstCalls.map((r) => r.usage.cache_creation_input_tokens + r.usage.input_tokens);
|
|
131
|
+
const sumFirstCallRead = firstCalls.reduce((s, r) => s + r.usage.cache_read_input_tokens, 0);
|
|
132
|
+
const sumFirstCallBillable = firstCalls.reduce((s, r) => s + billableInputTokens(r.usage), 0);
|
|
133
|
+
const sumFirstCallWrite = firstCalls.reduce((s, r) => s + r.usage.cache_creation_input_tokens, 0);
|
|
134
|
+
|
|
135
|
+
return {
|
|
136
|
+
legs: firstCalls.length,
|
|
137
|
+
median_first_call_written_or_uncached: median(writtenOrUncached),
|
|
138
|
+
mean_first_call_written_or_uncached: mean(writtenOrUncached),
|
|
139
|
+
first_call_cache_read_share: sumFirstCallBillable > 0 ? sumFirstCallRead / sumFirstCallBillable : 0,
|
|
140
|
+
cold_start_share_of_write_volume: totalWriteVolume > 0 ? sumFirstCallWrite / totalWriteVolume : 0,
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
// ── per-agentId breakdown ───────────────────────────────────────────────
|
|
145
|
+
|
|
146
|
+
export interface AgentAggregate extends BucketAggregate {
|
|
147
|
+
agentId: string;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
export function aggregateByAgent(records: readonly TranscriptRecord[]): AgentAggregate[] {
|
|
151
|
+
const byAgent = new Map<string, TranscriptRecord[]>();
|
|
152
|
+
for (const r of records) {
|
|
153
|
+
if (r.bucket !== 'subagent' || r.agentId === null) continue;
|
|
154
|
+
const arr = byAgent.get(r.agentId) ?? [];
|
|
155
|
+
arr.push(r);
|
|
156
|
+
byAgent.set(r.agentId, arr);
|
|
157
|
+
}
|
|
158
|
+
const out: AgentAggregate[] = [];
|
|
159
|
+
for (const [agentId, recs] of byAgent) {
|
|
160
|
+
// Every rec here is bucket==='subagent', so aggregateByBucket's
|
|
161
|
+
// `.subagent` slot carries this agent's aggregate; `.main` stays
|
|
162
|
+
// all-zero and is discarded. Reuses the shared aggregation math
|
|
163
|
+
// instead of re-summing the six counters by hand.
|
|
164
|
+
const agg = aggregateByBucket(recs).subagent;
|
|
165
|
+
out.push({ ...agg, agentId });
|
|
166
|
+
}
|
|
167
|
+
return out;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
// ── C-2: duplicate-scope byte census ────────────────────────────────────
|
|
171
|
+
|
|
172
|
+
export interface DuplicateScopeResult {
|
|
173
|
+
evaluable: boolean;
|
|
174
|
+
reason?: string | undefined;
|
|
175
|
+
shared_filenames: number;
|
|
176
|
+
duplicate_tokens_per_spawn: number;
|
|
177
|
+
spawn_count: number;
|
|
178
|
+
duplicate_token_estimate_total: number;
|
|
179
|
+
share_of_subagent_write_volume: number;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
/**
|
|
183
|
+
* For every `.md` filename present in BOTH `userRulesDir` and
|
|
184
|
+
* `projectRulesDir` — computed by the shared {@link censusDuplicateScope}
|
|
185
|
+
* primitive, reused (not reimplemented) so this and the `doctor`
|
|
186
|
+
* `duplicate-scope-rules` check can never disagree on what's shared — the
|
|
187
|
+
* redundant copy's byte estimate is converted to tokens at chars/4 (the same
|
|
188
|
+
* heuristic `pricing.ts#estimate_input_tokens` uses), then multiplied by
|
|
189
|
+
* `spawnCount` (the observed subagent leg count over the same measurement
|
|
190
|
+
* window) to get the total redundant-copy volume.
|
|
191
|
+
*/
|
|
192
|
+
export function computeDuplicateScope(
|
|
193
|
+
userRulesDir: string,
|
|
194
|
+
projectRulesDir: string,
|
|
195
|
+
subagentWriteVolume: number,
|
|
196
|
+
spawnCount: number,
|
|
197
|
+
): DuplicateScopeResult {
|
|
198
|
+
const census = censusDuplicateScope(userRulesDir, projectRulesDir);
|
|
199
|
+
if (!census.evaluable) {
|
|
200
|
+
return {
|
|
201
|
+
evaluable: false,
|
|
202
|
+
reason: census.reason,
|
|
203
|
+
shared_filenames: census.shared_filenames.length,
|
|
204
|
+
duplicate_tokens_per_spawn: 0,
|
|
205
|
+
spawn_count: spawnCount,
|
|
206
|
+
duplicate_token_estimate_total: 0,
|
|
207
|
+
share_of_subagent_write_volume: 0,
|
|
208
|
+
};
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
const duplicateTokensPerSpawn = census.duplicate_chars / 4;
|
|
212
|
+
const totalEstimate = duplicateTokensPerSpawn * spawnCount;
|
|
213
|
+
const evaluable = spawnCount > 0 && subagentWriteVolume > 0;
|
|
214
|
+
|
|
215
|
+
return {
|
|
216
|
+
evaluable,
|
|
217
|
+
reason: evaluable ? undefined : 'no subagent legs or no subagent write volume observed in the window',
|
|
218
|
+
shared_filenames: census.shared_filenames.length,
|
|
219
|
+
duplicate_tokens_per_spawn: duplicateTokensPerSpawn,
|
|
220
|
+
spawn_count: spawnCount,
|
|
221
|
+
duplicate_token_estimate_total: totalEstimate,
|
|
222
|
+
share_of_subagent_write_volume: subagentWriteVolume > 0 ? totalEstimate / subagentWriteVolume : 0,
|
|
223
|
+
};
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
// ── C-4: council mispricing ──────────────────────────────────────────────
|
|
227
|
+
|
|
228
|
+
export interface CouncilMispricingResult {
|
|
229
|
+
status: 'confirmed' | 'falsified' | 'pending';
|
|
230
|
+
reason?: string | undefined;
|
|
231
|
+
session?: string;
|
|
232
|
+
rounds?: number;
|
|
233
|
+
recorded_cost_usd?: number;
|
|
234
|
+
cache_aware_cost_usd?: number;
|
|
235
|
+
delta_pct?: number;
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
interface RawCouncilResponse {
|
|
239
|
+
provider?: unknown;
|
|
240
|
+
model?: unknown;
|
|
241
|
+
input_tokens?: unknown;
|
|
242
|
+
output_tokens?: unknown;
|
|
243
|
+
cache_read_input_tokens?: unknown;
|
|
244
|
+
cache_creation_input_tokens?: unknown;
|
|
245
|
+
error?: unknown;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
interface RawDebateRound {
|
|
249
|
+
debate_total_rounds?: unknown;
|
|
250
|
+
cost_usd_actual?: unknown;
|
|
251
|
+
responses?: RawCouncilResponse[];
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
function findDebateRoundFiles(councilRoot: string): string[] {
|
|
255
|
+
const base = path.join(councilRoot, 'agents', 'runtime', 'council', 'responses');
|
|
256
|
+
if (!fs.existsSync(base)) return [];
|
|
257
|
+
const out: string[] = [];
|
|
258
|
+
const stack: string[] = [base];
|
|
259
|
+
while (stack.length > 0) {
|
|
260
|
+
const dir = stack.pop() as string;
|
|
261
|
+
let entries: fs.Dirent[];
|
|
262
|
+
try {
|
|
263
|
+
entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
264
|
+
} catch {
|
|
265
|
+
continue;
|
|
266
|
+
}
|
|
267
|
+
for (const entry of entries) {
|
|
268
|
+
const full = path.join(dir, entry.name);
|
|
269
|
+
if (entry.isDirectory()) {
|
|
270
|
+
stack.push(full);
|
|
271
|
+
continue;
|
|
272
|
+
}
|
|
273
|
+
if (entry.isFile() && /^debate-round-\d+\.json$/.test(entry.name)) out.push(full);
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
return out;
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
function numOrUndef(v: unknown): number | undefined {
|
|
280
|
+
return typeof v === 'number' && Number.isFinite(v) ? v : undefined;
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
/**
|
|
284
|
+
* Finds the best available real multi-round debate artefact under
|
|
285
|
+
* `councilRoot/agents/runtime/council/responses/**\/debate-round-*.json`,
|
|
286
|
+
* reprices its recorded usage with `reprice_with_cache` (ttl='5m' — the only
|
|
287
|
+
* TTL the council's request builder currently emits, per
|
|
288
|
+
* `orchestrator.ts`'s own comment), and reports the delta against the
|
|
289
|
+
* originally recorded `cost_usd_actual` (the cache-blind figure the pre-fix
|
|
290
|
+
* `estimate_cost` call site produced, or whatever else was live at record
|
|
291
|
+
* time — the claim is about the DELTA cache-aware repricing produces, not
|
|
292
|
+
* about which historical code path wrote the recorded number).
|
|
293
|
+
*
|
|
294
|
+
* "Best" = the group (one directory of sibling `debate-round-N.json` files)
|
|
295
|
+
* with the LARGEST total cache-token volume (cache_read + cache_creation
|
|
296
|
+
* across all responses), requiring ≥2 rounds (a real debate, not a one-shot
|
|
297
|
+
* dispatch), non-error usage, and a non-zero recorded cost to divide by.
|
|
298
|
+
* Cache-token volume — not round count — is the right selection key: a
|
|
299
|
+
* 4-round debate with zero recorded cache activity can only ever show a 0%
|
|
300
|
+
* delta (there is nothing for `reprice_with_cache` to reprice), which would
|
|
301
|
+
* silently mask a real mispricing sitting in a session that actually used
|
|
302
|
+
* the cache. Ties break on rounds, then total token volume.
|
|
303
|
+
*/
|
|
304
|
+
export function computeCouncilMispricing(councilRoot: string): CouncilMispricingResult {
|
|
305
|
+
const files = findDebateRoundFiles(councilRoot);
|
|
306
|
+
if (files.length === 0) {
|
|
307
|
+
return {
|
|
308
|
+
status: 'pending',
|
|
309
|
+
reason: 'no agents/runtime/council/responses/**/debate-round-*.json artefact found under this root',
|
|
310
|
+
};
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
const groups = new Map<string, string[]>();
|
|
314
|
+
for (const f of files) {
|
|
315
|
+
const dir = path.dirname(f);
|
|
316
|
+
const arr = groups.get(dir) ?? [];
|
|
317
|
+
arr.push(f);
|
|
318
|
+
groups.set(dir, arr);
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
let table;
|
|
322
|
+
try {
|
|
323
|
+
table = load_prices();
|
|
324
|
+
} catch {
|
|
325
|
+
return { status: 'pending', reason: 'could not load the local price table (.agent-prices.md)' };
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
let best: { dir: string; rounds: number; recorded: number; cacheAware: number; tokens: number; cacheVolume: number } | null = null;
|
|
329
|
+
for (const [dir, groupFiles] of groups) {
|
|
330
|
+
let rounds = 0;
|
|
331
|
+
let recorded = 0;
|
|
332
|
+
let cacheAware = 0;
|
|
333
|
+
let tokens = 0;
|
|
334
|
+
let cacheVolume = 0;
|
|
335
|
+
for (const f of groupFiles) {
|
|
336
|
+
let data: RawDebateRound;
|
|
337
|
+
try {
|
|
338
|
+
data = JSON.parse(fs.readFileSync(f, 'utf-8')) as RawDebateRound;
|
|
339
|
+
} catch {
|
|
340
|
+
continue;
|
|
341
|
+
}
|
|
342
|
+
rounds = Math.max(rounds, numOrUndef(data.debate_total_rounds) ?? 0);
|
|
343
|
+
recorded += numOrUndef(data.cost_usd_actual) ?? 0;
|
|
344
|
+
for (const r of data.responses ?? []) {
|
|
345
|
+
if (r.error) continue;
|
|
346
|
+
const input = numOrUndef(r.input_tokens) ?? 0;
|
|
347
|
+
const output = numOrUndef(r.output_tokens) ?? 0;
|
|
348
|
+
const read = numOrUndef(r.cache_read_input_tokens) ?? 0;
|
|
349
|
+
const write = numOrUndef(r.cache_creation_input_tokens) ?? 0;
|
|
350
|
+
tokens += input + read + write;
|
|
351
|
+
cacheVolume += read + write;
|
|
352
|
+
if (typeof r.provider !== 'string' || typeof r.model !== 'string') continue;
|
|
353
|
+
const est = reprice_with_cache(
|
|
354
|
+
r.provider,
|
|
355
|
+
r.model,
|
|
356
|
+
{ input_tokens: input, cache_read_input_tokens: read, cache_creation_input_tokens: write, output_tokens: output },
|
|
357
|
+
table,
|
|
358
|
+
'5m',
|
|
359
|
+
);
|
|
360
|
+
cacheAware += est.input_usd + est.output_usd;
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
if (rounds < 2 || tokens === 0 || recorded === 0) continue;
|
|
364
|
+
if (
|
|
365
|
+
best === null ||
|
|
366
|
+
cacheVolume > best.cacheVolume ||
|
|
367
|
+
(cacheVolume === best.cacheVolume && rounds > best.rounds) ||
|
|
368
|
+
(cacheVolume === best.cacheVolume && rounds === best.rounds && tokens > best.tokens)
|
|
369
|
+
) {
|
|
370
|
+
best = { dir, rounds, recorded, cacheAware, tokens, cacheVolume };
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
if (best === null) {
|
|
375
|
+
return {
|
|
376
|
+
status: 'pending',
|
|
377
|
+
reason: 'found debate-round artefacts, but none had ≥2 recorded rounds with non-error usage and a non-zero recorded cost',
|
|
378
|
+
};
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
const deltaPct = (best.cacheAware - best.recorded) / best.recorded;
|
|
382
|
+
const status: CouncilMispricingResult['status'] = Math.abs(deltaPct) >= C4_COUNCIL_MISPRICING_THRESHOLD ? 'confirmed' : 'falsified';
|
|
383
|
+
return {
|
|
384
|
+
status,
|
|
385
|
+
session: path.relative(councilRoot, best.dir) || '(top-level)',
|
|
386
|
+
rounds: best.rounds,
|
|
387
|
+
recorded_cost_usd: best.recorded,
|
|
388
|
+
cache_aware_cost_usd: best.cacheAware,
|
|
389
|
+
delta_pct: deltaPct,
|
|
390
|
+
};
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
// ── C-5: worktree fragmentation ──────────────────────────────────────────
|
|
394
|
+
|
|
395
|
+
export interface WorktreeFragmentationResult {
|
|
396
|
+
status: 'confirmed' | 'falsified' | 'pending';
|
|
397
|
+
reason?: string | undefined;
|
|
398
|
+
established_project_dir?: string;
|
|
399
|
+
worktree_project_dirs?: string[];
|
|
400
|
+
established_first_call_read_share?: number;
|
|
401
|
+
worktree_first_call_read_share?: number;
|
|
402
|
+
/** worktree_first_call_read_share / established_first_call_read_share. */
|
|
403
|
+
ratio?: number;
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
/** Mirrors `cost/track.mjs`'s `encodeProjectPath` — the CC project-dir naming convention. */
|
|
407
|
+
export function encodeProjectPath(cwd: string): string {
|
|
408
|
+
return cwd.replace(/[/.]/g, '-');
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
/**
|
|
412
|
+
* `git worktree list --porcelain`'s first entry is always the main/original
|
|
413
|
+
* working tree; every subsequent entry is a linked worktree of the same
|
|
414
|
+
* repo. Returns `[]` (never throws) when `git` is unavailable or `cwd` is
|
|
415
|
+
* not a git checkout — the caller treats that as "not evaluable".
|
|
416
|
+
*/
|
|
417
|
+
export function listGitWorktrees(cwd: string): string[] {
|
|
418
|
+
try {
|
|
419
|
+
const out = execFileSync('git', ['worktree', 'list', '--porcelain'], { cwd, encoding: 'utf-8', timeout: 10_000 });
|
|
420
|
+
const paths: string[] = [];
|
|
421
|
+
for (const line of out.split('\n')) {
|
|
422
|
+
if (line.startsWith('worktree ')) paths.push(line.slice('worktree '.length).trim());
|
|
423
|
+
}
|
|
424
|
+
return paths;
|
|
425
|
+
} catch {
|
|
426
|
+
return [];
|
|
427
|
+
}
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
/**
|
|
431
|
+
* Compares the first-call `cache_read` share (see {@link computeColdStarts})
|
|
432
|
+
* between the repo's established (main) worktree and the pooled set of its
|
|
433
|
+
* linked worktrees, both scanned over the same `maxAgeDays` window used for
|
|
434
|
+
* the rest of the report. `worktreePaths` is injected (never calls `git`
|
|
435
|
+
* itself) so this stays a pure, easily-fixtured function — the CLI wrapper
|
|
436
|
+
* supplies the real list via {@link listGitWorktrees}.
|
|
437
|
+
*/
|
|
438
|
+
export function computeWorktreeFragmentation(
|
|
439
|
+
projectsRoot: string,
|
|
440
|
+
worktreePaths: readonly string[],
|
|
441
|
+
maxAgeDays: number,
|
|
442
|
+
): WorktreeFragmentationResult {
|
|
443
|
+
if (worktreePaths.length < 2) {
|
|
444
|
+
return { status: 'pending', reason: 'fewer than 2 git worktrees found for this repo — nothing to compare' };
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
const established = worktreePaths[0] as string; // git always lists the main worktree first
|
|
448
|
+
const encodedEstablished = encodeProjectPath(established);
|
|
449
|
+
const worktreeDirs = worktreePaths
|
|
450
|
+
.slice(1)
|
|
451
|
+
.map(encodeProjectPath)
|
|
452
|
+
.filter((d) => fs.existsSync(path.join(projectsRoot, d)));
|
|
453
|
+
|
|
454
|
+
if (!fs.existsSync(path.join(projectsRoot, encodedEstablished)) || worktreeDirs.length === 0) {
|
|
455
|
+
return {
|
|
456
|
+
status: 'pending',
|
|
457
|
+
reason: 'no transcript directory found for both an established and a fresh-worktree checkout of this repo',
|
|
458
|
+
};
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
const establishedScan = scanTranscripts({ root: projectsRoot, projectDir: encodedEstablished, maxAgeDays });
|
|
462
|
+
const establishedColdStart = computeColdStarts(establishedScan.records);
|
|
463
|
+
|
|
464
|
+
let worktreeRecords: TranscriptRecord[] = [];
|
|
465
|
+
for (const d of worktreeDirs) {
|
|
466
|
+
worktreeRecords = worktreeRecords.concat(scanTranscripts({ root: projectsRoot, projectDir: d, maxAgeDays }).records);
|
|
467
|
+
}
|
|
468
|
+
const worktreeColdStart = computeColdStarts(worktreeRecords);
|
|
469
|
+
|
|
470
|
+
if (establishedColdStart.legs === 0 || worktreeColdStart.legs === 0) {
|
|
471
|
+
return {
|
|
472
|
+
status: 'pending',
|
|
473
|
+
reason: `insufficient subagent legs in the ${maxAgeDays}-day window (established: ${establishedColdStart.legs}, worktrees: ${worktreeColdStart.legs})`,
|
|
474
|
+
established_project_dir: encodedEstablished,
|
|
475
|
+
worktree_project_dirs: worktreeDirs,
|
|
476
|
+
};
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
const establishedShare = establishedColdStart.first_call_cache_read_share;
|
|
480
|
+
const worktreeShare = worktreeColdStart.first_call_cache_read_share;
|
|
481
|
+
const ratio = establishedShare > 0 ? worktreeShare / establishedShare : worktreeShare === 0 ? 0 : Number.POSITIVE_INFINITY;
|
|
482
|
+
|
|
483
|
+
if (!Number.isFinite(ratio)) {
|
|
484
|
+
return {
|
|
485
|
+
status: 'pending',
|
|
486
|
+
reason: 'established directory shows a zero first-call cache-read share — the comparison ratio is undefined',
|
|
487
|
+
established_project_dir: encodedEstablished,
|
|
488
|
+
worktree_project_dirs: worktreeDirs,
|
|
489
|
+
established_first_call_read_share: establishedShare,
|
|
490
|
+
worktree_first_call_read_share: worktreeShare,
|
|
491
|
+
};
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
let status: WorktreeFragmentationResult['status'];
|
|
495
|
+
let reason: string | undefined;
|
|
496
|
+
if (ratio >= C5_FALSIFY_RATIO) {
|
|
497
|
+
status = 'falsified';
|
|
498
|
+
} else if (ratio < C5_CONFIRM_RATIO) {
|
|
499
|
+
status = 'confirmed';
|
|
500
|
+
} else {
|
|
501
|
+
status = 'pending';
|
|
502
|
+
reason = `ratio ${(ratio * 100).toFixed(1)}% falls between the confirm (<10%) and falsify (>=50%) thresholds`;
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
return {
|
|
506
|
+
status,
|
|
507
|
+
reason,
|
|
508
|
+
established_project_dir: encodedEstablished,
|
|
509
|
+
worktree_project_dirs: worktreeDirs,
|
|
510
|
+
established_first_call_read_share: establishedShare,
|
|
511
|
+
worktree_first_call_read_share: worktreeShare,
|
|
512
|
+
ratio,
|
|
513
|
+
};
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
// ── host version ─────────────────────────────────────────────────────────
|
|
517
|
+
|
|
518
|
+
/** Shells out to `claude --version`; `unknown` (never fabricated) on any failure. */
|
|
519
|
+
export function hostVersion(): string {
|
|
520
|
+
try {
|
|
521
|
+
const out = execFileSync('claude', ['--version'], { encoding: 'utf-8', timeout: 5_000 }).trim();
|
|
522
|
+
return out.length > 0 ? out : 'unknown';
|
|
523
|
+
} catch {
|
|
524
|
+
return 'unknown';
|
|
525
|
+
}
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
// ── claims ────────────────────────────────────────────────────────────────
|
|
529
|
+
|
|
530
|
+
export interface Claim {
|
|
531
|
+
id: 'C-1' | 'C-2' | 'C-3' | 'C-4' | 'C-5';
|
|
532
|
+
description: string;
|
|
533
|
+
threshold: string;
|
|
534
|
+
verdict: 'confirmed' | 'falsified' | 'pending';
|
|
535
|
+
measured?: number | undefined;
|
|
536
|
+
reason?: string | undefined;
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
export function buildClaims(opts: {
|
|
540
|
+
subagentColdStart: ColdStartStats;
|
|
541
|
+
duplicateScope: DuplicateScopeResult;
|
|
542
|
+
councilMispricing: CouncilMispricingResult;
|
|
543
|
+
worktreeFragmentation: WorktreeFragmentationResult;
|
|
544
|
+
}): Claim[] {
|
|
545
|
+
const claims: Claim[] = [];
|
|
546
|
+
|
|
547
|
+
const c1Value = opts.subagentColdStart.cold_start_share_of_write_volume;
|
|
548
|
+
claims.push({
|
|
549
|
+
id: 'C-1',
|
|
550
|
+
description: 'cold-start dominance: cold starts are ≥50% of subagent write volume (baseline 69.4%)',
|
|
551
|
+
threshold: '>= 0.50',
|
|
552
|
+
verdict: opts.subagentColdStart.legs === 0 ? 'pending' : c1Value >= C1_COLD_START_DOMINANCE_THRESHOLD ? 'confirmed' : 'falsified',
|
|
553
|
+
measured: opts.subagentColdStart.legs === 0 ? undefined : c1Value,
|
|
554
|
+
reason: opts.subagentColdStart.legs === 0 ? 'no subagent legs observed in the window' : undefined,
|
|
555
|
+
});
|
|
556
|
+
|
|
557
|
+
const d = opts.duplicateScope;
|
|
558
|
+
claims.push({
|
|
559
|
+
id: 'C-2',
|
|
560
|
+
description: 'duplicate-scope share: the redundant rule-set copy is ≥25% of subagent write volume (baseline ≈37%)',
|
|
561
|
+
threshold: '>= 0.25',
|
|
562
|
+
verdict: !d.evaluable ? 'pending' : d.share_of_subagent_write_volume >= C2_DUPLICATE_SCOPE_THRESHOLD ? 'confirmed' : 'falsified',
|
|
563
|
+
measured: d.evaluable ? d.share_of_subagent_write_volume : undefined,
|
|
564
|
+
reason: !d.evaluable ? d.reason : undefined,
|
|
565
|
+
});
|
|
566
|
+
|
|
567
|
+
claims.push({
|
|
568
|
+
id: 'C-3',
|
|
569
|
+
description: 'preamble reducibility: a shipped reduction moves median cold-start tokens by ≥15% with no eval regression',
|
|
570
|
+
threshold: '>= 0.15',
|
|
571
|
+
verdict: 'pending',
|
|
572
|
+
reason: 'requires an implemented preamble-reduction intervention (Phase 3) — none has landed yet',
|
|
573
|
+
});
|
|
574
|
+
|
|
575
|
+
const c = opts.councilMispricing;
|
|
576
|
+
claims.push({
|
|
577
|
+
id: 'C-4',
|
|
578
|
+
description: 'council mispricing magnitude: cache-aware repricing changes a real multi-round debate’s realized cost by ≥5%',
|
|
579
|
+
threshold: '>= 0.05 (absolute delta)',
|
|
580
|
+
verdict: c.status,
|
|
581
|
+
measured: c.delta_pct,
|
|
582
|
+
reason: c.reason,
|
|
583
|
+
});
|
|
584
|
+
|
|
585
|
+
const w = opts.worktreeFragmentation;
|
|
586
|
+
claims.push({
|
|
587
|
+
id: 'C-5',
|
|
588
|
+
description: "worktree fragmentation: a fresh worktree's first-call cache_read share is <10% of an established directory's (falsified at >=50%)",
|
|
589
|
+
threshold: '< 0.10 confirmed / >= 0.50 falsified',
|
|
590
|
+
verdict: w.status,
|
|
591
|
+
measured: w.ratio,
|
|
592
|
+
reason: w.reason,
|
|
593
|
+
});
|
|
594
|
+
|
|
595
|
+
return claims;
|
|
596
|
+
}
|
|
597
|
+
|
|
598
|
+
// ── CLI ───────────────────────────────────────────────────────────────────
|
|
599
|
+
|
|
600
|
+
export interface Options {
|
|
601
|
+
format: 'text' | 'json';
|
|
602
|
+
root: string;
|
|
603
|
+
maxAgeDays: number;
|
|
604
|
+
repoRoot: string;
|
|
605
|
+
councilRoot: string;
|
|
606
|
+
userRulesDir: string;
|
|
607
|
+
projectRulesDir: string;
|
|
608
|
+
}
|
|
609
|
+
|
|
610
|
+
function defaultOptions(): Options {
|
|
611
|
+
return {
|
|
612
|
+
format: 'text',
|
|
613
|
+
root: DEFAULT_PROJECTS_ROOT,
|
|
614
|
+
maxAgeDays: 14,
|
|
615
|
+
repoRoot: REPO_ROOT,
|
|
616
|
+
councilRoot: REPO_ROOT,
|
|
617
|
+
userRulesDir: path.join(homedir(), '.claude', 'rules'),
|
|
618
|
+
projectRulesDir: path.join(REPO_ROOT, 'dist', 'agent-src', 'rules'),
|
|
619
|
+
};
|
|
620
|
+
}
|
|
621
|
+
|
|
622
|
+
export function parseArgs(argv: string[]): Options {
|
|
623
|
+
const opts = defaultOptions();
|
|
624
|
+
for (let i = 0; i < argv.length; i++) {
|
|
625
|
+
const a = argv[i];
|
|
626
|
+
if (a === undefined) continue;
|
|
627
|
+
if (a === '--format') opts.format = (argv[++i] as Options['format']) ?? opts.format;
|
|
628
|
+
else if (a.startsWith('--format=')) opts.format = a.slice('--format='.length) as Options['format'];
|
|
629
|
+
else if (a === '--root') opts.root = argv[++i] ?? opts.root;
|
|
630
|
+
else if (a.startsWith('--root=')) opts.root = a.slice('--root='.length);
|
|
631
|
+
else if (a === '--max-age-days') opts.maxAgeDays = Number(argv[++i]) || opts.maxAgeDays;
|
|
632
|
+
else if (a.startsWith('--max-age-days=')) opts.maxAgeDays = Number(a.slice('--max-age-days='.length)) || opts.maxAgeDays;
|
|
633
|
+
else if (a === '--repo-root') opts.repoRoot = argv[++i] ?? opts.repoRoot;
|
|
634
|
+
else if (a.startsWith('--repo-root=')) opts.repoRoot = a.slice('--repo-root='.length);
|
|
635
|
+
else if (a === '--council-root') opts.councilRoot = argv[++i] ?? opts.councilRoot;
|
|
636
|
+
else if (a.startsWith('--council-root=')) opts.councilRoot = a.slice('--council-root='.length);
|
|
637
|
+
else if (a === '--user-rules-dir') opts.userRulesDir = argv[++i] ?? opts.userRulesDir;
|
|
638
|
+
else if (a.startsWith('--user-rules-dir=')) opts.userRulesDir = a.slice('--user-rules-dir='.length);
|
|
639
|
+
else if (a === '--project-rules-dir') opts.projectRulesDir = argv[++i] ?? opts.projectRulesDir;
|
|
640
|
+
else if (a.startsWith('--project-rules-dir=')) opts.projectRulesDir = a.slice('--project-rules-dir='.length);
|
|
641
|
+
}
|
|
642
|
+
if (opts.format !== 'text' && opts.format !== 'json') opts.format = 'text';
|
|
643
|
+
return opts;
|
|
644
|
+
}
|
|
645
|
+
|
|
646
|
+
export interface Report {
|
|
647
|
+
schema: 'cache-realization-report/v1';
|
|
648
|
+
host_version: string;
|
|
649
|
+
window_days: number;
|
|
650
|
+
root: string;
|
|
651
|
+
metric_definition: { billable_input: string; note: string };
|
|
652
|
+
dedup_ratio: number;
|
|
653
|
+
total_seen: number;
|
|
654
|
+
deduped_count: number;
|
|
655
|
+
buckets: Record<TranscriptBucket, BucketAggregate>;
|
|
656
|
+
subagent_cold_start: ColdStartStats;
|
|
657
|
+
by_agent: AgentAggregate[];
|
|
658
|
+
duplicate_scope: DuplicateScopeResult;
|
|
659
|
+
council_mispricing: CouncilMispricingResult;
|
|
660
|
+
worktree_fragmentation: WorktreeFragmentationResult;
|
|
661
|
+
claims: Claim[];
|
|
662
|
+
}
|
|
663
|
+
|
|
664
|
+
export function buildReport(opts: Options): Report {
|
|
665
|
+
const scan = scanTranscripts({ root: opts.root, maxAgeDays: opts.maxAgeDays });
|
|
666
|
+
const buckets = aggregateByBucket(scan.records);
|
|
667
|
+
const subagentColdStart = computeColdStarts(scan.records);
|
|
668
|
+
const byAgent = aggregateByAgent(scan.records);
|
|
669
|
+
|
|
670
|
+
const duplicateScope = computeDuplicateScope(
|
|
671
|
+
opts.userRulesDir,
|
|
672
|
+
opts.projectRulesDir,
|
|
673
|
+
buckets.subagent.cache_creation_input_tokens,
|
|
674
|
+
subagentColdStart.legs,
|
|
675
|
+
);
|
|
676
|
+
|
|
677
|
+
const councilMispricing = computeCouncilMispricing(opts.councilRoot);
|
|
678
|
+
|
|
679
|
+
const worktreePaths = listGitWorktrees(opts.repoRoot);
|
|
680
|
+
const worktreeFragmentation = computeWorktreeFragmentation(opts.root, worktreePaths, opts.maxAgeDays);
|
|
681
|
+
|
|
682
|
+
const claims = buildClaims({ subagentColdStart, duplicateScope, councilMispricing, worktreeFragmentation });
|
|
683
|
+
|
|
684
|
+
return {
|
|
685
|
+
schema: 'cache-realization-report/v1',
|
|
686
|
+
host_version: hostVersion(),
|
|
687
|
+
window_days: opts.maxAgeDays,
|
|
688
|
+
root: opts.root,
|
|
689
|
+
metric_definition: {
|
|
690
|
+
billable_input: 'input_tokens + cache_read_input_tokens + cache_creation_input_tokens',
|
|
691
|
+
note: "Anthropic's usage.input_tokens EXCLUDES cache tokens — it is only the uncached portion of the prompt.",
|
|
692
|
+
},
|
|
693
|
+
dedup_ratio: scan.dedup_ratio,
|
|
694
|
+
total_seen: scan.totalSeen,
|
|
695
|
+
deduped_count: scan.dedupedCount,
|
|
696
|
+
buckets,
|
|
697
|
+
subagent_cold_start: subagentColdStart,
|
|
698
|
+
by_agent: byAgent,
|
|
699
|
+
duplicate_scope: duplicateScope,
|
|
700
|
+
council_mispricing: councilMispricing,
|
|
701
|
+
worktree_fragmentation: worktreeFragmentation,
|
|
702
|
+
claims,
|
|
703
|
+
};
|
|
704
|
+
}
|
|
705
|
+
|
|
706
|
+
function pct(v: number): string {
|
|
707
|
+
return `${(v * 100).toFixed(1)}%`;
|
|
708
|
+
}
|
|
709
|
+
|
|
710
|
+
export function renderText(r: Report): string {
|
|
711
|
+
const out: string[] = [];
|
|
712
|
+
out.push('Cache-realization report');
|
|
713
|
+
out.push(` host_version: ${r.host_version}`);
|
|
714
|
+
out.push(` window: last ${r.window_days} days`);
|
|
715
|
+
out.push(` root: ${r.root}`);
|
|
716
|
+
out.push(` metric: billable_input = ${r.metric_definition.billable_input}`);
|
|
717
|
+
out.push(` ${r.metric_definition.note}`);
|
|
718
|
+
out.push(` dedup: ${r.deduped_count}/${r.total_seen} unique records kept (dedup_ratio ${pct(r.dedup_ratio)})`);
|
|
719
|
+
out.push('');
|
|
720
|
+
|
|
721
|
+
out.push('By bucket:');
|
|
722
|
+
for (const bucket of ['main', 'subagent'] as const) {
|
|
723
|
+
const b = r.buckets[bucket];
|
|
724
|
+
out.push(` ${bucket}: calls=${b.calls} read_share=${pct(b.read_share)} weighted_input_units=${Math.round(b.weighted_input_units)}`);
|
|
725
|
+
out.push(
|
|
726
|
+
` input=${b.input_tokens} cache_read=${b.cache_read_input_tokens} cache_creation=${b.cache_creation_input_tokens}` +
|
|
727
|
+
` (5m=${b.ephemeral_5m_input_tokens} 1h=${b.ephemeral_1h_input_tokens}) output=${b.output_tokens}`,
|
|
728
|
+
);
|
|
729
|
+
}
|
|
730
|
+
out.push('');
|
|
731
|
+
|
|
732
|
+
const cs = r.subagent_cold_start;
|
|
733
|
+
out.push('Subagent cold start (first call per leg):');
|
|
734
|
+
out.push(
|
|
735
|
+
` legs=${cs.legs} median_written_or_uncached=${Math.round(cs.median_first_call_written_or_uncached)}` +
|
|
736
|
+
` mean=${Math.round(cs.mean_first_call_written_or_uncached)}`,
|
|
737
|
+
);
|
|
738
|
+
out.push(` first_call_cache_read_share=${pct(cs.first_call_cache_read_share)}`);
|
|
739
|
+
out.push(` cold_start_share_of_subagent_write_volume=${pct(cs.cold_start_share_of_write_volume)}`);
|
|
740
|
+
out.push('');
|
|
741
|
+
|
|
742
|
+
out.push(`Per-agent breakdown: ${r.by_agent.length} distinct subagent legs (--format json carries all; top 10 by weighted_input_units below)`);
|
|
743
|
+
const top10 = [...r.by_agent].sort((a, b) => b.weighted_input_units - a.weighted_input_units).slice(0, 10);
|
|
744
|
+
for (const a of top10) {
|
|
745
|
+
out.push(` ${a.agentId}: calls=${a.calls} read_share=${pct(a.read_share)} weighted_input_units=${Math.round(a.weighted_input_units)}`);
|
|
746
|
+
}
|
|
747
|
+
out.push('');
|
|
748
|
+
|
|
749
|
+
out.push('Pre-registered claims:');
|
|
750
|
+
for (const c of r.claims) {
|
|
751
|
+
const measured = c.measured !== undefined ? ` (measured ${pct(c.measured)})` : '';
|
|
752
|
+
const reasonSuffix = c.verdict === 'pending' && c.reason ? ` — ${c.reason}` : '';
|
|
753
|
+
out.push(` ${c.id} [${c.verdict}]${measured}: ${c.description}${reasonSuffix}`);
|
|
754
|
+
}
|
|
755
|
+
out.push('');
|
|
756
|
+
|
|
757
|
+
out.push('Re-verification:');
|
|
758
|
+
out.push(' command: ./scripts-run src/scripts/cache_realization_report --format text');
|
|
759
|
+
out.push(` host_version at this run: ${r.host_version}`);
|
|
760
|
+
out.push(
|
|
761
|
+
` re-run + restamp this report if: read_share drops below ${pct(DRIFT_READ_SHARE_FLOOR)}, OR` +
|
|
762
|
+
` cold-start share drops below ${pct(DRIFT_COLD_START_SHARE_FLOOR)}`,
|
|
763
|
+
);
|
|
764
|
+
|
|
765
|
+
return out.join('\n');
|
|
766
|
+
}
|
|
767
|
+
|
|
768
|
+
export function main(argv: string[] = process.argv.slice(2)): number {
|
|
769
|
+
const opts = parseArgs(argv);
|
|
770
|
+
const report = buildReport(opts);
|
|
771
|
+
if (opts.format === 'json') {
|
|
772
|
+
process.stdout.write(JSON.stringify(report, null, 2) + '\n');
|
|
773
|
+
} else {
|
|
774
|
+
process.stdout.write(renderText(report) + '\n');
|
|
775
|
+
}
|
|
776
|
+
return 0;
|
|
777
|
+
}
|
|
778
|
+
|
|
779
|
+
if (process.argv[1] !== undefined) {
|
|
780
|
+
const invokedUrl = pathToFileURL(path.resolve(process.argv[1])).href;
|
|
781
|
+
if (import.meta.url === invokedUrl) process.exit(main());
|
|
782
|
+
}
|