@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
|
@@ -55,7 +55,30 @@ function makeBrokenRef(
|
|
|
55
55
|
return { file, line, ref, ref_type, severity, suggestion };
|
|
56
56
|
}
|
|
57
57
|
|
|
58
|
-
|
|
58
|
+
// `docs/guidelines` joins the scan on 2026-08-26 (`road-to-contract-review-deadlines`
|
|
59
|
+
// 4.3), and the decision is the NARROW one of the three that step offered —
|
|
60
|
+
// widen to the SHIPPED roots only.
|
|
61
|
+
//
|
|
62
|
+
// Priced before deciding, which is what the step asked for. Measured with
|
|
63
|
+
// `measure_docs_dead_links`: 544 dead relative links across `docs/`, of which
|
|
64
|
+
// **104 sat in files `package.json:files[]` publishes** and 440 did not.
|
|
65
|
+
// Widening to all of `docs/` would land ~300 findings on the next unrelated pull
|
|
66
|
+
// request — the flood that gets a gate waived rather than adopted, and the same
|
|
67
|
+
// argument this roadmap's Phase 0 already accepted for the beta backlog.
|
|
68
|
+
// Widening to the shipped roots lands **zero**, because 4.2 repaired all 104
|
|
69
|
+
// first, so the gate arrives green and holds the gain instead of announcing it.
|
|
70
|
+
//
|
|
71
|
+
// The excluded class is named rather than left implicit: **297 dead links in
|
|
72
|
+
// NON-shipped `docs/`** — analysis notes, ADR records, architecture pages — stay
|
|
73
|
+
// out of scope. They cost a maintainer a confused minute; a dead link under
|
|
74
|
+
// `docs/guidelines/` is shipped to a consumer and is the only half that reaches
|
|
75
|
+
// anyone. Re-measure any time with `./scripts-run src/scripts/measure_docs_dead_links`.
|
|
76
|
+
//
|
|
77
|
+
// The three named single-file contracts in `files[]`
|
|
78
|
+
// (`persona-schema`, `provider-lifecycle`, `settings-classes`) are NOT added:
|
|
79
|
+
// a directory scan cannot express "these three files under a directory that is
|
|
80
|
+
// otherwise excluded", and all three measure zero dead links today.
|
|
81
|
+
const SCAN_DIRS = ['dist/agent-src', 'agents', 'docs/guidelines'];
|
|
59
82
|
const SKIP_DIRS = [
|
|
60
83
|
// Archived roadmaps have historical refs — a link to a file that existed when
|
|
61
84
|
// the plan was written is not drift, so the exclusion is right on the merits.
|
|
@@ -18,7 +18,33 @@
|
|
|
18
18
|
* `_none_` everywhere. That removes the guaranteed first-run red (9.17.0,
|
|
19
19
|
* 9.18.0) without blunting this gate: a machine-written `_none_` was never the
|
|
20
20
|
* failure it was built for — a HUMAN writing one was (9.13.0, 9.14.0), and that
|
|
21
|
-
* still fails here.
|
|
21
|
+
* still fails here.
|
|
22
|
+
*
|
|
23
|
+
* ## REVERSED 2026-09-01 — an unrewritten derived line now BLOCKS
|
|
24
|
+
*
|
|
25
|
+
* This header used to end the paragraph above with *"An unrewritten derived
|
|
26
|
+
* line warns; it never blocks."* That is no longer the behaviour, and the
|
|
27
|
+
* sentence is replaced rather than deleted so the reversal is legible.
|
|
28
|
+
*
|
|
29
|
+
* **The premise was never wrong; the conclusion drawn from it was.** A derived
|
|
30
|
+
* line does carry true evidence — the deriving reason plus citing SHAs — so it
|
|
31
|
+
* is not false-if-shipped. What the advisory conclusion assumed is that
|
|
32
|
+
* "unpolished-if-unedited" would in fact get edited. Measured at `b50b27281`,
|
|
33
|
+
* it did not: `_auto-derived, rewrite before merge:_` shipped in FIVE
|
|
34
|
+
* consecutive released sections — 14.9.0 (4 lines), 14.10.0 (2), 14.11.0 (4),
|
|
35
|
+
* 14.12.0 (4), 14.13.0 (4), eighteen lines in total. A warning that has been
|
|
36
|
+
* ignored eighteen times is not a warning; it is a comment.
|
|
37
|
+
*
|
|
38
|
+
* **Instructing authority:** the maintainer, in the closing instruction of the
|
|
39
|
+
* 2026-09-a inbox round, requiring that the release-placeholder defect be taken
|
|
40
|
+
* into a roadmap and fixed. Carried into
|
|
41
|
+
* `agents/roadmaps/archive/road-to-publication-integrity-hard-fail.md` § Phase 1, which
|
|
42
|
+
* is the record of this change.
|
|
43
|
+
*
|
|
44
|
+
* **What did NOT change.** The read stays scoped to the section under release
|
|
45
|
+
* (`extract_changelog_section` below), so the eighteen historical lines cannot
|
|
46
|
+
* red a future release; a filled field is still never judged for prose quality;
|
|
47
|
+
* and the `_none_` contradiction check is untouched.
|
|
22
48
|
*
|
|
23
49
|
* Derivation is deliberately conservative (documented per-label below):
|
|
24
50
|
* a false red makes every release annoying; a miss only returns the head to
|
|
@@ -29,7 +55,8 @@
|
|
|
29
55
|
* [--changelog <path>]
|
|
30
56
|
*
|
|
31
57
|
* `--from` defaults to the latest reachable release tag before `--to`
|
|
32
|
-
* (default HEAD). Exit codes: 0 plausible · 1
|
|
58
|
+
* (default HEAD). Exit codes: 0 plausible · 1 refusal (an unrewritten
|
|
59
|
+
* auto-derived head line, or a `_none_` contradiction) · 2 usage error.
|
|
33
60
|
*/
|
|
34
61
|
import * as fs from 'node:fs';
|
|
35
62
|
import * as path from 'node:path';
|
|
@@ -37,6 +64,7 @@ import process from 'node:process';
|
|
|
37
64
|
import { fileURLToPath } from 'node:url';
|
|
38
65
|
|
|
39
66
|
import {
|
|
67
|
+
DERIVED_MARKER,
|
|
40
68
|
HEAD_LABELS,
|
|
41
69
|
HEAD_NONE,
|
|
42
70
|
type SpanCommit,
|
|
@@ -46,7 +74,10 @@ import {
|
|
|
46
74
|
previous_release_tag,
|
|
47
75
|
stale_draft_labels,
|
|
48
76
|
} from './_lib/release_highlights.js';
|
|
49
|
-
import {
|
|
77
|
+
import {
|
|
78
|
+
CURATED_HEAD_INSTRUCTION,
|
|
79
|
+
extract_changelog_section,
|
|
80
|
+
} from './_lib/release_material.js';
|
|
50
81
|
import { assertScanned, assertWatchlistResolves, DeadScopeError } from './_lib/scan_scope.js';
|
|
51
82
|
|
|
52
83
|
const _HERE = fileURLToPath(import.meta.url);
|
|
@@ -116,9 +147,17 @@ export function highlight_contradictions(
|
|
|
116
147
|
|
|
117
148
|
/**
|
|
118
149
|
* Exported so the advisory-vs-blocking decision is a fixture, not a claim.
|
|
150
|
+
*
|
|
151
|
+
* CORRECTED 2026-09-01 with the reversal. This comment used to say that
|
|
119
152
|
* `stale_draft_labels` firing while the exit code stays 0 is the behaviour the
|
|
120
|
-
* cadence blocker adjudicates
|
|
121
|
-
*
|
|
153
|
+
* cadence blocker adjudicates. That is no longer what happens — the branch at
|
|
154
|
+
* the call site returns 1 — and the sentence is replaced rather than deleted
|
|
155
|
+
* because it was the load-bearing claim on the other side.
|
|
156
|
+
*
|
|
157
|
+
* What it got RIGHT is worth keeping: the decision was a one-line diff with a
|
|
158
|
+
* test that notices, and the reversal proved it. The two fixtures that pinned
|
|
159
|
+
* the advisory branch were updated in place, not deleted, so the change of
|
|
160
|
+
* contract reads off the diff.
|
|
122
161
|
*/
|
|
123
162
|
export function main(argv: readonly string[]): number {
|
|
124
163
|
let version: string | null = null;
|
|
@@ -171,6 +210,33 @@ export function main(argv: readonly string[]): number {
|
|
|
171
210
|
process.stderr.write(`CHANGELOG carries no section for ${version}\n`);
|
|
172
211
|
return 2;
|
|
173
212
|
}
|
|
213
|
+
// A LEAKED AUTHORING INSTRUCTION REFUSES THE RELEASE (roadmap § 2.2).
|
|
214
|
+
//
|
|
215
|
+
// A different mechanism from the marker check below: that one catches an
|
|
216
|
+
// unpolished claim, this one catches a reminder to the releaser that was
|
|
217
|
+
// never meant to be release content at all. `CHANGELOG.md` is the bare
|
|
218
|
+
// entry in `package.json` `files`, so a comment surviving here is
|
|
219
|
+
// published to npm — it did, twice, before Option A stopped the writer
|
|
220
|
+
// emitting it.
|
|
221
|
+
//
|
|
222
|
+
// SAME SCOPE as the marker check, and for the same reason: `section` is
|
|
223
|
+
// the ONE section `extract_changelog_section` cut for `--version`. A
|
|
224
|
+
// historical section carrying the identical comment is not read here and
|
|
225
|
+
// does not block this release. Detection is the named sentinel, never a
|
|
226
|
+
// shape match over comment prose.
|
|
227
|
+
if (section.body.includes(CURATED_HEAD_INSTRUCTION)) {
|
|
228
|
+
process.stderr.write(
|
|
229
|
+
`❌ the ${version} section still carries the generator's authoring instruction ` +
|
|
230
|
+
`(\`${CURATED_HEAD_INSTRUCTION}\`).\n` +
|
|
231
|
+
' It is a reminder to the releaser, not release content, and CHANGELOG.md ' +
|
|
232
|
+
'is published to npm.\n' +
|
|
233
|
+
` Delete that comment line from the ${version} section. Only that section is ` +
|
|
234
|
+
'read; historical\n' +
|
|
235
|
+
' sections carrying the same comment are out of scope and do not block this ' +
|
|
236
|
+
'release.\n',
|
|
237
|
+
);
|
|
238
|
+
return 1;
|
|
239
|
+
}
|
|
174
240
|
const curated = parse_curated_head(section.body);
|
|
175
241
|
if (!curated) {
|
|
176
242
|
process.stdout.write(`ℹ️ no curated head in the ${version} section — nothing to check\n`);
|
|
@@ -199,17 +265,34 @@ export function main(argv: readonly string[]): number {
|
|
|
199
265
|
'could contradict. Deleting the scan root is not the same state — that is the ' +
|
|
200
266
|
'throwing branch, not this one.',
|
|
201
267
|
});
|
|
202
|
-
// A generator-derived line that nobody rewrote
|
|
203
|
-
//
|
|
204
|
-
//
|
|
205
|
-
// `_none_` check
|
|
206
|
-
//
|
|
268
|
+
// A generator-derived line that nobody rewrote REFUSES the release.
|
|
269
|
+
//
|
|
270
|
+
// REVERSED 2026-09-01. This block used to warn and return the exit code to
|
|
271
|
+
// the `_none_` check alone, on the reasoning that a derived line is true
|
|
272
|
+
// and merely unpolished. The reasoning still holds and the conclusion does
|
|
273
|
+
// not: the warning was emitted and ignored through five consecutive
|
|
274
|
+
// released sections. See this file's header for the full record and the
|
|
275
|
+
// instructing authority.
|
|
276
|
+
//
|
|
277
|
+
// SCOPE, and it is the load-bearing half (roadmap § 1.3): `curated` comes
|
|
278
|
+
// from `parse_curated_head(section.body)` above, and `section` is the ONE
|
|
279
|
+
// section `extract_changelog_section` cut for `--version`. No read here
|
|
280
|
+
// reaches another section, another era file, or `docs/archive/`. That is
|
|
281
|
+
// what keeps eighteen historical marker lines from turning this into a
|
|
282
|
+
// permanent red on every future release.
|
|
207
283
|
const drafts = stale_draft_labels(curated);
|
|
208
284
|
if (drafts.length > 0) {
|
|
209
|
-
process.
|
|
210
|
-
|
|
211
|
-
`${drafts.join(', ')}
|
|
285
|
+
process.stderr.write(
|
|
286
|
+
`❌ unrewritten auto-derived head line(s) in the ${version} section: ` +
|
|
287
|
+
`${drafts.join(', ')}\n` +
|
|
288
|
+
` Each still carries \`${DERIVED_MARKER}\` — the generator's draft, not a ` +
|
|
289
|
+
'curated claim.\n' +
|
|
290
|
+
` Rewrite those line(s) in the ${version} section of the changelog. Only that ` +
|
|
291
|
+
'section is read;\n' +
|
|
292
|
+
' historical sections carrying the same marker are out of scope and do not ' +
|
|
293
|
+
'block this release.\n',
|
|
212
294
|
);
|
|
295
|
+
return 1;
|
|
213
296
|
}
|
|
214
297
|
const derived = derive_categories(span);
|
|
215
298
|
const contradictions = highlight_contradictions(curated, derived);
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
* (Python-only); these pure regex/parse helpers are replicated here
|
|
16
16
|
* byte-for-byte from that module. Keep in lock-step with it.
|
|
17
17
|
*
|
|
18
|
-
* Every non-draft file under `agents/roadmaps/` (excluding `archive/`,
|
|
18
|
+
* Every non-draft file under `agents/roadmaps/` (excluding `archive/`, code-comment-allow provenance-comment -- the path is this script's operand, not where the code came from
|
|
19
19
|
* `skipped/`, template/README/open-questions) MUST:
|
|
20
20
|
* 1. Be parseable by the dashboard's `PHASE_RE` (>= one `## Phase <id>`).
|
|
21
21
|
* 2. Have at least one trackable checkbox under every parsed phase.
|
|
@@ -49,6 +49,15 @@ const PHASE_RE =
|
|
|
49
49
|
// FRONTMATTER_RE = re.compile(r"\A---\n(.*?)\n---\s*\n", re.DOTALL)
|
|
50
50
|
const FRONTMATTER_RE = /^---\n([\s\S]*?)\n---\s*\n/;
|
|
51
51
|
const DRAFT_VALUES: ReadonlySet<string> = new Set(['draft']);
|
|
52
|
+
/**
|
|
53
|
+
* A carrier holds obligations deferred out of an archived parent. It is not
|
|
54
|
+
* schedulable work — every item in it has an unmet resumption trigger — and it
|
|
55
|
+
* has no `## Phase` headings by construction, so it is skipped exactly where a
|
|
56
|
+
* draft is. It differs from a draft in what protects it: a draft may be deleted
|
|
57
|
+
* freely, a carrier may not, and `lint_carrier_integrity` reds when one loses
|
|
58
|
+
* its receiver.
|
|
59
|
+
*/
|
|
60
|
+
const CARRIER_VALUES: ReadonlySet<string> = new Set(['carrier']);
|
|
52
61
|
|
|
53
62
|
const EXCLUDE_NAMES: ReadonlySet<string> = new Set([
|
|
54
63
|
'template.md',
|
|
@@ -92,6 +101,11 @@ function is_draft(fm: Map<string, string>): boolean {
|
|
|
92
101
|
return DRAFT_VALUES.has((fm.get('status') ?? '').toLowerCase());
|
|
93
102
|
}
|
|
94
103
|
|
|
104
|
+
/** True for a `status: carrier` roadmap — see CARRIER_VALUES. */
|
|
105
|
+
function is_carrier(fm: Map<string, string>): boolean {
|
|
106
|
+
return CARRIER_VALUES.has((fm.get('status') ?? '').toLowerCase());
|
|
107
|
+
}
|
|
108
|
+
|
|
95
109
|
/** Mirror update_roadmap_progress.is_roadmap_candidate (POSIX path parts). */
|
|
96
110
|
function is_roadmap_candidate(p: string): boolean {
|
|
97
111
|
const name = path.basename(p);
|
|
@@ -168,7 +182,7 @@ function find_active_roadmaps(root: string): string[] {
|
|
|
168
182
|
continue;
|
|
169
183
|
}
|
|
170
184
|
const text = fs.readFileSync(p, 'utf-8');
|
|
171
|
-
if (is_draft(parse_frontmatter(text))) {
|
|
185
|
+
if (is_draft(parse_frontmatter(text)) || is_carrier(parse_frontmatter(text))) {
|
|
172
186
|
continue;
|
|
173
187
|
}
|
|
174
188
|
out.push(p);
|
|
@@ -345,6 +359,7 @@ export {
|
|
|
345
359
|
CHECKBOX_RE,
|
|
346
360
|
PHASE_RE,
|
|
347
361
|
is_draft,
|
|
362
|
+
is_carrier,
|
|
348
363
|
is_roadmap_candidate,
|
|
349
364
|
parse_frontmatter,
|
|
350
365
|
find_active_roadmaps,
|
|
@@ -0,0 +1,316 @@
|
|
|
1
|
+
#!/usr/bin/env tsx
|
|
2
|
+
/**
|
|
3
|
+
* Provenance-declaration gate for the security and safety floors.
|
|
4
|
+
*
|
|
5
|
+
* WHY THIS SCOPE AND NOT ALL 120 RULES. `src/rules/code-provenance.md`
|
|
6
|
+
* § The knowledge layer states the obligation for prose: an artefact asserting
|
|
7
|
+
* an externally-sourced claim either cites it or labels the statement as own
|
|
8
|
+
* analysis, and "silence is neither". That rule also says plainly that nothing
|
|
9
|
+
* enforces it — `lint_harvest_provenance` validates the harvest ledger's own
|
|
10
|
+
* rows and "cannot see a claim nobody recorded". This gate is the structural
|
|
11
|
+
* half for the surface where an unsourced normative claim costs the most.
|
|
12
|
+
*
|
|
13
|
+
* road-to-retired-claims-stay-retired Phase 3.2. The roadmap picked the ten
|
|
14
|
+
* deliberately: holding all 120 at once is the strict-gate-fires-on-everything
|
|
15
|
+
* failure this repository has recorded before, and the ten are the rules whose
|
|
16
|
+
* normative content most plausibly came from outside.
|
|
17
|
+
*
|
|
18
|
+
* WHAT IT CHECKS. Each in-scope rule carries an `evidence:` block with
|
|
19
|
+
* `source_type`, `verified_on` and `normative_level`. The block's SHAPE —
|
|
20
|
+
* enums, the date pattern, unknown keys — is `rule.schema.json`'s job via
|
|
21
|
+
* `validate_frontmatter`, and is deliberately not duplicated here: two
|
|
22
|
+
* validators for one shape drift, and the schema is the one a rule author
|
|
23
|
+
* already runs. This gate owns PRESENCE within a declared scope, which the
|
|
24
|
+
* schema cannot express because the block is optional everywhere else.
|
|
25
|
+
*
|
|
26
|
+
* THE SCOPE IS A LIST, AND THAT IS THE POINT. There is no frontmatter marker
|
|
27
|
+
* that delimits "security and safety floor" — measured 2026-08-30, the ten
|
|
28
|
+
* span three tiers (`2a`, `2b`, `safety-floor`), two `type` values and three
|
|
29
|
+
* pack sets, and `packs: [engineering-base]` also holds rules that are not
|
|
30
|
+
* safety floors. Deriving the scope from a proxy would silently admit and drop
|
|
31
|
+
* rules as unrelated frontmatter moved. An explicit list is reviewable, and a
|
|
32
|
+
* rule joining it is a decision somebody makes rather than a side effect.
|
|
33
|
+
*
|
|
34
|
+
* Exit codes: 0 = every in-scope rule declares · 1 = a declaration is missing
|
|
35
|
+
* or the scope is dead · 2 = usage error.
|
|
36
|
+
*
|
|
37
|
+
* Usage:
|
|
38
|
+
* ./scripts-run src/scripts/check_rule_evidence_declaration
|
|
39
|
+
* ./scripts-run src/scripts/check_rule_evidence_declaration --root <dir>
|
|
40
|
+
* ./scripts-run src/scripts/check_rule_evidence_declaration --self-test
|
|
41
|
+
*/
|
|
42
|
+
import * as fs from 'node:fs';
|
|
43
|
+
import * as os from 'node:os';
|
|
44
|
+
import * as path from 'node:path';
|
|
45
|
+
import { fileURLToPath } from 'node:url';
|
|
46
|
+
|
|
47
|
+
import { runSelfTest, type SelfTestCase } from './_lib/gate_self_test.js';
|
|
48
|
+
import { assertWatchlistResolves, DeadScopeError, reportScanned } from './_lib/scan_scope.js';
|
|
49
|
+
|
|
50
|
+
const _FILE = fileURLToPath(import.meta.url);
|
|
51
|
+
const REPO_ROOT = path.resolve(path.dirname(_FILE), '..', '..');
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* The declared scope, with the reason each row is in it.
|
|
55
|
+
*
|
|
56
|
+
* Growing this list is the intended way to widen the obligation: adding a row
|
|
57
|
+
* makes the gate fail until that rule declares, which is exactly the
|
|
58
|
+
* "an eleventh rule added without one fails" behaviour the roadmap asked for.
|
|
59
|
+
*/
|
|
60
|
+
export const SCOPE: ReadonlyArray<{ rule: string; why: string }> = [
|
|
61
|
+
{ rule: 'security-sensitive-stop', why: 'gates every edit to an auth / tenancy / billing / secrets surface' },
|
|
62
|
+
{ rule: 'untrusted-input-defense', why: 'the data-not-instructions boundary; cites OWASP LLM01' },
|
|
63
|
+
{ rule: 'lethal-trifecta-guard', why: 'the three-leg exfiltration shape; cites the OWASP ASI list' },
|
|
64
|
+
{ rule: 'secret-vcs-guard', why: 'the last gate before a credential reaches history' },
|
|
65
|
+
{ rule: 'broken-access-control', why: 'cites OWASP A01:2021 and BOLA/IDOR, and GDPR exposure' },
|
|
66
|
+
{ rule: 'tool-safety', why: 'Least Agency; cites OWASP ASI excessive-agency and LLM06' },
|
|
67
|
+
{ rule: 'domain-safety-pii', why: 'cites GDPR, CCPA, HIPAA, EEO and a k-anonymity figure' },
|
|
68
|
+
// NOT `non-destructive-by-default`, and the reason is a real constraint on
|
|
69
|
+
// this scope rather than a preference. That rule is `type: "always"`, so its
|
|
70
|
+
// bytes are charged to the kernel budget: adding the four-line block moved
|
|
71
|
+
// it 9,657 -> 9,752 chars and breached `check_always_budget`'s top-3 cap
|
|
72
|
+
// (37,948 > 37,855). An optional frontmatter block is not free on an
|
|
73
|
+
// always-rule, and trimming a kernel rule to make room is a maintainer
|
|
74
|
+
// decision this gate has no business forcing. `domain-safety-retention`
|
|
75
|
+
// takes the slot: same class, `type: "auto"`, and its normative content is
|
|
76
|
+
// more externally sourced than most (GDPR Art. 17, tax and VAT floors).
|
|
77
|
+
{ rule: 'domain-safety-retention', why: 'cites GDPR Art. 17 plus tax and VAT retention floors by jurisdiction' },
|
|
78
|
+
{ rule: 'engineering-safety-floor', why: 'the production / infra / bulk-destructive floor' },
|
|
79
|
+
{ rule: 'code-provenance', why: 'states the knowledge-layer obligation this gate enforces' },
|
|
80
|
+
];
|
|
81
|
+
|
|
82
|
+
/** Keys every declaration must carry, per rule.schema.json. */
|
|
83
|
+
const REQUIRED_KEYS = ['source_type'] as const;
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* `normative_level` is required only where an external source exists.
|
|
87
|
+
*
|
|
88
|
+
* It states how binding the SOURCE is. For `own-analysis` there is no external
|
|
89
|
+
* source, so the field answers a question that does not arise and `informative`
|
|
90
|
+
* is its only coherent value — requiring it there forces a non-answer. The
|
|
91
|
+
* schema draws the same line with an `if`/`then`, and the two are kept in step
|
|
92
|
+
* deliberately rather than one being inferred from the other: a gate that
|
|
93
|
+
* enforced more than the schema would reject a rule the schema accepts.
|
|
94
|
+
*/
|
|
95
|
+
const OWN_ANALYSIS = 'own-analysis';
|
|
96
|
+
|
|
97
|
+
export interface Finding {
|
|
98
|
+
rule: string;
|
|
99
|
+
reason: string;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/** Extract the frontmatter block of a markdown file, or `null`. */
|
|
103
|
+
function frontmatter(body: string): string | null {
|
|
104
|
+
if (!body.startsWith('---\n')) return null;
|
|
105
|
+
const end = body.indexOf('\n---', 3);
|
|
106
|
+
if (end === -1) return null;
|
|
107
|
+
return body.slice(4, end + 1);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* The `evidence:` mapping's own lines, or `null` when the key is absent.
|
|
112
|
+
*
|
|
113
|
+
* Deliberately a line scan rather than a YAML parse: this gate runs on every
|
|
114
|
+
* `task ci`, the schema validator already parses the same file properly, and a
|
|
115
|
+
* second parser is a second thing that can disagree about the first.
|
|
116
|
+
*/
|
|
117
|
+
export function evidenceLines(fm: string): string[] | null {
|
|
118
|
+
const lines = fm.split('\n');
|
|
119
|
+
const start = lines.findIndex((l) => /^evidence:\s*$/.test(l));
|
|
120
|
+
if (start === -1) return null;
|
|
121
|
+
const out: string[] = [];
|
|
122
|
+
for (const line of lines.slice(start + 1)) {
|
|
123
|
+
if (line.trim() === '') continue;
|
|
124
|
+
if (!/^\s+\S/.test(line)) break; // dedented — the block ended
|
|
125
|
+
out.push(line);
|
|
126
|
+
}
|
|
127
|
+
return out;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
export function analyse(root = REPO_ROOT): Finding[] {
|
|
131
|
+
const findings: Finding[] = [];
|
|
132
|
+
for (const { rule } of SCOPE) {
|
|
133
|
+
const abs = path.join(root, 'src', 'rules', `${rule}.md`);
|
|
134
|
+
let body: string;
|
|
135
|
+
try {
|
|
136
|
+
body = fs.readFileSync(abs, 'utf8');
|
|
137
|
+
} catch {
|
|
138
|
+
findings.push({ rule, reason: 'in scope but the rule file does not exist — remove the row or restore the rule' });
|
|
139
|
+
continue;
|
|
140
|
+
}
|
|
141
|
+
const fm = frontmatter(body);
|
|
142
|
+
if (fm === null) {
|
|
143
|
+
findings.push({ rule, reason: 'no frontmatter block' });
|
|
144
|
+
continue;
|
|
145
|
+
}
|
|
146
|
+
const block = evidenceLines(fm);
|
|
147
|
+
if (block === null) {
|
|
148
|
+
findings.push({
|
|
149
|
+
rule,
|
|
150
|
+
reason:
|
|
151
|
+
'carries no `evidence:` block — state where its normative content came from, ' +
|
|
152
|
+
'or record `source_type: own-analysis`, which is a complete discharge',
|
|
153
|
+
});
|
|
154
|
+
continue;
|
|
155
|
+
}
|
|
156
|
+
const has = (key: string): boolean =>
|
|
157
|
+
block.some((l) => new RegExp(`^\\s+${key}:\\s*\\S`).test(l));
|
|
158
|
+
for (const key of REQUIRED_KEYS) {
|
|
159
|
+
if (!has(key)) findings.push({ rule, reason: `evidence block is missing \`${key}\`` });
|
|
160
|
+
}
|
|
161
|
+
const ownAnalysis = block.some((l) => l.includes(`source_type: ${OWN_ANALYSIS}`));
|
|
162
|
+
if (!ownAnalysis && has('source_type')) {
|
|
163
|
+
for (const key of ['normative_level', 'verified_on'] as const) {
|
|
164
|
+
if (has(key)) continue;
|
|
165
|
+
findings.push({
|
|
166
|
+
rule,
|
|
167
|
+
reason:
|
|
168
|
+
`evidence block names an external source but no \`${key}\` — both are real ` +
|
|
169
|
+
'questions wherever a source exists, and neither is where one does not',
|
|
170
|
+
});
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
return findings;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
function runGate(root: string): number {
|
|
178
|
+
try {
|
|
179
|
+
assertWatchlistResolves({
|
|
180
|
+
gate: 'check_rule_evidence_declaration',
|
|
181
|
+
candidates: SCOPE.map((s) => `src/rules/${s.rule}.md`),
|
|
182
|
+
repoRoot: root,
|
|
183
|
+
});
|
|
184
|
+
} catch (exc) {
|
|
185
|
+
if (!(exc instanceof DeadScopeError)) throw exc;
|
|
186
|
+
process.stderr.write(`❌ ${exc.message}\n`);
|
|
187
|
+
return 1;
|
|
188
|
+
}
|
|
189
|
+
reportScanned({
|
|
190
|
+
gate: 'check_rule_evidence_declaration',
|
|
191
|
+
scanned: SCOPE.length,
|
|
192
|
+
units: 'in-scope rule(s)',
|
|
193
|
+
roots: ['src/rules/'],
|
|
194
|
+
});
|
|
195
|
+
const findings = analyse(root);
|
|
196
|
+
if (findings.length > 0) {
|
|
197
|
+
process.stderr.write(
|
|
198
|
+
`❌ check_rule_evidence_declaration: ${String(findings.length)} finding(s):\n`,
|
|
199
|
+
);
|
|
200
|
+
for (const f of findings) process.stderr.write(` src/rules/${f.rule}.md — ${f.reason}\n`);
|
|
201
|
+
process.stderr.write(
|
|
202
|
+
' → the block is documented at `evidence` in src/scripts/schemas/rule.schema.json.\n',
|
|
203
|
+
);
|
|
204
|
+
return 1;
|
|
205
|
+
}
|
|
206
|
+
process.stdout.write(
|
|
207
|
+
`✅ check_rule_evidence_declaration: ${String(SCOPE.length)} security/safety rule(s) declare their provenance.\n`,
|
|
208
|
+
);
|
|
209
|
+
return 0;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
function selfTest(): number {
|
|
213
|
+
const roots: string[] = [];
|
|
214
|
+
const fixture = (frontmatterBody: string, rules = [SCOPE[0]!.rule]): number => {
|
|
215
|
+
const dir = fs.mkdtempSync(path.join(os.tmpdir(), 'rule-evidence-'));
|
|
216
|
+
roots.push(dir);
|
|
217
|
+
fs.mkdirSync(path.join(dir, 'src', 'rules'), { recursive: true });
|
|
218
|
+
// Every in-scope rule must exist or the run fails for the wrong reason;
|
|
219
|
+
// the ones not under test get a well-formed block.
|
|
220
|
+
const good = ['evidence:', ' source_type: own-analysis'].join('\n');
|
|
221
|
+
for (const { rule } of SCOPE) {
|
|
222
|
+
const fm = rules.includes(rule) ? frontmatterBody : good;
|
|
223
|
+
fs.writeFileSync(
|
|
224
|
+
path.join(dir, 'src', 'rules', `${rule}.md`),
|
|
225
|
+
`---\ntype: "auto"\n${fm}\n---\n\n# ${rule}\n`,
|
|
226
|
+
);
|
|
227
|
+
}
|
|
228
|
+
return runGate(dir);
|
|
229
|
+
};
|
|
230
|
+
|
|
231
|
+
const EXT = ['evidence:', ' source_type: external-standard', ' verified_on: 2026-08-30', ' normative_level: recommended'];
|
|
232
|
+
const OWN = ['evidence:', ' source_type: own-analysis'];
|
|
233
|
+
|
|
234
|
+
const cases: SelfTestCase[] = [
|
|
235
|
+
{
|
|
236
|
+
name: 'every in-scope rule declares → accept',
|
|
237
|
+
expect: 'accept',
|
|
238
|
+
run: () => fixture(EXT.join('\n')),
|
|
239
|
+
},
|
|
240
|
+
{
|
|
241
|
+
name: 'an in-scope rule with NO evidence block → reject',
|
|
242
|
+
expect: 'reject',
|
|
243
|
+
run: () => fixture('description: "a rule with no provenance"'),
|
|
244
|
+
},
|
|
245
|
+
{
|
|
246
|
+
// The conditional rule, in the direction that must REJECT: an
|
|
247
|
+
// external source is named, so how binding it is and when it was
|
|
248
|
+
// last checked are both real questions.
|
|
249
|
+
name: 'an external-source block missing normative_level → reject',
|
|
250
|
+
expect: 'reject',
|
|
251
|
+
run: () => fixture(['evidence:', ' source_type: external-standard', ' verified_on: 2026-08-30'].join('\n')),
|
|
252
|
+
},
|
|
253
|
+
{
|
|
254
|
+
name: 'an external-source block missing verified_on → reject',
|
|
255
|
+
expect: 'reject',
|
|
256
|
+
run: () => fixture(['evidence:', ' source_type: external-standard', ' normative_level: recommended'].join('\n')),
|
|
257
|
+
},
|
|
258
|
+
{
|
|
259
|
+
name: 'a source_type present but valueless → reject',
|
|
260
|
+
expect: 'reject',
|
|
261
|
+
run: () => fixture(['evidence:', ' source_type:'].join('\n')),
|
|
262
|
+
},
|
|
263
|
+
{
|
|
264
|
+
// The same shape in the direction that must ACCEPT. `own-analysis`
|
|
265
|
+
// names no external source, so neither field has a question to
|
|
266
|
+
// answer — requiring them there would force a non-answer, and a
|
|
267
|
+
// gate that rejected this would reject what the schema accepts.
|
|
268
|
+
name: 'an own-analysis block with neither field → accept',
|
|
269
|
+
expect: 'accept',
|
|
270
|
+
run: () => fixture(OWN.join('\n')),
|
|
271
|
+
},
|
|
272
|
+
];
|
|
273
|
+
|
|
274
|
+
try {
|
|
275
|
+
return runSelfTest({
|
|
276
|
+
gate: 'check_rule_evidence_declaration',
|
|
277
|
+
cases,
|
|
278
|
+
minCases: 6,
|
|
279
|
+
minRejectCases: 4,
|
|
280
|
+
});
|
|
281
|
+
} finally {
|
|
282
|
+
for (const d of roots) fs.rmSync(d, { recursive: true, force: true });
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
export function main(argv: string[] = process.argv.slice(2)): number {
|
|
287
|
+
if (argv.includes('--self-test')) return selfTest();
|
|
288
|
+
let root = REPO_ROOT;
|
|
289
|
+
for (let i = 0; i < argv.length; i += 1) {
|
|
290
|
+
const a = argv[i]!;
|
|
291
|
+
if (a === '--root') {
|
|
292
|
+
const v = argv[i + 1];
|
|
293
|
+
if (v === undefined) {
|
|
294
|
+
process.stderr.write('check_rule_evidence_declaration: --root needs a directory\n');
|
|
295
|
+
return 2;
|
|
296
|
+
}
|
|
297
|
+
root = path.resolve(v);
|
|
298
|
+
i += 1;
|
|
299
|
+
} else if (a === '--quiet') {
|
|
300
|
+
continue;
|
|
301
|
+
} else if (a === '-h' || a === '--help') {
|
|
302
|
+
process.stdout.write(
|
|
303
|
+
'usage: check_rule_evidence_declaration [--root DIR] [--quiet] [--self-test]\n',
|
|
304
|
+
);
|
|
305
|
+
return 0;
|
|
306
|
+
} else {
|
|
307
|
+
process.stderr.write(`check_rule_evidence_declaration: unrecognized argument: ${a}\n`);
|
|
308
|
+
return 2;
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
return runGate(root);
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
if (process.argv[1] !== undefined && process.argv[1].includes('check_rule_evidence_declaration')) {
|
|
315
|
+
process.exit(main());
|
|
316
|
+
}
|
|
@@ -6,10 +6,20 @@
|
|
|
6
6
|
* WHY THIS GATE EXISTS (road-to-conformance-round5 Phase 1, measured 2026-08-07)
|
|
7
7
|
* ---------------------------------------------------------------------------
|
|
8
8
|
* `docs/contracts/rule-router.md` (§ "The router earns its place as a
|
|
9
|
-
* **compile-time** artifact"
|
|
10
|
-
* `
|
|
11
|
-
*
|
|
12
|
-
*
|
|
9
|
+
* **compile-time** artifact") states that under every shipped default nothing
|
|
10
|
+
* loads `dist/router.json` at runtime, so **projection is the only reach
|
|
11
|
+
* mechanism there is**:
|
|
12
|
+
*
|
|
13
|
+
* CORRECTED 2026-08-26. This docblock used to cite that section's "measured:
|
|
14
|
+
* zero consumers under `src/scripts/hooks/`", and that measurement is stale: the
|
|
15
|
+
* `rule-inject` concern reads the router via `_lib/rule_injection.ts:76-79` and
|
|
16
|
+
* is bound on three slots. The gate's rationale survives the correction because
|
|
17
|
+
* the concern is DEFAULT-OFF and returns before reading the router unless
|
|
18
|
+
* `lean_projection.mode: delivery` is set — so on a shipped default, projection
|
|
19
|
+
* IS still the only reach mechanism. What no longer holds is the stronger claim
|
|
20
|
+
* that no such mechanism exists. Stated here rather than quietly re-worded,
|
|
21
|
+
* because a gate whose stated reason rests on a refuted premise is exactly the
|
|
22
|
+
* decoration ADR-127 rejects: a non-kernel rule activates by the model's judgment over text
|
|
13
23
|
* already in context, and the per-tool rule tree is what puts it there. That
|
|
14
24
|
* makes the state of the projection load-bearing, and it was broken:
|
|
15
25
|
*
|
|
@@ -63,6 +63,7 @@ import { fileURLToPath, pathToFileURL } from 'node:url';
|
|
|
63
63
|
import * as os from 'node:os';
|
|
64
64
|
import { parse as parseYaml } from 'yaml';
|
|
65
65
|
import { runGateCli, runSelfTest, type SelfTestCase } from './_lib/gate_self_test.js';
|
|
66
|
+
import { GateLedger } from './_lib/gate_ledger.js';
|
|
66
67
|
|
|
67
68
|
const _FILE = fileURLToPath(import.meta.url);
|
|
68
69
|
const REPO = path.resolve(path.dirname(_FILE), '..', '..');
|
|
@@ -323,37 +324,57 @@ export function checkRubric(rubric: Row, rowCount: number, ids: string[]): Findi
|
|
|
323
324
|
|
|
324
325
|
/* ── driver ────────────────────────────────────────────────────────────────── */
|
|
325
326
|
|
|
326
|
-
export function check(rel: string): Finding[] {
|
|
327
|
+
export function check(rel: string, ledger?: GateLedger): Finding[] {
|
|
327
328
|
// An absolute `--file` must be honoured as given. path.join(REPO, '/abs')
|
|
328
329
|
// silently produces REPO + '/abs', which reports `missing_file` for a file
|
|
329
330
|
// that exists — the shape a test using a temp copy hits first.
|
|
330
331
|
const abs = path.isAbsolute(rel) ? rel : path.join(REPO, rel);
|
|
331
332
|
if (!fs.existsSync(abs)) {
|
|
333
|
+
ledger?.plan([rel]);
|
|
334
|
+
ledger?.fail(rel, 'scorecard does not exist');
|
|
332
335
|
return [{ where: rel, code: 'missing_file', detail: 'scorecard does not exist' }];
|
|
333
336
|
}
|
|
334
337
|
let doc: unknown;
|
|
335
338
|
try {
|
|
336
339
|
doc = parseYaml(fs.readFileSync(abs, 'utf8'));
|
|
337
340
|
} catch (exc) {
|
|
341
|
+
ledger?.plan([rel]);
|
|
342
|
+
ledger?.fail(rel, 'unparseable YAML');
|
|
338
343
|
return [{ where: rel, code: 'unparseable', detail: String(exc) }];
|
|
339
344
|
}
|
|
340
345
|
if (doc === null || typeof doc !== 'object') {
|
|
346
|
+
ledger?.plan([rel]);
|
|
347
|
+
ledger?.fail(rel, 'top level is not a mapping');
|
|
341
348
|
return [{ where: rel, code: 'unparseable', detail: 'top level is not a mapping' }];
|
|
342
349
|
}
|
|
343
350
|
const top = doc as Row;
|
|
344
351
|
const rubric = top['rubric'];
|
|
345
352
|
const cats = top['categories'];
|
|
346
353
|
if (rubric === undefined || typeof rubric !== 'object' || rubric === null) {
|
|
354
|
+
ledger?.plan([rel]);
|
|
355
|
+
ledger?.fail(rel, 'no `rubric:` block');
|
|
347
356
|
return [{ where: rel, code: 'missing_field', detail: 'no `rubric:` block' }];
|
|
348
357
|
}
|
|
349
358
|
if (!Array.isArray(cats)) {
|
|
359
|
+
ledger?.plan([rel]);
|
|
360
|
+
ledger?.fail(rel, '`categories:` must be a list');
|
|
350
361
|
return [{ where: rel, code: 'missing_field', detail: '`categories:` must be a list' }];
|
|
351
362
|
}
|
|
352
363
|
const rows = cats as Row[];
|
|
353
364
|
const ids = rows.map((r) => String(r['category'] ?? '<unnamed>'));
|
|
365
|
+
// Per-row accounting. Every early return above aborts BEFORE any row is
|
|
366
|
+
// read, and until this ledger existed those aborts produced a one-line
|
|
367
|
+
// finding indistinguishable, in the coverage record, from a full pass over
|
|
368
|
+
// 23 rows. The ledger separates "checked every row and found one problem"
|
|
369
|
+
// from "never reached a row".
|
|
370
|
+
ledger?.plan(ids.map((id, i) => `${id}#${String(i)}`));
|
|
354
371
|
const findings = [...checkRubric(rubric as Row, rows.length, ids)];
|
|
355
372
|
rows.forEach((r, i) => {
|
|
356
|
-
|
|
373
|
+
const target = `${ids[i] ?? '<unnamed>'}#${String(i)}`;
|
|
374
|
+
const rowFindings = checkRow(r, `${rel} → ${ids[i] ?? `row ${i}`}`);
|
|
375
|
+
findings.push(...rowFindings);
|
|
376
|
+
if (rowFindings.length > 0) ledger?.fail(target, `${String(rowFindings.length)} finding(s)`);
|
|
377
|
+
else ledger?.complete(target);
|
|
357
378
|
});
|
|
358
379
|
return findings;
|
|
359
380
|
}
|
|
@@ -450,7 +471,9 @@ export function main(argv: readonly string[] = process.argv.slice(2)): number {
|
|
|
450
471
|
process.stderr.write('usage: check_score_contract [--quiet] [--file <path>]\n');
|
|
451
472
|
return 2;
|
|
452
473
|
}
|
|
453
|
-
const
|
|
474
|
+
const ledger = new GateLedger('check_score_contract');
|
|
475
|
+
const findings = check(rel, ledger);
|
|
476
|
+
ledger.report(quiet ? () => undefined : undefined);
|
|
454
477
|
// Rule 1 of the gate-coverage contract: exactly one `scanned: <N>` line,
|
|
455
478
|
// emitted on the red path too — a gate that only reports coverage when it
|
|
456
479
|
// passes cannot be caught going blind at the moment it matters.
|