@event4u/agent-config 14.12.0 → 14.14.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/.augment-plugin/marketplace.json +3 -3
- package/.augment-plugin/plugin.json +1 -1
- package/.claude-plugin/marketplace.json +1 -1
- package/CHANGELOG.md +118 -155
- package/CONTRIBUTING.md +38 -0
- package/CREDITS.md +135 -0
- package/NOTICE +13 -0
- package/README.md +8 -6
- package/dist/agent-src/commands/analyze/inbox.md +145 -2
- package/dist/agent-src/commands/feature/dev.md +7 -2
- package/dist/agent-src/commands/ghostwriter/write.md +5 -1
- package/dist/agent-src/commands/implement-ticket.md +1 -1
- package/dist/agent-src/commands/mission/upgrade.md +1 -1
- package/dist/agent-src/commands/orchestrate.md +2 -2
- package/dist/agent-src/commands/post-as/me.md +5 -1
- package/dist/agent-src/commands/pr/merge.md +19 -6
- package/dist/agent-src/commands/roadmap/process-full.md +19 -5
- package/dist/agent-src/commands/tdd/red.md +12 -2
- package/dist/agent-src/commands/work.md +1 -1
- package/dist/agent-src/contexts/communication/rules-auto/token-efficiency-mechanics.md +40 -0
- package/dist/agent-src/contexts/execution/auto-dispatch-classification.md +5 -2
- package/dist/agent-src/contexts/execution/autonomy-mechanics.md +21 -0
- package/dist/agent-src/contexts/execution/orchestration-telemetry.md +1 -0
- package/dist/agent-src/contexts/execution/subagent-response-contract.md +40 -0
- package/dist/agent-src/contexts/execution/subagent-steering.md +13 -1
- package/dist/agent-src/contexts/execution/terminal-states.md +96 -0
- package/dist/agent-src/rules/artifact-drafting-protocol.md +1 -1
- package/dist/agent-src/rules/broken-access-control.md +4 -0
- package/dist/agent-src/rules/code-comment-discipline.md +6 -0
- package/dist/agent-src/rules/code-provenance.md +4 -0
- package/dist/agent-src/rules/design-fidelity.md +1 -1
- package/dist/agent-src/rules/domain-safety-pii.md +4 -0
- package/dist/agent-src/rules/domain-safety-retention.md +4 -0
- package/dist/agent-src/rules/engineering-safety-floor.md +2 -0
- package/dist/agent-src/rules/external-code-graph-interop.md +14 -12
- package/dist/agent-src/rules/improve-before-implement.md +6 -8
- package/dist/agent-src/rules/laravel-routing.md +1 -1
- package/dist/agent-src/rules/lethal-trifecta-guard.md +4 -0
- package/dist/agent-src/rules/secret-vcs-guard.md +2 -0
- package/dist/agent-src/rules/security-sensitive-stop.md +2 -0
- package/dist/agent-src/rules/source-confidentiality.md +12 -34
- package/dist/agent-src/rules/symfony-routing.md +1 -1
- package/dist/agent-src/rules/token-efficiency.md +14 -0
- package/dist/agent-src/rules/tool-safety.md +4 -0
- package/dist/agent-src/rules/untrusted-input-defense.md +4 -0
- package/dist/agent-src/scripts/archive_completed_roadmaps.ts +252 -8
- package/dist/agent-src/scripts/guarded_baseline.ts +343 -0
- package/dist/agent-src/scripts/roadmap_set_step.ts +253 -0
- package/dist/agent-src/scripts/stub_queue.ts +82 -0
- package/dist/agent-src/scripts/stubs_due.ts +516 -0
- package/dist/agent-src/scripts/ticket_bundles.ts +84 -0
- package/dist/agent-src/scripts/update_roadmap_progress.ts +16 -12
- package/dist/agent-src/skills/brand-asset-generation/SKILL.md +17 -4
- package/dist/agent-src/skills/brand-audit/SKILL.md +33 -0
- package/dist/agent-src/skills/code-intelligence/SKILL.md +57 -0
- package/dist/agent-src/skills/database/SKILL.md +8 -0
- package/dist/agent-src/skills/dependency-upgrade/SKILL.md +27 -0
- package/dist/agent-src/skills/design-review/SKILL.md +1 -1
- package/dist/agent-src/skills/doc-coauthoring/SKILL.md +1 -1
- package/dist/agent-src/skills/existing-ui-audit/SKILL.md +17 -1
- package/dist/agent-src/skills/feature-planning/SKILL.md +9 -2
- package/dist/agent-src/skills/frontend-render-security/SKILL.md +44 -0
- package/dist/agent-src/skills/git-workflow/SKILL.md +1 -1
- package/dist/agent-src/skills/js-library-packaging/scripts/check_package_surface.ts +38 -4
- package/dist/agent-src/skills/judge-artifact-completeness/rubrics/ticket-quality-score.json +2 -2
- package/dist/agent-src/skills/laravel/SKILL.md +35 -0
- package/dist/agent-src/skills/laravel-migration/SKILL.md +57 -3
- package/dist/agent-src/skills/monorepo-workspace/SKILL.md +26 -0
- package/dist/agent-src/skills/playbook-authoring/SKILL.md +28 -1
- package/dist/agent-src/skills/react-shadcn-ui/SKILL.md +1 -1
- package/dist/agent-src/skills/skill-writing/references/procedure.md +5 -5
- package/dist/agent-src/skills/sql-writing/SKILL.md +7 -1
- package/dist/agent-src/skills/standards-from-config/SKILL.md +27 -4
- package/dist/agent-src/skills/supply-chain-intake/SKILL.md +11 -4
- package/dist/agent-src/skills/symfony-workflow/SKILL.md +35 -0
- package/dist/agent-src/skills/test-case-discovery/SKILL.md +85 -0
- package/dist/agent-src/skills/test-driven-development/SKILL.md +33 -9
- package/dist/agent-src/skills/testing-anti-patterns/SKILL.md +1 -1
- package/dist/agent-src/skills/testing-anti-patterns/process-anti-patterns.md +37 -0
- package/dist/agent-src/skills/ui-component-architect/SKILL.md +45 -2
- package/dist/agent-src/skills/upstream-contribute/SKILL.md +38 -1
- package/dist/agent-src/skills/verify-repair-loop/SKILL.md +9 -4
- package/dist/agent-src/templates/agents/agent-project-settings.example.yml +1 -1
- package/dist/agent-src/templates/roadmaps.md +97 -3
- package/dist/agent-src/templates/scripts/check_memory.ts +258 -17
- package/dist/agent-src/templates/scripts/check_memory_proposal.ts +9 -3
- package/dist/agent-src/templates/scripts/memory_lookup.ts +86 -0
- package/dist/agent-src/templates/scripts/memory_signal.ts +44 -0
- package/dist/agent-src/templates/scripts/work_engine/directives/backend/implement.ts +90 -0
- package/dist/agent-src/templates/scripts/work_engine/directives/backend/index.ts +11 -0
- package/dist/agent-src/templates/scripts/work_engine/directives/backend/test.ts +23 -1
- package/dist/agent-src/templates/scripts/work_engine/directives/backend/verify.ts +10 -1
- package/dist/agent-src/templates/scripts/work_engine/directives/mixed/stitch.ts +5 -1
- package/dist/agent-src/templates/scripts/work_engine/stack/runner.ts +102 -14
- package/dist/cli/commands/uiAudit.js +124 -5
- package/dist/cli/registry.js +2 -0
- package/dist/cli-delegate/{chunk-HYWSRNUX.js → chunk-2DK2VJWG.js} +3 -3
- package/dist/cli-delegate/{chunk-JCW7ZLHK.js → chunk-4FS4WRXP.js} +5 -0
- package/dist/cli-delegate/{chunk-OMIVVCG2.js → chunk-A4QJ6ENT.js} +24 -0
- package/dist/cli-delegate/{chunk-JJA2QEWA.js → chunk-AKJGUQNO.js} +466 -285
- package/dist/cli-delegate/{chunk-E46KPN6K.js → chunk-BTWUYDGN.js} +424 -363
- package/dist/cli-delegate/{chunk-K4FFODTS.js → chunk-ILMUPLGW.js} +1227 -316
- package/dist/cli-delegate/{chunk-FF7WAFMR.js → chunk-KPBWFOPZ.js} +5 -1
- package/dist/cli-delegate/cmd_adr_effective.js +102 -0
- package/dist/cli-delegate/cmd_conformance.js +80 -11
- package/dist/cli-delegate/cmd_doctor.js +3 -3
- package/dist/cli-delegate/cmd_export.js +3 -2
- package/dist/cli-delegate/cmd_fleet.js +2 -2
- package/dist/cli-delegate/cmd_handoff.js +1 -1
- package/dist/cli-delegate/cmd_preflight.js +2 -2
- package/dist/cli-delegate/cmd_prune.js +3 -2
- package/dist/cli-delegate/cmd_settings_get.js +1 -1
- package/dist/cli-delegate/cmd_settings_migrate.js +3 -2
- package/dist/cli-delegate/cmd_settings_set.js +2 -2
- package/dist/cli-delegate/cmd_sync.js +3 -2
- package/dist/cli-delegate/cmd_uninstall.js +3 -2
- package/dist/cli-delegate/cmd_validate.js +3 -2
- package/dist/discovery/deprecation-report.md +1 -1
- package/dist/discovery/discovery-manifest.json +58 -58
- package/dist/discovery/discovery-manifest.json.sha256 +1 -1
- package/dist/discovery/discovery-manifest.summary.md +1 -1
- package/dist/discovery/dormancy-report.md +1 -1
- package/dist/discovery/orphan-report.md +1 -1
- package/dist/discovery/packs.json +2 -2
- package/dist/discovery/trust-report.md +1 -1
- package/dist/discovery/workspaces.json +2 -2
- package/dist/hooks/dispatch.js +2900 -1049
- package/dist/install/claudeRuleRewrite.js +254 -0
- package/dist/install/detect.js +29 -16
- package/dist/install/detect_php_shape.js +159 -0
- package/dist/install/install.mjs +634 -428
- package/dist/mcp/awesome-mcp-servers.row.md +1 -1
- package/dist/mcp/mcp-cloudflare-catalogue.json +1 -1
- package/dist/mcp/registry-manifest.json +3 -3
- package/dist/mcp/server.json +3 -3
- package/dist/mcp/server.mjs +4895 -2627
- package/dist/server/schemas/settings.js +3 -0
- package/dist/ui/assets/index-D0jaCRPM.js +29 -0
- package/dist/ui/index.html +1 -1
- package/docs/MIGRATION.md +1 -1
- package/docs/THIRD-PARTY-NOTICES.md +25 -0
- package/docs/contracts/provider-lifecycle.md +1 -1
- package/docs/contracts/settings-classes.md +10 -4
- package/docs/guidelines/agent-infra/5w2h-analysis.md +3 -3
- package/docs/guidelines/agent-infra/agent-interaction-and-decision-quality.md +1 -0
- package/docs/guidelines/agent-infra/artifact-drafting-protocol-mechanics.md +58 -3
- package/docs/guidelines/agent-infra/ask-when-uncertain-demos.md +2 -2
- package/docs/guidelines/agent-infra/asking-and-brevity-examples.md +3 -3
- package/docs/guidelines/agent-infra/break-glass-usage.md +7 -7
- package/docs/guidelines/agent-infra/carve-out-predicates.md +3 -3
- package/docs/guidelines/agent-infra/comparison-matrix.md +1 -1
- package/docs/guidelines/agent-infra/critical-thinking.md +4 -4
- package/docs/guidelines/agent-infra/direct-answers-demos.md +2 -2
- package/docs/guidelines/agent-infra/domain-eval-anti-pattern.md +1 -1
- package/docs/guidelines/agent-infra/engineering-memory-data-format.md +3 -3
- package/docs/guidelines/agent-infra/existence-question-verdicts.md +80 -0
- package/docs/guidelines/agent-infra/first-principles.md +2 -2
- package/docs/guidelines/agent-infra/framework-neutrality-patterns.md +2 -2
- package/docs/guidelines/agent-infra/guarded-baseline.md +39 -0
- package/docs/guidelines/agent-infra/inversion-thinking.md +5 -5
- package/docs/guidelines/agent-infra/language-and-tone-examples.md +1 -1
- package/docs/guidelines/agent-infra/layered-settings.md +10 -10
- package/docs/guidelines/agent-infra/memory-access.md +1 -1
- package/docs/guidelines/agent-infra/mental-models.md +3 -3
- package/docs/guidelines/agent-infra/reuse-verdict-mechanics.md +71 -0
- package/docs/guidelines/agent-infra/review-routing-data-format.md +7 -7
- package/docs/guidelines/agent-infra/roadmap-progress-mechanics.md +13 -7
- package/docs/guidelines/agent-infra/role-contracts.md +2 -2
- package/docs/guidelines/agent-infra/role-mode-router.md +3 -3
- package/docs/guidelines/agent-infra/rule-type-governance.md +2 -2
- package/docs/guidelines/agent-infra/scqa-framework.md +5 -5
- package/docs/guidelines/agent-infra/self-improvement-pipeline.md +6 -6
- package/docs/guidelines/agent-infra/simplicity-and-goal-demos.md +2 -2
- package/docs/guidelines/agent-infra/six-hats.md +3 -3
- package/docs/guidelines/agent-infra/skill-quality-checklist.md +6 -6
- package/docs/guidelines/agent-infra/source-confidentiality-mechanics.md +109 -0
- package/docs/guidelines/agent-infra/systems-thinking.md +1 -1
- package/docs/guidelines/agent-infra/verify-before-complete-demos.md +2 -2
- package/docs/guidelines/augment-portability-patterns.md +6 -4
- package/docs/guidelines/code-clarity.md +18 -0
- package/docs/guidelines/component-oriented-and-oop-development.md +3 -2
- package/docs/guidelines/cross-role-handoff.md +2 -2
- package/docs/guidelines/design-fidelity-mechanics.md +1 -1
- package/docs/guidelines/docs/readme-size-and-splitting.md +3 -3
- package/docs/guidelines/php/database.md +90 -7
- package/docs/guidelines/prompt-templates.md +7 -7
- package/llms.txt +2 -2
- package/package.json +5 -2
- package/src/agent-src/scripts/archive_completed_roadmaps.ts +252 -8
- package/src/agent-src/scripts/guarded_baseline.ts +343 -0
- package/src/agent-src/scripts/roadmap_set_step.ts +253 -0
- package/src/agent-src/scripts/stub_queue.ts +82 -0
- package/src/agent-src/scripts/stubs_due.ts +516 -0
- package/src/agent-src/scripts/ticket_bundles.ts +84 -0
- package/src/agent-src/scripts/update_roadmap_progress.ts +16 -12
- package/src/agent-src/templates/scripts/check_memory.ts +258 -17
- package/src/agent-src/templates/scripts/check_memory_proposal.ts +9 -3
- package/src/agent-src/templates/scripts/memory_lookup.ts +86 -0
- package/src/agent-src/templates/scripts/memory_signal.ts +44 -0
- package/src/agent-src/templates/scripts/work_engine/directives/backend/implement.ts +90 -0
- package/src/agent-src/templates/scripts/work_engine/directives/backend/index.ts +11 -0
- package/src/agent-src/templates/scripts/work_engine/directives/backend/test.ts +23 -1
- package/src/agent-src/templates/scripts/work_engine/directives/backend/verify.ts +10 -1
- package/src/agent-src/templates/scripts/work_engine/directives/mixed/stitch.ts +5 -1
- package/src/agent-src/templates/scripts/work_engine/stack/runner.ts +102 -14
- package/src/config/agent-settings.template.yml +32 -3
- package/src/config/assurance-capability-registry.json +21 -9
- package/src/config/canonical-terms.yml +119 -0
- package/src/config/capability-native-outcome-bars.json +81 -0
- package/src/config/ci-local-parity.yml +80 -0
- package/src/config/drafting-channels.yml +43 -0
- package/src/config/estate-count-budget.json +57 -36
- package/src/config/evaluator-budgets.json +14 -14
- package/src/config/gate-coverage.yml +729 -63
- package/src/config/gate-reachability-exemptions.json +21 -0
- package/src/config/gate-violation-baselines.json +42 -19
- package/src/config/harness-evolution-budget.json +25 -0
- package/src/config/lapsed-beta-baseline.json +96 -0
- package/src/config/memory-twin-verdicts.yml +129 -0
- package/src/config/metric-registry.yml +124 -0
- package/src/config/pack-size-budget.json +16 -15
- package/src/config/preamble-payload-budget.json +12 -4
- package/src/config/profiles/balanced.ini +27 -0
- package/src/config/profiles/full.ini +27 -0
- package/src/config/profiles/minimal.ini +27 -0
- package/src/config/publish-surface.json +9 -2
- package/src/config/routing-coverage-seed.json +16 -2
- package/src/config/rule-stub-ceilings.json +133 -112
- package/src/config/turnaround-budget.json +66 -0
- package/src/install/claudeRuleRewrite.ts +288 -0
- package/src/install/detect.ts +60 -17
- package/src/install/detect_php_shape.ts +191 -0
- package/src/scripts/_cli/cmd_doctor.ts +27 -112
- package/src/scripts/_dispatch.bash +23 -0
- package/src/scripts/_lib/activation_ladder.ts +255 -0
- package/src/scripts/_lib/activation_receipt_producer.ts +341 -0
- package/src/scripts/_lib/activation_states.ts +88 -0
- package/src/scripts/_lib/adherence_detectors.ts +143 -0
- package/src/scripts/_lib/adr_frontmatter.ts +26 -0
- package/src/scripts/_lib/arith_claims.ts +181 -0
- package/src/scripts/_lib/arm_ranking.ts +62 -0
- package/src/scripts/_lib/asset_delivery_ledger.ts +303 -0
- package/src/scripts/_lib/audit_field_provenance.ts +54 -0
- package/src/scripts/_lib/auto_dispatch.ts +32 -3
- package/src/scripts/_lib/bench_ab_size_claim.ts +98 -4
- package/src/scripts/_lib/benchmark_cache_fields.ts +158 -0
- package/src/scripts/_lib/candidate_pair_delta.ts +349 -0
- package/src/scripts/_lib/candidate_proposer.ts +402 -0
- package/src/scripts/_lib/candidate_record.ts +601 -0
- package/src/scripts/_lib/capture_rate.ts +319 -0
- package/src/scripts/_lib/carrier_status.ts +118 -0
- package/src/scripts/_lib/cascade_stage_enumeration.ts +92 -0
- package/src/scripts/_lib/collector_denominator.ts +771 -0
- package/src/scripts/_lib/collector_record.ts +340 -0
- package/src/scripts/_lib/collector_store.ts +664 -0
- package/src/scripts/_lib/collector_supervision.ts +827 -0
- package/src/scripts/_lib/concern_estate.ts +77 -0
- package/src/scripts/_lib/config_chain.ts +477 -0
- package/src/scripts/_lib/config_cost.ts +209 -0
- package/src/scripts/_lib/corpus_manifest.ts +726 -0
- package/src/scripts/_lib/council_settings_block.ts +6 -0
- package/src/scripts/_lib/curator_ops.ts +172 -0
- package/src/scripts/_lib/delivery_arm_experiment.ts +282 -0
- package/src/scripts/_lib/delivery_criticality.ts +126 -0
- package/src/scripts/_lib/doctor_runtime_checks.ts +70 -0
- package/src/scripts/_lib/empty_cycles.ts +88 -0
- package/src/scripts/_lib/estate_carrier_cases.ts +72 -0
- package/src/scripts/_lib/eval_publication.ts +354 -0
- package/src/scripts/_lib/evaluation_cascade.ts +452 -0
- package/src/scripts/_lib/evaluation_vector.ts +283 -0
- package/src/scripts/_lib/evaluator_promotion.ts +225 -0
- package/src/scripts/_lib/evidence_basis.ts +118 -0
- package/src/scripts/_lib/evolution_roi.ts +562 -0
- package/src/scripts/_lib/exec_evidence.ts +8 -0
- package/src/scripts/_lib/experience_card.ts +272 -0
- package/src/scripts/_lib/experience_report.ts +151 -0
- package/src/scripts/_lib/experiment_freeze.ts +112 -0
- package/src/scripts/_lib/generated_by.ts +66 -0
- package/src/scripts/_lib/harness_evolution_guards.ts +239 -0
- package/src/scripts/_lib/hook_effect_probe.ts +141 -0
- package/src/scripts/_lib/host_denominator.ts +687 -0
- package/src/scripts/_lib/host_projection_reach.ts +157 -0
- package/src/scripts/_lib/ignored_blocker.ts +148 -0
- package/src/scripts/_lib/install_reach_checks.ts +495 -0
- package/src/scripts/_lib/json_duplicate_keys.ts +150 -0
- package/src/scripts/_lib/judge_hygiene.ts +228 -0
- package/src/scripts/_lib/legacy_boundary_map.ts +228 -0
- package/src/scripts/_lib/lexical_shortlist.ts +215 -0
- package/src/scripts/_lib/llm_candidate_proposer.ts +461 -0
- package/src/scripts/_lib/llm_proposer_transport.ts +153 -0
- package/src/scripts/_lib/loop_guards.ts +299 -0
- package/src/scripts/_lib/loss_class.ts +129 -0
- package/src/scripts/_lib/machine_wake.ts +51 -0
- package/src/scripts/_lib/md_prose_lines.ts +177 -0
- package/src/scripts/_lib/minimality_tiebreak.ts +168 -0
- package/src/scripts/_lib/one_resolver_invariant.ts +449 -0
- package/src/scripts/_lib/orchestration_record.ts +253 -5
- package/src/scripts/_lib/outcome_envelope.ts +227 -0
- package/src/scripts/_lib/outcome_vocabularies.ts +125 -0
- package/src/scripts/_lib/paired_stats.ts +245 -0
- package/src/scripts/_lib/paired_verdict.ts +226 -0
- package/src/scripts/_lib/pathology_archive.ts +393 -0
- package/src/scripts/_lib/prefix_stable_surfaces.ts +123 -0
- package/src/scripts/_lib/privacy_class.ts +47 -0
- package/src/scripts/_lib/promotion_capability.ts +315 -0
- package/src/scripts/_lib/promotion_evidence.ts +414 -0
- package/src/scripts/_lib/promotion_review.ts +294 -0
- package/src/scripts/_lib/prompt_shape.ts +92 -0
- package/src/scripts/_lib/regression_neighbourhood.ts +259 -0
- package/src/scripts/_lib/release_highlights.ts +70 -1
- package/src/scripts/_lib/release_material.ts +125 -2
- package/src/scripts/_lib/repeated_failure.ts +105 -0
- package/src/scripts/_lib/repo_root.ts +111 -0
- package/src/scripts/_lib/review_skipped_record.ts +37 -0
- package/src/scripts/_lib/role_split.ts +338 -0
- package/src/scripts/_lib/routing_corpus.ts +307 -0
- package/src/scripts/_lib/routing_index_input.ts +104 -0
- package/src/scripts/_lib/rule_injection.ts +22 -1
- package/src/scripts/_lib/runtime_journal.ts +1499 -0
- package/src/scripts/_lib/runtime_wiring_checks.ts +430 -0
- package/src/scripts/_lib/semantic_noop.ts +167 -0
- package/src/scripts/_lib/skill_catalogue.ts +11 -1
- package/src/scripts/_lib/source_digest.ts +200 -0
- package/src/scripts/_lib/source_redact.ts +260 -0
- package/src/scripts/_lib/source_shape.ts +502 -0
- package/src/scripts/_lib/source_snapshot_dedup.ts +199 -0
- package/src/scripts/_lib/strip_comments.d.mts +8 -0
- package/src/scripts/_lib/strip_comments.mjs +65 -0
- package/src/scripts/_lib/test_red_state.ts +154 -0
- package/src/scripts/_lib/trigger_shift.ts +144 -0
- package/src/scripts/_lib/untrusted_content.ts +82 -7
- package/src/scripts/activation_receipt.ts +258 -0
- package/src/scripts/adoption_report.ts +1 -1
- package/src/scripts/adr/evidence_census.ts +1 -1
- package/src/scripts/adr/regenerate_index.ts +26 -2
- package/src/scripts/adr_cite_check.ts +164 -1
- package/src/scripts/ai_council/blind_review.ts +11 -1
- package/src/scripts/ai_council/clients.ts +4 -0
- package/src/scripts/ai_council/config.ts +3 -0
- package/src/scripts/ai_council/consensus.ts +28 -8
- package/src/scripts/ai_council/consensus_round.ts +226 -0
- package/src/scripts/ai_council/cross_exam.ts +128 -0
- package/src/scripts/ai_council/disagreement_signal.ts +338 -0
- package/src/scripts/ai_council/explain_route.ts +157 -0
- package/src/scripts/ai_council/information_gain.ts +293 -0
- package/src/scripts/ai_council/inline_findings.ts +340 -0
- package/src/scripts/ai_council/judge_position_bias.ts +197 -0
- package/src/scripts/ai_council/leakage_corpus.ts +385 -0
- package/src/scripts/ai_council/leakage_patterns.ts +453 -0
- package/src/scripts/ai_council/minority_retention.ts +171 -0
- package/src/scripts/ai_council/orchestrator.ts +16 -203
- package/src/scripts/ai_council/orchestrator_results.ts +23 -3
- package/src/scripts/ai_council/pricing.ts +106 -0
- package/src/scripts/ai_council/prompts.ts +74 -7
- package/src/scripts/ai_council/provider_leakage_bench.ts +327 -0
- package/src/scripts/ai_council/py_format.ts +14 -3
- package/src/scripts/ai_council/recouncil_guard.ts +293 -0
- package/src/scripts/ai_council/recouncil_savings.ts +299 -0
- package/src/scripts/ai_council/replay_route.ts +223 -0
- package/src/scripts/ai_council/response_record.ts +50 -0
- package/src/scripts/ai_council/reviewer_assignment.ts +279 -0
- package/src/scripts/ai_council/routing_training_row.ts +197 -0
- package/src/scripts/ai_council/synthesis_strategy.ts +159 -0
- package/src/scripts/ai_council/topology_bench_manifest.ts +860 -0
- package/src/scripts/ai_council/topology_vocabulary.ts +175 -0
- package/src/scripts/asset_delivery_ledger.ts +157 -0
- package/src/scripts/attest_artifact.ts +193 -0
- package/src/scripts/audit_auto_rules.ts +2 -1
- package/src/scripts/audit_command_surface.ts +1 -1
- package/src/scripts/audit_mcp_tools.ts +2 -2
- package/src/scripts/audit_skill_overlap_allowlist.json +6 -1
- package/src/scripts/audit_user_type_axis.ts +2 -1
- package/src/scripts/bench_ab_clone.ts +215 -10
- package/src/scripts/bench_ab_integrity.ts +119 -5
- package/src/scripts/bench_ab_v2_stats.ts +40 -213
- package/src/scripts/build_archive_index.ts +1 -1
- package/src/scripts/build_linear_digest.ts +1 -1
- package/src/scripts/build_proof.ts +11 -4
- package/src/scripts/build_rule_trigger_matrix.ts +1 -1
- package/src/scripts/build_source_digests.ts +157 -0
- package/src/scripts/cache_realization_report.ts +103 -0
- package/src/scripts/check_adr_frontmatter.ts +131 -10
- package/src/scripts/check_benchmark_report_fields.ts +207 -0
- package/src/scripts/check_beta_review_markers.ts +235 -6
- package/src/scripts/check_bundle_path_leakage.ts +34 -1
- package/src/scripts/check_claims.ts +576 -6
- package/src/scripts/check_composite_arming.ts +35 -0
- package/src/scripts/check_concern_admissions.ts +365 -0
- package/src/scripts/check_enforcement_coverage.ts +28 -0
- package/src/scripts/check_estate_count.ts +347 -25
- package/src/scripts/check_gate_reachability.ts +383 -0
- package/src/scripts/check_host_loadability.ts +104 -0
- package/src/scripts/check_loss_class_declared.ts +308 -0
- package/src/scripts/check_md_language.ts +15 -98
- package/src/scripts/check_memory_proposal.ts +18 -11
- package/src/scripts/check_no_currency_in_cost_surfaces.ts +225 -0
- package/src/scripts/check_no_external_sources.ts +281 -6
- package/src/scripts/check_pack_conformance_fixture.ts +11 -1
- package/src/scripts/check_pack_size.ts +59 -2
- package/src/scripts/check_preamble_payload_budget.ts +114 -3
- package/src/scripts/check_prefix_stable_mutation.ts +372 -0
- package/src/scripts/check_publish_surface.ts +10 -1
- package/src/scripts/check_references.ts +24 -1
- package/src/scripts/check_release_highlights.ts +96 -13
- package/src/scripts/check_roadmap_trackable.ts +17 -2
- package/src/scripts/check_rule_evidence_declaration.ts +316 -0
- package/src/scripts/check_rule_projection_integrity.ts +14 -4
- package/src/scripts/check_score_contract.ts +26 -3
- package/src/scripts/check_static_parity.ts +285 -0
- package/src/scripts/check_supervision_claim_atomicity.ts +498 -0
- package/src/scripts/check_suppression_hygiene.ts +15 -0
- package/src/scripts/ci_settle.ts +39 -2
- package/src/scripts/code_graph/build.ts +60 -3
- package/src/scripts/code_graph/extract.ts +44 -0
- package/src/scripts/code_graph/types.ts +24 -0
- package/src/scripts/collector_daemon.ts +714 -0
- package/src/scripts/config_cost_report.ts +302 -0
- package/src/scripts/consumer_matrix.ts +74 -1
- package/src/scripts/corpus_manifest.ts +235 -0
- package/src/scripts/cost/budget.mjs +10 -3
- package/src/scripts/cost/track.mjs +10 -3
- package/src/scripts/council_cli.ts +37 -54
- package/src/scripts/dispatch_r2_reviewer.ts +46 -5
- package/src/scripts/evolution_lab.ts +1153 -0
- package/src/scripts/external_sources_denylist.json +5 -18
- package/src/scripts/extract_audit_patterns.ts +21 -0
- package/src/scripts/fold_intake.ts +12 -1
- package/src/scripts/gen_discovery_baseline.ts +1 -1
- package/src/scripts/generate_capabilities_index.ts +12 -5
- package/src/scripts/generate_capability_matrix.ts +3 -3
- package/src/scripts/generate_command_flows.ts +2 -2
- package/src/scripts/generate_cookbook.ts +2 -2
- package/src/scripts/generate_index.ts +8 -1
- package/src/scripts/generate_knowledge_index.ts +2 -1
- package/src/scripts/generate_ownership_matrix.ts +2 -1
- package/src/scripts/generate_pack_manifests.ts +10 -2
- package/src/scripts/generate_role_experiences_catalog.ts +2 -2
- package/src/scripts/generate_settings_reference.ts +1 -1
- package/src/scripts/git_authorization_hook.ts +22 -1
- package/src/scripts/grade_target_readiness.ts +48 -5
- package/src/scripts/hook_effect_doctor.ts +261 -0
- package/src/scripts/hook_manifest.json +1 -1
- package/src/scripts/hook_manifest.yaml +125 -16
- package/src/scripts/hooks/block_speaking_inbox_dir.ts +271 -0
- package/src/scripts/hooks/block_unauthorized_git.ts +18 -0
- package/src/scripts/hooks/comment_discipline_hook.ts +146 -0
- package/src/scripts/hooks/concern_registry.ts +6 -0
- package/src/scripts/hooks/dispatch_hook.ts +32 -0
- package/src/scripts/hooks/journal_record_hook.ts +345 -0
- package/src/scripts/hooks/prepush_metadata_sources.sh +110 -0
- package/src/scripts/hooks/run_continuation_hook.ts +44 -9
- package/src/scripts/hooks/shims/install.sh +61 -0
- package/src/scripts/hooks/shims/php +101 -0
- package/src/scripts/hooks/suggestion_capture_hook.ts +10 -0
- package/src/scripts/hooks/turn_end_gate_hook.ts +9 -1
- package/src/scripts/hot_context_hook.ts +16 -0
- package/src/scripts/install-hooks.sh +20 -5
- package/src/scripts/install.ts +17 -35
- package/src/scripts/inventory_frontmatter.ts +2 -1
- package/src/scripts/language_mirror_hook.ts +14 -2
- package/src/scripts/lint_adr_sweep_routing.ts +12 -0
- package/src/scripts/lint_canonical_terms.ts +604 -0
- package/src/scripts/lint_carrier_integrity.ts +820 -0
- package/src/scripts/lint_code_comments.ts +643 -0
- package/src/scripts/lint_composition_review.ts +619 -0
- package/src/scripts/lint_consolidation_lineage.ts +666 -0
- package/src/scripts/lint_eval_specs.ts +593 -0
- package/src/scripts/lint_hook_manifest.ts +19 -0
- package/src/scripts/lint_host_portability.ts +373 -0
- package/src/scripts/lint_judge_prompt_expectation.ts +27 -1
- package/src/scripts/lint_memory_twin_parity.ts +335 -0
- package/src/scripts/lint_metric_consumers.ts +355 -0
- package/src/scripts/lint_plan_risk_register.ts +39 -19
- package/src/scripts/lint_promotion_paths.ts +779 -0
- package/src/scripts/lint_skill_descriptions.ts +18 -1
- package/src/scripts/lint_skill_frontmatter_safety.ts +58 -0
- package/src/scripts/lint_skill_link_reach.ts +252 -0
- package/src/scripts/lint_skill_trigger_corpus.ts +426 -23
- package/src/scripts/lint_ticket_buildable.ts +17 -1
- package/src/scripts/llm_propose.ts +256 -0
- package/src/scripts/mcp_server/consumer_tool_catalog.json +1 -1
- package/src/scripts/mcp_server/tool_catalog_source.ts +1 -1
- package/src/scripts/measure_delivery_sets.ts +361 -0
- package/src/scripts/measure_docs_dead_links.ts +348 -0
- package/src/scripts/measure_host_capture.ts +461 -0
- package/src/scripts/measure_routing_signal.ts +307 -0
- package/src/scripts/migration_status.ts +3 -3
- package/src/scripts/model_rule_injection.ts +76 -0
- package/src/scripts/orchestration_record.ts +14 -0
- package/src/scripts/preamble_byte_census.ts +139 -10
- package/src/scripts/prepack-check.mjs +4 -1
- package/src/scripts/probe_council_retention.ts +495 -0
- package/src/scripts/probe_turnaround.ts +384 -0
- package/src/scripts/probe_unblocked_ask.ts +279 -0
- package/src/scripts/release.ts +21 -37
- package/src/scripts/release_drill.ts +143 -0
- package/src/scripts/release_env.ts +35 -0
- package/src/scripts/release_publication.ts +84 -0
- package/src/scripts/render_benchmark_md.ts +1 -1
- package/src/scripts/rule_activation_census.ts +70 -9
- package/src/scripts/rule_backlinks.ts +1 -1
- package/src/scripts/run_lifecycle_suite.ts +208 -0
- package/src/scripts/run_skill_evals.ts +40 -0
- package/src/scripts/schemas/delivery-manifest.schema.json +43 -0
- package/src/scripts/schemas/drafting-channels.schema.json +43 -0
- package/src/scripts/schemas/evals.schema.json +24 -1
- package/src/scripts/schemas/rule.schema.json +52 -1
- package/src/scripts/schemas/skill.schema.json +17 -2
- package/src/scripts/skill_overlap.ts +7 -1
- package/src/scripts/skill_tools/run_block_d_eval.ts +8 -1
- package/src/scripts/skill_tools/score_skill_relevance.ts +84 -3
- package/src/scripts/skill_tools/suggest_skill_for_task.ts +8 -1
- package/src/scripts/skill_usage_report.ts +2 -1
- package/src/scripts/stubs_due.ts +211 -0
- package/src/scripts/sweep_source_surfaces.ts +678 -0
- package/src/scripts/sync_pr_branch.ts +3 -3
- package/src/scripts/trigger_eval_grandfather.json +202 -222
- package/src/scripts/utilization_report.ts +22 -2
- package/src/server/schemas/settings.ts +5 -0
- package/src/templates/marketing-copy.yml +1 -1
- package/dist/ui/assets/index-Cxgy63kz.js +0 -26
|
@@ -36,6 +36,15 @@ import * as path from 'node:path';
|
|
|
36
36
|
import process from 'node:process';
|
|
37
37
|
import { fileURLToPath, pathToFileURL } from 'node:url';
|
|
38
38
|
|
|
39
|
+
// `mcnemar_exact` and `cohens_h` live in `_lib/paired_stats.ts` and are
|
|
40
|
+
// re-exported here, so every existing importer of this module is unchanged.
|
|
41
|
+
// Extracted rather than left in place: this file sits above the 1500-line
|
|
42
|
+
// ceiling `check_source_size_budget` charges, so lines added to it are paid
|
|
43
|
+
// back by extraction rather than by raising a baseline.
|
|
44
|
+
import { cohens_h, mcnemar_exact, _pyRound, _pyRoundNoArg, wilcoxon } from './_lib/paired_stats.js';
|
|
45
|
+
|
|
46
|
+
export { cohens_h, mcnemar_exact, wilcoxon };
|
|
47
|
+
|
|
39
48
|
import { cost_usd, tier_for_model, type TierRates } from './_lib/bench_ab_activation.js';
|
|
40
49
|
import { load_pricing } from './_lib/bench_cost.js';
|
|
41
50
|
|
|
@@ -80,180 +89,10 @@ const COMPARISONS: Array<[string, string, string]> = [
|
|
|
80
89
|
|
|
81
90
|
// ── CPython math.erf / math.comb ports ────────────────────────────────────
|
|
82
91
|
//
|
|
83
|
-
//
|
|
84
|
-
//
|
|
85
|
-
//
|
|
86
|
-
|
|
87
|
-
const _ERF_SERIES_CUTOFF = 1.5;
|
|
88
|
-
const _ERF_SERIES_TERMS = 25;
|
|
89
|
-
const _ERFC_CONTFRAC_CUTOFF = 30.0;
|
|
90
|
-
const _ERFC_CONTFRAC_TERMS = 50;
|
|
91
|
-
const _SQRTPI = 1.772453850905516027298167483341145182798;
|
|
92
|
-
|
|
93
|
-
function _m_erf_series(x: number): number {
|
|
94
|
-
// erf(x) = 2/sqrt(pi) * x * sum_{k>=0} (-x^2)^k / (k! (2k+1))
|
|
95
|
-
let x2 = x * x;
|
|
96
|
-
let acc = 0.0;
|
|
97
|
-
let fk = _ERF_SERIES_TERMS + 0.5;
|
|
98
|
-
for (let i = 0; i < _ERF_SERIES_TERMS; i += 1) {
|
|
99
|
-
acc = 2.0 + (x2 * acc) / fk;
|
|
100
|
-
fk -= 1.0;
|
|
101
|
-
}
|
|
102
|
-
return (acc * x * Math.exp(-x2)) / _SQRTPI;
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
function _m_erfc_contfrac(x: number): number {
|
|
106
|
-
if (x >= _ERFC_CONTFRAC_CUTOFF) {
|
|
107
|
-
return 0.0;
|
|
108
|
-
}
|
|
109
|
-
const x2 = x * x;
|
|
110
|
-
let a = 0.0;
|
|
111
|
-
let da = 0.5;
|
|
112
|
-
let p = 1.0;
|
|
113
|
-
let p_last = 0.0;
|
|
114
|
-
let q = da + x2;
|
|
115
|
-
let q_last = 1.0;
|
|
116
|
-
for (let i = 0; i < _ERFC_CONTFRAC_TERMS; i += 1) {
|
|
117
|
-
a += da;
|
|
118
|
-
da += 2.0;
|
|
119
|
-
const b = da + x2;
|
|
120
|
-
const temp_p = b * p - a * p_last;
|
|
121
|
-
p_last = p;
|
|
122
|
-
p = temp_p;
|
|
123
|
-
const temp_q = b * q - a * q_last;
|
|
124
|
-
q_last = q;
|
|
125
|
-
q = temp_q;
|
|
126
|
-
}
|
|
127
|
-
return (((p / q) * x) * Math.exp(-x2)) / _SQRTPI;
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
function _erf(x: number): number {
|
|
131
|
-
if (Number.isNaN(x)) {
|
|
132
|
-
return x;
|
|
133
|
-
}
|
|
134
|
-
const absx = Math.abs(x);
|
|
135
|
-
if (absx < _ERF_SERIES_CUTOFF) {
|
|
136
|
-
return _m_erf_series(x);
|
|
137
|
-
}
|
|
138
|
-
const cf = _m_erfc_contfrac(absx);
|
|
139
|
-
return x > 0.0 ? 1.0 - cf : cf - 1.0;
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
/** Python `math.comb(n, k)` — exact non-negative integer (BigInt → Number). */
|
|
143
|
-
function _comb(n: number, k: number): number {
|
|
144
|
-
if (k < 0 || k > n) {
|
|
145
|
-
return 0;
|
|
146
|
-
}
|
|
147
|
-
let kk = BigInt(Math.min(k, n - k));
|
|
148
|
-
if (kk === 0n) {
|
|
149
|
-
return 1;
|
|
150
|
-
}
|
|
151
|
-
const N = BigInt(n);
|
|
152
|
-
let result = 1n;
|
|
153
|
-
let i = 0n;
|
|
154
|
-
while (i < kk) {
|
|
155
|
-
result = (result * (N - i)) / (i + 1n);
|
|
156
|
-
i += 1n;
|
|
157
|
-
}
|
|
158
|
-
return Number(result);
|
|
159
|
-
}
|
|
92
|
+
// The erf/normal-CDF port and `wilcoxon` live in `_lib/paired_stats.ts`,
|
|
93
|
+
// re-exported above. Same reason as the two functions beside them: this file
|
|
94
|
+
// is over the 1500-line ceiling, so additions are paid back by extraction.
|
|
160
95
|
|
|
161
|
-
function _phi(z: number): number {
|
|
162
|
-
// Standard-normal CDF via erf.
|
|
163
|
-
return 0.5 * (1.0 + _erf(z / Math.sqrt(2.0)));
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
export function mcnemar_exact(b: number, c: number): number {
|
|
167
|
-
// Two-sided exact McNemar p-value (binomial on discordant pairs).
|
|
168
|
-
const n = b + c;
|
|
169
|
-
if (n === 0) {
|
|
170
|
-
return 1.0;
|
|
171
|
-
}
|
|
172
|
-
const k = Math.min(b, c);
|
|
173
|
-
let tail = 0;
|
|
174
|
-
for (let i = 0; i <= k; i += 1) {
|
|
175
|
-
tail += _comb(n, i);
|
|
176
|
-
}
|
|
177
|
-
tail = tail * 0.5 ** n;
|
|
178
|
-
return Math.min(1.0, 2.0 * tail);
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
export function cohens_h(p1: number, p2: number): number {
|
|
182
|
-
return (
|
|
183
|
-
2 * Math.asin(Math.sqrt(Math.max(0, Math.min(1, p1)))) -
|
|
184
|
-
2 * Math.asin(Math.sqrt(Math.max(0, Math.min(1, p2))))
|
|
185
|
-
);
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
interface WilcoxonResult {
|
|
189
|
-
n: number;
|
|
190
|
-
W_plus: number; // PyFloat-flagged at dump for the rounded case
|
|
191
|
-
W_minus: number;
|
|
192
|
-
p: number;
|
|
193
|
-
rank_biserial: number;
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
export function wilcoxon(diffs: number[]): WilcoxonResult {
|
|
197
|
-
// Wilcoxon signed-rank on paired differences (treatment - baseline).
|
|
198
|
-
// Returns W+, W-, normal-approx two-sided p (continuity-corrected), and
|
|
199
|
-
// rank-biserial effect size. Zeros are dropped.
|
|
200
|
-
const nz = diffs.filter((d) => Math.abs(d) > 1e-9);
|
|
201
|
-
const n = nz.length;
|
|
202
|
-
if (n === 0) {
|
|
203
|
-
return { n: 0, W_plus: 0, W_minus: 0, p: 1.0, rank_biserial: 0.0 };
|
|
204
|
-
}
|
|
205
|
-
// order = sorted(range(n), key=lambda i: abs(nz[i])) — stable sort.
|
|
206
|
-
const order = Array.from({ length: n }, (_, i) => i).sort((x, y) => {
|
|
207
|
-
const ax = Math.abs(nz[x] as number);
|
|
208
|
-
const ay = Math.abs(nz[y] as number);
|
|
209
|
-
return ax < ay ? -1 : ax > ay ? 1 : x - y; // stable on tie
|
|
210
|
-
});
|
|
211
|
-
const ranks: number[] = new Array(n).fill(0.0);
|
|
212
|
-
let i = 0;
|
|
213
|
-
while (i < n) {
|
|
214
|
-
let j = i;
|
|
215
|
-
while (j + 1 < n && Math.abs(nz[order[j + 1] as number] as number) === Math.abs(nz[order[i] as number] as number)) {
|
|
216
|
-
j += 1;
|
|
217
|
-
}
|
|
218
|
-
const avg = (i + 1 + j + 1) / 2.0; // average rank for ties (1-based)
|
|
219
|
-
for (let k = i; k <= j; k += 1) {
|
|
220
|
-
ranks[order[k] as number] = avg;
|
|
221
|
-
}
|
|
222
|
-
i = j + 1;
|
|
223
|
-
}
|
|
224
|
-
let w_plus = 0.0;
|
|
225
|
-
let w_minus = 0.0;
|
|
226
|
-
for (let idx = 0; idx < n; idx += 1) {
|
|
227
|
-
if ((nz[idx] as number) > 0) {
|
|
228
|
-
w_plus += ranks[idx] as number;
|
|
229
|
-
} else if ((nz[idx] as number) < 0) {
|
|
230
|
-
w_minus += ranks[idx] as number;
|
|
231
|
-
}
|
|
232
|
-
}
|
|
233
|
-
const total = w_plus + w_minus;
|
|
234
|
-
const rb = total ? (w_plus - w_minus) / total : 0.0;
|
|
235
|
-
// Normal approximation (ok-ish for n>=10; for small n it's conservative —
|
|
236
|
-
// we surface n so the reader can weight it).
|
|
237
|
-
const mean = (n * (n + 1)) / 4.0;
|
|
238
|
-
const sd = Math.sqrt((n * (n + 1) * (2 * n + 1)) / 24.0);
|
|
239
|
-
const w = Math.min(w_plus, w_minus);
|
|
240
|
-
let p: number;
|
|
241
|
-
if (sd === 0) {
|
|
242
|
-
p = 1.0;
|
|
243
|
-
} else {
|
|
244
|
-
const z = (w - mean + 0.5) / sd;
|
|
245
|
-
p = Math.min(1.0, 2.0 * _phi(z));
|
|
246
|
-
}
|
|
247
|
-
return {
|
|
248
|
-
n,
|
|
249
|
-
// W_plus / W_minus are not surfaced in JSON/markdown (compare() drops
|
|
250
|
-
// them), so plain numbers suffice; p / rank_biserial are floats.
|
|
251
|
-
W_plus: _pyRound(w_plus, 1),
|
|
252
|
-
W_minus: _pyRound(w_minus, 1),
|
|
253
|
-
p: _pyRound(p, 4),
|
|
254
|
-
rank_biserial: _pyRound(rb, 4),
|
|
255
|
-
};
|
|
256
|
-
}
|
|
257
96
|
|
|
258
97
|
/** Wrap a `round(...)`/float result so it renders `1.0` not `1` (Python float). */
|
|
259
98
|
function PF(x: number): PyFloat {
|
|
@@ -478,6 +317,14 @@ function _paired_median_block(t: number[], b: number[], diffs: number[]): Dict {
|
|
|
478
317
|
// Percent change of the medians. A zero baseline has no percent change —
|
|
479
318
|
// report null rather than Infinity, which would render as a win.
|
|
480
319
|
const pct = mb === 0 ? null : PF(_pyRound(((mt - mb) / Math.abs(mb)) * 100, 4));
|
|
320
|
+
// Direction counts, ADDITIVE (Phase-3 PREREG amendment v2, 2026-08-26).
|
|
321
|
+
// The significance half of the size verdict now reads these rather than
|
|
322
|
+
// `wilcoxon_p`; every pre-existing key is untouched, so a consumer reading
|
|
323
|
+
// named keys is unaffected. Tie epsilon matches `wilcoxon`'s own 1e-9 zero
|
|
324
|
+
// drop, so "non-tied" means the same thing to both tests — two definitions
|
|
325
|
+
// of a tie in one report is how the numbers start disagreeing.
|
|
326
|
+
const wins = diffs.filter((d) => d < -1e-9).length;
|
|
327
|
+
const losses = diffs.filter((d) => d > 1e-9).length;
|
|
481
328
|
return {
|
|
482
329
|
measured: true,
|
|
483
330
|
n_pairs: diffs.length,
|
|
@@ -488,6 +335,13 @@ function _paired_median_block(t: number[], b: number[], diffs: number[]): Dict {
|
|
|
488
335
|
wilcoxon_p: PF(wil.p),
|
|
489
336
|
rank_biserial: PF(wil.rank_biserial),
|
|
490
337
|
n_nonzero: wil.n,
|
|
338
|
+
// "Win" is DIRECTION-OF-INTEREST, not sign: for added lines and for
|
|
339
|
+
// cognitive complexity a NEGATIVE delta is the improvement. Naming them
|
|
340
|
+
// wins/losses here rather than positive/negative keeps the verdict from
|
|
341
|
+
// having to know which endpoint it is looking at.
|
|
342
|
+
direction_wins: wins,
|
|
343
|
+
direction_losses: losses,
|
|
344
|
+
direction_ties: diffs.length - wins - losses,
|
|
491
345
|
};
|
|
492
346
|
}
|
|
493
347
|
|
|
@@ -733,6 +587,15 @@ function _toContinuous(block: Dict): PairedContinuous {
|
|
|
733
587
|
median_delta_pct: block['median_delta_pct'] == null ? null : _pyFloat(block['median_delta_pct']),
|
|
734
588
|
median_delta: _pyFloat(block['median_delta']),
|
|
735
589
|
wilcoxon_p: _pyFloat(block['wilcoxon_p']),
|
|
590
|
+
// Optional-absent rather than defaulted to 0: an older report carries
|
|
591
|
+
// no direction counts, and zeroing them would read as "no trial went
|
|
592
|
+
// either way", which is a measurement rather than a missing field.
|
|
593
|
+
...(block['direction_wins'] === undefined
|
|
594
|
+
? {}
|
|
595
|
+
: {
|
|
596
|
+
direction_wins: _pyFloat(block['direction_wins']),
|
|
597
|
+
direction_losses: _pyFloat(block['direction_losses']),
|
|
598
|
+
}),
|
|
736
599
|
};
|
|
737
600
|
}
|
|
738
601
|
|
|
@@ -813,7 +676,7 @@ export function to_markdown(analysis: Dict, payload: Dict): string {
|
|
|
813
676
|
L.push('# Discipline-Axis Wrapper-Lift Benchmark (v2)');
|
|
814
677
|
L.push('');
|
|
815
678
|
L.push(
|
|
816
|
-
'> Generated by `
|
|
679
|
+
'> Generated by `bench_ab_v2_stats --markdown`. Do not edit. Source: ' +
|
|
817
680
|
'`internal/bench/reports/ab-v2/`. Re-render with `task bench:ab:v2:diff`.',
|
|
818
681
|
);
|
|
819
682
|
L.push('');
|
|
@@ -1366,46 +1229,10 @@ function _pyStr(v: unknown): string {
|
|
|
1366
1229
|
return String(v);
|
|
1367
1230
|
}
|
|
1368
1231
|
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
const floor = Math.floor(x);
|
|
1373
|
-
const frac = x - floor;
|
|
1374
|
-
if (frac < 0.5) return floor;
|
|
1375
|
-
if (frac > 0.5) return floor + 1;
|
|
1376
|
-
return floor % 2 === 0 ? floor : floor + 1;
|
|
1377
|
-
}
|
|
1232
|
+
// `_pyRound` / `_pyRoundNoArg` live in `_lib/paired_stats.ts` (imported above):
|
|
1233
|
+
// `wilcoxon` needs them and moved there, and two copies of a float-parity
|
|
1234
|
+
// rounder is how byte-stable output stops being byte-stable.
|
|
1378
1235
|
|
|
1379
|
-
/** Python `round(x, ndigits)` — round-half-to-even on the exact double. */
|
|
1380
|
-
function _pyRound(value: number, ndigits: number): number {
|
|
1381
|
-
if (!Number.isFinite(value) || value === 0) {
|
|
1382
|
-
return value;
|
|
1383
|
-
}
|
|
1384
|
-
const neg = value < 0;
|
|
1385
|
-
const abs = Math.abs(value);
|
|
1386
|
-
const exact = abs.toFixed(40);
|
|
1387
|
-
const dot = exact.indexOf('.');
|
|
1388
|
-
const intPart = dot === -1 ? exact : exact.slice(0, dot);
|
|
1389
|
-
const fracPart = dot === -1 ? '' : exact.slice(dot + 1);
|
|
1390
|
-
const keepFrac = fracPart.slice(0, ndigits).padEnd(ndigits, '0');
|
|
1391
|
-
const rest = fracPart.slice(ndigits);
|
|
1392
|
-
const scaledStr = (intPart + keepFrac).replace(/^0+(?=\d)/, '');
|
|
1393
|
-
let scaled = BigInt(scaledStr === '' ? '0' : scaledStr);
|
|
1394
|
-
if (rest.length > 0) {
|
|
1395
|
-
const firstRest = rest.charCodeAt(0) - 48;
|
|
1396
|
-
const hasMore = /[1-9]/.test(rest.slice(1));
|
|
1397
|
-
if (firstRest > 5 || (firstRest === 5 && hasMore)) {
|
|
1398
|
-
scaled += 1n;
|
|
1399
|
-
} else if (firstRest === 5 && !hasMore) {
|
|
1400
|
-
if (scaled % 2n === 1n) {
|
|
1401
|
-
scaled += 1n;
|
|
1402
|
-
}
|
|
1403
|
-
}
|
|
1404
|
-
}
|
|
1405
|
-
const factor = 10 ** ndigits;
|
|
1406
|
-
const result = Number(scaled) / factor;
|
|
1407
|
-
return neg ? -result : result;
|
|
1408
|
-
}
|
|
1409
1236
|
|
|
1410
1237
|
/** `format(x, '.Nf')` — round-half-even on the exact double, fixed N decimals. */
|
|
1411
1238
|
function _pyFixed(x: number, ndigits: number): string {
|
|
@@ -249,7 +249,7 @@ export function renderJson(entries: readonly ArchiveEntry[]): string {
|
|
|
249
249
|
return (
|
|
250
250
|
JSON.stringify(
|
|
251
251
|
{
|
|
252
|
-
generated_by: '
|
|
252
|
+
generated_by: 'build_archive_index',
|
|
253
253
|
source: ARCHIVE_REL,
|
|
254
254
|
count: entries.length,
|
|
255
255
|
entries,
|
|
@@ -171,7 +171,7 @@ export function render_digest(layer: string, entries: RuleEntry[]): [string, Dig
|
|
|
171
171
|
const parts: string[] = [];
|
|
172
172
|
parts.push(`# event4u/agent-config — Linear AI ${_title(layer)} Digest\n`);
|
|
173
173
|
parts.push(
|
|
174
|
-
'>
|
|
174
|
+
'> Generated by `build_linear_digest`. Do not edit. From ' +
|
|
175
175
|
'`dist/agent-src/rules/` (condensed source) plus the inclusion list ' +
|
|
176
176
|
'at `docs/contracts/linear-ai-rules-inclusion.md`. Do not edit ' +
|
|
177
177
|
'this file by hand — re-run `task build-linear-digest` to ' +
|
|
@@ -157,7 +157,7 @@ function render(): string {
|
|
|
157
157
|
const resolvedNull = entries.filter((e) => e.status === 'resolved-null');
|
|
158
158
|
|
|
159
159
|
const L: string[] = [];
|
|
160
|
-
L.push('<!-- GENERATED by
|
|
160
|
+
L.push('<!-- GENERATED by build_proof — do NOT hand-edit.');
|
|
161
161
|
L.push(' Drift-checked in CI (`task build-proof-check`). Regenerate with');
|
|
162
162
|
L.push(' `./scripts-run src/scripts/build_proof` after editing docs/CLAIMS.md. -->');
|
|
163
163
|
L.push('');
|
|
@@ -449,11 +449,18 @@ function render(): string {
|
|
|
449
449
|
`${nulls} resolved-null.`,
|
|
450
450
|
);
|
|
451
451
|
L.push('');
|
|
452
|
-
|
|
453
|
-
|
|
452
|
+
// `Measured on` exists because a status alone cannot say that a real
|
|
453
|
+
// measurement describes a build that no longer exists — and an AI
|
|
454
|
+
// council (2026-08-26, 2/2) required the binding to reach every index,
|
|
455
|
+
// not only the detailed entry, since a prose-only qualification drifts
|
|
456
|
+
// from the structured record it qualifies. Empty for every claim that
|
|
457
|
+
// describes the current tree, which is almost all of them.
|
|
458
|
+
L.push('| Claim id | Kind | Status | Measured on | Evidence pointer |');
|
|
459
|
+
L.push('|---|---|---|---|---|');
|
|
454
460
|
for (const e of ledger) {
|
|
455
461
|
const ev = e.evidence.length > 0 ? `\`${e.evidence.replace(/\|/g, '\\|')}\`` : '—';
|
|
456
|
-
|
|
462
|
+
const on = e.measured_on.length > 0 ? e.measured_on.replace(/\|/g, '\\|') : '—';
|
|
463
|
+
L.push(`| \`${e.id}\` | ${e.kind} | ${e.status} | ${on} | ${ev} |`);
|
|
457
464
|
}
|
|
458
465
|
}
|
|
459
466
|
L.push('');
|
|
@@ -340,7 +340,7 @@ function emit(): number {
|
|
|
340
340
|
lines.push('');
|
|
341
341
|
lines.push('**Source:** Phase 1 of `road-to-rule-hardening.md` (self-check audit) +');
|
|
342
342
|
lines.push('Phase 1 of `road-to-context-layer-maturity.md` (`load_context:` inventory).');
|
|
343
|
-
lines.push('**Generated by:** `
|
|
343
|
+
lines.push('**Generated by:** `build_rule_trigger_matrix` — re-run after rule');
|
|
344
344
|
lines.push("set changes. Manual classifications live in the script's `CLASSIFICATION`");
|
|
345
345
|
lines.push('table; size and context-chain columns are derived from the rule files.');
|
|
346
346
|
lines.push('');
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
#!/usr/bin/env tsx
|
|
2
|
+
/**
|
|
3
|
+
* build_source_digests — derive the tracked deny digests from the private
|
|
4
|
+
* master (`road-to-source-silence` Phase 1.1, resolution (c)).
|
|
5
|
+
*
|
|
6
|
+
* ## The shape the council chose
|
|
7
|
+
*
|
|
8
|
+
* Humans edit a readable list; the repository never sees it.
|
|
9
|
+
*
|
|
10
|
+
* src/scripts/external_sources_denylist.private.json ← gitignored MASTER
|
|
11
|
+
* │ { "deny": ["<readable pattern>", …] }
|
|
12
|
+
* ▼ build_source_digests (needs SOURCE_DENY_KEY)
|
|
13
|
+
* src/scripts/external_sources_denylist.json ← tracked, DERIVED
|
|
14
|
+
* { "deny_digests": ["<64 hex>", …] }
|
|
15
|
+
*
|
|
16
|
+
* "Plaintext in the tree" becomes structurally impossible rather than
|
|
17
|
+
* disciplined away: the tracked artefact is derivational, and the readable list
|
|
18
|
+
* exists in exactly one place, which is private.
|
|
19
|
+
*
|
|
20
|
+
* ## STATUS: this ships DORMANT and changes nothing by itself
|
|
21
|
+
*
|
|
22
|
+
* Running it is one quarter of the maintainer's atomic cutover. The other three
|
|
23
|
+
* quarters — provisioning the CI secret, deleting the tracked plaintext `deny`
|
|
24
|
+
* array, and switching CI to strict mode — are NOT in this change and must not
|
|
25
|
+
* be split from each other. `docs/maintainers/source-deny-digests.md` is the
|
|
26
|
+
* recipe. Until then `deny_digests` is empty, the plaintext gate stays in force,
|
|
27
|
+
* and the digest code path does nothing.
|
|
28
|
+
*
|
|
29
|
+
* Modes:
|
|
30
|
+
* (default) write digests into the tracked config from the private master
|
|
31
|
+
* --check verify the tracked digests match the master; exit 1 on drift
|
|
32
|
+
* --stdout print the digest array instead of writing (for inspection)
|
|
33
|
+
*
|
|
34
|
+
* Exit codes: 0 = done / in sync, 1 = drift (--check), 2 = usage or missing
|
|
35
|
+
* input, 3 = no key (`SOURCE_DENY_KEY` unset).
|
|
36
|
+
*/
|
|
37
|
+
|
|
38
|
+
import * as fs from 'node:fs';
|
|
39
|
+
import * as path from 'node:path';
|
|
40
|
+
import process from 'node:process';
|
|
41
|
+
import { fileURLToPath, pathToFileURL } from 'node:url';
|
|
42
|
+
|
|
43
|
+
import { digest, DIGEST_RE, EXIT_NO_KEY, KEY_ENV, normalise } from './_lib/source_digest.js';
|
|
44
|
+
|
|
45
|
+
const _HERE = fileURLToPath(import.meta.url);
|
|
46
|
+
const DIR = path.dirname(_HERE);
|
|
47
|
+
export const TRACKED_CONFIG = path.join(DIR, 'external_sources_denylist.json');
|
|
48
|
+
export const PRIVATE_MASTER = path.join(DIR, 'external_sources_denylist.private.json');
|
|
49
|
+
|
|
50
|
+
interface Master {
|
|
51
|
+
deny: string[];
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Digests for a master list, sorted and deduplicated.
|
|
56
|
+
*
|
|
57
|
+
* Sorted so the tracked artefact's diff shows an ADDITION as one line rather
|
|
58
|
+
* than a reshuffle, and so two maintainers with the same master produce the
|
|
59
|
+
* same file. Deduplicated because two spellings of one name fold to one digest
|
|
60
|
+
* — `normalise` is not injective and must not be assumed to be.
|
|
61
|
+
*/
|
|
62
|
+
export function digestsFor(deny: readonly string[], key: string): string[] {
|
|
63
|
+
const out = new Set<string>();
|
|
64
|
+
for (const raw of deny) {
|
|
65
|
+
const bare = normalise(raw.replace(/\\b/g, ''));
|
|
66
|
+
if (bare.length < 3) continue;
|
|
67
|
+
out.add(digest(bare, key));
|
|
68
|
+
}
|
|
69
|
+
return [...out].sort();
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
function readMaster(): Master {
|
|
73
|
+
const raw = fs.readFileSync(PRIVATE_MASTER, 'utf-8');
|
|
74
|
+
const parsed = JSON.parse(raw) as Partial<Master>;
|
|
75
|
+
if (!Array.isArray(parsed.deny) || parsed.deny.length === 0) {
|
|
76
|
+
throw new Error('private master has no non-empty `deny` array');
|
|
77
|
+
}
|
|
78
|
+
return { deny: parsed.deny };
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
export function main(argv: readonly string[]): number {
|
|
82
|
+
const check = argv.includes('--check');
|
|
83
|
+
const toStdout = argv.includes('--stdout');
|
|
84
|
+
|
|
85
|
+
const key = process.env[KEY_ENV] ?? '';
|
|
86
|
+
if (key === '') {
|
|
87
|
+
process.stderr.write(
|
|
88
|
+
`❌ ${KEY_ENV} is unset. The digest construction is KEYED on purpose: the candidate\n` +
|
|
89
|
+
' space is public repository slugs, so an unsalted hash of a slug is a lookup,\n' +
|
|
90
|
+
' not a secret. Nothing is written without the key.\n',
|
|
91
|
+
);
|
|
92
|
+
return EXIT_NO_KEY;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
let master: Master;
|
|
96
|
+
try {
|
|
97
|
+
master = readMaster();
|
|
98
|
+
} catch (exc) {
|
|
99
|
+
process.stderr.write(
|
|
100
|
+
`❌ cannot read the private master at ${path.basename(PRIVATE_MASTER)}: ` +
|
|
101
|
+
`${(exc as Error).message}\n` +
|
|
102
|
+
' It is gitignored by design and must be created by the maintainer — see\n' +
|
|
103
|
+
' docs/maintainers/source-deny-digests.md.\n',
|
|
104
|
+
);
|
|
105
|
+
return 2;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
const digests = digestsFor(master.deny, key);
|
|
109
|
+
if (!digests.every((d) => DIGEST_RE.test(d))) {
|
|
110
|
+
process.stderr.write('❌ internal error: a produced digest is not 64 lowercase hex chars\n');
|
|
111
|
+
return 2;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
if (toStdout) {
|
|
115
|
+
process.stdout.write(JSON.stringify(digests, null, 2) + '\n');
|
|
116
|
+
return 0;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
const cfg = JSON.parse(fs.readFileSync(TRACKED_CONFIG, 'utf-8')) as Record<string, unknown>;
|
|
120
|
+
const current = Array.isArray(cfg.deny_digests) ? (cfg.deny_digests as string[]) : [];
|
|
121
|
+
|
|
122
|
+
if (check) {
|
|
123
|
+
const same = current.length === digests.length && current.every((d, i) => d === digests[i]);
|
|
124
|
+
if (same) {
|
|
125
|
+
process.stdout.write(`✅ ${String(digests.length)} deny digest(s) in sync with the private master.\n`);
|
|
126
|
+
return 0;
|
|
127
|
+
}
|
|
128
|
+
process.stderr.write(
|
|
129
|
+
`❌ deny_digests drift: tracked ${String(current.length)}, derived ${String(digests.length)}.\n` +
|
|
130
|
+
' Re-run without --check to regenerate.\n',
|
|
131
|
+
);
|
|
132
|
+
return 1;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
cfg.deny_digests = digests;
|
|
136
|
+
fs.writeFileSync(TRACKED_CONFIG, JSON.stringify(cfg, null, 2) + '\n', 'utf-8');
|
|
137
|
+
process.stdout.write(`✅ wrote ${String(digests.length)} deny digest(s) to ${path.basename(TRACKED_CONFIG)}.\n`);
|
|
138
|
+
process.stdout.write(
|
|
139
|
+
' This is ONE QUARTER of the cutover. The CI secret, the deletion of the plaintext\n' +
|
|
140
|
+
' deny array and the switch to strict mode ship in the SAME change or not at all.\n',
|
|
141
|
+
);
|
|
142
|
+
return 0;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
function _isCliEntry(): boolean {
|
|
146
|
+
if (process.argv[1] === undefined) return false;
|
|
147
|
+
if (import.meta.url === pathToFileURL(path.resolve(process.argv[1])).href) return true;
|
|
148
|
+
try {
|
|
149
|
+
return fs.realpathSync(fileURLToPath(import.meta.url)) === fs.realpathSync(path.resolve(process.argv[1]));
|
|
150
|
+
} catch {
|
|
151
|
+
return false;
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
if (_isCliEntry()) {
|
|
156
|
+
process.exit(main(process.argv.slice(2)));
|
|
157
|
+
}
|
|
@@ -36,6 +36,8 @@ import { homedir } from 'node:os';
|
|
|
36
36
|
import * as path from 'node:path';
|
|
37
37
|
import { fileURLToPath, pathToFileURL } from 'node:url';
|
|
38
38
|
|
|
39
|
+
import { buildReport as buildDriftReport } from './orchestration_payload_hash_drift.js';
|
|
40
|
+
import type { PayloadHashDriftReport } from './_lib/payload_hash_drift.js';
|
|
39
41
|
import {
|
|
40
42
|
aggregateByBucket,
|
|
41
43
|
billableInputTokens,
|
|
@@ -635,6 +637,7 @@ export interface Options {
|
|
|
635
637
|
councilRoot: string;
|
|
636
638
|
userRulesDir: string;
|
|
637
639
|
projectRulesDir: string;
|
|
640
|
+
auditDir: string;
|
|
638
641
|
}
|
|
639
642
|
|
|
640
643
|
function defaultOptions(): Options {
|
|
@@ -646,6 +649,7 @@ function defaultOptions(): Options {
|
|
|
646
649
|
councilRoot: REPO_ROOT,
|
|
647
650
|
userRulesDir: path.join(homedir(), '.claude', 'rules'),
|
|
648
651
|
projectRulesDir: path.join(REPO_ROOT, 'dist', 'agent-src', 'rules'),
|
|
652
|
+
auditDir: path.join(REPO_ROOT, 'agents', 'runtime', 'state', 'audit'),
|
|
649
653
|
};
|
|
650
654
|
}
|
|
651
655
|
|
|
@@ -668,11 +672,82 @@ export function parseArgs(argv: string[]): Options {
|
|
|
668
672
|
else if (a.startsWith('--user-rules-dir=')) opts.userRulesDir = a.slice('--user-rules-dir='.length);
|
|
669
673
|
else if (a === '--project-rules-dir') opts.projectRulesDir = argv[++i] ?? opts.projectRulesDir;
|
|
670
674
|
else if (a.startsWith('--project-rules-dir=')) opts.projectRulesDir = a.slice('--project-rules-dir='.length);
|
|
675
|
+
else if (a === '--audit-dir') opts.auditDir = argv[++i] ?? opts.auditDir;
|
|
676
|
+
else if (a.startsWith('--audit-dir=')) opts.auditDir = a.slice('--audit-dir='.length);
|
|
671
677
|
}
|
|
672
678
|
if (opts.format !== 'text' && opts.format !== 'json') opts.format = 'text';
|
|
673
679
|
return opts;
|
|
674
680
|
}
|
|
675
681
|
|
|
682
|
+
/**
|
|
683
|
+
* Prefix-stability verdict, carried in the cost report rather than left latent
|
|
684
|
+
* in a separate CLI (`road-to-runtime-context-floors` step 1.3).
|
|
685
|
+
*
|
|
686
|
+
* `_lib/payload_hash_drift` already splits dispatches into a STABLE cohort
|
|
687
|
+
* (repeat occurrences of one payload hash) and an UNSTABLE one (hashes seen
|
|
688
|
+
* once). Nothing read the split, so the one outcome that matters — a stable
|
|
689
|
+
* cohort whose cache-read share is BELOW its unstable cohort, which means the
|
|
690
|
+
* prefix is being rewritten between repeats — was measurable and unreported.
|
|
691
|
+
*
|
|
692
|
+
* `verdict` is deliberately three-valued. `insufficient-data` is not a number
|
|
693
|
+
* and must never be rendered as one: with either cohort empty there is no
|
|
694
|
+
* comparison to make, and printing `0.0%` for "nothing was measured" is the
|
|
695
|
+
* shape that turns a blind report into a believed one.
|
|
696
|
+
*/
|
|
697
|
+
export type PrefixStabilityVerdict = 'stable-higher' | 'inverted' | 'insufficient-data';
|
|
698
|
+
|
|
699
|
+
export interface PrefixStabilityResult {
|
|
700
|
+
verdict: PrefixStabilityVerdict;
|
|
701
|
+
/** Why, in one sentence — always populated, including for `insufficient-data`. */
|
|
702
|
+
reason: string;
|
|
703
|
+
stable_cohort: { n: number; read_share: number | null };
|
|
704
|
+
unstable_cohort: { n: number; read_share: number | null };
|
|
705
|
+
lines_with_data: number;
|
|
706
|
+
}
|
|
707
|
+
|
|
708
|
+
export function computePrefixStability(drift: PayloadHashDriftReport): PrefixStabilityResult {
|
|
709
|
+
const stable = { n: drift.stable_cohort.n, read_share: drift.stable_cohort.hit_rate };
|
|
710
|
+
const unstable = { n: drift.unstable_cohort.n, read_share: drift.unstable_cohort.hit_rate };
|
|
711
|
+
|
|
712
|
+
if (stable.read_share === null || unstable.read_share === null) {
|
|
713
|
+
const empty = [stable.read_share === null ? 'stable' : null, unstable.read_share === null ? 'unstable' : null]
|
|
714
|
+
.filter((x) => x !== null)
|
|
715
|
+
.join(' and ');
|
|
716
|
+
const plural = empty.includes(' and ') ? 'cohorts are' : 'cohort is';
|
|
717
|
+
return {
|
|
718
|
+
verdict: 'insufficient-data',
|
|
719
|
+
reason:
|
|
720
|
+
`the ${empty} ${plural} empty (${drift.lines_with_data} audit line(s) carry both ` +
|
|
721
|
+
'payload_hash and cache_hit) — no comparison exists, and a share is not reported for one',
|
|
722
|
+
stable_cohort: stable,
|
|
723
|
+
unstable_cohort: unstable,
|
|
724
|
+
lines_with_data: drift.lines_with_data,
|
|
725
|
+
};
|
|
726
|
+
}
|
|
727
|
+
if (stable.read_share < unstable.read_share) {
|
|
728
|
+
return {
|
|
729
|
+
verdict: 'inverted',
|
|
730
|
+
reason:
|
|
731
|
+
`repeat dispatches of the same payload shape hit the cache LESS often ` +
|
|
732
|
+
`(${(stable.read_share * 100).toFixed(1)}%) than one-off shapes ` +
|
|
733
|
+
`(${(unstable.read_share * 100).toFixed(1)}%) — a prefix-stable surface is being ` +
|
|
734
|
+
'rewritten between repeats',
|
|
735
|
+
stable_cohort: stable,
|
|
736
|
+
unstable_cohort: unstable,
|
|
737
|
+
lines_with_data: drift.lines_with_data,
|
|
738
|
+
};
|
|
739
|
+
}
|
|
740
|
+
return {
|
|
741
|
+
verdict: 'stable-higher',
|
|
742
|
+
reason:
|
|
743
|
+
`repeat dispatches hit the cache at ${(stable.read_share * 100).toFixed(1)}% against ` +
|
|
744
|
+
`${(unstable.read_share * 100).toFixed(1)}% for one-off shapes, which is the expected ordering`,
|
|
745
|
+
stable_cohort: stable,
|
|
746
|
+
unstable_cohort: unstable,
|
|
747
|
+
lines_with_data: drift.lines_with_data,
|
|
748
|
+
};
|
|
749
|
+
}
|
|
750
|
+
|
|
676
751
|
export interface Report {
|
|
677
752
|
schema: 'cache-realization-report/v1';
|
|
678
753
|
host_version: string;
|
|
@@ -688,6 +763,7 @@ export interface Report {
|
|
|
688
763
|
duplicate_scope: DuplicateScopeResult;
|
|
689
764
|
council_mispricing: CouncilMispricingResult;
|
|
690
765
|
worktree_fragmentation: WorktreeFragmentationResult;
|
|
766
|
+
prefix_stability: PrefixStabilityResult;
|
|
691
767
|
claims: Claim[];
|
|
692
768
|
}
|
|
693
769
|
|
|
@@ -709,6 +785,22 @@ export function buildReport(opts: Options): Report {
|
|
|
709
785
|
const worktreePaths = listGitWorktrees(opts.repoRoot);
|
|
710
786
|
const worktreeFragmentation = computeWorktreeFragmentation(opts.root, worktreePaths, opts.maxAgeDays);
|
|
711
787
|
|
|
788
|
+
// A missing or unreadable audit directory is a real, expected state — the
|
|
789
|
+
// two fields are lean-init extensions and no caller wires them yet — so it
|
|
790
|
+
// resolves to `insufficient-data` with a reason, never to a fabricated share.
|
|
791
|
+
let prefixStability: PrefixStabilityResult;
|
|
792
|
+
try {
|
|
793
|
+
prefixStability = computePrefixStability(buildDriftReport(opts.auditDir));
|
|
794
|
+
} catch (err) {
|
|
795
|
+
prefixStability = {
|
|
796
|
+
verdict: 'insufficient-data',
|
|
797
|
+
reason: `the audit ledger at ${opts.auditDir} could not be read: ${(err as Error).message}`,
|
|
798
|
+
stable_cohort: { n: 0, read_share: null },
|
|
799
|
+
unstable_cohort: { n: 0, read_share: null },
|
|
800
|
+
lines_with_data: 0,
|
|
801
|
+
};
|
|
802
|
+
}
|
|
803
|
+
|
|
712
804
|
const claims = buildClaims({ subagentColdStart, duplicateScope, councilMispricing, worktreeFragmentation });
|
|
713
805
|
|
|
714
806
|
return {
|
|
@@ -729,6 +821,7 @@ export function buildReport(opts: Options): Report {
|
|
|
729
821
|
duplicate_scope: duplicateScope,
|
|
730
822
|
council_mispricing: councilMispricing,
|
|
731
823
|
worktree_fragmentation: worktreeFragmentation,
|
|
824
|
+
prefix_stability: prefixStability,
|
|
732
825
|
claims,
|
|
733
826
|
};
|
|
734
827
|
}
|
|
@@ -748,6 +841,16 @@ export function renderText(r: Report): string {
|
|
|
748
841
|
out.push(` dedup: ${r.deduped_count}/${r.total_seen} unique records kept (dedup_ratio ${pct(r.dedup_ratio)})`);
|
|
749
842
|
out.push('');
|
|
750
843
|
|
|
844
|
+
const ps = r.prefix_stability;
|
|
845
|
+
const share = (v: number | null): string => (v === null ? 'insufficient data' : pct(v));
|
|
846
|
+
const mark = ps.verdict === 'inverted' ? '⚠️ ' : '';
|
|
847
|
+
out.push('Prefix stability (payload_hash × cache_hit):');
|
|
848
|
+
out.push(` ${mark}verdict: ${ps.verdict}`);
|
|
849
|
+
out.push(` stable cohort: n=${ps.stable_cohort.n} read_share=${share(ps.stable_cohort.read_share)}`);
|
|
850
|
+
out.push(` unstable cohort: n=${ps.unstable_cohort.n} read_share=${share(ps.unstable_cohort.read_share)}`);
|
|
851
|
+
out.push(` ${ps.reason}`);
|
|
852
|
+
out.push('');
|
|
853
|
+
|
|
751
854
|
out.push('By bucket:');
|
|
752
855
|
for (const bucket of ['main', 'subagent'] as const) {
|
|
753
856
|
const b = r.buckets[bucket];
|