@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
package/src/scripts/release.ts
CHANGED
|
@@ -126,10 +126,10 @@ import {
|
|
|
126
126
|
} from './_lib/release_highlights.js';
|
|
127
127
|
import {
|
|
128
128
|
NEXT_SECTION_RE,
|
|
129
|
+
RELEASE_HEAD_DEFAULT,
|
|
129
130
|
extract_changelog_section,
|
|
130
131
|
pr_body_from_section,
|
|
131
132
|
release_notes_from_section,
|
|
132
|
-
tag_message_from_section,
|
|
133
133
|
} from './_lib/release_material.js';
|
|
134
134
|
|
|
135
135
|
// `__doc__.splitlines()[0]` in `_parse_args` — the argparse description. Kept
|
|
@@ -144,6 +144,8 @@ import {
|
|
|
144
144
|
AUGMENT_MARKETPLACE_JSON,
|
|
145
145
|
AUGMENT_PLUGIN_JSON,
|
|
146
146
|
CHANGELOG,
|
|
147
|
+
_set_changelog_reader,
|
|
148
|
+
read_changelog_text,
|
|
147
149
|
CalledProcessError,
|
|
148
150
|
GH_PR_BODY_LIMIT,
|
|
149
151
|
GH_RELEASE_NOTES_LIMIT,
|
|
@@ -188,6 +190,8 @@ import {
|
|
|
188
190
|
_tag_exists_local,
|
|
189
191
|
_tag_exists_remote,
|
|
190
192
|
_target_from_branch,
|
|
193
|
+
create_and_push_annotated_tag,
|
|
194
|
+
guard_publication,
|
|
191
195
|
die,
|
|
192
196
|
gh,
|
|
193
197
|
git,
|
|
@@ -269,24 +273,7 @@ const RELEASE_HEAD_SECTIONS: ReadonlyArray<string> = HEAD_LABELS;
|
|
|
269
273
|
* (`_lib/changelog_eras.ts`, 250 lines per era), so an unbounded head would
|
|
270
274
|
* quietly consume it.
|
|
271
275
|
*/
|
|
272
|
-
export
|
|
273
|
-
|
|
274
|
-
/**
|
|
275
|
-
* The fallback value of a head line the span does not substantiate.
|
|
276
|
-
*
|
|
277
|
-
* `_none_` and not a placeholder token: where nothing was derived it is the
|
|
278
|
-
* **true** answer, and a release that genuinely changed no defaults should say
|
|
279
|
-
* so rather than carry an unfilled marker.
|
|
280
|
-
*
|
|
281
|
-
* It is a fallback and no longer a blanket default. Writing `_none_` into
|
|
282
|
-
* every field made the generator assert five things it had not checked, and
|
|
283
|
-
* `check_release_highlights` rejected exactly that assertion the moment the
|
|
284
|
-
* span contradicted it — which for this package is every release, because every
|
|
285
|
-
* release touches `src/rules/` or `src/scripts/schemas/`. Substantiated labels
|
|
286
|
-
* are now pre-filled from the span (`_derive_head_prefill`), so the tool states
|
|
287
|
-
* only what it can support and `_none_` means what it says.
|
|
288
|
-
*/
|
|
289
|
-
const HEAD_DEFAULT = '_none_';
|
|
276
|
+
export { RELEASE_HEAD_CAP_LINES } from './_lib/release_material.js';
|
|
290
277
|
|
|
291
278
|
/**
|
|
292
279
|
* Pre-fill values for the curated head from the release span.
|
|
@@ -313,20 +300,21 @@ function _derive_head_prefill(prev: string | null): Record<string, string> {
|
|
|
313
300
|
/**
|
|
314
301
|
* Render the curated head. Emitted by the generator on every release so it
|
|
315
302
|
* cannot be forgotten; edited by the maintainer before merge.
|
|
303
|
+
*
|
|
304
|
+
* **The authoring instruction is NOT emitted here** (2026-09-01, roadmap
|
|
305
|
+
* `road-to-publication-integrity-hard-fail` § Phase 2, Option A). This writer
|
|
306
|
+
* used to append `CURATED_HEAD_INSTRUCTION`, nothing removed it at release
|
|
307
|
+
* time, and it published twice in `package/CHANGELOG.md`. The reminder now
|
|
308
|
+
* rides in the release-PR body's PR-only region — never published — see
|
|
309
|
+
* `pr_body_from_section` in `_lib/release_material.ts`.
|
|
316
310
|
*/
|
|
317
311
|
export function render_release_head(
|
|
318
312
|
filled: Readonly<Record<string, string>> = {},
|
|
319
313
|
): string[] {
|
|
320
|
-
const lines: string[] = [
|
|
321
|
-
'### Release highlights',
|
|
322
|
-
'',
|
|
323
|
-
'<!-- Curated head: fill before merge, keep it under ' +
|
|
324
|
-
`${RELEASE_HEAD_CAP_LINES} lines, and leave \`${HEAD_DEFAULT}\` where it is ` +
|
|
325
|
-
'genuinely the answer. The generated log below is unchanged. -->',
|
|
326
|
-
];
|
|
314
|
+
const lines: string[] = ['### Release highlights', ''];
|
|
327
315
|
for (const label of RELEASE_HEAD_SECTIONS) {
|
|
328
316
|
const value = (filled[label] ?? '').trim();
|
|
329
|
-
lines.push(`- **${label}:** ${value === '' ?
|
|
317
|
+
lines.push(`- **${label}:** ${value === '' ? RELEASE_HEAD_DEFAULT : value}`);
|
|
330
318
|
}
|
|
331
319
|
return lines;
|
|
332
320
|
}
|
|
@@ -1179,6 +1167,7 @@ function _step(n: number, total: number, msg: string): void {
|
|
|
1179
1167
|
process.stdout.write(`[${n}/${total}] ${msg}\n`);
|
|
1180
1168
|
}
|
|
1181
1169
|
|
|
1170
|
+
|
|
1182
1171
|
function execute(
|
|
1183
1172
|
plan: Plan,
|
|
1184
1173
|
opts: { wait_for_checks: boolean; dry_run: boolean; resume?: boolean; ci?: boolean },
|
|
@@ -1342,7 +1331,7 @@ function execute(
|
|
|
1342
1331
|
// Derive the PR body from the CHANGELOG section step 2 just wrote —
|
|
1343
1332
|
// the file is the single source; the in-memory plan is only its
|
|
1344
1333
|
// author (release-truth Phase 1).
|
|
1345
|
-
const section = extract_changelog_section(
|
|
1334
|
+
const section = extract_changelog_section(read_changelog_text(), plan.target);
|
|
1346
1335
|
if (!section) {
|
|
1347
1336
|
die(`CHANGELOG.md carries no section for ${plan.target} — cannot derive PR body`);
|
|
1348
1337
|
}
|
|
@@ -1388,6 +1377,7 @@ function execute(
|
|
|
1388
1377
|
_step(8, total, `Tag ${plan.target} already on ${REMOTE} — skip`);
|
|
1389
1378
|
} else {
|
|
1390
1379
|
_step(8, total, `Tag ${plan.target} exists locally — push only`);
|
|
1380
|
+
guard_publication(plan.target, 'tag push (resumed)');
|
|
1391
1381
|
_push_tag(plan.target);
|
|
1392
1382
|
}
|
|
1393
1383
|
} else {
|
|
@@ -1398,15 +1388,7 @@ function execute(
|
|
|
1398
1388
|
// tag replaces the previous lightweight one so tag metadata is a
|
|
1399
1389
|
// fourth surface carrying the same single-source content.
|
|
1400
1390
|
_step(8, total, `Tag merge commit (annotated, from merged CHANGELOG) and push ${plan.target}`);
|
|
1401
|
-
|
|
1402
|
-
if (!merged) {
|
|
1403
|
-
die(
|
|
1404
|
-
`CHANGELOG.md on ${MAIN_BRANCH} carries no section for ${plan.target} — ` +
|
|
1405
|
-
'refusing to tag a release whose changelog entry is missing',
|
|
1406
|
-
);
|
|
1407
|
-
}
|
|
1408
|
-
run(['git', 'tag', '-a', plan.target, '-m', tag_message_from_section(merged!.body, plan.target)]);
|
|
1409
|
-
_push_tag(plan.target);
|
|
1391
|
+
create_and_push_annotated_tag(plan.target);
|
|
1410
1392
|
}
|
|
1411
1393
|
|
|
1412
1394
|
// ─── 9. GitHub Release ──────────────────────────────────────────────────
|
|
@@ -1436,6 +1418,7 @@ function execute(
|
|
|
1436
1418
|
GH_RELEASE_NOTES_LIMIT,
|
|
1437
1419
|
'`CHANGELOG.md`',
|
|
1438
1420
|
);
|
|
1421
|
+
guard_publication(plan.target, 'GitHub Release notes');
|
|
1439
1422
|
gh(['release', 'create', plan.target, '--title', plan.target, '--notes', notes]);
|
|
1440
1423
|
|
|
1441
1424
|
// ─── 9b. dispatch-chain the tag-triggered workflows (--ci only) ──────
|
|
@@ -2014,6 +1997,7 @@ export {
|
|
|
2014
1997
|
// Drill seam (release_drill.ts) — the step machinery under a simulated
|
|
2015
1998
|
// git/gh world, so orchestration bugs surface in vitest, not mid-release.
|
|
2016
1999
|
execute,
|
|
2000
|
+
_set_changelog_reader,
|
|
2017
2001
|
_set_exec_override,
|
|
2018
2002
|
push_release_branch,
|
|
2019
2003
|
merge_release_pr,
|
|
@@ -31,11 +31,13 @@ import { fileURLToPath, pathToFileURL } from 'node:url';
|
|
|
31
31
|
|
|
32
32
|
import {
|
|
33
33
|
_MERGE_UPDATE_ROUNDS,
|
|
34
|
+
_set_changelog_reader,
|
|
34
35
|
_set_exec_override,
|
|
35
36
|
execute,
|
|
36
37
|
Plan,
|
|
37
38
|
SystemExitError,
|
|
38
39
|
} from './release.js';
|
|
40
|
+
import { DERIVED_MARKER } from './_lib/release_highlights.js';
|
|
39
41
|
|
|
40
42
|
const _HERE = fileURLToPath(import.meta.url);
|
|
41
43
|
const REPO_ROOT = path.resolve(path.dirname(_HERE), '..', '..');
|
|
@@ -92,6 +94,34 @@ interface WorldConfig {
|
|
|
92
94
|
* removes.
|
|
93
95
|
*/
|
|
94
96
|
changelog?: string;
|
|
97
|
+
/**
|
|
98
|
+
* Content the WORKING-TREE read returns — `read_changelog_text()`, used by
|
|
99
|
+
* step 5 (PR body) and step 8 (annotated-tag message).
|
|
100
|
+
*
|
|
101
|
+
* Added 2026-09-01 with the publication guard (roadmap § 3.1). `changelog`
|
|
102
|
+
* above only covers `git show <tag>:CHANGELOG.md`; the working tree was
|
|
103
|
+
* still the REAL file, whose `14.13.0` section carries four
|
|
104
|
+
* `_auto-derived, rewrite before merge:_` lines. A guard at the tag call
|
|
105
|
+
* site therefore refused every scenario for a reason unrelated to what the
|
|
106
|
+
* scenario tested — the same coupling `changelog` was introduced to
|
|
107
|
+
* remove, on the other read.
|
|
108
|
+
*
|
|
109
|
+
* Defaults to `defaultChangelogFixture(target)`, which is policy-valid by
|
|
110
|
+
* construction.
|
|
111
|
+
*/
|
|
112
|
+
changelog_file?: string;
|
|
113
|
+
/**
|
|
114
|
+
* The tag already exists locally and was never pushed — the § 3.2 resume
|
|
115
|
+
* state, which reached `_push_tag` having read no changelog at all.
|
|
116
|
+
*/
|
|
117
|
+
tag_created_unpushed?: boolean;
|
|
118
|
+
/**
|
|
119
|
+
* The tag is already on the remote, so step 8 skips entirely and step 9 —
|
|
120
|
+
* the GitHub Release body — is the FIRST irreversible transition the run
|
|
121
|
+
* reaches. The only state in which the Release guard can be exercised on
|
|
122
|
+
* its own, because a marker otherwise stops the run at step 8.
|
|
123
|
+
*/
|
|
124
|
+
tag_already_remote?: boolean;
|
|
95
125
|
}
|
|
96
126
|
|
|
97
127
|
/**
|
|
@@ -122,6 +152,21 @@ export function defaultChangelogFixture(target: string): string {
|
|
|
122
152
|
].join('\n');
|
|
123
153
|
}
|
|
124
154
|
|
|
155
|
+
/**
|
|
156
|
+
* `defaultChangelogFixture` with one head line still carrying the generator's
|
|
157
|
+
* draft marker — the exact state five released sections shipped in.
|
|
158
|
+
*
|
|
159
|
+
* Built from `DERIVED_MARKER` rather than from a literal string: a fixture
|
|
160
|
+
* that hardcodes the marker text keeps passing after the marker is renamed,
|
|
161
|
+
* which is a guard policing a population of zero.
|
|
162
|
+
*/
|
|
163
|
+
export function markedChangelogFixture(target: string): string {
|
|
164
|
+
return defaultChangelogFixture(target).replace(
|
|
165
|
+
'- fixture entry for the release drill',
|
|
166
|
+
`### Release highlights\n\n- **Behaviour changes:** ${DERIVED_MARKER} rule/schema diffs in abc1234.\n\n- fixture entry for the release drill`,
|
|
167
|
+
);
|
|
168
|
+
}
|
|
169
|
+
|
|
125
170
|
/**
|
|
126
171
|
* A scriptable stand-in for every git/gh/task command execute() issues.
|
|
127
172
|
* Stateful where the real world is: checkouts move HEAD, `git tag` makes the
|
|
@@ -144,6 +189,8 @@ class FakeWorld {
|
|
|
144
189
|
private merge_fails_hard: boolean;
|
|
145
190
|
private checks_fail: boolean;
|
|
146
191
|
private readonly changelog: string;
|
|
192
|
+
/** Working-tree content; see `WorldConfig.changelog_file`. */
|
|
193
|
+
readonly changelog_file: string;
|
|
147
194
|
|
|
148
195
|
constructor(
|
|
149
196
|
readonly branch: string,
|
|
@@ -152,6 +199,9 @@ class FakeWorld {
|
|
|
152
199
|
) {
|
|
153
200
|
this.push_rejections = cfg.push_rejections ?? 0;
|
|
154
201
|
this.changelog = cfg.changelog ?? defaultChangelogFixture(target);
|
|
202
|
+
this.changelog_file = cfg.changelog_file ?? defaultChangelogFixture(target);
|
|
203
|
+
this.tag_local = (cfg.tag_created_unpushed ?? false) || (cfg.tag_already_remote ?? false);
|
|
204
|
+
this.tag_remote = cfg.tag_already_remote ?? false;
|
|
155
205
|
this.behind_probes = cfg.behind_probes ?? 0;
|
|
156
206
|
this.merge_races_once = cfg.merge_races_once ?? false;
|
|
157
207
|
this.merge_fails_hard = cfg.merge_fails_hard ?? false;
|
|
@@ -325,6 +375,95 @@ function _count(world: FakeWorld, needle: string): number {
|
|
|
325
375
|
}
|
|
326
376
|
|
|
327
377
|
const SCENARIOS: Record<string, Scenario> = {
|
|
378
|
+
'marker-refuses-before-tag': {
|
|
379
|
+
summary:
|
|
380
|
+
'step 8: a draft marker in the merged section refuses BEFORE the annotated tag is created',
|
|
381
|
+
config: { changelog_file: markedChangelogFixture(current_version()) },
|
|
382
|
+
expect_success: false,
|
|
383
|
+
verify: (w, err) => {
|
|
384
|
+
const f: string[] = [];
|
|
385
|
+
_expect(
|
|
386
|
+
(err ?? '').includes('refusing to publish the annotated tag'),
|
|
387
|
+
`died for the wrong reason: ${err ?? '(no error)'}`,
|
|
388
|
+
f,
|
|
389
|
+
);
|
|
390
|
+
// The load-bearing assertion, and it is about ORDER, not about the
|
|
391
|
+
// message: nothing irreversible may run after the refusal.
|
|
392
|
+
_expect(
|
|
393
|
+
!w.calls.some((c) => c.startsWith('git tag -a ')),
|
|
394
|
+
'an annotated tag was created after the refusal',
|
|
395
|
+
f,
|
|
396
|
+
);
|
|
397
|
+
_expect(!w.tag_local && !w.tag_remote, 'a tag exists after the refusal', f);
|
|
398
|
+
_expect(!w.release_created, 'a GitHub Release was created after the refusal', f);
|
|
399
|
+
return f;
|
|
400
|
+
},
|
|
401
|
+
},
|
|
402
|
+
'marker-refuses-resumed-tag-push': {
|
|
403
|
+
summary:
|
|
404
|
+
'step 8 (§ 3.2): a tag created but never pushed is NOT pushed when its section carries the marker',
|
|
405
|
+
config: {
|
|
406
|
+
tag_created_unpushed: true,
|
|
407
|
+
changelog_file: markedChangelogFixture(current_version()),
|
|
408
|
+
},
|
|
409
|
+
expect_success: false,
|
|
410
|
+
verify: (w, err) => {
|
|
411
|
+
const f: string[] = [];
|
|
412
|
+
_expect(
|
|
413
|
+
(err ?? '').includes('refusing to publish the tag push (resumed)'),
|
|
414
|
+
`died for the wrong reason: ${err ?? '(no error)'}`,
|
|
415
|
+
f,
|
|
416
|
+
);
|
|
417
|
+
// The recorded bypass: this path read no changelog at all, so the
|
|
418
|
+
// push was the FIRST thing that happened. It must now be the thing
|
|
419
|
+
// that does not happen.
|
|
420
|
+
_expect(!w.tag_remote, 'the tag was pushed after the refusal', f);
|
|
421
|
+
_expect(
|
|
422
|
+
!w.calls.includes(`git push origin ${w.target}`),
|
|
423
|
+
'a tag push ran after the refusal',
|
|
424
|
+
f,
|
|
425
|
+
);
|
|
426
|
+
_expect(!w.release_created, 'a GitHub Release was created after the refusal', f);
|
|
427
|
+
return f;
|
|
428
|
+
},
|
|
429
|
+
},
|
|
430
|
+
'marker-refuses-github-release': {
|
|
431
|
+
summary:
|
|
432
|
+
'step 9: with the tag already pushed, a marker in the TAGGED section refuses before the Release is created',
|
|
433
|
+
config: {
|
|
434
|
+
tag_already_remote: true,
|
|
435
|
+
changelog: markedChangelogFixture(current_version()),
|
|
436
|
+
changelog_file: markedChangelogFixture(current_version()),
|
|
437
|
+
},
|
|
438
|
+
expect_success: false,
|
|
439
|
+
verify: (w, err) => {
|
|
440
|
+
const f: string[] = [];
|
|
441
|
+
_expect(
|
|
442
|
+
(err ?? '').includes('refusing to publish the GitHub Release notes'),
|
|
443
|
+
`died for the wrong reason: ${err ?? '(no error)'}`,
|
|
444
|
+
f,
|
|
445
|
+
);
|
|
446
|
+
_expect(!w.release_created, 'the GitHub Release was created after the refusal', f);
|
|
447
|
+
_expect(
|
|
448
|
+
!w.calls.some((c) => c.startsWith(`gh release create ${w.target}`)),
|
|
449
|
+
'gh release create ran after the refusal',
|
|
450
|
+
f,
|
|
451
|
+
);
|
|
452
|
+
return f;
|
|
453
|
+
},
|
|
454
|
+
},
|
|
455
|
+
'clean-section-still-publishes': {
|
|
456
|
+
summary:
|
|
457
|
+
'the guard is scoped to a real defect: a policy-valid section tags and releases as before',
|
|
458
|
+
config: {},
|
|
459
|
+
expect_success: true,
|
|
460
|
+
verify: (w, _err) => {
|
|
461
|
+
const f: string[] = [];
|
|
462
|
+
_expect(w.tag_remote, 'tag never pushed', f);
|
|
463
|
+
_expect(w.release_created, 'GitHub Release never created', f);
|
|
464
|
+
return f;
|
|
465
|
+
},
|
|
466
|
+
},
|
|
328
467
|
'happy-resume': {
|
|
329
468
|
summary: 'resume with everything green runs checkout → checks → merge → tag → release',
|
|
330
469
|
config: {},
|
|
@@ -472,6 +611,9 @@ function run_scenario(name: string): ScenarioOutcome {
|
|
|
472
611
|
return true;
|
|
473
612
|
};
|
|
474
613
|
_set_exec_override((args) => world.exec(args));
|
|
614
|
+
// The working-tree read, faked for the same reason the command layer is.
|
|
615
|
+
// Without this the drill's step 8 reads the repository's real CHANGELOG.md.
|
|
616
|
+
_set_changelog_reader(() => world.changelog_file);
|
|
475
617
|
try {
|
|
476
618
|
execute(plan, { wait_for_checks: true, dry_run: false, resume: true });
|
|
477
619
|
} catch (err) {
|
|
@@ -482,6 +624,7 @@ function run_scenario(name: string): ScenarioOutcome {
|
|
|
482
624
|
}
|
|
483
625
|
} finally {
|
|
484
626
|
_set_exec_override(null);
|
|
627
|
+
_set_changelog_reader(null);
|
|
485
628
|
process.stdout.write = orig_out;
|
|
486
629
|
process.stderr.write = orig_err;
|
|
487
630
|
}
|
|
@@ -91,6 +91,39 @@ const PROJECT_TEMPLATE = path.join(
|
|
|
91
91
|
'agent-project-settings.example.yml',
|
|
92
92
|
);
|
|
93
93
|
const CHANGELOG = path.join(REPO_ROOT, 'CHANGELOG.md');
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Overridable reader for the WORKING-TREE changelog.
|
|
97
|
+
*
|
|
98
|
+
* Mirrors `_set_exec_override` in `release_publication.ts`, and exists for the
|
|
99
|
+
* same reason: `execute()` reads `CHANGELOG.md` off disk at two points (the PR
|
|
100
|
+
* body and the annotated-tag message), and the release drill fakes commands
|
|
101
|
+
* but not the filesystem. Before this seam the drill's step 8 read the
|
|
102
|
+
* repository's REAL changelog — whose current section carries four
|
|
103
|
+
* `_auto-derived, rewrite before merge:_` lines at `14.13.0` — so a
|
|
104
|
+
* publication guard added at that call site refused every drill scenario for a
|
|
105
|
+
* reason that had nothing to do with what the scenario was testing.
|
|
106
|
+
*
|
|
107
|
+
* That is the failure mode the `WorldConfig.changelog` fixture already removed
|
|
108
|
+
* for `git show`, and the AI council of 2026-08-23 (2/2 convergent) chose a
|
|
109
|
+
* controlled fixture over a policy exemption when it removed it. This is the
|
|
110
|
+
* same choice applied to the other read: the drill supplies policy-valid
|
|
111
|
+
* content and exercises the real parsing and guarding path, rather than being
|
|
112
|
+
* exempted from it.
|
|
113
|
+
*
|
|
114
|
+
* `null` restores the real filesystem read. Test-only; nothing in production
|
|
115
|
+
* sets it.
|
|
116
|
+
*/
|
|
117
|
+
let _changelog_reader: ((file: string) => string) | null = null;
|
|
118
|
+
|
|
119
|
+
function _set_changelog_reader(fn: ((file: string) => string) | null): void {
|
|
120
|
+
_changelog_reader = fn;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/** The working-tree changelog text, through the seam above. */
|
|
124
|
+
function read_changelog_text(): string {
|
|
125
|
+
return _changelog_reader ? _changelog_reader(CHANGELOG) : fs.readFileSync(CHANGELOG, 'utf-8');
|
|
126
|
+
}
|
|
94
127
|
const MAIN_BRANCH = 'main';
|
|
95
128
|
const REMOTE = 'origin';
|
|
96
129
|
const REPO_SLUG = 'event4u-app/agent-config';
|
|
@@ -282,6 +315,8 @@ export {
|
|
|
282
315
|
_cap_body,
|
|
283
316
|
CHANGELOG,
|
|
284
317
|
CalledProcessError,
|
|
318
|
+
_set_changelog_reader,
|
|
319
|
+
read_changelog_text,
|
|
285
320
|
GH_PR_BODY_LIMIT,
|
|
286
321
|
GH_RELEASE_NOTES_LIMIT,
|
|
287
322
|
MAIN_BRANCH,
|
|
@@ -16,12 +16,14 @@
|
|
|
16
16
|
* import path changes.
|
|
17
17
|
*/
|
|
18
18
|
import { spawnSync } from 'node:child_process';
|
|
19
|
+
import { publication_blockers } from './_lib/release_highlights.js';
|
|
19
20
|
import * as fs from 'node:fs';
|
|
20
21
|
import process from 'node:process';
|
|
21
22
|
|
|
22
23
|
import { gh_argv_label, gh_retry } from './_lib/gh_transient.js';
|
|
23
24
|
import {
|
|
24
25
|
extract_changelog_section,
|
|
26
|
+
tag_message_from_section,
|
|
25
27
|
pr_body_from_section,
|
|
26
28
|
} from './_lib/release_material.js';
|
|
27
29
|
|
|
@@ -34,6 +36,7 @@ import {
|
|
|
34
36
|
REPO_ROOT,
|
|
35
37
|
SystemExitError,
|
|
36
38
|
_cap_body,
|
|
39
|
+
read_changelog_text,
|
|
37
40
|
} from './release_env.js';
|
|
38
41
|
|
|
39
42
|
function die(msg: string, code = 2): never {
|
|
@@ -718,3 +721,84 @@ export {
|
|
|
718
721
|
run,
|
|
719
722
|
watch_pr_checks,
|
|
720
723
|
};
|
|
724
|
+
|
|
725
|
+
/**
|
|
726
|
+
* Refuse an irreversible publication whose section is not publishable.
|
|
727
|
+
*
|
|
728
|
+
* Called at the THREE call sites that publish, never inside a formatter:
|
|
729
|
+
* annotated-tag creation, the resumed push of a tag created but never pushed,
|
|
730
|
+
* and the GitHub Release body. A pure formatter has no notion of whether it is
|
|
731
|
+
* actually publishing, which is why an earlier attempt at that placement was
|
|
732
|
+
* refused; the call site does, and it is the one that can still stop.
|
|
733
|
+
*
|
|
734
|
+
* **The resumed push is the bypass worth naming.** The changelog is read only
|
|
735
|
+
* in the tag-CREATION branch, so a resume over a tag that was created but never
|
|
736
|
+
* pushed reached `_push_tag` having read nothing. A guard covering creation
|
|
737
|
+
* alone misses exactly that path, and pushing a tag is as irreversible as
|
|
738
|
+
* creating it.
|
|
739
|
+
*
|
|
740
|
+
* `die` throws before the command runs, so nothing irreversible fires after a
|
|
741
|
+
* refusal — an ordering asserted against the drill's recorded command list
|
|
742
|
+
* rather than by reading this comment.
|
|
743
|
+
*
|
|
744
|
+
* Lives here rather than in `release.ts` because that file is 2000+ lines and
|
|
745
|
+
* every line above 1500 is charged by the source-size growth ratchet, while
|
|
746
|
+
* this module is far below it and already owns `die`. Behaviour unchanged.
|
|
747
|
+
*/
|
|
748
|
+
export function _refuse_unpublishable(sectionBody: string, version: string, surface: string): void {
|
|
749
|
+
const blockers = publication_blockers(sectionBody, version);
|
|
750
|
+
if (blockers.length === 0) {
|
|
751
|
+
return;
|
|
752
|
+
}
|
|
753
|
+
die(
|
|
754
|
+
`refusing to publish the ${surface} for ${version} — ` +
|
|
755
|
+
`${String(blockers.length)} publication blocker(s):\n` +
|
|
756
|
+
blockers.map((b) => ` - ${b}`).join('\n'),
|
|
757
|
+
);
|
|
758
|
+
}
|
|
759
|
+
|
|
760
|
+
/**
|
|
761
|
+
* Read the section under release and refuse if it is not publishable.
|
|
762
|
+
*
|
|
763
|
+
* One helper for all three publish sites so the read, the missing-section
|
|
764
|
+
* refusal and the blocker refusal cannot drift apart between them — the
|
|
765
|
+
* resumed-push path drifted exactly that way before this existed, reaching
|
|
766
|
+
* `_push_tag` having read nothing.
|
|
767
|
+
*/
|
|
768
|
+
export function guard_publication(version: string, surface: string): void {
|
|
769
|
+
const section = extract_changelog_section(read_changelog_text(), version);
|
|
770
|
+
if (!section) {
|
|
771
|
+
die(
|
|
772
|
+
`CHANGELOG.md on ${MAIN_BRANCH} carries no section for ${version} — ` +
|
|
773
|
+
`refusing to publish the ${surface}`,
|
|
774
|
+
);
|
|
775
|
+
return;
|
|
776
|
+
}
|
|
777
|
+
_refuse_unpublishable(section.body, version, surface);
|
|
778
|
+
}
|
|
779
|
+
|
|
780
|
+
/**
|
|
781
|
+
* Derive the tag message from the MERGED changelog, refuse if unpublishable,
|
|
782
|
+
* create the annotated tag and push it.
|
|
783
|
+
*
|
|
784
|
+
* The three steps are one function because they are one irreversible act with
|
|
785
|
+
* one precondition, and splitting them across call sites is what let the
|
|
786
|
+
* resumed-push path reach `_push_tag` having read nothing. Sequencing is
|
|
787
|
+
* load-bearing (release-truth Phase 1, council 2026-08-03): merge FIRST, pull
|
|
788
|
+
* main, THEN derive the message — tagging before the merge reads a section that
|
|
789
|
+
* does not exist yet. The annotated tag replaces the previous lightweight one so
|
|
790
|
+
* tag metadata is a fourth surface carrying the same single-source content.
|
|
791
|
+
*/
|
|
792
|
+
export function create_and_push_annotated_tag(version: string): void {
|
|
793
|
+
const merged = extract_changelog_section(read_changelog_text(), version);
|
|
794
|
+
if (!merged) {
|
|
795
|
+
die(
|
|
796
|
+
`CHANGELOG.md on ${MAIN_BRANCH} carries no section for ${version} — ` +
|
|
797
|
+
'refusing to tag a release whose changelog entry is missing',
|
|
798
|
+
);
|
|
799
|
+
return;
|
|
800
|
+
}
|
|
801
|
+
_refuse_unpublishable(merged.body, version, 'annotated tag');
|
|
802
|
+
run(['git', 'tag', '-a', version, '-m', tag_message_from_section(merged.body, version)]);
|
|
803
|
+
_push_tag(version);
|
|
804
|
+
}
|
|
@@ -617,7 +617,7 @@ export function render(quiet = false): number {
|
|
|
617
617
|
const parts = [
|
|
618
618
|
'# Package-Impact A/B Benchmark',
|
|
619
619
|
'',
|
|
620
|
-
'> Generated by `
|
|
620
|
+
'> Generated by `render_benchmark_md`. Do not edit. Source of truth: ' +
|
|
621
621
|
'`internal/bench/reports/ab/`. Re-render anytime with `task bench:ab:diff`.',
|
|
622
622
|
'',
|
|
623
623
|
render_headline(trackA, trackB, trackBRdp),
|
|
@@ -58,6 +58,7 @@ import * as fs from 'node:fs';
|
|
|
58
58
|
import * as path from 'node:path';
|
|
59
59
|
import { fileURLToPath, pathToFileURL } from 'node:url';
|
|
60
60
|
|
|
61
|
+
import { isExclusivelyPackageOnly } from '../install/partitionEligibility.js';
|
|
61
62
|
import { _claude_paths_plan, _has_non_path_trigger, _parse_frontmatter } from './condense.js';
|
|
62
63
|
|
|
63
64
|
const RULES_DIR = path.join('src', 'rules');
|
|
@@ -83,6 +84,13 @@ export interface RuleActivation {
|
|
|
83
84
|
emitted_globs: string[];
|
|
84
85
|
/** Patterns the emitter deliberately drops, with the reason it records. */
|
|
85
86
|
dropped: { pattern: string; reason: string }[];
|
|
87
|
+
/**
|
|
88
|
+
* Scoped to this package alone, so ADR-236 withholds it from every global
|
|
89
|
+
* host layer. Load-bearing for the projection comparison: a package-only
|
|
90
|
+
* rule is counted by the source verdict and is absent from a delivered
|
|
91
|
+
* tree by design, not by drift.
|
|
92
|
+
*/
|
|
93
|
+
package_only: boolean;
|
|
86
94
|
/**
|
|
87
95
|
* The emitter's verdict in one word.
|
|
88
96
|
* `scoped` — loads on a path match · `unconditional` — loads every session ·
|
|
@@ -111,7 +119,11 @@ function _declares(meta: Record<string, unknown>, keys: readonly string[]): bool
|
|
|
111
119
|
}
|
|
112
120
|
|
|
113
121
|
/** Classify one rule file through the emitter's own exported decision path. */
|
|
114
|
-
export function classify_rule(
|
|
122
|
+
export function classify_rule(
|
|
123
|
+
id: string,
|
|
124
|
+
content: string,
|
|
125
|
+
package_only = false,
|
|
126
|
+
): RuleActivation {
|
|
115
127
|
const [meta] = _parse_frontmatter(content);
|
|
116
128
|
const plan = _claude_paths_plan(meta);
|
|
117
129
|
const has_path_trigger = _declares(meta, PATH_TRIGGER_KEYS);
|
|
@@ -139,6 +151,7 @@ export function classify_rule(id: string, content: string): RuleActivation {
|
|
|
139
151
|
emitted_globs: plan.globs,
|
|
140
152
|
dropped: plan.dropped.map((d) => ({ pattern: d.pattern, reason: d.reason })),
|
|
141
153
|
verdict,
|
|
154
|
+
package_only,
|
|
142
155
|
};
|
|
143
156
|
}
|
|
144
157
|
|
|
@@ -150,7 +163,11 @@ export function census(root: string): RuleActivation[] {
|
|
|
150
163
|
.map((e) => e.name)
|
|
151
164
|
.sort();
|
|
152
165
|
return files.map((f) =>
|
|
153
|
-
classify_rule(
|
|
166
|
+
classify_rule(
|
|
167
|
+
f.replace(/\.md$/, ''),
|
|
168
|
+
fs.readFileSync(path.join(dir, f), 'utf8'),
|
|
169
|
+
isExclusivelyPackageOnly(path.join(dir, f)),
|
|
170
|
+
),
|
|
154
171
|
);
|
|
155
172
|
}
|
|
156
173
|
|
|
@@ -223,10 +240,14 @@ export function main(): number {
|
|
|
223
240
|
|
|
224
241
|
const rows = census(root);
|
|
225
242
|
const sum = summarize(rows);
|
|
243
|
+
const resolved_projection_dir =
|
|
244
|
+
projection_dir === undefined || projection_dir === null || projection_dir === ''
|
|
245
|
+
? ''
|
|
246
|
+
: path.isAbsolute(projection_dir)
|
|
247
|
+
? projection_dir
|
|
248
|
+
: path.join(root, projection_dir);
|
|
226
249
|
const projection = projection_dir
|
|
227
|
-
? projection_reading(
|
|
228
|
-
? projection_dir
|
|
229
|
-
: path.join(root, projection_dir))
|
|
250
|
+
? projection_reading(resolved_projection_dir)
|
|
230
251
|
: null;
|
|
231
252
|
|
|
232
253
|
if (as_json) {
|
|
@@ -259,11 +280,51 @@ export function main(): number {
|
|
|
259
280
|
`\n host projection at ${projection_dir} — reported SEPARATELY, not merged:\n` +
|
|
260
281
|
` files ${projection.files} · declaring paths: ${projection.with_paths}\n`,
|
|
261
282
|
);
|
|
262
|
-
|
|
283
|
+
// The source verdict counts EVERY rule in `src/rules/`. A GLOBAL host
|
|
284
|
+
// layer does not carry the package-only ones: ADR-236 partitions them to
|
|
285
|
+
// the project layer, so such a tree is expected to be short by exactly
|
|
286
|
+
// that many. Comparing the raw counts reported a divergence on every
|
|
287
|
+
// partitioned install forever — the emitter was right and the
|
|
288
|
+
// comparator was not subtracting.
|
|
289
|
+
//
|
|
290
|
+
// But the subtraction is NOT unconditional, and making it so was its own
|
|
291
|
+
// regression (completion review, 2026-08-30): a full or project-layer
|
|
292
|
+
// projection — which is also the fail-safe default `partitionEligibility`
|
|
293
|
+
// returns on a fresh checkout, an absent install record, or a version or
|
|
294
|
+
// fingerprint mismatch — DOES carry those rules, and for this repo's own
|
|
295
|
+
// project layer `source-of-truth` is the one rule delivered there and the
|
|
296
|
+
// only one declaring `paths:`. Subtracting it there inverts the line.
|
|
297
|
+
//
|
|
298
|
+
// So the partition is DETECTED from the projection rather than assumed:
|
|
299
|
+
// if a package-only rule's file is present, this is not a global layer.
|
|
300
|
+
const pkg_only_ids = rows.filter((r) => r.package_only).map((r) => r.id);
|
|
301
|
+
const partitioned = !pkg_only_ids.some((id) =>
|
|
302
|
+
fs.existsSync(path.join(resolved_projection_dir, `${id}.md`)),
|
|
303
|
+
);
|
|
304
|
+
const scoped_pkg_only = partitioned
|
|
305
|
+
? rows.filter((r) => r.verdict === 'scoped' && r.package_only)
|
|
306
|
+
: [];
|
|
307
|
+
const expected = sum.scoped - scoped_pkg_only.length;
|
|
308
|
+
if (scoped_pkg_only.length > 0) {
|
|
309
|
+
process.stdout.write(
|
|
310
|
+
` source scopes ${sum.scoped}; ${scoped_pkg_only.length} of those ` +
|
|
311
|
+
`${scoped_pkg_only.length === 1 ? 'is' : 'are'} package-only and never\n` +
|
|
312
|
+
` delivered (${scoped_pkg_only.map((r) => r.id).join(', ')}), so a ` +
|
|
313
|
+
`partitioned projection is\n expected to declare ${expected}.\n`,
|
|
314
|
+
);
|
|
315
|
+
}
|
|
316
|
+
if (projection.with_paths !== expected) {
|
|
317
|
+
process.stdout.write(
|
|
318
|
+
` ⚠️ diverges from the source verdict (${expected} expected` +
|
|
319
|
+
`${scoped_pkg_only.length > 0 ? `, ${sum.scoped} before the package-only partition` : ''}).\n` +
|
|
320
|
+
` A projection carries no record of the scope or commit it was generated\n` +
|
|
321
|
+
` at, so this is a reason to regenerate it — never a reading of the\n` +
|
|
322
|
+
` emitter.\n`,
|
|
323
|
+
);
|
|
324
|
+
} else {
|
|
263
325
|
process.stdout.write(
|
|
264
|
-
`
|
|
265
|
-
|
|
266
|
-
` is a reason to regenerate it — never a reading of the emitter.\n`,
|
|
326
|
+
` ✅ consistent with the source verdict (${expected} expected, ` +
|
|
327
|
+
`${projection.with_paths} found).\n`,
|
|
267
328
|
);
|
|
268
329
|
}
|
|
269
330
|
} else if (projection_dir) {
|
|
@@ -228,7 +228,7 @@ export function render(
|
|
|
228
228
|
validation: ValidationResult = validate_targets(byTarget),
|
|
229
229
|
): string {
|
|
230
230
|
const L: string[] = [];
|
|
231
|
-
L.push('<!-- GENERATED by
|
|
231
|
+
L.push('<!-- GENERATED by rule_backlinks — do NOT hand-edit.');
|
|
232
232
|
L.push(' Regenerate after each P4 migration batch. Report-only. -->');
|
|
233
233
|
L.push('');
|
|
234
234
|
L.push('# Rule backlinks — which rules route here');
|