@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
|
@@ -0,0 +1,647 @@
|
|
|
1
|
+
#!/usr/bin/env tsx
|
|
2
|
+
/**
|
|
3
|
+
* lint_rule_law_section — every routed rule states its law in one section short
|
|
4
|
+
* enough to stand on its own.
|
|
5
|
+
*
|
|
6
|
+
* THE DEFECT. Measured 2026-10-01 over `dist/router.json`'s 106 tier rules:
|
|
7
|
+
* 71 carry a heading matching `Iron Law`, 35 do not — among them
|
|
8
|
+
* `runtime-safety` and `tool-safety`, which govern tool grants and execution
|
|
9
|
+
* handlers. Several of the 35 state a law in bold text or a bare fence instead,
|
|
10
|
+
* so 35 is an upper bound on what is genuinely missing, not a count of
|
|
11
|
+
* lawless rules. Nothing asserted either way: law sections were an authoring
|
|
12
|
+
* habit, never a state.
|
|
13
|
+
*
|
|
14
|
+
* That matters now because `project_thin_rules` ships a class of rules as a
|
|
15
|
+
* stub plus their own law section. A rule with no law section cannot be in that
|
|
16
|
+
* class, and a rule whose law section is 5,387 characters defeats the point of
|
|
17
|
+
* a stub. This gate holds three lines so the projector can rely on them.
|
|
18
|
+
*
|
|
19
|
+
* WHAT IT ASSERTS, three axes, each with its own ratchet:
|
|
20
|
+
*
|
|
21
|
+
* 1. PRESENCE (`--axis presence`). Every routed tier rule has a law section, or
|
|
22
|
+
* is named in the `missing` baseline. SHRINK-ONLY: an id may leave that list
|
|
23
|
+
* freely, and a routed rule that is not on it and has no law section fails.
|
|
24
|
+
* A NEW routed rule therefore cannot be born lawless.
|
|
25
|
+
*
|
|
26
|
+
* 2. LAW CEILING (`--axis ceiling`). Target 1,200 characters, REPORTED and
|
|
27
|
+
* never failing; hard 2,000, failing. A rule over the hard ceiling today is
|
|
28
|
+
* named in `law_exceptions` with an owner and a review date, and may only
|
|
29
|
+
* shrink — its recorded size is a ceiling, not a licence.
|
|
30
|
+
*
|
|
31
|
+
* 3. BODY CEILING (`--axis body-ceiling`). 8,000 characters of
|
|
32
|
+
* comment-stripped body, the unit a full runtime delivery carries, so it is
|
|
33
|
+
* priced in the same unit the installed-layer report uses. Today's larger
|
|
34
|
+
* rules are named in `body_exceptions`, shrink-only on the same terms.
|
|
35
|
+
*
|
|
36
|
+
* 4. TRIGGER PRESENCE (`--axis trigger`). Added by step 3.4 of
|
|
37
|
+
* `road-to-an-installed-layer-that-is-thinned`: a stub is a pointer a prompt
|
|
38
|
+
* must be able to pull in, so a routed rule with ZERO triggers in
|
|
39
|
+
* `dist/router.json` cannot be discovered once it ships as a stub — the
|
|
40
|
+
* pointer sits in the installed layer forever and the law behind it never
|
|
41
|
+
* arrives. Four rules read zero today (measured 2026-10-06) and are named in
|
|
42
|
+
* `no_trigger`, SHRINK-ONLY on the same terms as `missing`: each is delivered
|
|
43
|
+
* by a mechanism other than a keyword match — a path collision
|
|
44
|
+
* (`collision_ok`) or an unconditional load with no scoping at all — which is
|
|
45
|
+
* a deliberate routing choice recorded in the rule's own frontmatter, not an
|
|
46
|
+
* oversight this gate should paper over. A NEW routed rule therefore cannot
|
|
47
|
+
* be born with no trigger a prompt can fire, same as it cannot be born
|
|
48
|
+
* lawless.
|
|
49
|
+
*
|
|
50
|
+
* WHY THE TARGET IS REPORTED AND NOT ENFORCED. A rule shortened to fit a number
|
|
51
|
+
* is the failure this roadmap says it will not cause. 1,200 is where the
|
|
52
|
+
* distribution sits (median 511, p90 1,787) and a rule between target and hard
|
|
53
|
+
* ceiling is a rule to look at, not a rule to cut. Only 2,000 — above p90, so
|
|
54
|
+
* no rule is truncated by it — refuses.
|
|
55
|
+
*
|
|
56
|
+
* WHY SCOPED TO TIER RULES. "Routed" means present in `router.json`'s `tier_1`
|
|
57
|
+
* or `tier_2`. The nine kernel rules are excluded and the exclusion is a fact
|
|
58
|
+
* about this repository, not a judgement: kernel rule files are agent-write-
|
|
59
|
+
* denied, and two of them (`agent-authority`, `scope-control`) carry no Iron-Law
|
|
60
|
+
* heading today, so a gate that included them would be a gate no agent could
|
|
61
|
+
* ever make green. They are counted and printed under `kernel (reported)` so
|
|
62
|
+
* the exclusion is visible rather than silent, and `project_thin_rules` keeps
|
|
63
|
+
* the kernel full-bodied anyway — it never ships a kernel stub, so the stub-law
|
|
64
|
+
* question does not arise there.
|
|
65
|
+
*
|
|
66
|
+
* WHAT IT DOES NOT ASSERT. Not that the extracted section is the rule's real
|
|
67
|
+
* obligation — a heading match is structural and checkable, "this sentence is
|
|
68
|
+
* the obligation" is not; the ids in `src/config/rule-obligations.json` and
|
|
69
|
+
* `report_obligation_carriers` own that. Not that a rule at its recorded
|
|
70
|
+
* exception is correct, only that it is not worse. And not a cross-commit
|
|
71
|
+
* ratchet: this gate reads one tree, so "shrink-only" means the tree sits at or
|
|
72
|
+
* under what is committed, and a silently LOWERED baseline is a question the
|
|
73
|
+
* diff answers, not this gate. Saying so is the point.
|
|
74
|
+
*
|
|
75
|
+
* Exit codes: 0 clean, 1 violations, 2 usage error, 3 internal error.
|
|
76
|
+
*/
|
|
77
|
+
import * as fs from 'node:fs';
|
|
78
|
+
import * as os from 'node:os';
|
|
79
|
+
import * as path from 'node:path';
|
|
80
|
+
import process from 'node:process';
|
|
81
|
+
import { fileURLToPath, pathToFileURL } from 'node:url';
|
|
82
|
+
|
|
83
|
+
import { asOf } from './_lib/as_of.js';
|
|
84
|
+
import { measureRuleFile, type RuleLawMeasure } from './_lib/rule_law_section.js';
|
|
85
|
+
import { DeadScopeError, reportScanned } from './_lib/scan_scope.js';
|
|
86
|
+
|
|
87
|
+
const _HERE = fileURLToPath(import.meta.url);
|
|
88
|
+
export const REPO_ROOT = path.resolve(path.dirname(_HERE), '..', '..');
|
|
89
|
+
|
|
90
|
+
export const CONFIG_REL = 'src/config/rule-law-ceilings.json';
|
|
91
|
+
export const RULES_REL = 'src/rules';
|
|
92
|
+
export const ROUTER_REL = 'dist/router.json';
|
|
93
|
+
|
|
94
|
+
/** Reported, never failing — a rule above it is a rule to look at. */
|
|
95
|
+
export const LAW_TARGET_CHARS = 1_200;
|
|
96
|
+
/** Refused. Above p90, so no rule in the distribution is truncated by it. */
|
|
97
|
+
export const LAW_HARD_CHARS = 2_000;
|
|
98
|
+
/** Refused. The unit a full runtime delivery carries. */
|
|
99
|
+
export const BODY_HARD_CHARS = 8_000;
|
|
100
|
+
|
|
101
|
+
export interface SizeException {
|
|
102
|
+
/** Recorded size at adoption. The rule may sit at or under it, never above. */
|
|
103
|
+
chars: number;
|
|
104
|
+
/** Who answers for this rule staying oversized. */
|
|
105
|
+
owner: string;
|
|
106
|
+
/** `YYYY-MM-DD` the exception is due for review. */
|
|
107
|
+
review: string;
|
|
108
|
+
/** Why this rule cannot state its law under the ceiling today. */
|
|
109
|
+
reason: string;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
export interface LawConfig {
|
|
113
|
+
_comment?: string;
|
|
114
|
+
measured_at_commit?: string;
|
|
115
|
+
/** Routed rules with no law section. Shrink-only: ids may leave, never join. */
|
|
116
|
+
missing: string[];
|
|
117
|
+
/** Routed rules with no trigger a prompt can fire. Shrink-only, same terms as `missing`. */
|
|
118
|
+
no_trigger: string[];
|
|
119
|
+
/** Rules whose law exceeds {@link LAW_HARD_CHARS}. */
|
|
120
|
+
law_exceptions: Record<string, SizeException>;
|
|
121
|
+
/** Rules whose body exceeds {@link BODY_HARD_CHARS}. */
|
|
122
|
+
body_exceptions: Record<string, SizeException>;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
export type Axis = 'presence' | 'ceiling' | 'body-ceiling' | 'trigger' | 'all';
|
|
126
|
+
|
|
127
|
+
export interface Finding {
|
|
128
|
+
id: string;
|
|
129
|
+
axis: Exclude<Axis, 'all'>;
|
|
130
|
+
kind: string;
|
|
131
|
+
detail: string;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
export interface LintResult {
|
|
135
|
+
findings: Finding[];
|
|
136
|
+
/** Rules at or above the soft target but under the hard ceiling. */
|
|
137
|
+
overTarget: Array<{ id: string; chars: number }>;
|
|
138
|
+
measures: RuleLawMeasure[];
|
|
139
|
+
kernelReported: Array<{ id: string; sections: number }>;
|
|
140
|
+
scanned: number;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/** Routed tier rule ids, sorted — `tier_1` + `tier_2`, kernel excluded. */
|
|
144
|
+
export function routedRuleIds(root = REPO_ROOT): string[] {
|
|
145
|
+
const data = JSON.parse(fs.readFileSync(path.join(root, ROUTER_REL), 'utf-8')) as Record<
|
|
146
|
+
string,
|
|
147
|
+
unknown
|
|
148
|
+
>;
|
|
149
|
+
const ids: string[] = [];
|
|
150
|
+
for (const tier of ['tier_1', 'tier_2']) {
|
|
151
|
+
const entries = data[tier];
|
|
152
|
+
if (!Array.isArray(entries)) continue;
|
|
153
|
+
for (const e of entries) ids.push(String((e as Record<string, unknown>).id));
|
|
154
|
+
}
|
|
155
|
+
return [...new Set(ids)].sort();
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
export function kernelRuleIds(root = REPO_ROOT): string[] {
|
|
159
|
+
const data = JSON.parse(fs.readFileSync(path.join(root, ROUTER_REL), 'utf-8')) as Record<
|
|
160
|
+
string,
|
|
161
|
+
unknown
|
|
162
|
+
>;
|
|
163
|
+
const kernel = data.kernel;
|
|
164
|
+
return Array.isArray(kernel) ? kernel.map((x) => String(x)).sort() : [];
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
export function readConfig(root = REPO_ROOT): LawConfig {
|
|
168
|
+
const p = path.join(root, CONFIG_REL);
|
|
169
|
+
const raw = JSON.parse(fs.readFileSync(p, 'utf-8')) as Partial<LawConfig>;
|
|
170
|
+
return {
|
|
171
|
+
missing: Array.isArray(raw.missing) ? raw.missing : [],
|
|
172
|
+
no_trigger: Array.isArray(raw.no_trigger) ? raw.no_trigger : [],
|
|
173
|
+
law_exceptions: raw.law_exceptions ?? {},
|
|
174
|
+
body_exceptions: raw.body_exceptions ?? {},
|
|
175
|
+
measured_at_commit: raw.measured_at_commit ?? '',
|
|
176
|
+
};
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
/** Measure every routed rule that has a file. */
|
|
180
|
+
export function measureRouted(root = REPO_ROOT): RuleLawMeasure[] {
|
|
181
|
+
const out: RuleLawMeasure[] = [];
|
|
182
|
+
for (const id of routedRuleIds(root)) {
|
|
183
|
+
const p = path.join(root, RULES_REL, `${id}.md`);
|
|
184
|
+
if (!fs.existsSync(p)) continue;
|
|
185
|
+
out.push(measureRuleFile(id, p));
|
|
186
|
+
}
|
|
187
|
+
return out;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
/** Trigger count per routed tier rule id, straight off `dist/router.json`. */
|
|
191
|
+
export function routedRuleTriggerCounts(root = REPO_ROOT): Map<string, number> {
|
|
192
|
+
const data = JSON.parse(fs.readFileSync(path.join(root, ROUTER_REL), 'utf-8')) as Record<
|
|
193
|
+
string,
|
|
194
|
+
unknown
|
|
195
|
+
>;
|
|
196
|
+
const counts = new Map<string, number>();
|
|
197
|
+
for (const tier of ['tier_1', 'tier_2']) {
|
|
198
|
+
const entries = data[tier];
|
|
199
|
+
if (!Array.isArray(entries)) continue;
|
|
200
|
+
for (const e of entries) {
|
|
201
|
+
const rec = e as Record<string, unknown>;
|
|
202
|
+
const triggers = rec['triggers'];
|
|
203
|
+
counts.set(String(rec['id']), Array.isArray(triggers) ? triggers.length : 0);
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
return counts;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
export function lint(root = REPO_ROOT, axis: Axis = 'all'): LintResult {
|
|
210
|
+
const cfg = readConfig(root);
|
|
211
|
+
const measures = measureRouted(root);
|
|
212
|
+
const triggerCounts = routedRuleTriggerCounts(root);
|
|
213
|
+
const findings: Finding[] = [];
|
|
214
|
+
const overTarget: Array<{ id: string; chars: number }> = [];
|
|
215
|
+
const baselined = new Set(cfg.missing);
|
|
216
|
+
const noTriggerBaselined = new Set(cfg.no_trigger);
|
|
217
|
+
const want = (a: Exclude<Axis, 'all'>): boolean => axis === 'all' || axis === a;
|
|
218
|
+
|
|
219
|
+
for (const m of measures) {
|
|
220
|
+
if (want('trigger') && (triggerCounts.get(m.id) ?? 0) === 0 && !noTriggerBaselined.has(m.id)) {
|
|
221
|
+
findings.push({
|
|
222
|
+
id: m.id,
|
|
223
|
+
axis: 'trigger',
|
|
224
|
+
kind: 'no-trigger',
|
|
225
|
+
detail:
|
|
226
|
+
'routed rule has no trigger in `dist/router.json` — a prompt can never pull it in, ' +
|
|
227
|
+
`so it cannot ship as a stub; add a trigger, or add the id to \`no_trigger\` in ` +
|
|
228
|
+
`${CONFIG_REL} (that list is shrink-only, so a new routed rule may not join it)`,
|
|
229
|
+
});
|
|
230
|
+
}
|
|
231
|
+
if (want('presence') && m.law === null && !baselined.has(m.id)) {
|
|
232
|
+
findings.push({
|
|
233
|
+
id: m.id,
|
|
234
|
+
axis: 'presence',
|
|
235
|
+
kind: 'no-law-section',
|
|
236
|
+
detail:
|
|
237
|
+
'routed rule has no heading matching `Iron Law` — state the obligation under ' +
|
|
238
|
+
`one, or add the id to \`missing\` in ${CONFIG_REL} (that list is shrink-only, ` +
|
|
239
|
+
'so a new routed rule may not join it)',
|
|
240
|
+
});
|
|
241
|
+
}
|
|
242
|
+
if (want('ceiling') && m.law !== null) {
|
|
243
|
+
const exc = cfg.law_exceptions[m.id];
|
|
244
|
+
if (exc === undefined) {
|
|
245
|
+
if (m.lawChars > LAW_HARD_CHARS) {
|
|
246
|
+
findings.push({
|
|
247
|
+
id: m.id,
|
|
248
|
+
axis: 'ceiling',
|
|
249
|
+
kind: 'law-over-hard-ceiling',
|
|
250
|
+
detail:
|
|
251
|
+
`law section is ${m.lawChars} chars, over the ${LAW_HARD_CHARS} hard ceiling — ` +
|
|
252
|
+
'move the discussion under it behind `load_context`, or record a dated ' +
|
|
253
|
+
`exception with an owner in ${CONFIG_REL}`,
|
|
254
|
+
});
|
|
255
|
+
} else if (m.lawChars > LAW_TARGET_CHARS) {
|
|
256
|
+
overTarget.push({ id: m.id, chars: m.lawChars });
|
|
257
|
+
}
|
|
258
|
+
} else if (m.lawChars > exc.chars) {
|
|
259
|
+
findings.push({
|
|
260
|
+
id: m.id,
|
|
261
|
+
axis: 'ceiling',
|
|
262
|
+
kind: 'law-exception-grew',
|
|
263
|
+
detail:
|
|
264
|
+
`law section is ${m.lawChars} chars, above its recorded exception of ` +
|
|
265
|
+
`${exc.chars} (owner ${exc.owner}, review ${exc.review}) — an exception is ` +
|
|
266
|
+
'a ceiling, not a licence; it may only shrink',
|
|
267
|
+
});
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
if (want('body-ceiling')) {
|
|
271
|
+
const exc = cfg.body_exceptions[m.id];
|
|
272
|
+
if (exc === undefined) {
|
|
273
|
+
if (m.bodyChars > BODY_HARD_CHARS) {
|
|
274
|
+
findings.push({
|
|
275
|
+
id: m.id,
|
|
276
|
+
axis: 'body-ceiling',
|
|
277
|
+
kind: 'body-over-hard-ceiling',
|
|
278
|
+
detail:
|
|
279
|
+
`body is ${m.bodyChars} chars, over the ${BODY_HARD_CHARS} hard ceiling — ` +
|
|
280
|
+
'move history and mechanism discussion into a context file the rule names ' +
|
|
281
|
+
`in \`load_context\`, or record a dated exception in ${CONFIG_REL}`,
|
|
282
|
+
});
|
|
283
|
+
}
|
|
284
|
+
} else if (m.bodyChars > exc.chars) {
|
|
285
|
+
findings.push({
|
|
286
|
+
id: m.id,
|
|
287
|
+
axis: 'body-ceiling',
|
|
288
|
+
kind: 'body-exception-grew',
|
|
289
|
+
detail:
|
|
290
|
+
`body is ${m.bodyChars} chars, above its recorded exception of ${exc.chars} ` +
|
|
291
|
+
`(owner ${exc.owner}, review ${exc.review}) — it may only shrink`,
|
|
292
|
+
});
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
// A baseline entry for a rule that now HAS a law section is debt that was
|
|
298
|
+
// paid and never collected. Reported as a finding, because a stale
|
|
299
|
+
// suppression is how a ratchet hardens into configuration.
|
|
300
|
+
if (want('presence')) {
|
|
301
|
+
const haveLaw = new Set(measures.filter((m) => m.law !== null).map((m) => m.id));
|
|
302
|
+
const routed = new Set(measures.map((m) => m.id));
|
|
303
|
+
for (const id of cfg.missing) {
|
|
304
|
+
if (haveLaw.has(id)) {
|
|
305
|
+
findings.push({
|
|
306
|
+
id,
|
|
307
|
+
axis: 'presence',
|
|
308
|
+
kind: 'stale-baseline-entry',
|
|
309
|
+
detail: `now has a law section — remove it from \`missing\` in ${CONFIG_REL}`,
|
|
310
|
+
});
|
|
311
|
+
} else if (!routed.has(id)) {
|
|
312
|
+
findings.push({
|
|
313
|
+
id,
|
|
314
|
+
axis: 'presence',
|
|
315
|
+
kind: 'stale-baseline-entry',
|
|
316
|
+
detail: `is not a routed rule any more — remove it from \`missing\` in ${CONFIG_REL}`,
|
|
317
|
+
});
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
// Same stale-debt check for the trigger baseline: an id that gained a
|
|
323
|
+
// trigger, or left the routed set, is debt that was paid and never
|
|
324
|
+
// collected.
|
|
325
|
+
if (want('trigger')) {
|
|
326
|
+
const routed = new Set(measures.map((m) => m.id));
|
|
327
|
+
for (const id of cfg.no_trigger) {
|
|
328
|
+
if (!routed.has(id)) {
|
|
329
|
+
findings.push({
|
|
330
|
+
id,
|
|
331
|
+
axis: 'trigger',
|
|
332
|
+
kind: 'stale-baseline-entry',
|
|
333
|
+
detail: `is not a routed rule any more — remove it from \`no_trigger\` in ${CONFIG_REL}`,
|
|
334
|
+
});
|
|
335
|
+
} else if ((triggerCounts.get(id) ?? 0) > 0) {
|
|
336
|
+
findings.push({
|
|
337
|
+
id,
|
|
338
|
+
axis: 'trigger',
|
|
339
|
+
kind: 'stale-baseline-entry',
|
|
340
|
+
detail: `now has a trigger — remove it from \`no_trigger\` in ${CONFIG_REL}`,
|
|
341
|
+
});
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
const kernelReported = kernelRuleIds(root).map((id) => {
|
|
347
|
+
const p = path.join(root, RULES_REL, `${id}.md`);
|
|
348
|
+
return { id, sections: fs.existsSync(p) ? measureRuleFile(id, p).sections : 0 };
|
|
349
|
+
});
|
|
350
|
+
|
|
351
|
+
findings.sort((a, b) => (a.id < b.id ? -1 : a.id > b.id ? 1 : a.kind < b.kind ? -1 : 1));
|
|
352
|
+
overTarget.sort((a, b) => b.chars - a.chars);
|
|
353
|
+
return { findings, overTarget, measures, kernelReported, scanned: measures.length };
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
/** Rebuild the config from the current tree. Never raises an existing ceiling. */
|
|
357
|
+
export function writeBaseline(root = REPO_ROOT, today: string): string {
|
|
358
|
+
const prev = fs.existsSync(path.join(root, CONFIG_REL))
|
|
359
|
+
? readConfig(root)
|
|
360
|
+
: { missing: [], no_trigger: [], law_exceptions: {}, body_exceptions: {} };
|
|
361
|
+
const measures = measureRouted(root);
|
|
362
|
+
const triggerCounts = routedRuleTriggerCounts(root);
|
|
363
|
+
const missing = measures.filter((m) => m.law === null).map((m) => m.id).sort();
|
|
364
|
+
const no_trigger = measures
|
|
365
|
+
.filter((m) => (triggerCounts.get(m.id) ?? 0) === 0)
|
|
366
|
+
.map((m) => m.id)
|
|
367
|
+
.sort();
|
|
368
|
+
const law_exceptions: Record<string, SizeException> = {};
|
|
369
|
+
const body_exceptions: Record<string, SizeException> = {};
|
|
370
|
+
for (const m of measures) {
|
|
371
|
+
if (m.law !== null && m.lawChars > LAW_HARD_CHARS) {
|
|
372
|
+
const old = prev.law_exceptions[m.id];
|
|
373
|
+
law_exceptions[m.id] = {
|
|
374
|
+
chars: old === undefined ? m.lawChars : Math.min(old.chars, m.lawChars),
|
|
375
|
+
owner: old?.owner ?? 'agent-config-maintainer',
|
|
376
|
+
review: old?.review ?? today,
|
|
377
|
+
reason: old?.reason ?? 'recorded at adoption; not yet reviewed',
|
|
378
|
+
};
|
|
379
|
+
}
|
|
380
|
+
if (m.bodyChars > BODY_HARD_CHARS) {
|
|
381
|
+
const old = prev.body_exceptions[m.id];
|
|
382
|
+
body_exceptions[m.id] = {
|
|
383
|
+
chars: old === undefined ? m.bodyChars : Math.min(old.chars, m.bodyChars),
|
|
384
|
+
owner: old?.owner ?? 'agent-config-maintainer',
|
|
385
|
+
review: old?.review ?? today,
|
|
386
|
+
reason: old?.reason ?? 'recorded at adoption; not yet reviewed',
|
|
387
|
+
};
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
const cfg = {
|
|
391
|
+
_comment:
|
|
392
|
+
'Per-rule law-section and body ceilings (road-to-rule-laws-that-can-stand Phase 1) plus ' +
|
|
393
|
+
'the trigger-presence baseline (road-to-an-installed-layer-that-is-thinned step 3.4). Two ' +
|
|
394
|
+
'different guarantees, not one: `law_exceptions` and `body_exceptions` are numeric ' +
|
|
395
|
+
'ceilings `--write-baseline` structurally refuses to raise (it re-records the SMALLER of ' +
|
|
396
|
+
'old and current, never the current alone) — a rule at its exception is not thereby ' +
|
|
397
|
+
'correct, only not worse. `missing` and `no_trigger` are LIST membership: an id SHOULD ' +
|
|
398
|
+
'only leave, never join, but that is a review convention the generator does not enforce ' +
|
|
399
|
+
'by construction — `--write-baseline` re-records every id that currently fails ' +
|
|
400
|
+
'presence/trigger, full stop, so a newly-broken rule is swept in exactly like a ' +
|
|
401
|
+
'genuinely-fixed one is swept out. The `stale-baseline-entry` finding makes a fixed id ' +
|
|
402
|
+
'visible for removal; nothing makes a newly-broken id visible for refusal except a human ' +
|
|
403
|
+
'reading the diff. Regenerate with `lint_rule_law_section --write-baseline`; never ' +
|
|
404
|
+
'hand-edit the counts, but DO hand-edit `owner`, `review` and `reason` — those are the ' +
|
|
405
|
+
'review contract and the generator only seeds them.',
|
|
406
|
+
measured_at_commit: prev.measured_at_commit ?? '',
|
|
407
|
+
no_trigger,
|
|
408
|
+
missing,
|
|
409
|
+
law_exceptions,
|
|
410
|
+
body_exceptions,
|
|
411
|
+
};
|
|
412
|
+
const text = JSON.stringify(cfg, null, 4) + '\n';
|
|
413
|
+
fs.writeFileSync(path.join(root, CONFIG_REL), text, 'utf-8');
|
|
414
|
+
return text;
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
interface Args {
|
|
418
|
+
axis: Axis;
|
|
419
|
+
quiet: boolean;
|
|
420
|
+
writeBaseline: boolean;
|
|
421
|
+
root: string;
|
|
422
|
+
selfTest: boolean;
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
const USAGE =
|
|
426
|
+
'usage: lint_rule_law_section [--axis presence|ceiling|body-ceiling|trigger|all] [--quiet] ' +
|
|
427
|
+
'[--write-baseline] [--root DIR] [--self-test]\n';
|
|
428
|
+
|
|
429
|
+
function parseArgs(argv: string[]): Args {
|
|
430
|
+
const out: Args = { axis: 'all', quiet: false, writeBaseline: false, root: REPO_ROOT, selfTest: false };
|
|
431
|
+
for (let i = 0; i < argv.length; i += 1) {
|
|
432
|
+
const a = argv[i] as string;
|
|
433
|
+
if (a === '-h' || a === '--help') {
|
|
434
|
+
process.stdout.write(USAGE);
|
|
435
|
+
process.exit(0);
|
|
436
|
+
} else if (a === '--quiet') {
|
|
437
|
+
out.quiet = true;
|
|
438
|
+
} else if (a === '--write-baseline') {
|
|
439
|
+
out.writeBaseline = true;
|
|
440
|
+
} else if (a === '--self-test') {
|
|
441
|
+
out.selfTest = true;
|
|
442
|
+
} else if (a === '--axis') {
|
|
443
|
+
const v = argv[i + 1];
|
|
444
|
+
if (v === undefined) {
|
|
445
|
+
process.stderr.write(USAGE);
|
|
446
|
+
process.exit(2);
|
|
447
|
+
}
|
|
448
|
+
out.axis = v as Axis;
|
|
449
|
+
i += 1;
|
|
450
|
+
} else if (a.startsWith('--axis=')) {
|
|
451
|
+
out.axis = a.slice('--axis='.length) as Axis;
|
|
452
|
+
} else if (a === '--root') {
|
|
453
|
+
const v = argv[i + 1];
|
|
454
|
+
if (v === undefined) {
|
|
455
|
+
process.stderr.write(USAGE);
|
|
456
|
+
process.exit(2);
|
|
457
|
+
}
|
|
458
|
+
out.root = path.resolve(v);
|
|
459
|
+
i += 1;
|
|
460
|
+
} else if (a.startsWith('--root=')) {
|
|
461
|
+
out.root = path.resolve(a.slice('--root='.length));
|
|
462
|
+
} else {
|
|
463
|
+
process.stderr.write(USAGE);
|
|
464
|
+
process.stderr.write(`lint_rule_law_section: error: unrecognized argument: ${a}\n`);
|
|
465
|
+
process.exit(2);
|
|
466
|
+
}
|
|
467
|
+
}
|
|
468
|
+
if (!['presence', 'ceiling', 'body-ceiling', 'trigger', 'all'].includes(out.axis)) {
|
|
469
|
+
process.stderr.write(USAGE);
|
|
470
|
+
process.stderr.write(`lint_rule_law_section: error: unknown axis: ${out.axis}\n`);
|
|
471
|
+
process.exit(2);
|
|
472
|
+
}
|
|
473
|
+
return out;
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
/**
|
|
477
|
+
* Prove the gate's reading changes its verdict, not just that it read
|
|
478
|
+
* something. A `scanned:` floor says a corpus was inspected; only a rejecting
|
|
479
|
+
* case says the inspection decides anything.
|
|
480
|
+
*/
|
|
481
|
+
export function selfTest(write: (s: string) => void = (s) => process.stdout.write(s)): number {
|
|
482
|
+
const tmp = fs.mkdtempSync(path.join(os.tmpdir(), 'law-selftest-'));
|
|
483
|
+
try {
|
|
484
|
+
fs.mkdirSync(path.join(tmp, 'src', 'rules'), { recursive: true });
|
|
485
|
+
fs.mkdirSync(path.join(tmp, 'src', 'config'), { recursive: true });
|
|
486
|
+
fs.mkdirSync(path.join(tmp, 'dist'), { recursive: true });
|
|
487
|
+
fs.writeFileSync(
|
|
488
|
+
path.join(tmp, ROUTER_REL),
|
|
489
|
+
JSON.stringify({
|
|
490
|
+
kernel: [],
|
|
491
|
+
tier_1: [
|
|
492
|
+
{ id: 'lawless', triggers: [{ keyword: 'lawless-word' }] },
|
|
493
|
+
{ id: 'lawful', triggers: [{ keyword: 'lawful-word' }] },
|
|
494
|
+
{ id: 'mute', triggers: [] },
|
|
495
|
+
{ id: 'vocal', triggers: [{ keyword: 'vocal-word' }] },
|
|
496
|
+
],
|
|
497
|
+
tier_2: [],
|
|
498
|
+
}),
|
|
499
|
+
);
|
|
500
|
+
fs.writeFileSync(
|
|
501
|
+
path.join(tmp, CONFIG_REL),
|
|
502
|
+
JSON.stringify({ missing: [], no_trigger: [], law_exceptions: {}, body_exceptions: {} }),
|
|
503
|
+
);
|
|
504
|
+
fs.writeFileSync(path.join(tmp, 'src/rules/lawless.md'), '---\nx: 1\n---\n\n# Lawless\n\nProse.\n');
|
|
505
|
+
fs.writeFileSync(
|
|
506
|
+
path.join(tmp, 'src/rules/lawful.md'),
|
|
507
|
+
'---\nx: 1\n---\n\n# Lawful\n\n## The Iron Law\n\nNEVER DO THE THING.\n',
|
|
508
|
+
);
|
|
509
|
+
fs.writeFileSync(
|
|
510
|
+
path.join(tmp, 'src/rules/mute.md'),
|
|
511
|
+
'---\nx: 1\n---\n\n# Mute\n\n## The Iron Law\n\nNEVER DO THE THING.\n',
|
|
512
|
+
);
|
|
513
|
+
fs.writeFileSync(
|
|
514
|
+
path.join(tmp, 'src/rules/vocal.md'),
|
|
515
|
+
'---\nx: 1\n---\n\n# Vocal\n\n## The Iron Law\n\nNEVER DO THE THING.\n',
|
|
516
|
+
);
|
|
517
|
+
|
|
518
|
+
const rejecting = lint(tmp, 'presence');
|
|
519
|
+
const accepting = (() => {
|
|
520
|
+
fs.writeFileSync(
|
|
521
|
+
path.join(tmp, CONFIG_REL),
|
|
522
|
+
JSON.stringify({
|
|
523
|
+
missing: ['lawless'],
|
|
524
|
+
no_trigger: [],
|
|
525
|
+
law_exceptions: {},
|
|
526
|
+
body_exceptions: {},
|
|
527
|
+
}),
|
|
528
|
+
);
|
|
529
|
+
return lint(tmp, 'presence');
|
|
530
|
+
})();
|
|
531
|
+
const ok =
|
|
532
|
+
rejecting.findings.length === 1 &&
|
|
533
|
+
rejecting.findings[0]?.kind === 'no-law-section' &&
|
|
534
|
+
accepting.findings.length === 0;
|
|
535
|
+
|
|
536
|
+
// Same rejecting/accepting shape for the trigger axis (step 3.4):
|
|
537
|
+
// `mute` has a law but no trigger and is unbaselined, `vocal` has both.
|
|
538
|
+
const triggerRejecting = lint(tmp, 'trigger');
|
|
539
|
+
const triggerAccepting = (() => {
|
|
540
|
+
fs.writeFileSync(
|
|
541
|
+
path.join(tmp, CONFIG_REL),
|
|
542
|
+
JSON.stringify({
|
|
543
|
+
missing: ['lawless'],
|
|
544
|
+
no_trigger: ['mute'],
|
|
545
|
+
law_exceptions: {},
|
|
546
|
+
body_exceptions: {},
|
|
547
|
+
}),
|
|
548
|
+
);
|
|
549
|
+
return lint(tmp, 'trigger');
|
|
550
|
+
})();
|
|
551
|
+
const triggerOk =
|
|
552
|
+
triggerRejecting.findings.map((f) => f.id).sort().join(',') === 'mute' &&
|
|
553
|
+
triggerRejecting.findings.every((f) => f.kind === 'no-trigger') &&
|
|
554
|
+
triggerAccepting.findings.length === 0;
|
|
555
|
+
|
|
556
|
+
const allOk = ok && triggerOk;
|
|
557
|
+
write(
|
|
558
|
+
allOk
|
|
559
|
+
? '✅ self-test: presence + trigger axes each have a rejecting and an accepting case\n'
|
|
560
|
+
: `❌ self-test FAILED: presence rejecting=${rejecting.findings.length} ` +
|
|
561
|
+
`accepting=${accepting.findings.length}; trigger rejecting=` +
|
|
562
|
+
`${triggerRejecting.findings.length} accepting=${triggerAccepting.findings.length}\n`,
|
|
563
|
+
);
|
|
564
|
+
return allOk ? 0 : 1;
|
|
565
|
+
} finally {
|
|
566
|
+
fs.rmSync(tmp, { recursive: true, force: true });
|
|
567
|
+
}
|
|
568
|
+
}
|
|
569
|
+
|
|
570
|
+
export function main(argv: string[] | null = null): number {
|
|
571
|
+
const args = parseArgs(argv ?? process.argv.slice(2));
|
|
572
|
+
if (args.selfTest) {
|
|
573
|
+
return selfTest();
|
|
574
|
+
}
|
|
575
|
+
if (args.writeBaseline) {
|
|
576
|
+
const today = asOf().toISOString().slice(0, 10);
|
|
577
|
+
writeBaseline(args.root, today);
|
|
578
|
+
process.stdout.write(`wrote ${CONFIG_REL}\n`);
|
|
579
|
+
return 0;
|
|
580
|
+
}
|
|
581
|
+
|
|
582
|
+
let res: LintResult;
|
|
583
|
+
try {
|
|
584
|
+
res = lint(args.root, args.axis);
|
|
585
|
+
} catch (exc) {
|
|
586
|
+
process.stderr.write(`❌ lint_rule_law_section: ${(exc as Error).message}\n`);
|
|
587
|
+
return 3;
|
|
588
|
+
}
|
|
589
|
+
|
|
590
|
+
// Outside the `--quiet` guard on purpose: CI passes `--quiet`, and a gate
|
|
591
|
+
// whose count disappears under the flag reads as silent to the coverage
|
|
592
|
+
// census.
|
|
593
|
+
try {
|
|
594
|
+
reportScanned({
|
|
595
|
+
gate: 'lint_rule_law_section',
|
|
596
|
+
scanned: res.scanned,
|
|
597
|
+
units: 'routed rule(s)',
|
|
598
|
+
roots: [RULES_REL, ROUTER_REL],
|
|
599
|
+
});
|
|
600
|
+
} catch (exc) {
|
|
601
|
+
if (exc instanceof DeadScopeError) {
|
|
602
|
+
process.stderr.write(`❌ ${exc.message}\n`);
|
|
603
|
+
return 1;
|
|
604
|
+
}
|
|
605
|
+
throw exc;
|
|
606
|
+
}
|
|
607
|
+
|
|
608
|
+
if (!args.quiet) {
|
|
609
|
+
const withLaw = res.measures.filter((m) => m.law !== null).length;
|
|
610
|
+
process.stdout.write(
|
|
611
|
+
`law sections: ${withLaw}/${res.measures.length} routed rules; ` +
|
|
612
|
+
`kernel reported separately (${res.kernelReported.filter((k) => k.sections > 0).length}/` +
|
|
613
|
+
`${res.kernelReported.length} carry one, write-denied so never failed here)\n`,
|
|
614
|
+
);
|
|
615
|
+
for (const t of res.overTarget) {
|
|
616
|
+
process.stdout.write(
|
|
617
|
+
` over target (${LAW_TARGET_CHARS}), not a failure: ${t.id} — ${t.chars} chars\n`,
|
|
618
|
+
);
|
|
619
|
+
}
|
|
620
|
+
}
|
|
621
|
+
|
|
622
|
+
if (res.findings.length > 0) {
|
|
623
|
+
for (const f of res.findings) {
|
|
624
|
+
process.stderr.write(`❌ ${f.id} [${f.axis}/${f.kind}] ${f.detail}\n`);
|
|
625
|
+
}
|
|
626
|
+
process.stderr.write(`❌ lint_rule_law_section: ${res.findings.length} finding(s)\n`);
|
|
627
|
+
return 1;
|
|
628
|
+
}
|
|
629
|
+
if (!args.quiet) {
|
|
630
|
+
process.stdout.write('✅ lint_rule_law_section clean\n');
|
|
631
|
+
}
|
|
632
|
+
return 0;
|
|
633
|
+
}
|
|
634
|
+
|
|
635
|
+
function isCliEntry(): boolean {
|
|
636
|
+
if (process.argv[1] === undefined) return false;
|
|
637
|
+
if (import.meta.url === pathToFileURL(path.resolve(process.argv[1])).href) return true;
|
|
638
|
+
try {
|
|
639
|
+
return fs.realpathSync(fileURLToPath(import.meta.url)) === fs.realpathSync(path.resolve(process.argv[1]));
|
|
640
|
+
} catch {
|
|
641
|
+
return false;
|
|
642
|
+
}
|
|
643
|
+
}
|
|
644
|
+
|
|
645
|
+
if (isCliEntry()) {
|
|
646
|
+
process.exit(main());
|
|
647
|
+
}
|
|
@@ -35,6 +35,23 @@
|
|
|
35
35
|
* the wizard may offer it and the user may decline, so an invariant that
|
|
36
36
|
* counted it would pass on installs that do not exist.
|
|
37
37
|
*
|
|
38
|
+
* SIBLING GATE, OPPOSITE READING, SAME REASONING (2026-10-09). Since D5 of
|
|
39
|
+
* `road-to-gates-a-pull-request-can-hear`, `lint_pack_boundaries` DOES read
|
|
40
|
+
* `suggests` — as permitting a cross-pack link. That is not a contradiction of
|
|
41
|
+
* the paragraph above, and the discriminator is the direction of the claim
|
|
42
|
+
* each gate makes:
|
|
43
|
+
*
|
|
44
|
+
* - THIS gate asserts a route WILL RESOLVE on the installs it covers.
|
|
45
|
+
* Counting an advisory edge would assert resolution on installs that may
|
|
46
|
+
* not exist — a false negative in the dangerous direction.
|
|
47
|
+
* - The boundary gate reports a link that MAY DANGLE. An advisory edge is
|
|
48
|
+
* the author stating they accept the dangle for a declining consumer, so
|
|
49
|
+
* reading it there downgrades a finding the author has already answered.
|
|
50
|
+
*
|
|
51
|
+
* Practical consequence, stated because it is the mistake the asymmetry
|
|
52
|
+
* invites: adding a `suggests` edge does NOT clear an `unreachable-route`
|
|
53
|
+
* finding here. It never will. Fix the route or accept the finding.
|
|
54
|
+
*
|
|
38
55
|
* ADVISORY UNTIL ITS FINDING SET IS EMPTY, AND THE FIRST RUN SAYS WHY.
|
|
39
56
|
* Measured on introduction: 12 `unreachable-route` and 14 `unrouted-skill`
|
|
40
57
|
* findings across 116 rules. The UI pair is one instance of an estate-wide
|
|
@@ -604,7 +604,7 @@ function main(): number {
|
|
|
604
604
|
for (const [removedKey, reason] of REMOVED_KEYS) {
|
|
605
605
|
if (reason.trim() === '') {
|
|
606
606
|
findings.push(
|
|
607
|
-
`src/scripts/_lib/
|
|
607
|
+
`src/scripts/_lib/settings_removed_keys.ts \`${removedKey}\` is in REMOVED_KEYS with an empty ` +
|
|
608
608
|
'reason — name what decides instead, not that it is gone.',
|
|
609
609
|
);
|
|
610
610
|
}
|