@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
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The council-rung topology vocabulary, closed at seven names.
|
|
3
|
+
*
|
|
4
|
+
* `road-to-inbox-harvest-2026-08-e-council-topology-evidence` step 7.1 asks
|
|
5
|
+
* for a vocabulary that "admits no eighth member without a schema change" and
|
|
6
|
+
* in which `team` / `user_required` are "not representable". Those are two
|
|
7
|
+
* different claims and they need two different mechanisms, so this module
|
|
8
|
+
* carries both.
|
|
9
|
+
*
|
|
10
|
+
* ## Where this sits — and what it deliberately is NOT
|
|
11
|
+
*
|
|
12
|
+
* It is **not** a resolver. `src/scripts/_lib/judgment_ladder.ts` is the ONE
|
|
13
|
+
* task-side resolver, and `src/scripts/_lib/one_resolver_invariant.ts` fails
|
|
14
|
+
* the build on a second one. This module exports a NAME SET and two
|
|
15
|
+
* predicates; it classifies nothing, reads no request, and takes no routing
|
|
16
|
+
* decision. It also lives under `ai_council/`, which the one-resolver scan
|
|
17
|
+
* treats as council-internal and skips by construction — the topology
|
|
18
|
+
* refinement hangs off the council rung *after* the ladder has already
|
|
19
|
+
* resolved to it, exactly as the roadmap's goal diagram draws it.
|
|
20
|
+
*
|
|
21
|
+
* The selector that will eventually CONSUME this vocabulary is step 7.2 and is
|
|
22
|
+
* not built here. Shipping the vocabulary first is deliberate: it is the half
|
|
23
|
+
* that can be closed without pre-empting the selector's design.
|
|
24
|
+
*
|
|
25
|
+
* ## Claim 1 — no eighth member without a source change that fails a gate
|
|
26
|
+
*
|
|
27
|
+
* {@link COUNCIL_TOPOLOGIES} is a frozen `as const` tuple, so its `length` is
|
|
28
|
+
* the literal `7` and {@link CouncilTopology} is a closed union. Appending an
|
|
29
|
+
* eighth entry turns the length into `8`, and {@link VocabularyIsClosed}'s
|
|
30
|
+
* first assertion then fails `npm run typecheck` — a CI gate. The same edit
|
|
31
|
+
* also fails {@link auditCouncilTopologyVocabulary}, which is the runtime half
|
|
32
|
+
* for the compiled `dist/` path where types no longer exist.
|
|
33
|
+
*
|
|
34
|
+
* ## Claim 2 — `team` and `user_required` are not representable
|
|
35
|
+
*
|
|
36
|
+
* Omitting two strings from a list is the weak form: nothing stops the next
|
|
37
|
+
* author adding them. The strong form binds the exclusion to the vocabularies
|
|
38
|
+
* that actually own those names, via TYPE-ONLY imports that are erased at
|
|
39
|
+
* compile time and couple nothing at runtime:
|
|
40
|
+
*
|
|
41
|
+
* - `team` is a `LadderVerdict` — rung 3, `judgment_ladder.ts:45`. The ladder
|
|
42
|
+
* owns it.
|
|
43
|
+
* - `user_required` is an `ImpactClass` — `necessity.ts:550`, and it sits in
|
|
44
|
+
* `LOCKED_IMPACT_CLASSES` (`necessity.ts:557-560`), the set structurally
|
|
45
|
+
* locked to `user` routing. The Hard Floor owns it.
|
|
46
|
+
*
|
|
47
|
+
* {@link VocabularyIsClosed} asserts that NO `LadderVerdict` and NO
|
|
48
|
+
* `ImpactClass` is a `CouncilTopology` — which is stronger than naming two
|
|
49
|
+
* strings, because it also excludes `script`, `subagent`, `council`, `ask`,
|
|
50
|
+
* `in-session`, `high_impact` and the rest. It further asserts that the two
|
|
51
|
+
* names in {@link RESERVED_BY_OTHER_LAYERS} really ARE members of those
|
|
52
|
+
* foreign vocabularies, so a rename on the ladder or in the necessity gate
|
|
53
|
+
* reds this file rather than silently orphaning the exclusion.
|
|
54
|
+
*
|
|
55
|
+
* ## Why not a JSON schema, and why not the config contract
|
|
56
|
+
*
|
|
57
|
+
* `src/scripts/schemas/` carries no council schema at all — `.ai-council.yml`
|
|
58
|
+
* is validated by the hand-rolled loader in `ai_council/config.ts`, so there
|
|
59
|
+
* is no enum surface there to extend. And this vocabulary is deliberately
|
|
60
|
+
* absent from `docs/contracts/ai-council-config.md`: that document describes
|
|
61
|
+
* what a USER may configure, while step 12.4 requires consumer surfaces to
|
|
62
|
+
* request capabilities and never topology names. Documenting it as config
|
|
63
|
+
* would invite exactly the coupling 12.4 forbids.
|
|
64
|
+
*/
|
|
65
|
+
import type { LadderVerdict } from '../_lib/judgment_ladder.js';
|
|
66
|
+
|
|
67
|
+
import type { ImpactClass } from './necessity.js';
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* The closed topology vocabulary, verbatim from the roadmap's goal diagram
|
|
71
|
+
* (`road-to-inbox-harvest-2026-08-e-council-topology-evidence.md:62-68`).
|
|
72
|
+
* Order is the diagram's order and carries no precedence.
|
|
73
|
+
*/
|
|
74
|
+
export const COUNCIL_TOPOLOGIES = Object.freeze([
|
|
75
|
+
'single_external',
|
|
76
|
+
'dual_independent',
|
|
77
|
+
'advisor_diversity',
|
|
78
|
+
'peer_review',
|
|
79
|
+
'judge_synthesis',
|
|
80
|
+
'targeted_cross_exam',
|
|
81
|
+
'full_debate',
|
|
82
|
+
] as const);
|
|
83
|
+
|
|
84
|
+
/** The closed union. There is no widening escape hatch on purpose. */
|
|
85
|
+
export type CouncilTopology = (typeof COUNCIL_TOPOLOGIES)[number];
|
|
86
|
+
|
|
87
|
+
/** Declared arity. Changing the tuple without changing this reds the type layer. */
|
|
88
|
+
export const COUNCIL_TOPOLOGY_ARITY = 7;
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Names owned by other layers, restated here so the runtime half can reject
|
|
92
|
+
* them without importing a value across the layer boundary. The type layer
|
|
93
|
+
* below pins each one to its real owning vocabulary.
|
|
94
|
+
*/
|
|
95
|
+
export const RESERVED_BY_OTHER_LAYERS = Object.freeze(['team', 'user_required'] as const);
|
|
96
|
+
|
|
97
|
+
/** A name this vocabulary must never admit. */
|
|
98
|
+
export type ReservedElsewhere = (typeof RESERVED_BY_OTHER_LAYERS)[number];
|
|
99
|
+
|
|
100
|
+
/** Fails to instantiate unless `T` is exactly `true`. */
|
|
101
|
+
type Assert<T extends true> = T;
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* The compile-time half of both claims. Every member must stay `true`; each
|
|
105
|
+
* one is a distinct way the vocabulary could be opened, and `npm run
|
|
106
|
+
* typecheck` is the gate that runs them.
|
|
107
|
+
*
|
|
108
|
+
* 1. arity is exactly {@link COUNCIL_TOPOLOGY_ARITY} — an eighth member reds it
|
|
109
|
+
* 2. no ladder verdict is a topology — `team` included, by construction
|
|
110
|
+
* 3. no impact class is a topology — `user_required` included, by construction
|
|
111
|
+
* 4. both reserved names are real members of those foreign vocabularies, so a
|
|
112
|
+
* rename upstream cannot orphan the exclusion into a dead string
|
|
113
|
+
* 5. neither reserved name is representable as a topology
|
|
114
|
+
*
|
|
115
|
+
* The `[X] extends [never]` tuple form is deliberate: it suppresses
|
|
116
|
+
* distribution, so an empty `Extract` reads as the single type `never` rather
|
|
117
|
+
* than as an empty union of branches.
|
|
118
|
+
*/
|
|
119
|
+
export type VocabularyIsClosed = [
|
|
120
|
+
Assert<(typeof COUNCIL_TOPOLOGIES)['length'] extends typeof COUNCIL_TOPOLOGY_ARITY ? true : false>,
|
|
121
|
+
Assert<[Extract<CouncilTopology, LadderVerdict>] extends [never] ? true : false>,
|
|
122
|
+
Assert<[Extract<CouncilTopology, ImpactClass>] extends [never] ? true : false>,
|
|
123
|
+
Assert<ReservedElsewhere extends LadderVerdict | ImpactClass ? true : false>,
|
|
124
|
+
Assert<[Extract<CouncilTopology, ReservedElsewhere>] extends [never] ? true : false>,
|
|
125
|
+
];
|
|
126
|
+
|
|
127
|
+
/** Is this value one of the seven? `team` and `user_required` are not. */
|
|
128
|
+
export function isCouncilTopology(value: unknown): value is CouncilTopology {
|
|
129
|
+
return typeof value === 'string' && (COUNCIL_TOPOLOGIES as readonly string[]).includes(value);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* The runtime half, and the reason it takes arguments rather than reading the
|
|
134
|
+
* constants directly: a guard that can only ever be handed the correct input
|
|
135
|
+
* has unknown sensitivity. Callers in `dist/` pass the shipped constants; the
|
|
136
|
+
* test passes mutations and asserts each one is caught.
|
|
137
|
+
*
|
|
138
|
+
* @returns one string per problem found; empty means the vocabulary is closed.
|
|
139
|
+
*/
|
|
140
|
+
export function auditCouncilTopologyVocabulary(
|
|
141
|
+
topologies: readonly string[] = COUNCIL_TOPOLOGIES,
|
|
142
|
+
reserved: readonly string[] = RESERVED_BY_OTHER_LAYERS,
|
|
143
|
+
): string[] {
|
|
144
|
+
const problems: string[] = [];
|
|
145
|
+
if (topologies.length !== COUNCIL_TOPOLOGY_ARITY) {
|
|
146
|
+
problems.push(
|
|
147
|
+
`arity: expected exactly ${COUNCIL_TOPOLOGY_ARITY} topologies, found ${topologies.length}. ` +
|
|
148
|
+
'The vocabulary is closed; an eighth member is a schema change, not an append.',
|
|
149
|
+
);
|
|
150
|
+
}
|
|
151
|
+
if (new Set(topologies).size !== topologies.length) {
|
|
152
|
+
problems.push('duplicate: the vocabulary contains a repeated name.');
|
|
153
|
+
}
|
|
154
|
+
for (const name of reserved) {
|
|
155
|
+
if (topologies.includes(name)) {
|
|
156
|
+
problems.push(
|
|
157
|
+
`reserved: \`${name}\` is owned by another layer (the judgment ladder for ` +
|
|
158
|
+
'`team`, the locked impact classes for `user_required`) and is not ' +
|
|
159
|
+
'representable as a council topology.',
|
|
160
|
+
);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
return problems;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* Module-load guard. Types are erased in `dist/`, so without this the runtime
|
|
168
|
+
* artefact carries no version of claim 1 or claim 2 at all. It can only fire
|
|
169
|
+
* on a source edit that also reds `npm run typecheck`, which is the point:
|
|
170
|
+
* two independent layers, not one restated twice.
|
|
171
|
+
*/
|
|
172
|
+
const _shippedProblems = auditCouncilTopologyVocabulary();
|
|
173
|
+
if (_shippedProblems.length > 0) {
|
|
174
|
+
throw new Error(`council topology vocabulary is not closed:\n ${_shippedProblems.join('\n ')}`);
|
|
175
|
+
}
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
#!/usr/bin/env tsx
|
|
2
|
+
/**
|
|
3
|
+
* Per-asset delivery ledger — which assets produce the standing payload
|
|
4
|
+
* (`road-to-delivered-cost-truth` step 2.1).
|
|
5
|
+
*
|
|
6
|
+
* `check_preamble_payload_budget` measures three BUCKET totals and refuses
|
|
7
|
+
* growth. It cannot say which asset inside a bucket produces the cost, so a
|
|
8
|
+
* reduction effort has a number (35,692 tokens over a published milestone) and
|
|
9
|
+
* no target. This command ranks the assets behind that number.
|
|
10
|
+
*
|
|
11
|
+
* Class A per ADR-124: in-process, per-invocation, no socket, no daemon, no
|
|
12
|
+
* network, no writes outside a stdout/JSON report.
|
|
13
|
+
*
|
|
14
|
+
* Usage:
|
|
15
|
+
* ./scripts-run src/scripts/asset_delivery_ledger [--format text|json]
|
|
16
|
+
* [--top <n>] [--root <path>]
|
|
17
|
+
*/
|
|
18
|
+
import * as path from 'node:path';
|
|
19
|
+
|
|
20
|
+
import {
|
|
21
|
+
buildLedger,
|
|
22
|
+
reconcile,
|
|
23
|
+
RECONCILE_MARGIN,
|
|
24
|
+
type AssetRow,
|
|
25
|
+
type LedgerVerdict,
|
|
26
|
+
type Reconciliation,
|
|
27
|
+
} from './_lib/asset_delivery_ledger.js';
|
|
28
|
+
import { measureDeterministicPayload } from './check_preamble_payload_budget.js';
|
|
29
|
+
import { prefixStableDirRoots } from './_lib/prefix_stable_surfaces.js';
|
|
30
|
+
|
|
31
|
+
const HERE = path.dirname(new URL(import.meta.url).pathname);
|
|
32
|
+
const REPO_ROOT = path.resolve(HERE, '..', '..');
|
|
33
|
+
|
|
34
|
+
export interface Options {
|
|
35
|
+
format: 'text' | 'json';
|
|
36
|
+
top: number;
|
|
37
|
+
root: string;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export function parseArgs(argv: string[]): Options {
|
|
41
|
+
const opts: Options = { format: 'text', top: 20, root: REPO_ROOT };
|
|
42
|
+
for (let i = 0; i < argv.length; i++) {
|
|
43
|
+
const a = argv[i];
|
|
44
|
+
if (a === undefined) continue;
|
|
45
|
+
if (a === '--format') opts.format = (argv[++i] as Options['format']) ?? opts.format;
|
|
46
|
+
else if (a.startsWith('--format=')) opts.format = a.slice('--format='.length) as Options['format'];
|
|
47
|
+
else if (a === '--top') opts.top = Number(argv[++i]) || opts.top;
|
|
48
|
+
else if (a.startsWith('--top=')) opts.top = Number(a.slice('--top='.length)) || opts.top;
|
|
49
|
+
else if (a === '--root') opts.root = path.resolve(argv[++i] ?? opts.root);
|
|
50
|
+
else if (a.startsWith('--root=')) opts.root = path.resolve(a.slice('--root='.length));
|
|
51
|
+
}
|
|
52
|
+
if (opts.format !== 'text' && opts.format !== 'json') opts.format = 'text';
|
|
53
|
+
return opts;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export interface Report {
|
|
57
|
+
schema: 'asset-delivery-ledger/v1';
|
|
58
|
+
ledger: LedgerVerdict;
|
|
59
|
+
reconciliation: Reconciliation[];
|
|
60
|
+
reconcile_margin: number;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export function buildReport(root: string): Report {
|
|
64
|
+
// Roots come from the prefix-stable registry, the same module the payload
|
|
65
|
+
// gate resolves its census roots from. A third statement of the same
|
|
66
|
+
// boundary is the drift shape this repository already pays for.
|
|
67
|
+
const [rulesRel, skillsRel] = prefixStableDirRoots();
|
|
68
|
+
const ledger = buildLedger(
|
|
69
|
+
path.join(root, rulesRel ?? 'dist/agent-src/rules'),
|
|
70
|
+
path.join(root, skillsRel ?? 'dist/agent-src/skills'),
|
|
71
|
+
root,
|
|
72
|
+
);
|
|
73
|
+
return {
|
|
74
|
+
schema: 'asset-delivery-ledger/v1',
|
|
75
|
+
ledger,
|
|
76
|
+
reconciliation: reconcile(ledger, measureDeterministicPayload(root)),
|
|
77
|
+
reconcile_margin: RECONCILE_MARGIN,
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
function pct(v: number): string {
|
|
82
|
+
return `${(v * 100).toFixed(1)}%`;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
export function renderText(r: Report, top: number): string {
|
|
86
|
+
const out: string[] = [];
|
|
87
|
+
const l = r.ledger;
|
|
88
|
+
out.push('Per-asset delivery ledger — what every spawn pays for');
|
|
89
|
+
out.push(
|
|
90
|
+
` measurement: ${l.exact_throughout ? 'exact BPE throughout' : 'MIXED — some rows fall back to the chars/4 proxy'}`,
|
|
91
|
+
);
|
|
92
|
+
out.push(` total: ${l.total_tokens} tok across ${l.rows.length} asset(s)`);
|
|
93
|
+
out.push(
|
|
94
|
+
` by kind: rules ${l.by_kind.rule.tokens} tok (${l.by_kind.rule.count}) · ` +
|
|
95
|
+
`skill catalogue lines ${l.by_kind['skill-catalogue-line'].tokens} tok (${l.by_kind['skill-catalogue-line'].count})`,
|
|
96
|
+
);
|
|
97
|
+
out.push('');
|
|
98
|
+
out.push(`Top ${Math.min(top, l.rows.length)} by delivered tokens:`);
|
|
99
|
+
out.push(` ${'tokens'.padStart(7)} ${'share'.padStart(6)} ${'method'.padEnd(6)} asset`);
|
|
100
|
+
for (const row of l.rows.slice(0, top)) {
|
|
101
|
+
out.push(
|
|
102
|
+
` ${String(row.tokens).padStart(7)} ${pct(row.share).padStart(6)} ${row.method.padEnd(6)} ${row.name} (${row.kind})`,
|
|
103
|
+
);
|
|
104
|
+
}
|
|
105
|
+
out.push('');
|
|
106
|
+
out.push('Reconciliation against the payload gate\'s own bucket totals:');
|
|
107
|
+
if (r.reconciliation.length === 0) {
|
|
108
|
+
out.push(' no bucket to reconcile against — the payload census measured nothing');
|
|
109
|
+
}
|
|
110
|
+
for (const rec of r.reconciliation) {
|
|
111
|
+
const mark = rec.within_margin ? '✅' : '❌';
|
|
112
|
+
out.push(
|
|
113
|
+
` ${mark} ${rec.bucket}: ledger ${rec.ledger_proxy_tokens} tok vs bucket ${rec.bucket_tokens} tok ` +
|
|
114
|
+
`(drift ${pct(rec.drift)}, margin ${pct(r.reconcile_margin)}) · both chars/4` +
|
|
115
|
+
`\n exact BPE for the same assets: ${rec.ledger_exact_tokens} tok` +
|
|
116
|
+
` (${pct(1 - rec.ledger_exact_tokens / Math.max(rec.ledger_proxy_tokens, 1))} below the proxy)`,
|
|
117
|
+
);
|
|
118
|
+
}
|
|
119
|
+
out.push('');
|
|
120
|
+
out.push(' Reconciled like-for-like: both sides are chars/4, so what remains is real');
|
|
121
|
+
out.push(' disagreement rather than a method gap. The exact BPE figure is shown beside each');
|
|
122
|
+
out.push(' bucket because the gap is the interesting part — chars/4 overestimates short');
|
|
123
|
+
out.push(' structured lines far more than it does prose, which is why the skill catalogue');
|
|
124
|
+
out.push(' and the rule bodies diverge from the proxy by very different amounts.');
|
|
125
|
+
return out.join('\n') + '\n';
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
export function main(argv: string[] = process.argv.slice(2)): number {
|
|
129
|
+
const opts = parseArgs(argv);
|
|
130
|
+
let report: Report;
|
|
131
|
+
try {
|
|
132
|
+
report = buildReport(opts.root);
|
|
133
|
+
} catch (err) {
|
|
134
|
+
process.stderr.write(`❌ asset_delivery_ledger: ${(err as Error).message}\n`);
|
|
135
|
+
return 2;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
if (report.ledger.rows.length === 0) {
|
|
139
|
+
process.stderr.write(
|
|
140
|
+
'❌ asset_delivery_ledger: no asset measured. The standing rule and skill trees are\n' +
|
|
141
|
+
' generated (`task sync && task generate-tools`); a checkout that has not run them\n' +
|
|
142
|
+
' has nothing to rank. This is a stated reason, not an empty ledger reported as zero.\n',
|
|
143
|
+
);
|
|
144
|
+
return 2;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
process.stdout.write(
|
|
148
|
+
opts.format === 'json' ? JSON.stringify(report, null, 2) + '\n' : renderText(report, opts.top),
|
|
149
|
+
);
|
|
150
|
+
return report.reconciliation.every((r) => r.within_margin) ? 0 : 1;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
if (process.argv[1] !== undefined && import.meta.url === `file://${process.argv[1]}`) {
|
|
154
|
+
process.exit(main());
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
export type { AssetRow };
|
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
#!/usr/bin/env tsx
|
|
2
|
+
/**
|
|
3
|
+
* Content attestation for any artifact a hook would INJECT.
|
|
4
|
+
*
|
|
5
|
+
* `road-to-skill-ecosystem-runtime-enforcement` Phase 5, Steps 6-7, and the
|
|
6
|
+
* ordering in that step is the argument: attestation is the **precondition** for
|
|
7
|
+
* auto-injection, not a follow-up to it.
|
|
8
|
+
*
|
|
9
|
+
* ── The threat, concretely ──────────────────────────────────────────────────
|
|
10
|
+
* A hook that reads a tracked file and injects its contents into the model's
|
|
11
|
+
* context turns that file into a **standing injection amplifier**. Whoever can
|
|
12
|
+
* write the file can write the agent's instructions, on every session, without
|
|
13
|
+
* a review — which is `untrusted-input-defense`'s found-instructions case
|
|
14
|
+
* arriving through a file the repository itself vouches for. The file being
|
|
15
|
+
* tracked is not the control: a tracked file changes in a pull request, and a
|
|
16
|
+
* pull request that changes an injected file is indistinguishable in the diff
|
|
17
|
+
* from one that changes documentation.
|
|
18
|
+
*
|
|
19
|
+
* ── The contract ────────────────────────────────────────────────────────────
|
|
20
|
+
* An injectable artifact carries a sidecar `<file>.attest.json` holding the
|
|
21
|
+
* sha256 of its bytes and the date the attestation was recorded. Before
|
|
22
|
+
* injecting, a caller asks {@link verifyArtifact}:
|
|
23
|
+
*
|
|
24
|
+
* - hash matches → `ok`, inject.
|
|
25
|
+
* - hash differs → `mismatch`, REFUSE. The content changed since a human
|
|
26
|
+
* vouched for it; re-attesting is a deliberate act with a diff.
|
|
27
|
+
* - no sidecar → `unattested`, REFUSE. **Not "allow because nothing said
|
|
28
|
+
* no"** — that default makes the whole mechanism opt-out, and the file an
|
|
29
|
+
* attacker adds is exactly the one with no sidecar.
|
|
30
|
+
* - file missing → `absent`, REFUSE.
|
|
31
|
+
*
|
|
32
|
+
* ── What this does NOT claim ────────────────────────────────────────────────
|
|
33
|
+
* The sidecar is committed beside the artifact, so an attacker who can write
|
|
34
|
+
* both can write a consistent pair. This is NOT a cryptographic signature and
|
|
35
|
+
* does not pretend to be one. What it buys is that the change becomes VISIBLE:
|
|
36
|
+
* a diff that touches an injected file must also touch its attestation, and a
|
|
37
|
+
* hash line changing in a review is a question, where a prose change in the same
|
|
38
|
+
* file is not. Making a change reviewable is the honest claim; making it
|
|
39
|
+
* impossible would need a key this repository does not have.
|
|
40
|
+
*
|
|
41
|
+
* Exit codes: 0 verified · 1 refused (mismatch / unattested / absent) · 2 usage.
|
|
42
|
+
*
|
|
43
|
+
* Usage:
|
|
44
|
+
* ./scripts-run src/scripts/attest_artifact --record <file>
|
|
45
|
+
* ./scripts-run src/scripts/attest_artifact --verify <file>
|
|
46
|
+
* ./scripts-run src/scripts/attest_artifact --verify <file> --json
|
|
47
|
+
*/
|
|
48
|
+
import * as crypto from 'node:crypto';
|
|
49
|
+
import * as fs from 'node:fs';
|
|
50
|
+
import * as path from 'node:path';
|
|
51
|
+
import process from 'node:process';
|
|
52
|
+
import { fileURLToPath, pathToFileURL } from 'node:url';
|
|
53
|
+
|
|
54
|
+
const _HERE = fileURLToPath(import.meta.url);
|
|
55
|
+
|
|
56
|
+
/** Sidecar suffix. Beside the artifact, so a move takes the attestation with it. */
|
|
57
|
+
export const ATTEST_SUFFIX = '.attest.json';
|
|
58
|
+
|
|
59
|
+
export type AttestStatus = 'ok' | 'mismatch' | 'unattested' | 'absent';
|
|
60
|
+
|
|
61
|
+
export interface Attestation {
|
|
62
|
+
schema_version: 1;
|
|
63
|
+
/** sha256 of the artifact's bytes, hex. */
|
|
64
|
+
sha256: string;
|
|
65
|
+
/** `YYYY-MM-DD` the attestation was recorded. */
|
|
66
|
+
recorded_at: string;
|
|
67
|
+
/** Bytes at record time — a cheap second signal that costs nothing to store. */
|
|
68
|
+
bytes: number;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
export interface Verdict {
|
|
72
|
+
status: AttestStatus;
|
|
73
|
+
/** True only for `ok`. Every other status refuses. */
|
|
74
|
+
inject: boolean;
|
|
75
|
+
detail: string;
|
|
76
|
+
expected?: string;
|
|
77
|
+
actual?: string;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
export function sidecarPath(artifact: string): string {
|
|
81
|
+
return `${artifact}${ATTEST_SUFFIX}`;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
export function hashFile(artifact: string): string {
|
|
85
|
+
return crypto.createHash('sha256').update(fs.readFileSync(artifact)).digest('hex');
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Verify an artifact against its sidecar.
|
|
90
|
+
*
|
|
91
|
+
* Every non-`ok` status sets `inject: false`. That is the whole safety property
|
|
92
|
+
* and it is expressed as data rather than left to each caller's `if`: a caller
|
|
93
|
+
* that reads `verdict.inject` cannot accidentally treat `unattested` as
|
|
94
|
+
* permissive, which is the mistake an `status === 'mismatch'` check invites.
|
|
95
|
+
*/
|
|
96
|
+
export function verifyArtifact(artifact: string, today?: string): Verdict {
|
|
97
|
+
void today;
|
|
98
|
+
if (!fs.existsSync(artifact)) {
|
|
99
|
+
return { status: 'absent', inject: false, detail: `${artifact} does not exist` };
|
|
100
|
+
}
|
|
101
|
+
const side = sidecarPath(artifact);
|
|
102
|
+
if (!fs.existsSync(side)) {
|
|
103
|
+
return {
|
|
104
|
+
status: 'unattested',
|
|
105
|
+
inject: false,
|
|
106
|
+
detail:
|
|
107
|
+
`${artifact} has no ${ATTEST_SUFFIX} sidecar — REFUSED. An unattested artifact is ` +
|
|
108
|
+
'not "allowed because nothing said no": that default makes attestation opt-out, and ' +
|
|
109
|
+
'the file an attacker adds is precisely the one with no sidecar.',
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
let att: Partial<Attestation>;
|
|
113
|
+
try {
|
|
114
|
+
att = JSON.parse(fs.readFileSync(side, 'utf8')) as Partial<Attestation>;
|
|
115
|
+
} catch (e) {
|
|
116
|
+
return {
|
|
117
|
+
status: 'unattested',
|
|
118
|
+
inject: false,
|
|
119
|
+
detail: `${side} does not parse (${e instanceof Error ? e.message : String(e)}) — treated as absent`,
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
const actual = hashFile(artifact);
|
|
123
|
+
if (typeof att.sha256 !== 'string' || att.sha256 === '') {
|
|
124
|
+
return { status: 'unattested', inject: false, detail: `${side} carries no sha256`, actual };
|
|
125
|
+
}
|
|
126
|
+
if (att.sha256 !== actual) {
|
|
127
|
+
return {
|
|
128
|
+
status: 'mismatch',
|
|
129
|
+
inject: false,
|
|
130
|
+
detail:
|
|
131
|
+
`${artifact} changed since it was attested — REFUSED. Re-attest deliberately ` +
|
|
132
|
+
`(--record) so the new hash lands in a diff a reviewer sees.`,
|
|
133
|
+
expected: att.sha256,
|
|
134
|
+
actual,
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
return { status: 'ok', inject: true, detail: `${artifact} matches its attestation`, expected: att.sha256, actual };
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/** Record (or re-record) an attestation. Deliberate, and it lands in a diff. */
|
|
141
|
+
export function recordAttestation(artifact: string, today = new Date().toISOString().slice(0, 10)): Attestation {
|
|
142
|
+
const att: Attestation = {
|
|
143
|
+
schema_version: 1,
|
|
144
|
+
sha256: hashFile(artifact),
|
|
145
|
+
recorded_at: today,
|
|
146
|
+
bytes: fs.statSync(artifact).size,
|
|
147
|
+
};
|
|
148
|
+
fs.writeFileSync(sidecarPath(artifact), `${JSON.stringify(att, null, 2)}\n`, 'utf8');
|
|
149
|
+
return att;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
export function main(argv: string[] = process.argv.slice(2)): number {
|
|
153
|
+
const usage =
|
|
154
|
+
'usage: attest_artifact (--record | --verify) <file> [--json]\n' +
|
|
155
|
+
' --verify exits 1 on mismatch, unattested or absent. Refusal is the default.\n';
|
|
156
|
+
if (argv.includes('-h') || argv.includes('--help')) {
|
|
157
|
+
process.stdout.write(usage);
|
|
158
|
+
return 0;
|
|
159
|
+
}
|
|
160
|
+
const asJson = argv.includes('--json');
|
|
161
|
+
const record = argv.includes('--record');
|
|
162
|
+
const verify = argv.includes('--verify');
|
|
163
|
+
const file = argv.find((a) => !a.startsWith('--'));
|
|
164
|
+
if (record === verify || file === undefined) {
|
|
165
|
+
process.stderr.write(`attest_artifact: error: exactly one of --record / --verify plus a file\n${usage}`);
|
|
166
|
+
return 2;
|
|
167
|
+
}
|
|
168
|
+
const target = path.resolve(file);
|
|
169
|
+
if (record) {
|
|
170
|
+
if (!fs.existsSync(target)) {
|
|
171
|
+
process.stderr.write(`attest_artifact: ${file} does not exist\n`);
|
|
172
|
+
return 2;
|
|
173
|
+
}
|
|
174
|
+
const att = recordAttestation(target);
|
|
175
|
+
process.stdout.write(`✅ attested ${file} — sha256 ${att.sha256.slice(0, 16)}… (${String(att.bytes)} bytes)\n`);
|
|
176
|
+
return 0;
|
|
177
|
+
}
|
|
178
|
+
const v = verifyArtifact(target);
|
|
179
|
+
if (asJson) {
|
|
180
|
+
process.stdout.write(`${JSON.stringify(v, null, 2)}\n`);
|
|
181
|
+
} else if (v.inject) {
|
|
182
|
+
process.stdout.write(`✅ ${v.detail}\n`);
|
|
183
|
+
} else {
|
|
184
|
+
process.stderr.write(`❌ [${v.status}] ${v.detail}\n`);
|
|
185
|
+
}
|
|
186
|
+
return v.inject ? 0 : 1;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
/* c8 ignore start */
|
|
190
|
+
if (process.argv[1] !== undefined && pathToFileURL(path.resolve(process.argv[1])).href === pathToFileURL(_HERE).href) {
|
|
191
|
+
process.exit(main());
|
|
192
|
+
}
|
|
193
|
+
/* c8 ignore stop */
|
|
@@ -29,6 +29,7 @@ import { parse as parseYaml } from 'yaml';
|
|
|
29
29
|
|
|
30
30
|
import { artefact_roots } from './_lib/agent_src.js';
|
|
31
31
|
import { assertScanned, DeadScopeError } from './_lib/scan_scope.js';
|
|
32
|
+
import { generatedBy } from './_lib/generated_by.js';
|
|
32
33
|
|
|
33
34
|
const _HERE = fileURLToPath(import.meta.url);
|
|
34
35
|
// src/scripts/audit_auto_rules.py → parent.parent.parent == repo root.
|
|
@@ -270,7 +271,7 @@ export function render_markdown(rules: RuleEntry[]): string {
|
|
|
270
271
|
`<!-- analyzed: ${dateStr} | commit: ${commitShort} | files: ${rules.length} -->`,
|
|
271
272
|
'# Auto-Rule Audit',
|
|
272
273
|
'',
|
|
273
|
-
'
|
|
274
|
+
generatedBy('audit_auto_rules', 'For Phase 5 of'),
|
|
274
275
|
'`agents/roadmaps/archive/road-to-augment-limit-fit.md`. Re-run after',
|
|
275
276
|
'any rule add/merge/deprecate to refresh the baseline.',
|
|
276
277
|
'',
|
|
@@ -548,7 +548,7 @@ export function render_md(commands: Command[], pairs: OverlapPair[]): string {
|
|
|
548
548
|
const lines: string[] = [
|
|
549
549
|
'# Command-Surface Inventory',
|
|
550
550
|
'',
|
|
551
|
-
'> Generated by `
|
|
551
|
+
'> Generated by `audit_command_surface`. Do not edit. ' +
|
|
552
552
|
'Source: `.agent-src.uncondensed/commands/`.',
|
|
553
553
|
'',
|
|
554
554
|
'## Summary',
|
|
@@ -25,7 +25,7 @@ import { assertWatchlistResolves, DeadScopeError } from './_lib/scan_scope.js';
|
|
|
25
25
|
|
|
26
26
|
const _HERE = fileURLToPath(import.meta.url);
|
|
27
27
|
|
|
28
|
-
//
|
|
28
|
+
// audit_mcp_tools → parent.parent.parent of the .py file = repo root.
|
|
29
29
|
export const ROOT = path.resolve(path.dirname(_HERE), '..', '..');
|
|
30
30
|
export const CATALOG = path.join(ROOT, 'src/scripts/mcp_server/consumer_tool_catalog.json');
|
|
31
31
|
export const TOOLS_TS = path.join(ROOT, 'src/scripts/mcp_server/tools.ts');
|
|
@@ -145,7 +145,7 @@ function _render(catalog: Catalog, handlers: Map<string, number>, cat_lines: Map
|
|
|
145
145
|
lines.push('');
|
|
146
146
|
lines.push('# MCP tool inventory');
|
|
147
147
|
lines.push('');
|
|
148
|
-
lines.push('> Generated by [`
|
|
148
|
+
lines.push('> Generated by [`audit_mcp_tools`](../../audit_mcp_tools)');
|
|
149
149
|
lines.push('> from the source-of-truth catalog');
|
|
150
150
|
lines.push('> [`src/scripts/mcp_server/consumer_tool_catalog.json`](../../src/scripts/mcp_server/consumer_tool_catalog.json).');
|
|
151
151
|
lines.push('> Do **not** hand-edit; rerun `./scripts-run src/scripts/audit_mcp_tools --write`.');
|
|
@@ -1,4 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"_comment": "Reviewed same-pack overlaps at or above the canonical 0.70 threshold. Each entry needs a real reason — a pair is here because a human read both skills and decided the overlap is structural, not because the gate was noisy. Capped at 20 by audit_skill_overlap.ts: crossing the cap means the threshold is wrong, not that the corpus needs a twenty-first exception. Empty is the healthy state.",
|
|
3
|
-
"entries": [
|
|
3
|
+
"entries": [
|
|
4
|
+
{
|
|
5
|
+
"pair": "test-driven-development::testing-anti-patterns",
|
|
6
|
+
"reason": "Structural vocabulary overlap from a shared testing domain (test, assertion, mock, fixture, red, green), not duplicated responsibility. The two are architecturally distinct: test-driven-development is the PROCEDURE — four mode contracts with diff-checked Forbidden columns, mode inference on resume, the delete-and-restart law; testing-anti-patterns is the DIAGNOSTIC CATALOGUE — tautological assertions, hardcoded expectations, over-mocking, test-data realism. They answer different questions at different call sites. Measured 2026-08-26 with the audit's own collect()+_cosine(): the pair sat at 0.7000 before this change and 0.7120 after, so it was already at the cap and any body edit to either skill re-trips the gate. Migrating 11 lines of rationale into a non-SKILL.md companion was tried and measured (0.7056) and REJECTED: it still failed, and it removes guidance from the file the agent actually loads, which optimises for the detector rather than the reader. Merging was rejected — a procedure and a failure catalogue have distinct invocation needs. Invalidation trigger: reassess if either skill's scope materially changes, or if substantive guidance becomes duplicated between them rather than merely sharing vocabulary. Council 2026-08-26, 2/2 convergent (anthropic/claude-sonnet-4-5, openai/codex-default), agents/evidence/council/tdd-overlap-disposition.md."
|
|
7
|
+
}
|
|
8
|
+
]
|
|
4
9
|
}
|
|
@@ -35,6 +35,7 @@ import { fileURLToPath, pathToFileURL } from 'node:url';
|
|
|
35
35
|
import { SRC_SKILLS } from './_lib/agent_src.js';
|
|
36
36
|
import { checkRatchet } from './_lib/gate_baseline.js';
|
|
37
37
|
import { DeadScopeError, assertScanned } from './_lib/scan_scope.js';
|
|
38
|
+
import { generatedBy } from './_lib/generated_by.js';
|
|
38
39
|
|
|
39
40
|
const _HERE = fileURLToPath(import.meta.url);
|
|
40
41
|
|
|
@@ -198,7 +199,7 @@ export function _render_report(
|
|
|
198
199
|
const lines: string[] = [
|
|
199
200
|
'# User-type axis — frontmatter coverage audit',
|
|
200
201
|
'',
|
|
201
|
-
'
|
|
202
|
+
generatedBy('audit_user_type_axis', '(step-9 Phase 4.)'),
|
|
202
203
|
'',
|
|
203
204
|
`- Declared user-types (\`user-types/*.yml\`): **${declared.size}**`,
|
|
204
205
|
`- Distinct frontmatter values across skills: **${byValue.size}**`,
|