@event4u/agent-config 16.2.0 → 16.4.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 +337 -234
- package/README.md +15 -13
- package/agents/templates/.ai-council.yml.example +26 -8
- package/dist/agent-src/commands/analyze/inbox.md +11 -8
- package/dist/agent-src/commands/analyze/roadmap-repos.md +1 -1
- package/dist/agent-src/commands/bug/fix.md +17 -2
- package/dist/agent-src/commands/bug/investigate.md +1 -1
- package/dist/agent-src/commands/commit/in-chunks.md +40 -31
- package/dist/agent-src/commands/commit.md +72 -33
- package/dist/agent-src/commands/condense.md +2 -8
- package/dist/agent-src/commands/council/debate.md +11 -7
- package/dist/agent-src/commands/council/default.md +10 -9
- package/dist/agent-src/commands/council.md +1 -1
- package/dist/agent-src/commands/estimate-ticket.md +1 -1
- package/dist/agent-src/commands/feature/explore.md +3 -3
- package/dist/agent-src/commands/feature/plan.md +2 -2
- package/dist/agent-src/commands/feature/roadmap.md +1 -1
- package/dist/agent-src/commands/fix/ci.md +18 -4
- package/dist/agent-src/commands/fix/commit-messages.md +48 -23
- package/dist/agent-src/commands/fix/pr-comments.md +3 -6
- package/dist/agent-src/commands/implement-ticket.md +4 -4
- package/dist/agent-src/commands/jira-ticket.md +1 -1
- package/dist/agent-src/commands/memory/add.md +4 -16
- package/dist/agent-src/commands/memory/load.md +5 -6
- package/dist/agent-src/commands/memory/promote.md +3 -16
- package/dist/agent-src/commands/mission/upgrade.md +3 -2
- package/dist/agent-src/commands/optimize/agents-dir.md +2 -2
- package/dist/agent-src/commands/optimize/deep.md +4 -2
- package/dist/agent-src/commands/optimize/rtk.md +4 -26
- package/dist/agent-src/commands/pr/create/description-only.md +18 -15
- package/dist/agent-src/commands/pr/create.md +42 -34
- package/dist/agent-src/commands/pr/merge.md +136 -9
- package/dist/agent-src/commands/prepare-for-review.md +13 -11
- package/dist/agent-src/commands/project/analyze.md +7 -35
- package/dist/agent-src/commands/refine-ticket.md +1 -1
- package/dist/agent-src/commands/review/changes.md +14 -19
- package/dist/agent-src/commands/roadmap/create.md +1 -1
- package/dist/agent-src/commands/roadmap/materialize.md +1 -1
- package/dist/agent-src/commands/roadmap/next.md +10 -1
- package/dist/agent-src/commands/roadmap/process-full.md +56 -42
- package/dist/agent-src/commands/roadmap/resolve-blockers.md +411 -0
- package/dist/agent-src/commands/roadmap/triage-parked.md +325 -0
- package/dist/agent-src/commands/roadmap.md +18 -4
- package/dist/agent-src/commands/tests/create.md +17 -3
- package/dist/agent-src/commands/tests/execute.md +22 -5
- package/dist/agent-src/commands/worktree/create.md +7 -3
- package/dist/agent-src/commands/worktree/verify.md +2 -1
- package/dist/agent-src/contexts/authority/decision-revisit-gate-enforcement.md +43 -0
- package/dist/agent-src/contexts/communication/rules-auto/design-fidelity-enforcement.md +24 -0
- package/dist/agent-src/contexts/communication/rules-auto/think-before-action-mechanics.md +5 -3
- package/dist/agent-src/contexts/communication/rules-auto/token-efficiency-mechanics.md +7 -9
- package/dist/agent-src/contexts/contracts/command-suggestion-flow.md +8 -6
- package/dist/agent-src/contexts/contracts/frugality-charter.md +8 -5
- package/dist/agent-src/contexts/execution/auto-dispatch-classification.md +7 -7
- package/dist/agent-src/contexts/execution/auto-orchestration-activation.md +0 -1
- package/dist/agent-src/contexts/execution/evidence-discipline.md +2 -2
- package/dist/agent-src/contexts/execution/non-interactive-contract.md +5 -8
- package/dist/agent-src/contexts/execution/rdp-gate.md +4 -4
- package/dist/agent-src/contexts/execution/roadmap-execution-contract.md +9 -8
- package/dist/agent-src/contexts/execution/roadmap-process-loop.md +99 -54
- package/dist/agent-src/contexts/execution/session-canary-enforcement-history.md +67 -0
- package/dist/agent-src/contexts/execution/subagent-routing.md +8 -8
- package/dist/agent-src/contexts/execution/subagent-steering.md +6 -4
- package/dist/agent-src/contexts/execution/terminal-states.md +2 -2
- package/dist/agent-src/contexts/execution/toolchain-resolver.md +95 -7
- package/dist/agent-src/contexts/subagent-configuration.md +1 -1
- package/dist/agent-src/guidelines/agent-infra/active-remediation-mechanics.md +39 -0
- package/dist/agent-src/guidelines/agent-infra/context-hygiene-mechanics.md +1 -1
- package/dist/agent-src/guidelines/agent-infra/cross-source-consistency-mechanics.md +8 -10
- package/dist/agent-src/guidelines/agent-infra/frontier-reasoning-operating-profile.md +3 -2
- package/dist/agent-src/guidelines/agent-infra/layered-settings.md +13 -1
- package/dist/agent-src/guidelines/agent-infra/roadmap-progress-mechanics.md +1 -1
- package/dist/agent-src/guidelines/agent-infra/self-improvement-pipeline.md +10 -3
- package/dist/agent-src/guidelines/agent-infra/size-and-scope.md +36 -0
- package/dist/agent-src/guidelines/php/git.md +15 -2
- package/dist/agent-src/rules/active-remediation.md +1 -2
- package/dist/agent-src/rules/analysis-skill-routing.md +0 -1
- package/dist/agent-src/rules/architecture.md +0 -1
- package/dist/agent-src/rules/artifact-drafting-protocol.md +0 -1
- package/dist/agent-src/rules/artifact-engagement-recording.md +0 -1
- package/dist/agent-src/rules/augment-edit-discipline.md +0 -1
- package/dist/agent-src/rules/autonomous-execution.md +1 -1
- package/dist/agent-src/rules/brand-consistency.md +0 -1
- package/dist/agent-src/rules/brand-source-of-truth.md +0 -1
- package/dist/agent-src/rules/broken-access-control.md +1 -1
- package/dist/agent-src/rules/cli-output-handling.md +0 -1
- package/dist/agent-src/rules/code-comment-discipline.md +0 -1
- package/dist/agent-src/rules/code-provenance.md +0 -1
- package/dist/agent-src/rules/command-suggestion-policy.md +1 -1
- package/dist/agent-src/rules/commit-conventions.md +1 -2
- package/dist/agent-src/rules/communication-through-line.md +1 -2
- package/dist/agent-src/rules/content-quoting-floor.md +1 -2
- package/dist/agent-src/rules/context-hygiene.md +6 -6
- package/dist/agent-src/rules/copilot-routing.md +1 -2
- package/dist/agent-src/rules/council-availability.md +4 -4
- package/dist/agent-src/rules/cross-source-consistency.md +4 -6
- package/dist/agent-src/rules/decision-revisit-gate.md +17 -35
- package/dist/agent-src/rules/delegation-policy.md +2 -3
- package/dist/agent-src/rules/design-fidelity.md +12 -16
- package/dist/agent-src/rules/design-review-after-ui-write.md +3 -3
- package/dist/agent-src/rules/devcontainer-routing.md +1 -2
- package/dist/agent-src/rules/doc-screenshot-hygiene.md +1 -1
- package/dist/agent-src/rules/docker-commands.md +0 -1
- package/dist/agent-src/rules/domain-adoption-policy.md +0 -1
- package/dist/agent-src/rules/domain-safety-disclaimer.md +1 -1
- package/dist/agent-src/rules/domain-safety-pii.md +1 -1
- package/dist/agent-src/rules/domain-safety-retention.md +1 -1
- package/dist/agent-src/rules/downstream-changes.md +0 -1
- package/dist/agent-src/rules/engineering-safety-floor.md +1 -1
- package/dist/agent-src/rules/evaluator-independence.md +3 -2
- package/dist/agent-src/rules/external-code-graph-interop.md +0 -1
- package/dist/agent-src/rules/external-reference-deep-dive.md +0 -1
- package/dist/agent-src/rules/fast-path-marker-visibility.md +2 -2
- package/dist/agent-src/rules/finance-safety-floor.md +1 -1
- package/dist/agent-src/rules/fix-what-you-see.md +6 -32
- package/dist/agent-src/rules/framework-neutrality-in-generic-skills.md +0 -1
- package/dist/agent-src/rules/git-history-discipline.md +2 -2
- package/dist/agent-src/rules/guidelines.md +0 -1
- package/dist/agent-src/rules/history-discipline.md +0 -1
- package/dist/agent-src/rules/icon-consistency.md +0 -1
- package/dist/agent-src/rules/image-likeness-and-rights.md +1 -1
- package/dist/agent-src/rules/improve-before-implement.md +0 -1
- package/dist/agent-src/rules/invite-challenge.md +0 -1
- package/dist/agent-src/rules/laravel-routing.md +1 -2
- package/dist/agent-src/rules/laravel-translations.md +0 -1
- package/dist/agent-src/rules/legal-safety-floor.md +3 -3
- package/dist/agent-src/rules/lethal-trifecta-guard.md +1 -1
- package/dist/agent-src/rules/linked-projects-onboarding-gate.md +0 -1
- package/dist/agent-src/rules/low-impact-corpus-privacy-floor.md +1 -1
- package/dist/agent-src/rules/markdown-safe-codeblocks.md +0 -1
- package/dist/agent-src/rules/media-governance-routing.md +13 -17
- package/dist/agent-src/rules/media-sync-ground-truth.md +0 -1
- package/dist/agent-src/rules/minimal-safe-diff.md +0 -1
- package/dist/agent-src/rules/missing-skill-recovery.md +0 -1
- package/dist/agent-src/rules/missing-tool-handling.md +0 -1
- package/dist/agent-src/rules/model-recommendation.md +0 -1
- package/dist/agent-src/rules/neighbour-precedence.md +64 -0
- package/dist/agent-src/rules/no-attribution-footers.md +0 -1
- package/dist/agent-src/rules/no-decorative-emojis-in-git-surfaces.md +0 -1
- package/dist/agent-src/rules/no-pr-progress-comments.md +0 -1
- package/dist/agent-src/rules/no-roadmap-references.md +0 -1
- package/dist/agent-src/rules/notes-first-reasoning.md +0 -1
- package/dist/agent-src/rules/onboarding-gate.md +0 -1
- package/dist/agent-src/rules/output-discipline.md +0 -1
- package/dist/agent-src/rules/package-ci-checks.md +0 -1
- package/dist/agent-src/rules/persona-governance.md +4 -5
- package/dist/agent-src/rules/php-coding.md +0 -1
- package/dist/agent-src/rules/prefer-enums-over-literals.md +0 -1
- package/dist/agent-src/rules/preservation-guard.md +0 -1
- package/dist/agent-src/rules/provider-lifecycle-discipline.md +3 -4
- package/dist/agent-src/rules/question-not-instruction.md +1 -1
- package/dist/agent-src/rules/reviewer-awareness.md +0 -1
- package/dist/agent-src/rules/roadmap-ci-steps-policy.md +0 -1
- package/dist/agent-src/rules/roadmap-progress-sync.md +4 -7
- package/dist/agent-src/rules/role-mode-adherence.md +0 -1
- package/dist/agent-src/rules/rule-type-governance.md +0 -1
- package/dist/agent-src/rules/runtime-safety.md +1 -1
- package/dist/agent-src/rules/scale-discipline.md +0 -1
- package/dist/agent-src/rules/secret-vcs-guard.md +1 -1
- package/dist/agent-src/rules/security-sensitive-stop.md +3 -3
- package/dist/agent-src/rules/self-repair-loop.md +0 -1
- package/dist/agent-src/rules/senior-engineering-discipline.md +0 -1
- package/dist/agent-src/rules/session-canary.md +7 -62
- package/dist/agent-src/rules/settings-ask-protocol.md +6 -6
- package/dist/agent-src/rules/size-enforcement.md +0 -1
- package/dist/agent-src/rules/skill-improvement-trigger.md +2 -3
- package/dist/agent-src/rules/skill-quality.md +0 -1
- package/dist/agent-src/rules/slash-command-routing-policy.md +0 -1
- package/dist/agent-src/rules/source-confidentiality.md +1 -1
- package/dist/agent-src/rules/source-discovery-gate.md +0 -1
- package/dist/agent-src/rules/source-of-truth.md +0 -1
- package/dist/agent-src/rules/spreadsheet-source-quality.md +1 -2
- package/dist/agent-src/rules/strategy-safety-floor.md +1 -1
- package/dist/agent-src/rules/symfony-routing.md +1 -2
- package/dist/agent-src/rules/think-before-action.md +0 -1
- package/dist/agent-src/rules/token-budget-discipline.md +12 -46
- package/dist/agent-src/rules/token-efficiency.md +0 -1
- package/dist/agent-src/rules/token-optimizer-maintenance.md +0 -1
- package/dist/agent-src/rules/tool-safety.md +1 -1
- package/dist/agent-src/rules/ui-audit-gate.md +1 -2
- package/dist/agent-src/rules/untrusted-input-defense.md +1 -1
- package/dist/agent-src/rules/upstream-proposal.md +0 -1
- package/dist/agent-src/rules/user-interaction.md +0 -1
- package/dist/agent-src/rules/user-interrupt-priority.md +1 -1
- package/dist/agent-src/scripts/archive_completed_roadmaps.ts +115 -20
- package/dist/agent-src/scripts/deferral_carry.ts +339 -0
- package/dist/agent-src/scripts/gate_budget.ts +47 -23
- package/dist/agent-src/scripts/gate_execute.ts +12 -4
- package/dist/agent-src/scripts/update_roadmap_progress.ts +4 -1
- package/dist/agent-src/skills/ai-council/SKILL.md +7 -4
- package/dist/agent-src/skills/ai-council/references/cost-and-redaction.md +21 -11
- package/dist/agent-src/skills/ai-council/references/procedure.md +12 -6
- package/dist/agent-src/skills/analysis-autonomous-mode/SKILL.md +1 -1
- package/dist/agent-src/skills/api-design/data/manifest.json +2 -2
- package/dist/agent-src/skills/api-testing/SKILL.md +17 -0
- package/dist/agent-src/skills/bug-analyzer/SKILL.md +1 -1
- package/dist/agent-src/skills/code-intelligence/SKILL.md +14 -2
- package/dist/agent-src/skills/command-routing/SKILL.md +3 -4
- package/dist/agent-src/skills/conventional-commits-writing/SKILL.md +127 -139
- package/dist/agent-src/skills/corpus-grounding/ATTRIBUTION.md +39 -0
- package/dist/agent-src/skills/corpus-grounding/SKILL.md +8 -2
- package/dist/agent-src/skills/database/data/manifest.json +2 -2
- package/dist/agent-src/skills/database/data/query-tuning.csv +13 -13
- package/dist/agent-src/skills/design-system-capture/SKILL.md +0 -3
- package/dist/agent-src/skills/design-system-capture/references/import-procedure.md +1 -1
- package/dist/agent-src/skills/estimate-ticket/SKILL.md +1 -1
- package/dist/agent-src/skills/existing-ui-audit/SKILL.md +2 -2
- package/dist/agent-src/skills/fe-design/SKILL.md +1 -1
- package/dist/agent-src/skills/feature-planning/SKILL.md +1 -1
- package/dist/agent-src/skills/git-workflow/SKILL.md +44 -44
- package/dist/agent-src/skills/git-workflow/references/branch-update.md +312 -0
- package/dist/agent-src/skills/git-workflow/references/commit-subject.md +205 -0
- package/dist/agent-src/skills/iconography/SKILL.md +1 -1
- package/dist/agent-src/skills/jira-integration/SKILL.md +3 -3
- package/dist/agent-src/skills/js-library-packaging/SKILL.md +2 -2
- package/dist/agent-src/skills/merge-conflicts/SKILL.md +10 -4
- package/dist/agent-src/skills/monorepo-workspace/SKILL.md +1 -1
- package/dist/agent-src/skills/po-discovery/SKILL.md +1 -1
- package/dist/agent-src/skills/quality-tools/SKILL.md +11 -1
- package/dist/agent-src/skills/quality-tools/references/go-tools.md +76 -0
- package/dist/agent-src/skills/quality-tools/references/python-tools.md +104 -0
- package/dist/agent-src/skills/refine-ticket/SKILL.md +4 -4
- package/dist/agent-src/skills/review-routing/SKILL.md +2 -2
- package/dist/agent-src/skills/roadmap-writing/SKILL.md +2 -2
- package/dist/agent-src/skills/skill-improvement-pipeline/SKILL.md +5 -3
- package/dist/agent-src/skills/source-discovery/SKILL.md +1 -1
- package/dist/agent-src/skills/storybook-workshop/SKILL.md +3 -3
- package/dist/agent-src/skills/tailwind-engineer/SKILL.md +4 -2
- package/dist/agent-src/skills/test-case-discovery/SKILL.md +7 -0
- package/dist/agent-src/skills/test-driven-development/SKILL.md +17 -0
- package/dist/agent-src/skills/test-performance/SKILL.md +19 -1
- package/dist/agent-src/skills/testing-anti-patterns/SKILL.md +1 -1
- package/dist/agent-src/skills/ui-component-architect/SKILL.md +2 -2
- package/dist/agent-src/skills/using-git-worktrees/SKILL.md +1 -1
- package/dist/agent-src/skills/verify-repair-loop/SKILL.md +2 -2
- package/dist/agent-src/templates/AGENTS.md +1 -1
- package/dist/agent-src/templates/agent-settings.md +46 -129
- package/dist/agent-src/templates/agents/agent-project-settings.example.yml +3 -3
- package/dist/agent-src/templates/command.md +2 -2
- package/dist/agent-src/templates/roadmaps.md +6 -1
- package/dist/agent-src/templates/scripts/work_engine/_lib/agent_settings.ts +0 -6
- package/dist/agent-src/templates/scripts/work_engine/directives/backend/_self_fix.ts +11 -7
- package/dist/agent-src/templates/scripts/work_engine/directives/ui/apply.ts +48 -6
- package/dist/agent-src/templates/scripts/work_engine/hooks/builtin/decision_trace.ts +3 -2
- package/dist/agent-src/templates/scripts/work_engine/hooks/builtin/memory_visibility.ts +2 -1
- package/dist/agent-src/templates/scripts/work_engine/hooks/settings.ts +0 -6
- package/dist/agent-src/templates/scripts/work_engine/scoring/decision_engine.ts +9 -12
- package/dist/agent-src/templates/scripts/work_engine/scoring/memory_visibility.ts +2 -1
- package/dist/agent-src/templates/scripts/work_engine/stack/runner.ts +774 -109
- package/dist/agent-src/templates/skill.md +1 -1
- package/dist/cli/registry.js +2 -1
- package/dist/cli-delegate/archive_completed_roadmaps.js +92 -12
- package/dist/cli-delegate/check_update_banner.js +207 -120
- package/dist/cli-delegate/chunk-523HCFYO.js +90 -0
- package/dist/cli-delegate/{chunk-FP36SWJD.js → chunk-5GPULQBE.js} +2797 -338
- package/dist/cli-delegate/{chunk-IGD6ERX6.js → chunk-6SRJTYJS.js} +42 -176
- package/dist/cli-delegate/chunk-6V5FMA3P.js +186 -0
- package/dist/cli-delegate/{chunk-M2DPGFZ4.js → chunk-6V6TA25H.js} +22 -152
- package/dist/cli-delegate/chunk-6YQC2HLF.js +415 -0
- package/dist/cli-delegate/{chunk-E4XIZDIB.js → chunk-7HKRE54K.js} +1 -64
- package/dist/cli-delegate/chunk-7IQE3D5S.js +191 -0
- package/dist/cli-delegate/{chunk-YJ72UIAK.js → chunk-AED2VQGM.js} +1245 -249
- package/dist/cli-delegate/{chunk-7HQ52DHU.js → chunk-AL3RZ22D.js} +1 -1
- package/dist/cli-delegate/chunk-DEIV7XP7.js +108 -0
- package/dist/cli-delegate/{chunk-DBH4AHDK.js → chunk-ED7KCMLB.js} +9 -11
- package/dist/cli-delegate/chunk-F3QDG2GT.js +2569 -0
- package/dist/cli-delegate/{chunk-6KFEC3G7.js → chunk-G5VVIZRC.js} +3 -3
- package/dist/cli-delegate/{chunk-FC75PGJE.js → chunk-H76PHZBI.js} +149 -61
- package/dist/cli-delegate/chunk-IAYTIIQW.js +67 -0
- package/dist/cli-delegate/chunk-JQOM7TTM.js +1201 -0
- package/dist/cli-delegate/chunk-KB5FZ655.js +208 -0
- package/dist/cli-delegate/{chunk-7RQP4UDH.js → chunk-KR6EM23A.js} +235 -1455
- package/dist/cli-delegate/{chunk-LTYVIY76.js → chunk-KXXWJTDO.js} +6 -11
- package/dist/cli-delegate/{chunk-T7L2QK3K.js → chunk-LQOCRFWT.js} +1 -1
- package/dist/cli-delegate/{chunk-6KM6ORRY.js → chunk-MDPPKQCQ.js} +58 -9
- package/dist/cli-delegate/{chunk-4XFP2Y3E.js → chunk-MSUL5NYP.js} +5 -5
- package/dist/cli-delegate/chunk-OAFSJBHH.js +272 -0
- package/dist/cli-delegate/{chunk-4E2W63DA.js → chunk-OKJUIAPS.js} +62 -1
- package/dist/cli-delegate/{chunk-QAJS5YWY.js → chunk-PHD7OOLE.js} +2 -1
- package/dist/cli-delegate/{chunk-P6ZHP5W2.js → chunk-PWX7CKMD.js} +4 -4
- package/dist/cli-delegate/{chunk-NDJLNC6Q.js → chunk-T6BP34WI.js} +1 -0
- package/dist/cli-delegate/{chunk-7XGBX6ZH.js → chunk-T7XSJSUQ.js} +1144 -589
- package/dist/cli-delegate/chunk-ULQRUR23.js +208 -0
- package/dist/cli-delegate/chunk-WQWXGIWB.js +1779 -0
- package/dist/cli-delegate/{chunk-RGNIWTEA.js → chunk-XQTPXKFA.js} +1 -1
- package/dist/cli-delegate/{chunk-NUHLI2RX.js → chunk-YCU3TIXH.js} +2 -0
- package/dist/cli-delegate/chunk-ZBZV2G5R.js +210 -0
- package/dist/cli-delegate/{chunk-WGXTVKCQ.js → chunk-ZUZKZYCN.js} +5 -3
- package/dist/cli-delegate/cmd_analyze_session.js +223 -43
- package/dist/cli-delegate/cmd_brand_status.js +3 -2
- package/dist/cli-delegate/cmd_conformance.js +1252 -249
- package/dist/cli-delegate/cmd_converge.js +3 -3
- package/dist/cli-delegate/cmd_doctor.js +19 -9
- package/dist/cli-delegate/cmd_doctor_neighbours.js +30 -0
- package/dist/cli-delegate/cmd_explain.js +45 -21
- package/dist/cli-delegate/cmd_export.js +13 -10
- package/dist/cli-delegate/cmd_fleet.js +3 -3
- package/dist/cli-delegate/cmd_git_convention.js +1851 -0
- package/dist/cli-delegate/cmd_handoff.js +44 -22
- package/dist/cli-delegate/cmd_mcp_available.js +3 -2
- package/dist/cli-delegate/cmd_memory_get.js +3 -1
- package/dist/cli-delegate/cmd_migrate.js +3 -3
- package/dist/cli-delegate/cmd_packs_active.js +5 -4
- package/dist/cli-delegate/cmd_preflight.js +6 -6
- package/dist/cli-delegate/cmd_prune.js +14 -11
- package/dist/cli-delegate/cmd_refresh.js +2 -1
- package/dist/cli-delegate/cmd_route_audit.js +10 -8
- package/dist/cli-delegate/cmd_route_explain.js +4 -4
- package/dist/cli-delegate/cmd_session_recycle.js +10 -7
- package/dist/cli-delegate/cmd_settings_check.js +54 -7
- package/dist/cli-delegate/cmd_settings_get.js +18 -8
- package/dist/cli-delegate/cmd_settings_migrate.js +13 -10
- package/dist/cli-delegate/cmd_settings_set.js +4 -4
- package/dist/cli-delegate/cmd_sync.js +14 -11
- package/dist/cli-delegate/cmd_uninstall.js +15 -12
- package/dist/cli-delegate/cmd_update.js +7 -7
- package/dist/cli-delegate/cmd_upgrade.js +9 -8
- package/dist/cli-delegate/cmd_validate.js +15 -12
- package/dist/cli-delegate/cmd_versions.js +5 -5
- package/dist/cli-delegate/deferral_carry.js +16 -0
- package/dist/cli-delegate/gate_budget.js +1 -1
- package/dist/cli-delegate/gate_execute.js +3 -3
- package/dist/cli-delegate/roadmap_gates.js +6 -6
- package/dist/cli-delegate/update_roadmap_progress.js +1 -1
- package/dist/discovery/deprecation-report.md +1 -1
- package/dist/discovery/discovery-manifest.json +232 -141
- package/dist/discovery/discovery-manifest.json.sha256 +1 -1
- package/dist/discovery/discovery-manifest.summary.md +3 -3
- package/dist/discovery/dormancy-report.md +1 -1
- package/dist/discovery/orphan-report.md +1 -1
- package/dist/discovery/packs.json +26 -9
- package/dist/discovery/trust-report.md +3 -3
- package/dist/discovery/workspaces.json +7 -4
- package/dist/hooks/dispatch.js +5655 -6623
- package/dist/hooks/dispatch.sha256 +1 -1
- package/dist/install/claudePathsPlan.js +47 -6
- package/dist/install/claudeRuleRewrite.js +7 -0
- package/dist/install/emit_host_rules_cli.js +39 -36
- package/dist/install/globalRuleScope.js +87 -0
- package/dist/install/host_rule_ownership.js +160 -0
- package/dist/install/install.mjs +2336 -1249
- package/dist/install/installThinLayer.js +289 -0
- package/dist/install/installedRuleLinks.js +262 -0
- package/dist/install/wizard-plan.js +24 -0
- package/dist/mcp/awesome-mcp-servers.row.md +1 -1
- package/dist/mcp/mcp-cloudflare-catalogue.json +2 -2
- package/dist/mcp/registry-manifest.json +5 -5
- package/dist/mcp/server.json +2 -2
- package/dist/mcp/server.mjs +36504 -30986
- package/dist/router.json +1 -1
- package/dist/scripts/_lib/agent_settings.js +26 -120
- package/dist/scripts/_lib/claude_settings_hooks.js +10 -8
- package/dist/scripts/_lib/compile_time_toggles.js +12 -21
- package/dist/scripts/_lib/git_convention.js +232 -0
- package/dist/scripts/_lib/global_deploy_inventory.js +730 -0
- package/dist/scripts/_lib/installed_layer.js +704 -0
- package/dist/scripts/_lib/lean_projection_mode.js +218 -15
- package/dist/scripts/_lib/package_root.js +68 -0
- package/dist/scripts/_lib/rule_consequence_class.js +45 -0
- package/dist/scripts/_lib/rule_injection.js +67 -10
- package/dist/scripts/_lib/rule_law_section.js +122 -0
- package/dist/scripts/_lib/settings_removed_keys.js +168 -0
- package/dist/scripts/_lib/thin_rules.js +535 -0
- package/dist/scripts/_lib/windsurf_render.js +60 -0
- package/dist/scripts/condense.js +14 -26
- package/dist/scripts/project_thin_rules.js +14 -294
- package/dist/server/app.js +2 -1
- package/dist/server/gitKeysGate.js +105 -0
- package/dist/server/routes/settings.js +67 -8
- package/dist/server/routes/wizard.js +4 -0
- package/dist/server/schemas/settings.js +29 -81
- package/dist/shared/skillRanking.js +103 -16
- package/dist/ui/assets/{index-Cwq4d0hX.js → index-C3djEJah.js} +2 -2
- package/dist/ui/index.html +1 -1
- package/docs/MIGRATION.md +72 -1
- package/docs/contracts/settings-classes.md +39 -67
- package/docs/guidelines/agent-infra/active-remediation-mechanics.md +39 -0
- package/docs/guidelines/agent-infra/context-hygiene-mechanics.md +1 -1
- package/docs/guidelines/agent-infra/cross-source-consistency-mechanics.md +8 -10
- package/docs/guidelines/agent-infra/frontier-reasoning-operating-profile.md +3 -2
- package/docs/guidelines/agent-infra/layered-settings.md +13 -1
- package/docs/guidelines/agent-infra/roadmap-progress-mechanics.md +1 -1
- package/docs/guidelines/agent-infra/self-improvement-pipeline.md +10 -3
- package/docs/guidelines/agent-infra/size-and-scope.md +36 -0
- package/docs/guidelines/php/git.md +15 -2
- package/package.json +1 -1
- package/src/agent-src/scripts/archive_completed_roadmaps.ts +115 -20
- package/src/agent-src/scripts/deferral_carry.ts +339 -0
- package/src/agent-src/scripts/gate_budget.ts +47 -23
- package/src/agent-src/scripts/gate_execute.ts +12 -4
- package/src/agent-src/scripts/update_roadmap_progress.ts +4 -1
- package/src/agent-src/templates/AGENTS.md +1 -1
- package/src/agent-src/templates/scripts/work_engine/_lib/agent_settings.ts +0 -6
- package/src/agent-src/templates/scripts/work_engine/directives/backend/_self_fix.ts +11 -7
- package/src/agent-src/templates/scripts/work_engine/directives/ui/apply.ts +48 -6
- package/src/agent-src/templates/scripts/work_engine/hooks/builtin/decision_trace.ts +3 -2
- package/src/agent-src/templates/scripts/work_engine/hooks/builtin/memory_visibility.ts +2 -1
- package/src/agent-src/templates/scripts/work_engine/hooks/settings.ts +0 -6
- package/src/agent-src/templates/scripts/work_engine/scoring/decision_engine.ts +9 -12
- package/src/agent-src/templates/scripts/work_engine/scoring/memory_visibility.ts +2 -1
- package/src/agent-src/templates/scripts/work_engine/stack/runner.ts +774 -109
- package/src/config/agent-settings.template.yml +141 -334
- package/src/config/agents-paths.yml +16 -0
- package/src/config/assurance-capability-registry.json +7 -3
- package/src/config/ci-local-parity.yml +3 -0
- package/src/config/continuity-surface.json +10 -3
- package/src/config/discovery/packs.yml +17 -1
- package/src/config/evaluator-budgets.json +23 -10
- package/src/config/gate-coverage.yml +138 -3
- package/src/config/gate-violation-baselines.json +64 -16
- package/src/config/gitignore-block.txt +19 -0
- package/src/config/hook-bundle-budget.json +25 -0
- package/src/config/hook-token-budget.json +6 -1
- package/src/config/host-instruction-limits.json +33 -0
- package/src/config/release-gate-locality.yml +2 -1
- package/src/config/routing-coverage-seed.json +67 -4
- package/src/config/rule-activation-census.json +7 -3
- package/src/config/rule-consequence-class.json +161 -0
- package/src/config/rule-law-ceilings.json +105 -0
- package/src/config/rule-obligations.json +833 -0
- package/src/install/claudePathsPlan.ts +46 -4
- package/src/install/claudeRuleRewrite.ts +10 -1
- package/src/install/emit_host_rules_cli.ts +43 -34
- package/src/install/globalRuleScope.ts +109 -0
- package/src/install/host_rule_ownership.ts +170 -0
- package/src/install/installThinLayer.ts +378 -0
- package/src/install/installedRuleLinks.ts +308 -0
- package/src/install/wizard-plan.ts +24 -0
- package/src/scripts/_cli/cmd_analyze_session.ts +9 -15
- package/src/scripts/_cli/cmd_conformance.ts +13 -2
- package/src/scripts/_cli/cmd_doctor.ts +33 -81
- package/src/scripts/_cli/cmd_doctor_neighbours.ts +426 -0
- package/src/scripts/_cli/cmd_explain.ts +72 -14
- package/src/scripts/_cli/cmd_git_convention.ts +637 -0
- package/src/scripts/_cli/cmd_settings_check.ts +66 -8
- package/src/scripts/_cli/cmd_settings_get.ts +18 -3
- package/src/scripts/_cli/doctor_execution.ts +72 -1
- package/src/scripts/_dispatch.bash +53 -4
- package/src/scripts/_lib/agent_settings.ts +26 -124
- package/src/scripts/_lib/blocked_by_marker.ts +1 -1
- package/src/scripts/_lib/claude_settings_hooks.ts +10 -8
- package/src/scripts/_lib/compile_time_toggles.ts +12 -21
- package/src/scripts/_lib/dispatch_import_closure.ts +163 -0
- package/src/scripts/_lib/estate_offsets.ts +241 -0
- package/src/scripts/_lib/exemption_shape.ts +143 -0
- package/src/scripts/_lib/fnv.ts +23 -0
- package/src/scripts/_lib/foreign_scan.ts +106 -0
- package/src/scripts/_lib/git_base_ref.ts +92 -0
- package/src/scripts/_lib/git_convention.ts +291 -0
- package/src/scripts/_lib/git_convention_carrier.ts +389 -0
- package/src/scripts/_lib/git_convention_grammar.ts +246 -0
- package/src/scripts/_lib/git_convention_measure.ts +344 -0
- package/src/scripts/_lib/gitignore_block.ts +314 -0
- package/src/scripts/_lib/global_deploy_inventory.ts +106 -0
- package/src/scripts/_lib/graph_feeder_record.ts +437 -0
- package/src/scripts/_lib/hook_settings.ts +73 -0
- package/src/scripts/_lib/host_capability.ts +40 -19
- package/src/scripts/_lib/host_hook_merge.ts +165 -0
- package/src/scripts/_lib/installed_layer.ts +963 -0
- package/src/scripts/_lib/json_merge.ts +82 -0
- package/src/scripts/_lib/json_pointers.ts +93 -11
- package/src/scripts/_lib/knowledge_global.ts +14 -1
- package/src/scripts/_lib/lean_projection_mode.ts +275 -15
- package/src/scripts/_lib/machine_wake.ts +16 -3
- package/src/scripts/_lib/module_reach.ts +456 -0
- package/src/scripts/_lib/neighbour_census.ts +760 -0
- package/src/scripts/_lib/neighbour_contradictions.ts +236 -0
- package/src/scripts/_lib/neighbour_scan.ts +122 -0
- package/src/scripts/_lib/neighbour_tool_use.ts +187 -0
- package/src/scripts/_lib/prompt_shape.ts +46 -0
- package/src/scripts/_lib/ratification_artifact.ts +220 -1
- package/src/scripts/_lib/ratification_subject.ts +92 -0
- package/src/scripts/_lib/release_findings_ingest.ts +15 -7
- package/src/scripts/_lib/release_highlights.ts +5 -0
- package/src/scripts/_lib/release_migration_gate.ts +19 -3
- package/src/scripts/_lib/reserved_name_sweep.ts +73 -0
- package/src/scripts/_lib/review_coverage.ts +134 -0
- package/src/scripts/_lib/rule_consequence_class.ts +71 -0
- package/src/scripts/_lib/rule_injection.ts +130 -10
- package/src/scripts/_lib/rule_law_section.ts +147 -0
- package/src/scripts/_lib/rule_layer_overlap.ts +58 -0
- package/src/scripts/_lib/rule_obligations.ts +205 -0
- package/src/scripts/_lib/self_repair.ts +1 -1
- package/src/scripts/_lib/settings_removed_keys.ts +173 -0
- package/src/scripts/_lib/skill_origin.ts +254 -0
- package/src/scripts/_lib/structured_ask.ts +64 -21
- package/src/scripts/_lib/test_red_state.ts +5 -0
- package/src/scripts/_lib/thin_rules.ts +620 -0
- package/src/scripts/_lib/touched_file_quality.ts +570 -0
- package/src/scripts/_lib/turn_end_refusals.ts +77 -2
- package/src/scripts/_lib/windsurf_render.ts +63 -0
- package/src/scripts/_lib/worker_budget.ts +1 -1
- package/src/scripts/adr/regenerate_index.ts +16 -1
- package/src/scripts/ai_council/cli_call_budget.ts +13 -5
- package/src/scripts/ai_council/clients.ts +26 -57
- package/src/scripts/ai_council/config.ts +8 -8
- package/src/scripts/ai_council/modification_review.ts +100 -0
- package/src/scripts/ai_council/modification_review_questions.ts +90 -0
- package/src/scripts/ai_council/orchestrator.ts +5 -5
- package/src/scripts/ai_council/spend_gate.ts +18 -7
- package/src/scripts/ai_council/vendor_defaults.ts +45 -0
- package/src/scripts/ai_team/config.ts +11 -16
- package/src/scripts/audit_skill_overlap.ts +261 -0
- package/src/scripts/audit_user_type_axis.ts +20 -8
- package/src/scripts/before_complete_hook.ts +243 -12
- package/src/scripts/bench_ab_clone.ts +1 -2
- package/src/scripts/bench_concern_spawn_path.ts +129 -0
- package/src/scripts/bench_graph_feeder_latency.ts +584 -0
- package/src/scripts/bench_touched_file_quality.ts +238 -0
- package/src/scripts/check_agent_artifact_location.ts +36 -0
- package/src/scripts/check_branch_freshness.ts +147 -24
- package/src/scripts/check_enforcement_coverage.ts +130 -0
- package/src/scripts/check_enforcement_matrix.ts +377 -20
- package/src/scripts/check_estate_count.ts +130 -153
- package/src/scripts/check_evaluator_budgets.ts +4 -0
- package/src/scripts/check_finding_dispositions.ts +196 -21
- package/src/scripts/check_gate_coverage.ts +4 -3
- package/src/scripts/check_gate_reachability.ts +48 -1
- package/src/scripts/check_generator_sync.ts +48 -0
- package/src/scripts/check_hook_bundle_composition.ts +477 -0
- package/src/scripts/check_kernel_edit_ratified.ts +132 -14
- package/src/scripts/check_memory.ts +7 -1
- package/src/scripts/check_pack_size.ts +1 -1
- package/src/scripts/check_release_highlights.ts +10 -0
- package/src/scripts/check_release_manifest_content.ts +189 -0
- package/src/scripts/check_release_pr_shape.ts +38 -15
- package/src/scripts/check_standing_rule_delivery.ts +129 -13
- package/src/scripts/check_suppression_hygiene.ts +2 -5
- package/src/scripts/check_verify_expectation_delta.ts +521 -0
- package/src/scripts/ci_settle.ts +42 -5
- package/src/scripts/classify_merge_risk.ts +320 -0
- package/src/scripts/closure_scan.ts +91 -1
- package/src/scripts/code_graph/detect.ts +127 -7
- package/src/scripts/code_graph/foreign.ts +194 -0
- package/src/scripts/code_graph/query.ts +217 -4
- package/src/scripts/code_graph/types.ts +26 -2
- package/src/scripts/code_graph/validate.ts +3 -1
- package/src/scripts/code_graph/verbs.ts +103 -0
- package/src/scripts/command_suggester/settings.ts +8 -108
- package/src/scripts/command_suggester/types.ts +4 -5
- package/src/scripts/compile_hook_manifest.ts +33 -1
- package/src/scripts/condense.ts +14 -27
- package/src/scripts/consumer_matrix.ts +102 -0
- package/src/scripts/context_hygiene_hook.ts +13 -23
- package/src/scripts/cost/preflight.mjs +12 -1
- package/src/scripts/council_cli.ts +7 -7
- package/src/scripts/dispatch_r2_reviewer.ts +24 -11
- package/src/scripts/estate_exemption_shape.ts +202 -0
- package/src/scripts/explain_run.ts +8 -13
- package/src/scripts/generate_git_convention_grammar.ts +127 -0
- package/src/scripts/generate_host_cost_table.ts +21 -4
- package/src/scripts/handoff_context_hook.ts +86 -37
- package/src/scripts/hook_manifest.json +1 -1
- package/src/scripts/hook_manifest.yaml +175 -15
- package/src/scripts/hooks/block_config_weakening.ts +115 -7
- package/src/scripts/hooks/block_plumbing_writes.ts +37 -5
- package/src/scripts/hooks/code_graph_context_hook.ts +252 -23
- package/src/scripts/hooks/concern_failure_policy.ts +280 -0
- package/src/scripts/hooks/concern_registry.ts +2 -0
- package/src/scripts/hooks/delegation_nudge_hook.ts +2 -3
- package/src/scripts/hooks/dispatch_hook.ts +52 -52
- package/src/scripts/hooks/evidence_independence.ts +12 -4
- package/src/scripts/hooks/exit_codes.ts +2 -1
- package/src/scripts/hooks/host_lowering.json +1 -1
- package/src/scripts/hooks/host_lowering.ts +19 -1
- package/src/scripts/hooks/mcp_usage_observation_hook.ts +121 -0
- package/src/scripts/hooks/one_question_per_ask_hook.ts +41 -25
- package/src/scripts/hooks/payload_stub.ts +10 -1
- package/src/scripts/hooks/push_settle_hook.ts +4 -3
- package/src/scripts/hooks/rule_inject_hook.ts +795 -60
- package/src/scripts/hooks/state_io.ts +8 -4
- package/src/scripts/hooks/table_fingerprint.ts +21 -0
- package/src/scripts/hooks/telemetry_usage_hook.ts +24 -7
- package/src/scripts/hooks/turn_end_gate_hook.ts +85 -0
- package/src/scripts/hooks_status.ts +112 -0
- package/src/scripts/injection_scan_hook.ts +7 -0
- package/src/scripts/install-hooks.sh +42 -14
- package/src/scripts/install.ts +78 -215
- package/src/scripts/installed_layer_report.ts +103 -0
- package/src/scripts/language_mirror_hook.ts +15 -6
- package/src/scripts/learning_sidecar.ts +119 -8
- package/src/scripts/lint_blocker_citations.ts +198 -0
- package/src/scripts/lint_evidence_artifacts.ts +9 -0
- package/src/scripts/lint_hook_concern_budget.ts +10 -21
- package/src/scripts/lint_hook_manifest.ts +53 -0
- package/src/scripts/lint_major_migration_sections.ts +156 -26
- package/src/scripts/lint_pack_boundaries.ts +465 -29
- package/src/scripts/lint_roadmap_blockers.ts +282 -29
- package/src/scripts/lint_roadmap_complexity.ts +4 -2
- package/src/scripts/lint_rule_law_section.ts +647 -0
- package/src/scripts/lint_rule_skill_pack_reach.ts +17 -0
- package/src/scripts/lint_settings_classes.ts +1 -1
- package/src/scripts/lint_ticked_unmet_criteria.ts +165 -0
- package/src/scripts/lint_workflow_security.ts +173 -6
- package/src/scripts/mcp_server/consumer_tool_catalog.json +53 -0
- package/src/scripts/mcp_server/graph_tools.ts +72 -3
- package/src/scripts/measure_routing_signal.ts +54 -16
- package/src/scripts/measure_skill_ranker_baseline.ts +221 -8
- package/src/scripts/memory_learn_hook.ts +91 -6
- package/src/scripts/model_rule_injection.ts +55 -8
- package/src/scripts/onboarding_gate_hook.ts +7 -6
- package/src/scripts/print_required_checks.ts +15 -3
- package/src/scripts/probe_host_compliance.ts +33 -5
- package/src/scripts/probe_turnaround.ts +183 -3
- package/src/scripts/project_thin_rules.ts +34 -327
- package/src/scripts/ratification_header.ts +77 -0
- package/src/scripts/refusal_envelope.ts +138 -0
- package/src/scripts/release_publication.ts +29 -3
- package/src/scripts/report_dispatch_import_closure.ts +76 -0
- package/src/scripts/report_evidence_temperature.ts +657 -0
- package/src/scripts/report_installed_rule_links.ts +274 -0
- package/src/scripts/report_label_agreement.ts +233 -0
- package/src/scripts/report_module_reach.ts +212 -0
- package/src/scripts/report_obligation_mechanism.ts +228 -0
- package/src/scripts/report_parked_blockers.ts +222 -0
- package/src/scripts/report_required_checks_drift.ts +196 -0
- package/src/scripts/report_single_token_triggers.ts +277 -0
- package/src/scripts/report_skill_ranker_confusion.ts +543 -0
- package/src/scripts/report_standing_payload_by_host.ts +188 -15
- package/src/scripts/report_verification_record_coverage.ts +306 -0
- package/src/scripts/routing_doctor.ts +2 -2
- package/src/scripts/rule_activation_census.ts +5 -2
- package/src/scripts/rule_trigger_eval.ts +9 -9
- package/src/scripts/schemas/agent-settings.schema.json +17 -31
- package/src/scripts/schemas/command.schema.json +1 -1
- package/src/scripts/schemas/review-findings.schema.json +3 -2
- package/src/scripts/schemas/rule.schema.json +5 -0
- package/src/scripts/schemas/skill.schema.json +1 -1
- package/src/scripts/self_review_gate.ts +101 -9
- package/src/scripts/skill_tools/score_skill_relevance.ts +314 -40
- package/src/scripts/sweep_skill_ranker_signals.ts +129 -0
- package/src/scripts/sync_gitignore.ts +29 -235
- package/src/scripts/sync_pr_branch.ts +403 -132
- package/src/scripts/trigger_eval_grandfather.json +0 -21
- package/src/server/schemas/settings.ts +42 -176
- package/src/shared/skillRanking.ts +169 -14
- package/dist/cli-delegate/chunk-5R7HOLAF.js +0 -99
- package/dist/cli-delegate/chunk-JNMVLWLR.js +0 -4457
- package/dist/cli-delegate/chunk-YDPILCOL.js +0 -152
- package/src/scripts/_lib/config_chain.ts +0 -477
- package/src/scripts/_lib/conformance_report.ts +0 -403
- package/src/scripts/_lib/eval_discrimination.ts +0 -95
- package/src/scripts/_lib/evaluator_promotion.ts +0 -225
- package/src/scripts/_lib/file_slicer.ts +0 -117
- package/src/scripts/_lib/legacy_boundary_map.ts +0 -228
- package/src/scripts/_lib/minimality_tiebreak.ts +0 -168
- package/src/scripts/_lib/overbuild_lens_contract.ts +0 -196
- package/src/scripts/_lib/role_split.ts +0 -338
|
@@ -34,13 +34,45 @@
|
|
|
34
34
|
* this gate now matches that definition.
|
|
35
35
|
* - **BROKEN deliberately:** exit code 2 is new (dead scan scope). 0 and 1
|
|
36
36
|
* keep their meanings.
|
|
37
|
+
* - **BROKEN deliberately (2026-10-01):** the always-installed set is the
|
|
38
|
+
* hard-coded `core` PLUS every pack flagged `always_on: true`. The original
|
|
39
|
+
* knew only `core`, so it reported a violation for a target the resolver
|
|
40
|
+
* provably does install — the same defect shape as the direct-vs-transitive
|
|
41
|
+
* `requires` comparison above. `config/packs.resolve_active_packs` seeds the
|
|
42
|
+
* active set with the always-on packs before expanding any selection, and
|
|
43
|
+
* `docs/contracts/capability-packs.md` § Always-on packs states such a pack
|
|
44
|
+
* "cannot be deselected". One-way: a link OUT of an always-on pack into a
|
|
45
|
+
* gated one still dangles and is still reported.
|
|
37
46
|
* - **STILL HOLDS:** the CLI surface (`--format text|json`, `--quiet`, `-h`),
|
|
38
47
|
* the link regex and its fragment/query stripping, link-resolution semantics
|
|
39
48
|
* (external / absolute / out-of-tree targets ignored), the allow rule
|
|
40
|
-
* (same pack ·
|
|
49
|
+
* (same pack · always-installed · declared `requires`), the per-violation text and
|
|
41
50
|
* JSON shapes, the stdout/stderr split, and exit 0 clean / 1 violations.
|
|
51
|
+
* - **ADDED (2026-10-07):** a `scanned: <N>` line on every path (stdout in text
|
|
52
|
+
* mode, stderr under `--format json` so the payload stays parseable), and
|
|
53
|
+
* `--self-test`, which runs this CLI against planted fixture trees. Both are
|
|
54
|
+
* what `src/config/gate-coverage.yml` asks of a gate a pull request runs.
|
|
42
55
|
*
|
|
43
|
-
*
|
|
56
|
+
* THE ADVISORY `suggests` EDGE, AND THE SIBLING GATE THAT REFUSES IT.
|
|
57
|
+
* Since D5 of `road-to-gates-a-pull-request-can-hear` (AI council 2026-10-07)
|
|
58
|
+
* this gate reads `suggests` as PERMITTING a cross-pack link: advisory,
|
|
59
|
+
* non-installing, one-hop, one-way. `lint_rule_skill_pack_reach` states in its
|
|
60
|
+
* own header that `suggests` is deliberately NOT followed. Both are correct,
|
|
61
|
+
* and the discriminator is the direction of the claim:
|
|
62
|
+
*
|
|
63
|
+
* - THAT gate asserts a route WILL RESOLVE. Counting an advisory edge would
|
|
64
|
+
* assert resolution on installs that may not exist.
|
|
65
|
+
* - THIS gate reports a link that MAY DANGLE. An advisory edge is the author
|
|
66
|
+
* stating they accept the dangle for a consumer who declines the companion,
|
|
67
|
+
* so reading it downgrades a finding the author has already answered.
|
|
68
|
+
*
|
|
69
|
+
* The permit is per EDGE, not per link. The council's condition — only
|
|
70
|
+
* safely-degrading links may be permitted — was verified once, by hand, over
|
|
71
|
+
* the 203 links at the 2026-10-09 baseline; nothing re-verifies it for links
|
|
72
|
+
* added later. That is why the permitted COUNT prints on every run including
|
|
73
|
+
* `--quiet`: it is the only standing signal that the set is growing.
|
|
74
|
+
*
|
|
75
|
+
* WHERE THE `requires` GRAPH IS READ FROM.
|
|
44
76
|
*
|
|
45
77
|
* `src/config/discovery/packs.yml` is the source of truth for the pack
|
|
46
78
|
* vocabulary and its `requires` edges — `generate_pack_manifests.ts` DERIVES
|
|
@@ -53,6 +85,7 @@
|
|
|
53
85
|
*/
|
|
54
86
|
|
|
55
87
|
import * as fs from 'node:fs';
|
|
88
|
+
import * as os from 'node:os';
|
|
56
89
|
import * as path from 'node:path';
|
|
57
90
|
import { fileURLToPath, pathToFileURL } from 'node:url';
|
|
58
91
|
import { parse as parseYaml } from 'yaml';
|
|
@@ -65,7 +98,8 @@ import {
|
|
|
65
98
|
iter_artefacts,
|
|
66
99
|
} from './_lib/agent_src.js';
|
|
67
100
|
import { checkRatchet } from './_lib/gate_baseline.js';
|
|
68
|
-
import {
|
|
101
|
+
import { runGateCli, runSelfTest } from './_lib/gate_self_test.js';
|
|
102
|
+
import { DeadScopeError, reportScanned } from './_lib/scan_scope.js';
|
|
69
103
|
import { parse_frontmatter } from './validate_frontmatter.js';
|
|
70
104
|
|
|
71
105
|
const _HERE = path.resolve(fileURLToPath(import.meta.url));
|
|
@@ -109,12 +143,66 @@ function _set_paths_for_test(opts: { root?: string; vocab?: string }): void {
|
|
|
109
143
|
}
|
|
110
144
|
}
|
|
111
145
|
|
|
146
|
+
// `--self-test` drives this CLI from a CHILD process, which cannot reach the
|
|
147
|
+
// setter above, so the fixture root is also readable from the environment.
|
|
148
|
+
// Applied through the setter rather than at the `ROOT` declaration, so a
|
|
149
|
+
// fixture run is still recognised as overridden and never judged by the
|
|
150
|
+
// repo's violation ratchet.
|
|
151
|
+
// Honoured only inside a self-test child, so an inherited value can never
|
|
152
|
+
// redirect the production gate or switch its ratchet off.
|
|
153
|
+
const _ENV_ROOT =
|
|
154
|
+
process.env['GATE_SELF_TEST_CHILD'] === '1' ? process.env['LINT_PACK_BOUNDARIES_ROOT'] : undefined;
|
|
155
|
+
if (_ENV_ROOT !== undefined && _ENV_ROOT !== '') {
|
|
156
|
+
_set_paths_for_test({ root: _realpath(path.resolve(_ENV_ROOT)) });
|
|
157
|
+
}
|
|
158
|
+
|
|
112
159
|
// [..](target) with an optional #fragment / ?query stripped from the target.
|
|
113
160
|
const LINK_RE = /\[[^\]]*\]\(([^)#?]+)(?:[#?][^)]*)?\)/g;
|
|
114
161
|
|
|
115
162
|
/** A pack every install carries — a link into it can never dangle. */
|
|
116
163
|
const ALWAYS_INSTALLED = 'core';
|
|
117
164
|
|
|
165
|
+
/**
|
|
166
|
+
* Packs every projection carries, so a link INTO one can never dangle.
|
|
167
|
+
*
|
|
168
|
+
* `core` is the hard-coded floor. Beyond it, `always_on: true` in the pack
|
|
169
|
+
* vocabulary means exactly this: `config/packs.resolve_active_packs` seeds the
|
|
170
|
+
* active set with every always-on pack BEFORE expanding the selected profile's
|
|
171
|
+
* `requires` closure, and `docs/contracts/capability-packs.md` § Always-on
|
|
172
|
+
* packs states the pack "is never gated by the selected profile, workspace, or
|
|
173
|
+
* pack set, and it cannot be deselected".
|
|
174
|
+
*
|
|
175
|
+
* Reading only `core` was the same class of defect this file's header already
|
|
176
|
+
* records for the direct-vs-transitive `requires` comparison: the gate reported
|
|
177
|
+
* a violation for a target the resolver provably does install. The direction is
|
|
178
|
+
* one-way — a link OUT of an always-on pack into a gated one still dangles and
|
|
179
|
+
* is still a violation.
|
|
180
|
+
*/
|
|
181
|
+
function _always_installed_packs(): Set<string> {
|
|
182
|
+
const out = new Set<string>([ALWAYS_INSTALLED]);
|
|
183
|
+
if (_exists(VOCAB)) {
|
|
184
|
+
const vocab = parseYaml(fs.readFileSync(VOCAB, 'utf-8'), { version: '1.1' });
|
|
185
|
+
if (Array.isArray(vocab)) {
|
|
186
|
+
for (const entry of vocab) {
|
|
187
|
+
if (entry !== null && typeof entry === 'object' && !Array.isArray(entry)) {
|
|
188
|
+
const e = entry as Record<string, unknown>;
|
|
189
|
+
if (typeof e['id'] === 'string' && e['always_on'] === true) {
|
|
190
|
+
out.add(e['id']);
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
for (const dir of _pack_home_dirs()) {
|
|
197
|
+
const meta = _load_pack_meta(dir);
|
|
198
|
+
if (meta['always_on'] === true) {
|
|
199
|
+
const id = typeof meta['id'] === 'string' ? meta['id'] : path.basename(dir);
|
|
200
|
+
out.add(id);
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
return out;
|
|
204
|
+
}
|
|
205
|
+
|
|
118
206
|
type ViolationKind =
|
|
119
207
|
/** Link crosses into a pack the source pack does not require. */
|
|
120
208
|
| 'cross-pack'
|
|
@@ -130,6 +218,35 @@ interface ViolationRecord {
|
|
|
130
218
|
link: string;
|
|
131
219
|
}
|
|
132
220
|
|
|
221
|
+
/**
|
|
222
|
+
* Which edge permits a cross-pack link. `null` is the violation case.
|
|
223
|
+
*
|
|
224
|
+
* `suggests` is the advisory, non-installing edge added for the base-into-
|
|
225
|
+
* narrow class (D5 of `road-to-gates-a-pull-request-can-hear`, AI council
|
|
226
|
+
* 2026-10-07). It is the WEAKEST promise in the list, which is why the ranking
|
|
227
|
+
* below exists: a link that needs it is reported as needing it, never as a
|
|
228
|
+
* `requires` link that happens to also hold.
|
|
229
|
+
*/
|
|
230
|
+
type PermitReason = 'same-pack' | 'always-installed' | 'requires' | 'suggests' | null;
|
|
231
|
+
|
|
232
|
+
/** Strength order — lower is a stronger guarantee that the target is present. */
|
|
233
|
+
const PERMIT_RANK: Record<Exclude<PermitReason, null>, number> = {
|
|
234
|
+
'same-pack': 0,
|
|
235
|
+
'always-installed': 1,
|
|
236
|
+
requires: 2,
|
|
237
|
+
suggests: 3,
|
|
238
|
+
};
|
|
239
|
+
|
|
240
|
+
/** A link permitted only by `suggests`, kept for the `--show-permitted` report. */
|
|
241
|
+
interface PermittedRecord {
|
|
242
|
+
source_pack: string;
|
|
243
|
+
target_pack: string;
|
|
244
|
+
source: string;
|
|
245
|
+
target: string;
|
|
246
|
+
link: string;
|
|
247
|
+
reason: Exclude<PermitReason, null>;
|
|
248
|
+
}
|
|
249
|
+
|
|
133
250
|
/** Mirror Python `Path.resolve()`: canonicalize existing prefix, append rest. */
|
|
134
251
|
function _realpath(p: string): string {
|
|
135
252
|
try {
|
|
@@ -275,7 +392,36 @@ function _pack_home_dirs(): string[] {
|
|
|
275
392
|
* manifests as an overlay for pack homes the vocabulary does not list.
|
|
276
393
|
*/
|
|
277
394
|
function _pack_requires(): Map<string, string[]> {
|
|
278
|
-
|
|
395
|
+
return _pack_edges().requires;
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
/**
|
|
399
|
+
* `pack id -> direct suggests`.
|
|
400
|
+
*
|
|
401
|
+
* Deliberately NOT expanded: `suggests` is one-hop. Transitive expansion would
|
|
402
|
+
* give the advisory edge the install-forcing reach `requires` has, which is the
|
|
403
|
+
* property the base-into-narrow decision depends on it not having.
|
|
404
|
+
*/
|
|
405
|
+
function _pack_suggests(): Map<string, string[]> {
|
|
406
|
+
return _pack_edges().suggests;
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
/**
|
|
410
|
+
* Both edge maps, from ONE read of the vocabulary and one walk of the pack
|
|
411
|
+
* homes.
|
|
412
|
+
*
|
|
413
|
+
* One reader rather than two near-identical ones, so the VOCAB-wins precedence
|
|
414
|
+
* below exists in a single place: two copies would have to be kept in step by
|
|
415
|
+
* hand, and a `requires` map that fell out of step with a `suggests` map read
|
|
416
|
+
* from the same file is a drift nothing reports.
|
|
417
|
+
*
|
|
418
|
+
* NOTE for anyone adding an edge: a `pack.yaml` is only consulted for a pack
|
|
419
|
+
* the vocabulary does not list, so declaring `suggests` there alone has no
|
|
420
|
+
* effect on this gate. `packs.yml` is where an edge has to go.
|
|
421
|
+
*/
|
|
422
|
+
function _pack_edges(): { requires: Map<string, string[]>; suggests: Map<string, string[]> } {
|
|
423
|
+
const requires = new Map<string, string[]>();
|
|
424
|
+
const suggests = new Map<string, string[]>();
|
|
279
425
|
const asList = (v: unknown): string[] => (Array.isArray(v) ? v.map(String) : []);
|
|
280
426
|
|
|
281
427
|
if (_exists(VOCAB)) {
|
|
@@ -285,7 +431,8 @@ function _pack_requires(): Map<string, string[]> {
|
|
|
285
431
|
if (entry !== null && typeof entry === 'object' && !Array.isArray(entry)) {
|
|
286
432
|
const e = entry as Record<string, unknown>;
|
|
287
433
|
if (typeof e['id'] === 'string') {
|
|
288
|
-
|
|
434
|
+
requires.set(e['id'], asList(e['requires']));
|
|
435
|
+
suggests.set(e['id'], asList(e['suggests']));
|
|
289
436
|
}
|
|
290
437
|
}
|
|
291
438
|
}
|
|
@@ -294,11 +441,12 @@ function _pack_requires(): Map<string, string[]> {
|
|
|
294
441
|
for (const dir of _pack_home_dirs()) {
|
|
295
442
|
const meta = _load_pack_meta(dir);
|
|
296
443
|
const id = typeof meta['id'] === 'string' ? meta['id'] : path.basename(dir);
|
|
297
|
-
if (!
|
|
298
|
-
|
|
444
|
+
if (!requires.has(id)) {
|
|
445
|
+
requires.set(id, asList(meta['requires']));
|
|
446
|
+
suggests.set(id, asList(meta['suggests']));
|
|
299
447
|
}
|
|
300
448
|
}
|
|
301
|
-
return
|
|
449
|
+
return { requires, suggests };
|
|
302
450
|
}
|
|
303
451
|
|
|
304
452
|
/** Transitive expansion of `requires`, cycle-safe. */
|
|
@@ -479,14 +627,45 @@ function _scan_file(p: string): string[] {
|
|
|
479
627
|
return out;
|
|
480
628
|
}
|
|
481
629
|
|
|
482
|
-
|
|
630
|
+
/**
|
|
631
|
+
* Which edge, if any, lets a link out of `source_pack` reach `target_pack`.
|
|
632
|
+
*
|
|
633
|
+
* `null` is the violation case. The reason is returned rather than a bare
|
|
634
|
+
* boolean because `suggests` is advisory: a reader who sees a permitted
|
|
635
|
+
* base-into-narrow link needs to know it was permitted by an edge that does
|
|
636
|
+
* NOT install the target, which is a different promise from `requires`.
|
|
637
|
+
*/
|
|
638
|
+
function _permit_reason(
|
|
639
|
+
source_pack: string,
|
|
640
|
+
target_pack: string,
|
|
641
|
+
requires: string[],
|
|
642
|
+
always_installed: ReadonlySet<string> = new Set([ALWAYS_INSTALLED]),
|
|
643
|
+
suggests: readonly string[] = [],
|
|
644
|
+
): PermitReason {
|
|
483
645
|
if (source_pack === target_pack) {
|
|
484
|
-
return
|
|
646
|
+
return 'same-pack';
|
|
485
647
|
}
|
|
486
|
-
if (target_pack
|
|
487
|
-
return
|
|
648
|
+
if (always_installed.has(target_pack)) {
|
|
649
|
+
return 'always-installed';
|
|
488
650
|
}
|
|
489
|
-
|
|
651
|
+
if ((requires || []).includes(target_pack)) {
|
|
652
|
+
return 'requires';
|
|
653
|
+
}
|
|
654
|
+
// One-hop and one-way by construction: the caller passes the SOURCE pack's
|
|
655
|
+
// own direct `suggests` list, never a closure over it. A transitive
|
|
656
|
+
// advisory edge would re-create the install-forcing reach `requires` has,
|
|
657
|
+
// which is the property this edge exists not to have.
|
|
658
|
+
return suggests.includes(target_pack) ? 'suggests' : null;
|
|
659
|
+
}
|
|
660
|
+
|
|
661
|
+
function _is_allowed(
|
|
662
|
+
source_pack: string,
|
|
663
|
+
target_pack: string,
|
|
664
|
+
requires: string[],
|
|
665
|
+
always_installed: ReadonlySet<string> = new Set([ALWAYS_INSTALLED]),
|
|
666
|
+
suggests: readonly string[] = [],
|
|
667
|
+
): boolean {
|
|
668
|
+
return _permit_reason(source_pack, target_pack, requires, always_installed, suggests) !== null;
|
|
490
669
|
}
|
|
491
670
|
|
|
492
671
|
/**
|
|
@@ -501,11 +680,48 @@ function _link_allowed(
|
|
|
501
680
|
source_packs: readonly string[],
|
|
502
681
|
target_packs: readonly string[],
|
|
503
682
|
closureOf: (pack: string) => Set<string>,
|
|
683
|
+
always_installed: ReadonlySet<string> = new Set([ALWAYS_INSTALLED]),
|
|
684
|
+
suggestsOf: (pack: string) => readonly string[] = () => [],
|
|
504
685
|
): boolean {
|
|
505
|
-
return
|
|
686
|
+
return (
|
|
687
|
+
_link_permit_reason(source_packs, target_packs, closureOf, always_installed, suggestsOf) !==
|
|
688
|
+
null
|
|
689
|
+
);
|
|
690
|
+
}
|
|
691
|
+
|
|
692
|
+
/**
|
|
693
|
+
* The weakest edge the link relies on, or `null` when nothing permits it.
|
|
694
|
+
*
|
|
695
|
+
* Weakest, not first: a link permitted for one source pack by `requires` and
|
|
696
|
+
* for another only by `suggests` is reported as `suggests`, because that is
|
|
697
|
+
* the promise a consumer actually gets.
|
|
698
|
+
*/
|
|
699
|
+
function _link_permit_reason(
|
|
700
|
+
source_packs: readonly string[],
|
|
701
|
+
target_packs: readonly string[],
|
|
702
|
+
closureOf: (pack: string) => Set<string>,
|
|
703
|
+
always_installed: ReadonlySet<string> = new Set([ALWAYS_INSTALLED]),
|
|
704
|
+
suggestsOf: (pack: string) => readonly string[] = () => [],
|
|
705
|
+
): PermitReason {
|
|
706
|
+
let weakest: PermitReason = 'same-pack';
|
|
707
|
+
for (const s of source_packs) {
|
|
506
708
|
const reach = [...closureOf(s)];
|
|
507
|
-
|
|
508
|
-
|
|
709
|
+
const sug = suggestsOf(s);
|
|
710
|
+
let best: PermitReason = null;
|
|
711
|
+
for (const t of target_packs) {
|
|
712
|
+
const r = _permit_reason(s, t, reach, always_installed, sug);
|
|
713
|
+
if (r !== null && (best === null || PERMIT_RANK[r] < PERMIT_RANK[best])) {
|
|
714
|
+
best = r;
|
|
715
|
+
}
|
|
716
|
+
}
|
|
717
|
+
if (best === null) {
|
|
718
|
+
return null;
|
|
719
|
+
}
|
|
720
|
+
if (PERMIT_RANK[best] > PERMIT_RANK[weakest]) {
|
|
721
|
+
weakest = best;
|
|
722
|
+
}
|
|
723
|
+
}
|
|
724
|
+
return weakest;
|
|
509
725
|
}
|
|
510
726
|
|
|
511
727
|
/** Mirror Python `json.dump(obj, indent=2)` with `ensure_ascii=True`. */
|
|
@@ -528,11 +744,14 @@ function _json_dumps_ascii(obj: unknown): string {
|
|
|
528
744
|
interface ParsedArgs {
|
|
529
745
|
format: 'text' | 'json';
|
|
530
746
|
quiet: boolean;
|
|
747
|
+
/** List the links permitted only by an advisory `suggests` edge. */
|
|
748
|
+
show_permitted: boolean;
|
|
531
749
|
}
|
|
532
750
|
|
|
533
751
|
function parse_args(argv: readonly string[]): ParsedArgs {
|
|
534
752
|
let format: 'text' | 'json' = 'text';
|
|
535
753
|
let quiet = false;
|
|
754
|
+
let show_permitted = false;
|
|
536
755
|
for (let i = 0; i < argv.length; i++) {
|
|
537
756
|
const arg = argv[i] as string;
|
|
538
757
|
if (arg === '--format') {
|
|
@@ -556,16 +775,19 @@ function parse_args(argv: readonly string[]): ParsedArgs {
|
|
|
556
775
|
format = v;
|
|
557
776
|
} else if (arg === '--quiet') {
|
|
558
777
|
quiet = true;
|
|
778
|
+
} else if (arg === '--show-permitted') {
|
|
779
|
+
show_permitted = true;
|
|
559
780
|
} else if (arg === '-h' || arg === '--help') {
|
|
560
781
|
process.stdout.write(
|
|
561
|
-
'usage: lint_pack_boundaries [-h] [--format {text,json}] [--quiet]
|
|
782
|
+
'usage: lint_pack_boundaries [-h] [--format {text,json}] [--quiet] ' +
|
|
783
|
+
'[--show-permitted] [--self-test]\n',
|
|
562
784
|
);
|
|
563
785
|
process.exit(0);
|
|
564
786
|
} else {
|
|
565
787
|
_argparse_error(`unrecognized arguments: ${arg}`);
|
|
566
788
|
}
|
|
567
789
|
}
|
|
568
|
-
return { format, quiet };
|
|
790
|
+
return { format, quiet, show_permitted };
|
|
569
791
|
}
|
|
570
792
|
|
|
571
793
|
function _argparse_error(message: string): never {
|
|
@@ -573,8 +795,161 @@ function _argparse_error(message: string): never {
|
|
|
573
795
|
process.exit(2);
|
|
574
796
|
}
|
|
575
797
|
|
|
798
|
+
/**
|
|
799
|
+
* Plant fixture trees and run this gate's real CLI against each one.
|
|
800
|
+
*
|
|
801
|
+
* Three rejecting cases cover the three exits a pull request can be failed by:
|
|
802
|
+
* an undeclared cross-pack link, an artefact with no resolvable pack, and an
|
|
803
|
+
* empty corpus. The two accepting cases pin the allow rule from the other side,
|
|
804
|
+
* so a gate that started rejecting everything fails here too.
|
|
805
|
+
*/
|
|
806
|
+
function selfTest(): number {
|
|
807
|
+
const plant = (name: string, files: Record<string, string>): string => {
|
|
808
|
+
const dir = fs.mkdtempSync(path.join(os.tmpdir(), `lpb-selftest-${name}-`));
|
|
809
|
+
for (const [rel, body] of Object.entries(files)) {
|
|
810
|
+
const p = path.join(dir, rel);
|
|
811
|
+
fs.mkdirSync(path.dirname(p), { recursive: true });
|
|
812
|
+
fs.writeFileSync(p, body, 'utf-8');
|
|
813
|
+
}
|
|
814
|
+
return dir;
|
|
815
|
+
};
|
|
816
|
+
const skill = (slug: string, packs: string, body: string): [string, string] => [
|
|
817
|
+
`skills/${slug}/SKILL.md`,
|
|
818
|
+
`---\nname: ${slug}\npacks: [${packs}]\n---\n\n${body}\n`,
|
|
819
|
+
];
|
|
820
|
+
const run = (dir: string): number => {
|
|
821
|
+
const prev = process.env['LINT_PACK_BOUNDARIES_ROOT'];
|
|
822
|
+
process.env['LINT_PACK_BOUNDARIES_ROOT'] = dir;
|
|
823
|
+
try {
|
|
824
|
+
return runGateCli(
|
|
825
|
+
_DEFAULT_ROOT,
|
|
826
|
+
path.join('src', 'scripts', 'lint_pack_boundaries.ts'),
|
|
827
|
+
['--quiet'],
|
|
828
|
+
_DEFAULT_ROOT,
|
|
829
|
+
);
|
|
830
|
+
} finally {
|
|
831
|
+
if (prev === undefined) {
|
|
832
|
+
delete process.env['LINT_PACK_BOUNDARIES_ROOT'];
|
|
833
|
+
} else {
|
|
834
|
+
process.env['LINT_PACK_BOUNDARIES_ROOT'] = prev;
|
|
835
|
+
}
|
|
836
|
+
fs.rmSync(dir, { recursive: true, force: true });
|
|
837
|
+
}
|
|
838
|
+
};
|
|
839
|
+
const twoPacks = '- id: alpha\n requires: []\n- id: beta\n requires: []\n';
|
|
840
|
+
// A reject case counts only on the exit it names: a crash or a dead-scope
|
|
841
|
+
// exit on a fixture that should yield a finding reads as NOT rejected.
|
|
842
|
+
const rejectsWith = (want: number, got: number): number => (got === want ? 1 : 0);
|
|
843
|
+
|
|
844
|
+
return runSelfTest({
|
|
845
|
+
gate: 'lint_pack_boundaries',
|
|
846
|
+
minCases: 7,
|
|
847
|
+
minRejectCases: 4,
|
|
848
|
+
cases: [
|
|
849
|
+
{
|
|
850
|
+
name: 'an undeclared cross-pack link is rejected with exit 1',
|
|
851
|
+
expect: 'reject',
|
|
852
|
+
run: () =>
|
|
853
|
+
rejectsWith(1, run(
|
|
854
|
+
plant('cross', {
|
|
855
|
+
'packs.yml': twoPacks,
|
|
856
|
+
...Object.fromEntries([
|
|
857
|
+
skill('a-one', 'alpha', 'reaches [b](../b-one/SKILL.md)'),
|
|
858
|
+
skill('b-one', 'beta', 'leaf'),
|
|
859
|
+
]),
|
|
860
|
+
}),
|
|
861
|
+
)),
|
|
862
|
+
},
|
|
863
|
+
{
|
|
864
|
+
name: 'a SKILL.md with no packs is a finding (exit 1), never a silent pass',
|
|
865
|
+
expect: 'reject',
|
|
866
|
+
run: () =>
|
|
867
|
+
rejectsWith(1, run(
|
|
868
|
+
plant('nopack', {
|
|
869
|
+
'packs.yml': twoPacks,
|
|
870
|
+
'skills/nopack/SKILL.md': '---\nname: nopack\n---\n\nno packs key\n',
|
|
871
|
+
}),
|
|
872
|
+
)),
|
|
873
|
+
},
|
|
874
|
+
{
|
|
875
|
+
name: 'an empty corpus is a dead scope (exit 2), not "no cross-pack drift"',
|
|
876
|
+
expect: 'reject',
|
|
877
|
+
run: () => rejectsWith(2, run(plant('empty', { 'packs.yml': twoPacks }))),
|
|
878
|
+
},
|
|
879
|
+
{
|
|
880
|
+
name: 'a link declared through requires passes',
|
|
881
|
+
expect: 'accept',
|
|
882
|
+
run: () =>
|
|
883
|
+
run(
|
|
884
|
+
plant('declared', {
|
|
885
|
+
'packs.yml': '- id: alpha\n requires: [beta]\n- id: beta\n requires: []\n',
|
|
886
|
+
...Object.fromEntries([
|
|
887
|
+
skill('a-one', 'alpha', 'reaches [b](../b-one/SKILL.md)'),
|
|
888
|
+
skill('b-one', 'beta', 'leaf'),
|
|
889
|
+
]),
|
|
890
|
+
}),
|
|
891
|
+
),
|
|
892
|
+
},
|
|
893
|
+
{
|
|
894
|
+
name: 'a link inside one pack passes',
|
|
895
|
+
expect: 'accept',
|
|
896
|
+
run: () =>
|
|
897
|
+
run(
|
|
898
|
+
plant('same', {
|
|
899
|
+
'packs.yml': twoPacks,
|
|
900
|
+
...Object.fromEntries([
|
|
901
|
+
skill('a-one', 'alpha', 'reaches [two](../a-two/SKILL.md)'),
|
|
902
|
+
skill('a-two', 'alpha', 'leaf'),
|
|
903
|
+
]),
|
|
904
|
+
}),
|
|
905
|
+
),
|
|
906
|
+
},
|
|
907
|
+
{
|
|
908
|
+
name: 'a link an advisory `suggests` edge permits passes',
|
|
909
|
+
expect: 'accept',
|
|
910
|
+
run: () =>
|
|
911
|
+
run(
|
|
912
|
+
plant('suggests-permit', {
|
|
913
|
+
'packs.yml':
|
|
914
|
+
'- id: alpha\n requires: []\n suggests: [beta]\n' +
|
|
915
|
+
'- id: beta\n requires: []\n',
|
|
916
|
+
...Object.fromEntries([
|
|
917
|
+
skill('a-one', 'alpha', 'reaches [b](../b-one/SKILL.md)'),
|
|
918
|
+
skill('b-one', 'beta', 'leaf'),
|
|
919
|
+
]),
|
|
920
|
+
}),
|
|
921
|
+
),
|
|
922
|
+
},
|
|
923
|
+
{
|
|
924
|
+
// The denial half. Without it the case above cannot tell a
|
|
925
|
+
// working permit from a gate that stopped reporting at all.
|
|
926
|
+
name: 'the same link without the `suggests` edge is still rejected with exit 1',
|
|
927
|
+
expect: 'reject',
|
|
928
|
+
run: () =>
|
|
929
|
+
rejectsWith(1, run(
|
|
930
|
+
plant('suggests-absent', {
|
|
931
|
+
'packs.yml': twoPacks,
|
|
932
|
+
...Object.fromEntries([
|
|
933
|
+
skill('a-one', 'alpha', 'reaches [b](../b-one/SKILL.md)'),
|
|
934
|
+
skill('b-one', 'beta', 'leaf'),
|
|
935
|
+
]),
|
|
936
|
+
}),
|
|
937
|
+
)),
|
|
938
|
+
},
|
|
939
|
+
],
|
|
940
|
+
});
|
|
941
|
+
}
|
|
942
|
+
|
|
576
943
|
function main(argv?: readonly string[]): number {
|
|
577
|
-
const
|
|
944
|
+
const rawArgv = argv ?? process.argv.slice(2);
|
|
945
|
+
if (rawArgv.includes('--self-test')) {
|
|
946
|
+
if (process.env['GATE_SELF_TEST_CHILD'] === '1') {
|
|
947
|
+
process.stderr.write('lint_pack_boundaries: --self-test does not recurse\n');
|
|
948
|
+
return 2;
|
|
949
|
+
}
|
|
950
|
+
return selfTest();
|
|
951
|
+
}
|
|
952
|
+
const args = parse_args(rawArgv);
|
|
578
953
|
|
|
579
954
|
const { index: artefact_pack, unassigned, scanned } = _build_artefact_index();
|
|
580
955
|
|
|
@@ -582,12 +957,17 @@ function main(argv?: readonly string[]): number {
|
|
|
582
957
|
// clean. That was this gate's shipped state until 2026-08-02 — it walked
|
|
583
958
|
// the deleted `packages/` tree and skipped green forever.
|
|
584
959
|
try {
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
960
|
+
reportScanned(
|
|
961
|
+
{
|
|
962
|
+
gate: 'lint_pack_boundaries',
|
|
963
|
+
scanned,
|
|
964
|
+
units: 'artefact(s)',
|
|
965
|
+
roots: _scan_roots().map((r) => _relPosix(r, ROOT) || '.'),
|
|
966
|
+
},
|
|
967
|
+
args.format === 'json'
|
|
968
|
+
? process.stderr.write.bind(process.stderr)
|
|
969
|
+
: process.stdout.write.bind(process.stdout),
|
|
970
|
+
);
|
|
591
971
|
} catch (exc) {
|
|
592
972
|
if (!(exc instanceof DeadScopeError)) {
|
|
593
973
|
throw exc;
|
|
@@ -596,7 +976,9 @@ function main(argv?: readonly string[]): number {
|
|
|
596
976
|
return 2;
|
|
597
977
|
}
|
|
598
978
|
|
|
599
|
-
const pack_requires =
|
|
979
|
+
const { requires: pack_requires, suggests: pack_suggests } = _pack_edges();
|
|
980
|
+
const suggestsOf = (pack: string): readonly string[] => pack_suggests.get(pack) ?? [];
|
|
981
|
+
const always_installed = _always_installed_packs();
|
|
600
982
|
const closureCache = new Map<string, Set<string>>();
|
|
601
983
|
const closureOf = (pack: string): Set<string> => {
|
|
602
984
|
let c = closureCache.get(pack);
|
|
@@ -608,6 +990,7 @@ function main(argv?: readonly string[]): number {
|
|
|
608
990
|
};
|
|
609
991
|
|
|
610
992
|
const violations: ViolationRecord[] = [];
|
|
993
|
+
const permitted: PermittedRecord[] = [];
|
|
611
994
|
|
|
612
995
|
// Fail-safe: a unit-defining artefact with no resolvable pack cannot be
|
|
613
996
|
// boundary-checked, so it is a finding rather than a silent exclusion.
|
|
@@ -635,7 +1018,27 @@ function main(argv?: readonly string[]): number {
|
|
|
635
1018
|
if (target_packs === undefined) {
|
|
636
1019
|
continue; // docs/, scripts/, root files, unassigned — not pack-scoped
|
|
637
1020
|
}
|
|
638
|
-
|
|
1021
|
+
const reason = _link_permit_reason(
|
|
1022
|
+
src_packs,
|
|
1023
|
+
target_packs,
|
|
1024
|
+
closureOf,
|
|
1025
|
+
always_installed,
|
|
1026
|
+
suggestsOf,
|
|
1027
|
+
);
|
|
1028
|
+
if (reason !== null) {
|
|
1029
|
+
// Only the advisory edge is worth reporting: the other three
|
|
1030
|
+
// mean the target is installed, so there is nothing a reader
|
|
1031
|
+
// has to weigh.
|
|
1032
|
+
if (reason === 'suggests') {
|
|
1033
|
+
permitted.push({
|
|
1034
|
+
source_pack: src_packs.join('+'),
|
|
1035
|
+
target_pack: target_packs.join('+'),
|
|
1036
|
+
source: rel_path,
|
|
1037
|
+
target: target_rel,
|
|
1038
|
+
link: raw,
|
|
1039
|
+
reason,
|
|
1040
|
+
});
|
|
1041
|
+
}
|
|
639
1042
|
continue;
|
|
640
1043
|
}
|
|
641
1044
|
violations.push({
|
|
@@ -665,6 +1068,7 @@ function main(argv?: readonly string[]): number {
|
|
|
665
1068
|
count: violations.length,
|
|
666
1069
|
scanned,
|
|
667
1070
|
unassigned: unassigned.length,
|
|
1071
|
+
permitted_by_suggests: permitted,
|
|
668
1072
|
ratchet:
|
|
669
1073
|
verdict === null ? null : { status: verdict.status, baseline: verdict.baseline },
|
|
670
1074
|
}) + '\n',
|
|
@@ -678,6 +1082,32 @@ function main(argv?: readonly string[]): number {
|
|
|
678
1082
|
`${pack_requires.size} packs (${unassigned.length} outside pack scope)\n`,
|
|
679
1083
|
);
|
|
680
1084
|
}
|
|
1085
|
+
// Two different questions, so two different defaults.
|
|
1086
|
+
//
|
|
1087
|
+
// HOW MANY links an advisory edge is carrying prints on EVERY run,
|
|
1088
|
+
// `--quiet` included. The permit is granted per EDGE, not per link: once an
|
|
1089
|
+
// edge is declared, every future link on it is permitted without anyone
|
|
1090
|
+
// re-checking that it degrades safely. An adversarial review demonstrated
|
|
1091
|
+
// that by planting a link on a declared edge and watching this gate exit 0
|
|
1092
|
+
// where it would previously have failed the pull request. `--quiet` is what
|
|
1093
|
+
// CI passes, so a count visible only without it would miss the one log that
|
|
1094
|
+
// matters.
|
|
1095
|
+
//
|
|
1096
|
+
// WHICH links they are stays behind `--show-permitted`. A permit is not a
|
|
1097
|
+
// finding, and printing dozens of lines beside the violations reads as one.
|
|
1098
|
+
process.stdout.write(
|
|
1099
|
+
`${permitted.length} link(s) permitted by an advisory \`suggests\` edge` +
|
|
1100
|
+
(args.show_permitted ? '' : ' (--show-permitted lists them)') +
|
|
1101
|
+
'\n',
|
|
1102
|
+
);
|
|
1103
|
+
if (args.show_permitted) {
|
|
1104
|
+
for (const p of permitted) {
|
|
1105
|
+
process.stdout.write(
|
|
1106
|
+
` ~ ${p.source_pack} -> ${p.target_pack} : ${p.source} \u2192 ${p.target} ` +
|
|
1107
|
+
`(link: ${p.link}) — permitted by \`${p.reason}\`\n`,
|
|
1108
|
+
);
|
|
1109
|
+
}
|
|
1110
|
+
}
|
|
681
1111
|
for (const v of violations) {
|
|
682
1112
|
if (v.kind === 'unresolved-pack') {
|
|
683
1113
|
process.stdout.write(
|
|
@@ -693,8 +1123,8 @@ function main(argv?: readonly string[]): number {
|
|
|
693
1123
|
}
|
|
694
1124
|
if (violations.length > 0) {
|
|
695
1125
|
process.stdout.write(
|
|
696
|
-
`\n${violations.length} cross-pack violation(s) — declare 'requires'
|
|
697
|
-
'
|
|
1126
|
+
`\n${violations.length} cross-pack violation(s) — declare 'requires' or an ` +
|
|
1127
|
+
"advisory 'suggests' edge in packs.yml, or move the artefact\n",
|
|
698
1128
|
);
|
|
699
1129
|
if (verdict !== null) {
|
|
700
1130
|
if (verdict.ok) {
|
|
@@ -743,9 +1173,15 @@ export {
|
|
|
743
1173
|
_build_artefact_index,
|
|
744
1174
|
_resolve_link,
|
|
745
1175
|
_scan_file,
|
|
1176
|
+
_always_installed_packs,
|
|
1177
|
+
type PermitReason,
|
|
746
1178
|
_is_allowed,
|
|
747
1179
|
_link_allowed,
|
|
1180
|
+
_link_permit_reason,
|
|
1181
|
+
_pack_suggests,
|
|
1182
|
+
_permit_reason,
|
|
748
1183
|
_load_pack_meta,
|
|
1184
|
+
_pack_edges,
|
|
749
1185
|
_pack_requires,
|
|
750
1186
|
_requires_closure,
|
|
751
1187
|
_packs_of,
|