@event4u/agent-config 14.10.0 → 14.12.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 +161 -208
- package/README.md +1 -1
- package/dist/agent-src/commands/design.md +88 -0
- package/dist/agent-src/commands/project/analyze.md +47 -0
- package/dist/agent-src/commands/review/changes.md +67 -6
- package/dist/agent-src/commands/roadmap/create.md +49 -0
- package/dist/agent-src/commands/roadmap/next.md +27 -11
- package/dist/agent-src/commands/roadmap/process-full.md +14 -0
- package/dist/agent-src/commands/video/from-script.md +60 -3
- package/dist/agent-src/commands/video/stitch.md +14 -0
- package/dist/agent-src/contexts/communication/rules-auto/guidelines-mechanics.md +1 -0
- package/dist/agent-src/contexts/execution/evidence-discipline.md +26 -0
- package/dist/agent-src/contexts/execution/roadmap-process-loop.md +154 -2
- package/dist/agent-src/rules/active-remediation.md +3 -3
- package/dist/agent-src/rules/code-provenance.md +2 -2
- package/dist/agent-src/rules/context-hygiene.md +13 -33
- package/dist/agent-src/rules/council-availability.md +2 -2
- package/dist/agent-src/rules/decision-revisit-gate.md +3 -1
- package/dist/agent-src/rules/design-fidelity.md +18 -0
- package/dist/agent-src/rules/design-review-after-ui-write.md +2 -2
- package/dist/agent-src/rules/evaluator-independence.md +56 -44
- package/dist/agent-src/rules/fix-what-you-see.md +9 -1
- package/dist/agent-src/rules/framework-neutrality-in-generic-skills.md +1 -1
- package/dist/agent-src/rules/minimal-safe-diff.md +14 -20
- package/dist/agent-src/rules/missing-skill-recovery.md +13 -1
- package/dist/agent-src/rules/playbook-precedence.md +105 -0
- package/dist/agent-src/rules/recurring-criticism.md +3 -1
- package/dist/agent-src/rules/roadmap-progress-sync.md +14 -13
- package/dist/agent-src/rules/scale-discipline.md +24 -0
- package/dist/agent-src/rules/security-sensitive-stop.md +2 -2
- package/dist/agent-src/rules/settings-ask-protocol.md +2 -2
- package/dist/agent-src/rules/ui-audit-gate.md +27 -15
- package/dist/agent-src/rules/untrusted-input-defense.md +2 -2
- package/dist/agent-src/skills/accessibility-auditor/SKILL.md +19 -0
- package/dist/agent-src/skills/adr-create/SKILL.md +7 -0
- package/dist/agent-src/skills/agents-md-thin-root/SKILL.md +33 -0
- package/dist/agent-src/skills/ai-council/references/advanced-modes.md +17 -3
- package/dist/agent-src/skills/ai-council/references/output-and-synthesis.md +31 -0
- package/dist/agent-src/skills/ai-council/references/procedure.md +19 -0
- package/dist/agent-src/skills/alerting-doctrine/SKILL.md +225 -0
- package/dist/agent-src/skills/authz-review/SKILL.md +0 -1
- package/dist/agent-src/skills/blast-radius-analyzer/SKILL.md +32 -0
- package/dist/agent-src/skills/brand/SKILL.md +3 -0
- package/dist/agent-src/skills/brand-asset-generation/SKILL.md +3 -0
- package/dist/agent-src/skills/brand-audit/SKILL.md +3 -0
- package/dist/agent-src/skills/brand-identity/SKILL.md +3 -0
- package/dist/agent-src/skills/brand-strategy/SKILL.md +3 -0
- package/dist/agent-src/skills/brand-to-tokens/SKILL.md +3 -0
- package/dist/agent-src/skills/check-refs/SKILL.md +3 -0
- package/dist/agent-src/skills/code-refactoring/SKILL.md +45 -1
- package/dist/agent-src/skills/code-review/SKILL.md +75 -5
- package/dist/agent-src/skills/command-routing/SKILL.md +6 -0
- package/dist/agent-src/skills/command-writing/SKILL.md +35 -0
- package/dist/agent-src/skills/condense-memory/SKILL.md +3 -0
- package/dist/agent-src/skills/context-authoring/SKILL.md +1 -1
- package/dist/agent-src/skills/conventional-commits-writing/SKILL.md +3 -0
- package/dist/agent-src/skills/copilot-agents-optimization/SKILL.md +10 -0
- package/dist/agent-src/skills/corpus-grounding/SKILL.md +3 -0
- package/dist/agent-src/skills/design-intelligence/SKILL.md +3 -0
- package/dist/agent-src/skills/design-intelligence/data/landing.csv +36 -35
- package/dist/agent-src/skills/design-intelligence/data/stacks/threejs.csv +1 -0
- package/dist/agent-src/skills/design-review/SKILL.md +79 -1
- package/dist/agent-src/skills/design-review/references/verification-automation.md +41 -0
- package/dist/agent-src/skills/design-system-capture/SKILL.md +35 -40
- package/dist/agent-src/skills/design-system-capture/references/import-procedure.md +50 -0
- package/dist/agent-src/skills/design-tokens/SKILL.md +3 -0
- package/dist/agent-src/skills/design-variations/SKILL.md +3 -0
- package/dist/agent-src/skills/developer-like-execution/SKILL.md +3 -0
- package/dist/agent-src/skills/estimate-ticket/SKILL.md +3 -0
- package/dist/agent-src/skills/existing-ui-audit/SKILL.md +28 -4
- package/dist/agent-src/skills/fe-design/SKILL.md +74 -41
- package/dist/agent-src/skills/fe-design/references/craft-floor.md +52 -0
- package/dist/agent-src/skills/fe-design/references/source-led-port.md +36 -0
- package/dist/agent-src/skills/file-editor/SKILL.md +5 -0
- package/dist/agent-src/skills/finishing-a-development-branch/SKILL.md +2 -2
- package/dist/agent-src/skills/git-workflow/SKILL.md +3 -0
- package/dist/agent-src/skills/html-deck/SKILL.md +3 -0
- package/dist/agent-src/skills/iconography/SKILL.md +3 -0
- package/dist/agent-src/skills/image-editing/SKILL.md +3 -0
- package/dist/agent-src/skills/image-generation/SKILL.md +3 -0
- package/dist/agent-src/skills/image-provider-routing/SKILL.md +3 -0
- package/dist/agent-src/skills/incident-commander/SKILL.md +10 -0
- package/dist/agent-src/skills/js-library-packaging/SKILL.md +173 -0
- package/dist/agent-src/skills/js-library-packaging/scripts/check_package_surface.ts +270 -0
- package/dist/agent-src/skills/laravel-migration/SKILL.md +3 -0
- package/dist/agent-src/skills/learning-to-rule-or-skill/SKILL.md +3 -0
- package/dist/agent-src/skills/lint-skills/SKILL.md +3 -0
- package/dist/agent-src/skills/llm-provider-knowledge/SKILL.md +3 -0
- package/dist/agent-src/skills/logging-monitoring/SKILL.md +234 -51
- package/dist/agent-src/skills/logo-generation/SKILL.md +3 -0
- package/dist/agent-src/skills/md-language-check/SKILL.md +3 -0
- package/dist/agent-src/skills/monorepo-workspace/SKILL.md +149 -0
- package/dist/agent-src/skills/motion-choreographer/SKILL.md +6 -0
- package/dist/agent-src/skills/multi-tenancy/SKILL.md +4 -0
- package/dist/agent-src/skills/operational-readiness/SKILL.md +184 -0
- package/dist/agent-src/skills/override-management/SKILL.md +3 -0
- package/dist/agent-src/skills/persona-improvement/SKILL.md +3 -0
- package/dist/agent-src/skills/pest-testing/SKILL.md +3 -0
- package/dist/agent-src/skills/playbook-authoring/SKILL.md +162 -0
- package/dist/agent-src/skills/playwright-testing/SKILL.md +3 -0
- package/dist/agent-src/skills/privacy-review/SKILL.md +3 -0
- package/dist/agent-src/skills/project-analysis-core/SKILL.md +23 -0
- package/dist/agent-src/skills/prompt-engineering-image/SKILL.md +3 -0
- package/dist/agent-src/skills/quality-tools/SKILL.md +5 -0
- package/dist/agent-src/skills/react-shadcn-ui/SKILL.md +81 -33
- package/dist/agent-src/skills/readme-reviewer/SKILL.md +3 -0
- package/dist/agent-src/skills/readme-writing/SKILL.md +3 -0
- package/dist/agent-src/skills/readme-writing-package/SKILL.md +3 -0
- package/dist/agent-src/skills/receiving-code-review/SKILL.md +2 -2
- package/dist/agent-src/skills/refine-prompt/SKILL.md +3 -0
- package/dist/agent-src/skills/refine-ticket/SKILL.md +3 -0
- package/dist/agent-src/skills/requesting-code-review/SKILL.md +2 -2
- package/dist/agent-src/skills/review-routing/SKILL.md +2 -2
- package/dist/agent-src/skills/roadmap-writing/SKILL.md +23 -41
- package/dist/agent-src/skills/roadmap-writing/references/follow-up-roadmap-shape.md +47 -0
- package/dist/agent-src/skills/rtk-output-filtering/SKILL.md +22 -6
- package/dist/agent-src/skills/runway-cognition/SKILL.md +3 -0
- package/dist/agent-src/skills/scene-expander/scene-blueprint.schema.yaml +26 -0
- package/dist/agent-src/skills/secrets-management/SKILL.md +4 -0
- package/dist/agent-src/skills/server-hardening/SKILL.md +159 -0
- package/dist/agent-src/skills/skill-improvement-pipeline/SKILL.md +3 -0
- package/dist/agent-src/skills/skill-management/SKILL.md +3 -0
- package/dist/agent-src/skills/skill-reviewer/SKILL.md +3 -0
- package/dist/agent-src/skills/skill-writing/SKILL.md +6 -0
- package/dist/agent-src/skills/skill-writing/references/procedure.md +24 -2
- package/dist/agent-src/skills/spreadsheet-authoring/SKILL.md +3 -0
- package/dist/agent-src/skills/storybook-workshop/SKILL.md +203 -0
- package/dist/agent-src/skills/storybook-workshop/scripts/story_contrast_floor.ts +134 -0
- package/dist/agent-src/skills/subagent-orchestration/SKILL.md +1 -1
- package/dist/agent-src/skills/subagent-orchestration/prompts/README.md +25 -0
- package/dist/agent-src/skills/supply-chain-intake/SKILL.md +12 -0
- package/dist/agent-src/skills/systematic-debugging/SKILL.md +1 -1
- package/dist/agent-src/skills/terraform/SKILL.md +3 -0
- package/dist/agent-src/skills/test-driven-development/SKILL.md +1 -1
- package/dist/agent-src/skills/threat-modeling/SKILL.md +0 -3
- package/dist/agent-src/skills/token-optimizer/SKILL.md +3 -0
- package/dist/agent-src/skills/typography-system/SKILL.md +3 -0
- package/dist/agent-src/skills/ui-component-architect/SKILL.md +17 -1
- package/dist/agent-src/skills/upstream-contribute/SKILL.md +3 -0
- package/dist/agent-src/skills/validate-feature-fit/SKILL.md +3 -0
- package/dist/agent-src/skills/verify-completion-evidence/SKILL.md +2 -2
- package/dist/agent-src/skills/wireframe/SKILL.md +3 -0
- package/dist/agent-src/skills/wireframe/references/story-beat-ledger.schema.json +115 -0
- package/dist/agent-src/skills/workspace-link/SKILL.md +131 -0
- package/dist/agent-src/templates/agents/agent-project-settings.example.yml +1 -1
- package/dist/agent-src/templates/playbook.md +75 -0
- package/dist/agent-src/templates/roadmaps.md +37 -0
- package/dist/agent-src/templates/scripts/check_playbook_invokes.ts +231 -0
- package/dist/agent-src/templates/scripts/work_engine/directives/ui/apply.ts +24 -0
- package/dist/agent-src/templates/scripts/work_engine/directives/ui/polish.ts +2 -0
- package/dist/agent-src/templates/scripts/work_engine/directives/ui/review.ts +216 -0
- package/dist/agent-src/templates/scripts/work_engine/directives/ui/scaffold.ts +159 -0
- package/dist/agent-src/templates/scripts/work_engine/directives/ui/stack_bundles.ts +73 -4
- package/dist/agent-src/templates/scripts/work_engine/stack/detect.ts +325 -40
- package/dist/cli/commands/uiAudit.js +221 -0
- package/dist/cli/commands/uiRender.js +206 -0
- package/dist/cli/main.js +22 -1
- package/dist/cli/mcp/content.js +64 -1
- package/dist/cli/mcp/dispatch.js +175 -10
- package/dist/cli/registry.js +3 -0
- package/dist/cli-delegate/{chunk-G23AT6GD.js → chunk-DMSZHXZS.js} +57 -1
- package/dist/cli-delegate/{chunk-77GR3VD4.js → chunk-FF7WAFMR.js} +58 -3
- package/dist/cli-delegate/{chunk-YM4GZDJG.js → chunk-JCW7ZLHK.js} +10 -0
- package/dist/cli-delegate/{chunk-H4VIVD4C.js → chunk-JJA2QEWA.js} +413 -391
- package/dist/cli-delegate/{chunk-PLSG6UL5.js → chunk-K4FFODTS.js} +341 -204
- package/dist/cli-delegate/{chunk-B2ERU2VA.js → chunk-WOKWX5PL.js} +1 -1
- package/dist/cli-delegate/cmd_brand_status.js +8 -6
- package/dist/cli-delegate/cmd_conformance.js +3 -3
- package/dist/cli-delegate/cmd_doctor.js +3 -3
- package/dist/cli-delegate/cmd_export.js +4 -4
- package/dist/cli-delegate/cmd_handoff.js +1 -1
- package/dist/cli-delegate/cmd_preflight.js +2 -2
- package/dist/cli-delegate/cmd_prune.js +4 -4
- package/dist/cli-delegate/cmd_session_recycle.js +70 -9
- package/dist/cli-delegate/cmd_settings_migrate.js +4 -4
- package/dist/cli-delegate/cmd_settings_set.js +1 -1
- package/dist/cli-delegate/cmd_sync.js +4 -4
- package/dist/cli-delegate/cmd_uninstall.js +4 -4
- package/dist/cli-delegate/cmd_validate.js +4 -4
- package/dist/discovery/deprecation-report.md +1 -1
- package/dist/discovery/discovery-manifest.json +362 -127
- package/dist/discovery/discovery-manifest.json.sha256 +1 -1
- package/dist/discovery/discovery-manifest.summary.md +4 -4
- package/dist/discovery/dormancy-report.md +1 -1
- package/dist/discovery/orphan-report.md +1 -1
- package/dist/discovery/packs.json +18 -8
- package/dist/discovery/trust-report.md +3 -3
- package/dist/discovery/workspaces.json +16 -6
- package/dist/hooks/dispatch.js +2575 -1472
- package/dist/install/install.mjs +800 -708
- package/dist/mcp/registry-manifest.json +3 -3
- package/dist/mcp/server.json +2 -2
- package/dist/mcp/server.mjs +1685 -1250
- package/dist/router.json +1 -1
- package/dist/scripts/_lib/lean_projection_mode.js +40 -0
- package/dist/scripts/_lib/scoped_projection.js +84 -0
- package/dist/scripts/_lib/ui_surface.js +89 -0
- package/dist/scripts/condense.js +6 -10
- package/dist/scripts/project_thin_rules.js +40 -2
- package/dist/server/schemas/settings.js +6 -0
- package/dist/shared/skillRanking.js +159 -0
- package/docs/contracts/provider-lifecycle.md +47 -18
- package/docs/contracts/settings-classes.md +35 -5
- package/docs/guidelines/agent-infra/context-hygiene-mechanics.md +49 -0
- package/docs/guidelines/agent-infra/downstream-changes-mechanics.md +91 -0
- package/docs/guidelines/agent-infra/evaluator-independence-mechanics.md +92 -0
- package/docs/guidelines/agent-infra/minimal-safe-diff-mechanics.md +45 -1
- package/docs/guidelines/agent-infra/roadmap-deferred-resolution-provenance.md +54 -0
- package/docs/guidelines/code-clarity.md +21 -0
- package/docs/guidelines/design-antipatterns.md +4 -2
- package/docs/guidelines/design-asset-discipline.md +38 -0
- package/docs/guidelines/design-fidelity-mechanics.md +45 -29
- package/docs/guidelines/design-handover-extraction.md +35 -5
- package/docs/guidelines/design-modes.md +41 -1
- package/docs/guidelines/monorepo-antipatterns.md +141 -0
- package/docs/guidelines/redundancy-taxonomy.md +180 -0
- package/llms.txt +50 -39
- package/package.json +6 -2
- package/src/agent-src/templates/scripts/check_playbook_invokes.ts +231 -0
- package/src/agent-src/templates/scripts/work_engine/directives/ui/apply.ts +24 -0
- package/src/agent-src/templates/scripts/work_engine/directives/ui/polish.ts +2 -0
- package/src/agent-src/templates/scripts/work_engine/directives/ui/review.ts +216 -0
- package/src/agent-src/templates/scripts/work_engine/directives/ui/scaffold.ts +159 -0
- package/src/agent-src/templates/scripts/work_engine/directives/ui/stack_bundles.ts +73 -4
- package/src/agent-src/templates/scripts/work_engine/stack/detect.ts +325 -40
- package/src/config/agent-settings.template.yml +44 -0
- package/src/config/assurance-capability-registry.json +223 -0
- package/src/config/assurance-threshold-budget.json +65 -0
- package/src/config/budgets.yml +19 -0
- package/src/config/ci-local-parity.yml +29 -0
- package/src/config/discovery/prompt-patterns.yml +56 -0
- package/src/config/discovery/unassigned-artefacts.yml +2 -0
- package/src/config/dispatch-economy-metrics.json +4 -2
- package/src/config/estate-count-budget.json +8 -3
- package/src/config/evaluator-budgets.json +14 -14
- package/src/config/gate-coverage.yml +392 -8
- package/src/config/gate-violation-baselines.json +76 -72
- package/src/config/hook-latency-budget.json +1 -0
- package/src/config/hook-token-budget.json +137 -125
- package/src/config/pack-size-budget.json +39 -10
- package/src/config/preamble-payload-budget.json +97 -71
- package/src/config/quorum-attendance-budget.json +12 -4
- package/src/config/routing-coverage-seed.json +29 -0
- package/src/config/rule-activation-census.json +7 -3
- package/src/config/rule-enforcement-baseline.json +0 -1
- package/src/config/rule-stub-ceilings.json +112 -91
- package/src/config/suggestion-capture.json +28 -0
- package/src/config/surface-matrix.yml +21 -2
- package/src/config/web-launch-readiness.json +188 -0
- package/src/scripts/_cli/cmd_doctor.ts +15 -16
- package/src/scripts/_cli/doctor_install_mode.ts +49 -0
- package/src/scripts/_cli/doctor_overrides.ts +154 -0
- package/src/scripts/_dispatch.bash +17 -0
- package/src/scripts/_lib/as_of.ts +412 -0
- package/src/scripts/_lib/exec_evidence.ts +7 -0
- package/src/scripts/_lib/gate_baseline.ts +150 -1
- package/src/scripts/_lib/hook_settings.ts +33 -0
- package/src/scripts/_lib/host_listing_model.ts +192 -0
- package/src/scripts/_lib/lean_projection_mode.ts +44 -0
- package/src/scripts/_lib/mcp_bridge.ts +199 -0
- package/src/scripts/_lib/review_independence.ts +62 -10
- package/src/scripts/_lib/rule_injection.ts +239 -0
- package/src/scripts/_lib/run_checkpoint.ts +54 -1
- package/src/scripts/_lib/scoped_projection.ts +96 -0
- package/src/scripts/_lib/session_register.ts +44 -2
- package/src/scripts/_lib/skill_catalogue.ts +38 -2
- package/src/scripts/_lib/skill_estate.ts +115 -0
- package/src/scripts/_lib/transcript_reads.ts +207 -0
- package/src/scripts/_lib/ui_authority.ts +343 -0
- package/src/scripts/ai-video/adapters/fal.sh +8 -3
- package/src/scripts/ai-video/adapters/gemini-veo.sh +10 -0
- package/src/scripts/ai-video/adapters/higgsfield.sh +10 -2
- package/src/scripts/ai-video/adapters/kling.sh +10 -0
- package/src/scripts/ai-video/adapters/sora.sh +10 -0
- package/src/scripts/ai-video/lib/calibrate-cost.sh +145 -0
- package/src/scripts/ai-video/lib/model-capabilities/README.md +53 -7
- package/src/scripts/ai-video/lib/model-capabilities/comfyui.json +15 -3
- package/src/scripts/ai-video/lib/model-capabilities/fal.json +36 -6
- package/src/scripts/ai-video/lib/model-capabilities/gemini-veo.json +23 -0
- package/src/scripts/ai-video/lib/model-capabilities/higgsfield.json +23 -0
- package/src/scripts/ai-video/lib/model-capabilities/kling.json +23 -0
- package/src/scripts/ai-video/lib/model-capabilities/musetalk.json +8 -2
- package/src/scripts/ai-video/lib/model-capabilities/replicate.json +36 -6
- package/src/scripts/ai-video/lib/model-capabilities/sora.json +45 -0
- package/src/scripts/ai-video/lib/model-capabilities/syncso.json +8 -2
- package/src/scripts/ai-video/lib/parse-blueprint.sh +52 -5
- package/src/scripts/ai-video/lib/resume-scan.sh +92 -3
- package/src/scripts/ai-video/lib/seam-plan.sh +212 -0
- package/src/scripts/ai-video/smoke-trace.sh +450 -2
- package/src/scripts/ai-video/stitch.sh +191 -10
- package/src/scripts/ai-video/test-pipeline.sh +84 -6
- package/src/scripts/ai_council/argument_exhaustion.ts +130 -0
- package/src/scripts/ai_council/cli_agency_bounds.ts +139 -0
- package/src/scripts/ai_council/cli_least_agency_canary.ts +347 -0
- package/src/scripts/ai_council/clients.ts +3 -2
- package/src/scripts/ai_council/consensus.ts +63 -6
- package/src/scripts/ai_council/events_log.ts +46 -1
- package/src/scripts/ai_council/orchestrator.ts +103 -108
- package/src/scripts/ai_council/orchestrator_results.ts +166 -0
- package/src/scripts/ai_council/prompts.ts +12 -5
- package/src/scripts/ai_council/quorum.ts +82 -1
- package/src/scripts/ai_council/quorum_wiring.ts +82 -5
- package/src/scripts/ai_council/stance_tally.ts +22 -0
- package/src/scripts/bench_hook_latency.ts +62 -0
- package/src/scripts/build_proof.ts +12 -1
- package/src/scripts/capture_skill_catalogue.ts +21 -0
- package/src/scripts/check_always_budget.ts +2 -1
- package/src/scripts/check_augmentignore.ts +2 -1
- package/src/scripts/check_beta_review_markers.ts +2 -1
- package/src/scripts/check_bundle_path_leakage.ts +162 -7
- package/src/scripts/check_command_examples.ts +557 -0
- package/src/scripts/check_composite_arming.ts +364 -0
- package/src/scripts/check_corpus_staleness.ts +2 -1
- package/src/scripts/check_council_pin_staleness.ts +3 -1
- package/src/scripts/check_enforcement_coverage.ts +116 -3
- package/src/scripts/check_enforcement_denominator.ts +365 -0
- package/src/scripts/check_estate_count.ts +122 -3
- package/src/scripts/check_gate_coverage.ts +2 -1
- package/src/scripts/check_hook_bundle_freshness.ts +13 -1
- package/src/scripts/check_knowledge_cards.ts +2 -1
- package/src/scripts/check_knowledge_pages.ts +3 -2
- package/src/scripts/check_memory.ts +2 -1
- package/src/scripts/check_no_automerge_key.ts +287 -0
- package/src/scripts/check_pack_conformance_fixture.ts +565 -0
- package/src/scripts/check_preamble_payload_budget.ts +30 -3
- package/src/scripts/check_proposal.ts +2 -1
- package/src/scripts/check_reach_staleness.ts +2 -1
- package/src/scripts/check_release_adjacent_health.ts +2 -1
- package/src/scripts/check_release_pr_shape.ts +5 -0
- package/src/scripts/check_review_schema.ts +34 -1
- package/src/scripts/check_roadmap_trackable.ts +48 -3
- package/src/scripts/check_routing_coverage.ts +352 -0
- package/src/scripts/check_score_contract.ts +505 -0
- package/src/scripts/check_skill_admissions.ts +514 -0
- package/src/scripts/check_source_size_budget.ts +2 -1
- package/src/scripts/check_standing_payload_delta.ts +505 -0
- package/src/scripts/check_trigger_evals.ts +2 -1
- package/src/scripts/check_web_launch_readiness.ts +705 -0
- package/src/scripts/classify_change_risk.ts +281 -0
- package/src/scripts/compute_skill_tiers.ts +186 -0
- package/src/scripts/condense.ts +8 -13
- package/src/scripts/council_attendance_metrics.ts +183 -0
- package/src/scripts/council_cli.ts +10 -8
- package/src/scripts/council_parse_rate.ts +116 -0
- package/src/scripts/derive_playbooks.ts +406 -0
- package/src/scripts/description_route_check.ts +494 -0
- package/src/scripts/design_slop_rules.ts +56 -2
- package/src/scripts/dispatch_r2_reviewer.ts +16 -0
- package/src/scripts/frontend_corpus_hash.ts +116 -0
- package/src/scripts/grade_target_readiness.ts +478 -0
- package/src/scripts/hook_manifest.json +1 -1
- package/src/scripts/hook_manifest.yaml +124 -16
- package/src/scripts/hooks/concern_registry.ts +6 -0
- package/src/scripts/hooks/design_pass_hook.ts +356 -0
- package/src/scripts/hooks/rtk_wrap_hook.ts +30 -7
- package/src/scripts/hooks/rule_inject_hook.ts +318 -0
- package/src/scripts/hooks/suggestion_capture_hook.ts +368 -0
- package/src/scripts/hot_context_hook.ts +74 -7
- package/src/scripts/install.ts +40 -89
- package/src/scripts/lint_adapter_tier.ts +663 -0
- package/src/scripts/lint_archived_skills.ts +93 -0
- package/src/scripts/lint_budget_ownership.ts +56 -5
- package/src/scripts/lint_deterministic_time.ts +470 -0
- package/src/scripts/lint_framework_leakage.ts +5 -0
- package/src/scripts/lint_handoffs.ts +525 -1
- package/src/scripts/lint_judge_prompt_expectation.ts +155 -0
- package/src/scripts/lint_marketplace.ts +88 -0
- package/src/scripts/lint_media_policy_linkage.ts +140 -1
- package/src/scripts/lint_one_off_age.ts +6 -1
- package/src/scripts/lint_override_kernel_guard.ts +87 -5
- package/src/scripts/lint_roadmap_complexity.ts +56 -0
- package/src/scripts/lint_rule_enforcement_declaration.ts +24 -7
- package/src/scripts/lint_rule_norm_pin.ts +321 -0
- package/src/scripts/lint_skill_trigger_corpus.ts +349 -0
- package/src/scripts/lint_spawn_payload.ts +42 -5
- package/src/scripts/lint_symptom_intake.ts +2 -1
- package/src/scripts/mcp_parity_smoke.ts +30 -4
- package/src/scripts/mcp_render.ts +66 -1
- package/src/scripts/mcp_tool_fingerprint.ts +241 -0
- package/src/scripts/measure_risk_class_drift.ts +140 -0
- package/src/scripts/measure_skill_ranker_baseline.ts +212 -0
- package/src/scripts/media/lib/adapter-common.sh +211 -1
- package/src/scripts/media/lib/adapter-contract.md +74 -6
- package/src/scripts/model_rule_injection.ts +907 -0
- package/src/scripts/pack_install_smoke.ts +363 -0
- package/src/scripts/pr_conflict_census.ts +187 -0
- package/src/scripts/project_thin_rules.ts +45 -2
- package/src/scripts/release.ts +66 -860
- package/src/scripts/release_drill.ts +59 -3
- package/src/scripts/release_env.ts +298 -0
- package/src/scripts/release_publication.ts +720 -0
- package/src/scripts/report_pack_delta.ts +204 -0
- package/src/scripts/roadmap_context.ts +778 -0
- package/src/scripts/schemas/fidelity-measurement-sheet.schema.json +169 -0
- package/src/scripts/schemas/rule.schema.json +24 -2
- package/src/scripts/schemas/skill.schema.json +39 -0
- package/src/scripts/schemas/ui-authority.schema.json +114 -0
- package/src/scripts/select_analysis_mode.ts +112 -0
- package/src/scripts/session_register_hook.ts +29 -3
- package/src/scripts/sessions_cli.ts +67 -3
- package/src/scripts/skill_tools/score_skill_relevance.ts +36 -53
- package/src/scripts/sync_pr_branch.ts +40 -1
- package/src/scripts/token_sink_report.ts +239 -0
- package/src/scripts/trigger_coverage.ts +122 -3
- package/src/scripts/update_counts.ts +7 -3
- package/src/scripts/validate_frontmatter.ts +66 -0
- package/src/server/schemas/settings.ts +10 -0
- package/src/shared/skillRanking.ts +183 -0
- package/dist/agent-src/skills/accessibility-auditor/evals/evals.json +0 -15
- package/dist/agent-src/skills/agent-security-review/evals/triggers.json +0 -52
- package/dist/agent-src/skills/ai-code-blindspots/evals/triggers.json +0 -52
- package/dist/agent-src/skills/analysis-skill-router/evals/evals.json +0 -13
- package/dist/agent-src/skills/brand/evals/triggers.json +0 -17
- package/dist/agent-src/skills/brand-asset-generation/evals/triggers.json +0 -17
- package/dist/agent-src/skills/brand-audit/evals/triggers.json +0 -17
- package/dist/agent-src/skills/brand-identity/evals/triggers.json +0 -17
- package/dist/agent-src/skills/brand-strategy/evals/triggers.json +0 -17
- package/dist/agent-src/skills/brand-to-tokens/evals/triggers.json +0 -17
- package/dist/agent-src/skills/bug-analyzer/evals/evals.json +0 -13
- package/dist/agent-src/skills/canvas-design/evals/triggers.json +0 -17
- package/dist/agent-src/skills/character-consistency/evals/evals.json +0 -16
- package/dist/agent-src/skills/code-intelligence/evals/triggers.json +0 -52
- package/dist/agent-src/skills/code-review/evals/evals.json +0 -100
- package/dist/agent-src/skills/command-routing/evals/evals.json +0 -14
- package/dist/agent-src/skills/complexity-first-planning/evals/triggers.json +0 -17
- package/dist/agent-src/skills/contract-review/evals/triggers.json +0 -17
- package/dist/agent-src/skills/conventional-commits-writing/evals/evals.json +0 -15
- package/dist/agent-src/skills/corpus-grounding/evals/triggers.json +0 -17
- package/dist/agent-src/skills/dashboard-design/evals/evals.json +0 -16
- package/dist/agent-src/skills/dcf-modeling/evals/domain-truth.json +0 -29
- package/dist/agent-src/skills/dcf-modeling/evals/evals.json +0 -20
- package/dist/agent-src/skills/decision-record/evals/evals.json +0 -20
- package/dist/agent-src/skills/decision-record/evals/triggers.json +0 -87
- package/dist/agent-src/skills/design-intelligence/evals/evals.json +0 -14
- package/dist/agent-src/skills/design-intelligence/evals/triggers.json +0 -17
- package/dist/agent-src/skills/design-system-capture/evals/evals.json +0 -15
- package/dist/agent-src/skills/design-tokens/evals/triggers.json +0 -17
- package/dist/agent-src/skills/design-variations/evals/triggers.json +0 -17
- package/dist/agent-src/skills/developer-like-execution/evals/evals.json +0 -16
- package/dist/agent-src/skills/doc-coauthoring/evals/evals.json +0 -16
- package/dist/agent-src/skills/doc-coauthoring/evals/triggers.json +0 -17
- package/dist/agent-src/skills/docx-authoring/evals/triggers.json +0 -52
- package/dist/agent-src/skills/dpa-review/evals/triggers.json +0 -17
- package/dist/agent-src/skills/editorial-calendar/evals/domain-truth.json +0 -16
- package/dist/agent-src/skills/editorial-calendar/evals/evals.json +0 -16
- package/dist/agent-src/skills/eloquent/evals/triggers.json +0 -17
- package/dist/agent-src/skills/estimate-ticket/evals/evals.json +0 -16
- package/dist/agent-src/skills/estimate-ticket/evals/output-schema.yml +0 -20
- package/dist/agent-src/skills/estimate-ticket/evals/triggers.json +0 -19
- package/dist/agent-src/skills/evaluate-llm-feature/evals/triggers.json +0 -52
- package/dist/agent-src/skills/existing-ui-audit/evals/triggers.json +0 -47
- package/dist/agent-src/skills/experiment-loop/evals/output-schema.yml +0 -27
- package/dist/agent-src/skills/experiment-loop/evals/triggers.json +0 -17
- package/dist/agent-src/skills/fe-design/evals/triggers.json +0 -55
- package/dist/agent-src/skills/forecasting/evals/domain-truth.json +0 -29
- package/dist/agent-src/skills/forecasting/evals/evals.json +0 -20
- package/dist/agent-src/skills/forensics-report/evals/triggers.json +0 -17
- package/dist/agent-src/skills/frontend-render-security/evals/triggers.json +0 -52
- package/dist/agent-src/skills/fundraising-narrative/evals/domain-truth.json +0 -16
- package/dist/agent-src/skills/fundraising-narrative/evals/evals.json +0 -16
- package/dist/agent-src/skills/gated-reach/evals/triggers.json +0 -72
- package/dist/agent-src/skills/github-ci/evals/evals.json +0 -25
- package/dist/agent-src/skills/history-design/evals/triggers.json +0 -17
- package/dist/agent-src/skills/html-deck/evals/triggers.json +0 -17
- package/dist/agent-src/skills/humanizer/evals/strip_fixtures.json +0 -57
- package/dist/agent-src/skills/humanizer/evals/triggers.json +0 -17
- package/dist/agent-src/skills/iconography/evals/triggers.json +0 -17
- package/dist/agent-src/skills/image-analyser/evals/triggers.json +0 -17
- package/dist/agent-src/skills/image-creator/evals/triggers.json +0 -17
- package/dist/agent-src/skills/image-editing/evals/triggers.json +0 -17
- package/dist/agent-src/skills/image-generation/evals/triggers.json +0 -17
- package/dist/agent-src/skills/image-provider-routing/evals/triggers.json +0 -17
- package/dist/agent-src/skills/incident-commander/evals/domain-truth.json +0 -16
- package/dist/agent-src/skills/incident-commander/evals/evals.json +0 -20
- package/dist/agent-src/skills/judge-artifact-completeness/evals/triggers.json +0 -17
- package/dist/agent-src/skills/judge-injection-defense/evals/triggers.json +0 -17
- package/dist/agent-src/skills/judge-synthesis/evals/triggers.json +0 -17
- package/dist/agent-src/skills/launch-readiness/evals/evals.json +0 -21
- package/dist/agent-src/skills/learning-tutor/evals/triggers.json +0 -52
- package/dist/agent-src/skills/legal-intake-triage/evals/triggers.json +0 -17
- package/dist/agent-src/skills/legal-practice-profile/evals/triggers.json +0 -17
- package/dist/agent-src/skills/license-compliance-audit/evals/triggers.json +0 -52
- package/dist/agent-src/skills/license-compliance-borrow-check/evals/triggers.json +0 -52
- package/dist/agent-src/skills/license-compliance-credits/evals/triggers.json +0 -52
- package/dist/agent-src/skills/llm-provider-knowledge/evals/triggers.json +0 -20
- package/dist/agent-src/skills/logging-monitoring/evals/evals.json +0 -16
- package/dist/agent-src/skills/logo-generation/evals/triggers.json +0 -17
- package/dist/agent-src/skills/messaging-architecture/evals/domain-truth.json +0 -16
- package/dist/agent-src/skills/messaging-architecture/evals/evals.json +0 -16
- package/dist/agent-src/skills/nda-triage/evals/triggers.json +0 -17
- package/dist/agent-src/skills/pdf-tools/evals/triggers.json +0 -52
- package/dist/agent-src/skills/perf-feedback-craft/evals/evals.json +0 -16
- package/dist/agent-src/skills/persona-improvement/evals/triggers.json +0 -52
- package/dist/agent-src/skills/php-coder/evals/triggers.json +0 -17
- package/dist/agent-src/skills/prediction-pool-optimizer/evals/triggers.json +0 -21
- package/dist/agent-src/skills/prompt-engineering-image/evals/triggers.json +0 -17
- package/dist/agent-src/skills/prompt-engineering-patterns/evals/evals.json +0 -16
- package/dist/agent-src/skills/prompt-validator/evals/triggers.json +0 -17
- package/dist/agent-src/skills/quality-tools/evals/evals.json +0 -15
- package/dist/agent-src/skills/reasoning-orchestrator/evals/triggers.json +0 -17
- package/dist/agent-src/skills/refine-prompt/evals/evals.json +0 -16
- package/dist/agent-src/skills/refine-ticket/evals/evals.json +0 -16
- package/dist/agent-src/skills/refine-ticket/evals/output-schema.yml +0 -16
- package/dist/agent-src/skills/refine-ticket/evals/triggers.json +0 -17
- package/dist/agent-src/skills/release-comms/evals/evals.json +0 -16
- package/dist/agent-src/skills/rice-prioritization/evals/evals.json +0 -20
- package/dist/agent-src/skills/runway-cognition/evals/domain-truth.json +0 -29
- package/dist/agent-src/skills/runway-cognition/evals/evals.json +0 -20
- package/dist/agent-src/skills/scenario-modeling/evals/domain-truth.json +0 -29
- package/dist/agent-src/skills/scenario-modeling/evals/evals.json +0 -20
- package/dist/agent-src/skills/schema-review/evals/triggers.json +0 -17
- package/dist/agent-src/skills/screenshot-hygiene/evals/triggers.json +0 -52
- package/dist/agent-src/skills/security-maturity-assessment/evals/triggers.json +0 -52
- package/dist/agent-src/skills/skill-writing/evals/triggers.json +0 -17
- package/dist/agent-src/skills/spreadsheet-authoring/evals/triggers.json +0 -47
- package/dist/agent-src/skills/subagent-orchestration/evals/evals.json +0 -60
- package/dist/agent-src/skills/supply-chain-intake/evals/triggers.json +0 -52
- package/dist/agent-src/skills/systematic-debugging/evals/evals.json +0 -20
- package/dist/agent-src/skills/test-case-discovery/evals/triggers.json +0 -52
- package/dist/agent-src/skills/test-driven-development/evals/evals.json +0 -16
- package/dist/agent-src/skills/threat-modeling/evals/evals.json +0 -21
- package/dist/agent-src/skills/typography-system/evals/evals.json +0 -14
- package/dist/agent-src/skills/typography-system/evals/triggers.json +0 -17
- package/dist/agent-src/skills/unit-economics-modeling/evals/domain-truth.json +0 -40
- package/dist/agent-src/skills/unit-economics-modeling/evals/evals.json +0 -24
- package/dist/agent-src/skills/verify-completion-evidence/evals/evals.json +0 -16
- package/dist/agent-src/skills/verify-repair-loop/evals/output-schema.yml +0 -20
- package/dist/agent-src/skills/verify-repair-loop/evals/triggers.json +0 -17
- package/dist/agent-src/skills/vision-articulation/evals/evals.json +0 -16
- package/dist/agent-src/skills/voice-and-tone-design/evals/evals.json +0 -16
- package/dist/agent-src/skills/wireframe/evals/triggers.json +0 -17
- package/dist/agent-src/skills/worktree-lifecycle/evals/evals.json +0 -38
- package/dist/agent-src/skills/worktree-lifecycle/evals/triggers.json +0 -52
- package/dist/cli/agent-config.js.map +0 -1
- package/dist/cli/bash/runBash.js.map +0 -1
- package/dist/cli/commands/commands.js.map +0 -1
- package/dist/cli/commands/config.js.map +0 -1
- package/dist/cli/commands/doctorShell.js.map +0 -1
- package/dist/cli/commands/mcpServer.js.map +0 -1
- package/dist/cli/commands/packs.js.map +0 -1
- package/dist/cli/commands/profiles.js.map +0 -1
- package/dist/cli/commands/recordTriggerEval.js.map +0 -1
- package/dist/cli/commands/rtkDetect.js.map +0 -1
- package/dist/cli/commands/settings.js.map +0 -1
- package/dist/cli/commands/uiServe.js.map +0 -1
- package/dist/cli/commands/versions.js.map +0 -1
- package/dist/cli/commands/workspaces.js.map +0 -1
- package/dist/cli/configRoot.js.map +0 -1
- package/dist/cli/discovery/loadManifest.js.map +0 -1
- package/dist/cli/firstRunNotice.js.map +0 -1
- package/dist/cli/help.js.map +0 -1
- package/dist/cli/initRouting.js.map +0 -1
- package/dist/cli/log/logger.js.map +0 -1
- package/dist/cli/main.js.map +0 -1
- package/dist/cli/mcp/content.js.map +0 -1
- package/dist/cli/mcp/dispatch.js.map +0 -1
- package/dist/cli/mcp/stdio.js.map +0 -1
- package/dist/cli/paths.js.map +0 -1
- package/dist/cli/python/knowledge_ingest.js.map +0 -1
- package/dist/cli/python/workspace_analytics.js.map +0 -1
- package/dist/cli/python/workspace_crypto.js.map +0 -1
- package/dist/cli/python/workspace_documents.js.map +0 -1
- package/dist/cli/python/workspace_drive.js.map +0 -1
- package/dist/cli/python/workspace_drive_health.js.map +0 -1
- package/dist/cli/python/workspace_explain.js.map +0 -1
- package/dist/cli/python/workspace_hosts.js.map +0 -1
- package/dist/cli/python/workspace_inbox.js.map +0 -1
- package/dist/cli/python/workspace_render.js.map +0 -1
- package/dist/cli/python/workspace_roles.js.map +0 -1
- package/dist/cli/python/workspace_secrets.js.map +0 -1
- package/dist/cli/python/workspace_sessions.js.map +0 -1
- package/dist/cli/python/workspace_skills.js.map +0 -1
- package/dist/cli/registry.js.map +0 -1
- package/dist/install/agentSwitchDetection.js.map +0 -1
- package/dist/install/agentSwitchProfile.js.map +0 -1
- package/dist/install/atomic.js.map +0 -1
- package/dist/install/claudePathsPlan.js.map +0 -1
- package/dist/install/conflict.js.map +0 -1
- package/dist/install/detect.js.map +0 -1
- package/dist/install/emit_host_rules_cli.js.map +0 -1
- package/dist/install/globalRuleLayers.js.map +0 -1
- package/dist/install/hostLayerFingerprint.js.map +0 -1
- package/dist/install/partitionEligibility.js.map +0 -1
- package/dist/install/paths.js.map +0 -1
- package/dist/install/plan.js.map +0 -1
- package/dist/install/preflight.js.map +0 -1
- package/dist/install/rtkDetection.js.map +0 -1
- package/dist/install/ruleInScope.js.map +0 -1
- package/dist/install/ruleLayerPartition.js.map +0 -1
- package/dist/install/rule_scope.js.map +0 -1
- package/dist/install/rule_scope_cli.js.map +0 -1
- package/dist/install/selectedTools.js.map +0 -1
- package/dist/install/toolDetection.js.map +0 -1
- package/dist/install/txlog.js.map +0 -1
- package/dist/install/types.js.map +0 -1
- package/dist/install/wizard-plan.js.map +0 -1
- package/dist/install/wizardDismissals.js.map +0 -1
- package/dist/scripts/_lib/agent_settings.js.map +0 -1
- package/dist/scripts/_lib/agent_src.js.map +0 -1
- package/dist/scripts/_lib/claude_builtin_names.js.map +0 -1
- package/dist/scripts/_lib/claude_plugin.js.map +0 -1
- package/dist/scripts/_lib/claude_settings_hooks.js.map +0 -1
- package/dist/scripts/_lib/compile_time_toggles.js.map +0 -1
- package/dist/scripts/_lib/environment_detector.js.map +0 -1
- package/dist/scripts/_lib/host_launch.js.map +0 -1
- package/dist/scripts/_lib/install_layout.js.map +0 -1
- package/dist/scripts/_lib/installed_lock.js.map +0 -1
- package/dist/scripts/_lib/model_tier.js.map +0 -1
- package/dist/scripts/_lib/prune_empty_dirs.js.map +0 -1
- package/dist/scripts/_lib/scoped_projection.js.map +0 -1
- package/dist/scripts/_lib/script_output.js.map +0 -1
- package/dist/scripts/_lib/spawn_env.js.map +0 -1
- package/dist/scripts/_lib/surface_tiers.js.map +0 -1
- package/dist/scripts/_lib/token_count.js.map +0 -1
- package/dist/scripts/_lib/trigger_eval_floors.js.map +0 -1
- package/dist/scripts/_lib/user_global_paths.js.map +0 -1
- package/dist/scripts/ai_council/modes.js.map +0 -1
- package/dist/scripts/ai_council/transport_resolver.js.map +0 -1
- package/dist/scripts/condense.js.map +0 -1
- package/dist/scripts/project_thin_rules.js.map +0 -1
- package/dist/server/app.js.map +0 -1
- package/dist/server/io/atomicMultiWrite.js.map +0 -1
- package/dist/server/io/atomicWrite.js.map +0 -1
- package/dist/server/io/sharedWriteCheck.js.map +0 -1
- package/dist/server/io/substituteTemplate.js.map +0 -1
- package/dist/server/io/yamlIO.js.map +0 -1
- package/dist/server/nicknameResolver.js.map +0 -1
- package/dist/server/port.js.map +0 -1
- package/dist/server/routes/discovery.js.map +0 -1
- package/dist/server/routes/install.js.map +0 -1
- package/dist/server/routes/ping.js.map +0 -1
- package/dist/server/routes/schema.js.map +0 -1
- package/dist/server/routes/settings.js.map +0 -1
- package/dist/server/routes/settingsChanges.js.map +0 -1
- package/dist/server/routes/userMd.js.map +0 -1
- package/dist/server/routes/wizard.js.map +0 -1
- package/dist/server/routes/workspace.js.map +0 -1
- package/dist/server/schemas/settings.js.map +0 -1
- package/dist/server/serverInfo.js.map +0 -1
- package/dist/server/token.js.map +0 -1
- package/dist/server/writeRoot.js.map +0 -1
- package/dist/shared/capabilities.js.map +0 -1
- package/dist/shared/interactiveContext.js.map +0 -1
- package/dist/shared/nicknamePrefill.js.map +0 -1
- package/dist/shared/settingsAsks.js.map +0 -1
- package/dist/shared/settingsCarveOut.js.map +0 -1
- package/dist/shared/settingsClasses.js.map +0 -1
- package/dist/shared/settingsConsent.js.map +0 -1
- package/dist/shared/settingsSurface.js.map +0 -1
- package/dist/shared/userMd/formAdapter.js.map +0 -1
- package/dist/shared/userMd/schema.js.map +0 -1
- package/dist/shared/userMd/utils.js.map +0 -1
- package/dist/ui/assets/index-Cxgy63kz.js.map +0 -1
- package/src/scripts/_lib/adr_frontmatter.test.ts +0 -365
- package/src/scripts/_lib/adversarial_council_gate.test.ts +0 -112
- package/src/scripts/_lib/adversarial_reconcile.test.ts +0 -197
- package/src/scripts/_lib/auto_dispatch.corpus.test.ts +0 -150
- package/src/scripts/_lib/secret_detector.test.ts +0 -108
- package/src/scripts/_lib/secret_detector_adversarial.test.ts +0 -116
- package/src/scripts/_lib/untrusted_content.test.ts +0 -175
- package/src/scripts/check_secret_leak.test.ts +0 -90
- package/src/scripts/design_slop_rules.test.ts +0 -239
- package/src/scripts/self_review_gate.test.ts +0 -296
- package/src/shared/capabilities.test.ts +0 -43
|
@@ -0,0 +1,365 @@
|
|
|
1
|
+
#!/usr/bin/env tsx
|
|
2
|
+
/**
|
|
3
|
+
* CI gate: exactly one enforcement denominator is quotable, and it comes from
|
|
4
|
+
* the resolver.
|
|
5
|
+
*
|
|
6
|
+
* WHY. Measured on 2026-08-23, the tree published **five** figures for one
|
|
7
|
+
* property — how many governed rules declare no enforcement backstop.
|
|
8
|
+
* `docs/proof.md` carried **86** in one place and **89** in another (two
|
|
9
|
+
* different frames quoted under one heading); a frontmatter-strict grep of
|
|
10
|
+
* `src/rules/` returned **87**; an any-line grep returned **82**; and a
|
|
11
|
+
* hand-written ledger entry at `docs/CLAIMS.md:203` carried its own snapshot.
|
|
12
|
+
* A reader had no way to tell which was the answer, and correcting any single
|
|
13
|
+
* figure would have left the plurality intact.
|
|
14
|
+
*
|
|
15
|
+
* `check_enforcement_coverage` is the only citable source: it RESOLVES rather
|
|
16
|
+
* than counts (a declared validator no workflow reaches is `unwired`, not
|
|
17
|
+
* covered) and it publishes its denominator with the frame that produced it.
|
|
18
|
+
* `docs/proof.md` § 4b projects that output. This gate is what stops a sixth
|
|
19
|
+
* number appearing — a sixth number would be the defect, not the fix.
|
|
20
|
+
*
|
|
21
|
+
* THE CONTRACT. In the scanned corpus, a line stating an enforcement count is a
|
|
22
|
+
* finding, full stop. Not "a wrong one" — the gate deliberately does NOT compare
|
|
23
|
+
* values against the resolver, because a hand-written figure that happens to be
|
|
24
|
+
* right today is the mechanism by which the plurality returned every previous
|
|
25
|
+
* time. The remedy is to cite the generated projection or the resolver's own
|
|
26
|
+
* output instead of restating a number.
|
|
27
|
+
*
|
|
28
|
+
* SCOPE, and why each exclusion is not a loophole:
|
|
29
|
+
* · `docs/**` plus `README.md` — the published surfaces. `agents/` is
|
|
30
|
+
* excluded wholesale because an evidence artefact records a measurement
|
|
31
|
+
* taken at a stated time, which is its job; freezing those would forbid
|
|
32
|
+
* measurement itself.
|
|
33
|
+
* · `docs/decisions/` — an ADR is a dated record of what was true when the
|
|
34
|
+
* decision was made. Rewriting one to today's number destroys the record.
|
|
35
|
+
* · `docs/archive/` — shipped changelogs, immutable by construction.
|
|
36
|
+
* · Any file whose head declares `GENERATED by` — that IS the resolver's
|
|
37
|
+
* projection, which is the sanctioned home for the number.
|
|
38
|
+
*
|
|
39
|
+
* Escape hatch: `<!-- enforcement-count-ok: <reason> -->` on the line, reason
|
|
40
|
+
* mandatory. A bare marker stays a finding.
|
|
41
|
+
*
|
|
42
|
+
* Exit codes:
|
|
43
|
+
* 0 — no hand-written enforcement count in the published corpus
|
|
44
|
+
* 1 — at least one (or a marker with no reason)
|
|
45
|
+
* 2 — the gate could not run (dead scan scope, bad args)
|
|
46
|
+
*/
|
|
47
|
+
import * as fs from 'node:fs';
|
|
48
|
+
import * as os from 'node:os';
|
|
49
|
+
import * as path from 'node:path';
|
|
50
|
+
import { fileURLToPath, pathToFileURL } from 'node:url';
|
|
51
|
+
|
|
52
|
+
import { GateLedger, LedgerUsageError } from './_lib/gate_ledger.js';
|
|
53
|
+
import { runGateCli, runSelfTest, type SelfTestCase } from './_lib/gate_self_test.js';
|
|
54
|
+
import { DeadScopeError, reportScanned } from './_lib/scan_scope.js';
|
|
55
|
+
|
|
56
|
+
const _HERE = fileURLToPath(import.meta.url);
|
|
57
|
+
const DEFAULT_ROOT = path.join(path.dirname(_HERE), '..', '..');
|
|
58
|
+
const SELF = 'src/scripts/check_enforcement_denominator.ts';
|
|
59
|
+
|
|
60
|
+
const SELF_TEST_MIN_CASES = 7;
|
|
61
|
+
const SELF_TEST_MIN_REJECT = 3;
|
|
62
|
+
|
|
63
|
+
/** Roots walked, repo-relative. */
|
|
64
|
+
const SCAN_ROOTS = ['docs', 'README.md'] as const;
|
|
65
|
+
|
|
66
|
+
/** Repo-relative prefixes excluded — see the docstring for why each is not a loophole. */
|
|
67
|
+
const EXCLUDED_PREFIXES = ['docs/decisions/', 'docs/archive/'] as const;
|
|
68
|
+
|
|
69
|
+
/** A file declaring this in its first few lines is the resolver's own projection. */
|
|
70
|
+
const GENERATED_MARKER = 'GENERATED by';
|
|
71
|
+
const GENERATED_HEAD_LINES = 5;
|
|
72
|
+
|
|
73
|
+
/** Same-line exemption; the reason after the colon must be non-empty. */
|
|
74
|
+
const MARKER = 'enforcement-count-ok:';
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* A line is a candidate only when it talks about enforcement AND carries a
|
|
78
|
+
* rule-count shape. Both halves are load-bearing: the keyword alone matches
|
|
79
|
+
* every prose mention of a backstop, and the shape alone matches "2 rules" in a
|
|
80
|
+
* concepts page, which is not this property at all.
|
|
81
|
+
*/
|
|
82
|
+
const ENFORCEMENT_KEYWORDS =
|
|
83
|
+
/undeclared|enforced_by|enforcement coverage|carry a backstop|backstop that fails/;
|
|
84
|
+
|
|
85
|
+
const COUNT_SHAPES: readonly RegExp[] = [
|
|
86
|
+
/\b\d+\s+of\s+\d+\s+(?:governed\s+)?rules?\b/,
|
|
87
|
+
/\b\d+\s+(?:governed\s+)?rules?\b/,
|
|
88
|
+
/\b\d+\s+undeclared\b/,
|
|
89
|
+
/\bundeclared\s+\d+\b/,
|
|
90
|
+
];
|
|
91
|
+
|
|
92
|
+
export interface Finding {
|
|
93
|
+
file: string;
|
|
94
|
+
line: number;
|
|
95
|
+
excerpt: string;
|
|
96
|
+
/** `raw` — an unmarked count. `bare-marker` — a marker with no reason. */
|
|
97
|
+
kind: 'raw' | 'bare-marker';
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
function markerOn(line: string): 'none' | 'bare' | 'reasoned' {
|
|
101
|
+
const at = line.indexOf(MARKER);
|
|
102
|
+
if (at < 0) return 'none';
|
|
103
|
+
const tail = line.slice(at + MARKER.length).replace(/-->\s*$/, '').trim();
|
|
104
|
+
return tail === '' ? 'bare' : 'reasoned';
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
export function scanText(relPath: string, text: string): Finding[] {
|
|
108
|
+
const out: Finding[] = [];
|
|
109
|
+
const lines = text.split('\n');
|
|
110
|
+
for (let i = 0; i < lines.length; i += 1) {
|
|
111
|
+
const line = lines[i] ?? '';
|
|
112
|
+
if (!ENFORCEMENT_KEYWORDS.test(line)) continue;
|
|
113
|
+
if (!COUNT_SHAPES.some((re) => re.test(line))) continue;
|
|
114
|
+
const marker = markerOn(line);
|
|
115
|
+
if (marker === 'reasoned') continue;
|
|
116
|
+
out.push({
|
|
117
|
+
file: relPath,
|
|
118
|
+
line: i + 1,
|
|
119
|
+
excerpt: line.trim().slice(0, 120),
|
|
120
|
+
kind: marker === 'bare' ? 'bare-marker' : 'raw',
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
return out;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/** `true` when the file declares itself generated — i.e. it IS the projection. */
|
|
127
|
+
export function isGenerated(text: string): boolean {
|
|
128
|
+
return text.split('\n', GENERATED_HEAD_LINES).join('\n').includes(GENERATED_MARKER);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/** Every markdown file in scope, repo-relative, sorted. */
|
|
132
|
+
export function corpus(root: string): string[] {
|
|
133
|
+
const out: string[] = [];
|
|
134
|
+
const walk = (rel: string): void => {
|
|
135
|
+
const abs = path.join(root, rel);
|
|
136
|
+
let st: fs.Stats;
|
|
137
|
+
try {
|
|
138
|
+
st = fs.statSync(abs);
|
|
139
|
+
} catch {
|
|
140
|
+
return;
|
|
141
|
+
}
|
|
142
|
+
if (st.isFile()) {
|
|
143
|
+
if (!rel.endsWith('.md')) return;
|
|
144
|
+
if (EXCLUDED_PREFIXES.some((p) => rel.startsWith(p))) return;
|
|
145
|
+
out.push(rel);
|
|
146
|
+
return;
|
|
147
|
+
}
|
|
148
|
+
if (!st.isDirectory()) return;
|
|
149
|
+
for (const name of fs.readdirSync(abs).sort()) walk(path.posix.join(rel, name));
|
|
150
|
+
};
|
|
151
|
+
for (const r of SCAN_ROOTS) walk(r);
|
|
152
|
+
return out.sort();
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
export function check(root: string): { code: number; findings: Finding[]; scanned: number } {
|
|
156
|
+
const files = corpus(root);
|
|
157
|
+
const findings: Finding[] = [];
|
|
158
|
+
const ledger = new GateLedger('check_enforcement_denominator');
|
|
159
|
+
|
|
160
|
+
try {
|
|
161
|
+
reportScanned({
|
|
162
|
+
gate: 'check_enforcement_denominator',
|
|
163
|
+
scanned: files.length,
|
|
164
|
+
units: 'published markdown file(s)',
|
|
165
|
+
roots: [...SCAN_ROOTS],
|
|
166
|
+
});
|
|
167
|
+
} catch (err) {
|
|
168
|
+
if (err instanceof DeadScopeError) {
|
|
169
|
+
process.stderr.write(`❌ ${err.message}\n`);
|
|
170
|
+
return { code: 2, findings, scanned: files.length };
|
|
171
|
+
}
|
|
172
|
+
throw err;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
try {
|
|
176
|
+
ledger.plan(files);
|
|
177
|
+
for (const rel of files) {
|
|
178
|
+
const text = fs.readFileSync(path.join(root, rel), 'utf-8');
|
|
179
|
+
if (isGenerated(text)) {
|
|
180
|
+
ledger.complete(rel);
|
|
181
|
+
continue;
|
|
182
|
+
}
|
|
183
|
+
const found = scanText(rel, text);
|
|
184
|
+
if (found.length > 0) {
|
|
185
|
+
findings.push(...found);
|
|
186
|
+
ledger.fail(rel, `${String(found.length)} hand-written enforcement count(s)`);
|
|
187
|
+
} else {
|
|
188
|
+
ledger.complete(rel);
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
} catch (err) {
|
|
192
|
+
if (err instanceof LedgerUsageError) {
|
|
193
|
+
process.stderr.write(`❌ ${err.message}\n`);
|
|
194
|
+
return { code: 2, findings, scanned: files.length };
|
|
195
|
+
}
|
|
196
|
+
throw err;
|
|
197
|
+
}
|
|
198
|
+
ledger.report();
|
|
199
|
+
|
|
200
|
+
return { code: findings.length > 0 ? 1 : 0, findings, scanned: files.length };
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
/* ------------------------------------------------------------------ *
|
|
204
|
+
* Self-test
|
|
205
|
+
* ------------------------------------------------------------------ */
|
|
206
|
+
|
|
207
|
+
function fixtureRoot(files: Record<string, string>): string {
|
|
208
|
+
const dir = fs.mkdtempSync(path.join(os.tmpdir(), 'enf-denom-'));
|
|
209
|
+
for (const [rel, body] of Object.entries(files)) {
|
|
210
|
+
const abs = path.join(dir, rel);
|
|
211
|
+
fs.mkdirSync(path.dirname(abs), { recursive: true });
|
|
212
|
+
fs.writeFileSync(abs, body);
|
|
213
|
+
}
|
|
214
|
+
return dir;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
export function selfTest(): number {
|
|
218
|
+
const made: string[] = [];
|
|
219
|
+
const run = (files: Record<string, string>): number => {
|
|
220
|
+
const d = fixtureRoot(files);
|
|
221
|
+
made.push(d);
|
|
222
|
+
return runGateCli(DEFAULT_ROOT, SELF, ['--quiet', '--root', d], DEFAULT_ROOT);
|
|
223
|
+
};
|
|
224
|
+
const CLEAN = '# Docs\n\nNothing about counts here.\n';
|
|
225
|
+
|
|
226
|
+
const cases: SelfTestCase[] = [
|
|
227
|
+
{
|
|
228
|
+
name: 'rejects a hand-written "N of M governed rules … backstop" figure',
|
|
229
|
+
expect: 'reject',
|
|
230
|
+
run: () =>
|
|
231
|
+
run({
|
|
232
|
+
'docs/a.md': '15 of 120 governed rules carry a backstop that fails a CI build.\n',
|
|
233
|
+
}),
|
|
234
|
+
},
|
|
235
|
+
{
|
|
236
|
+
name: 'rejects a hand-written undeclared count',
|
|
237
|
+
expect: 'reject',
|
|
238
|
+
run: () => run({ 'docs/a.md': 'Today 86 rules are undeclared.\n' }),
|
|
239
|
+
},
|
|
240
|
+
{
|
|
241
|
+
name: 'rejects the same figure in README.md',
|
|
242
|
+
expect: 'reject',
|
|
243
|
+
run: () => run({ 'README.md': '86 undeclared rules have no enforced_by.\n' }),
|
|
244
|
+
},
|
|
245
|
+
{
|
|
246
|
+
name: 'rejects a marker with no reason',
|
|
247
|
+
expect: 'reject',
|
|
248
|
+
run: () =>
|
|
249
|
+
run({
|
|
250
|
+
'docs/a.md': `86 rules are undeclared. <!-- ${MARKER} -->\n`,
|
|
251
|
+
}),
|
|
252
|
+
},
|
|
253
|
+
{
|
|
254
|
+
name: 'accepts a marker carrying a reason',
|
|
255
|
+
expect: 'accept',
|
|
256
|
+
run: () =>
|
|
257
|
+
run({
|
|
258
|
+
'docs/a.md': `86 rules are undeclared. <!-- ${MARKER} historical, dated in place -->\n`,
|
|
259
|
+
}),
|
|
260
|
+
},
|
|
261
|
+
{
|
|
262
|
+
name: "accepts the resolver's own generated projection",
|
|
263
|
+
expect: 'accept',
|
|
264
|
+
run: () =>
|
|
265
|
+
run({
|
|
266
|
+
'docs/proof.md':
|
|
267
|
+
`<!-- ${GENERATED_MARKER} src/scripts/build_proof.ts -->\n\n` +
|
|
268
|
+
'120 rules · 15 blocking · 86 undeclared (no enforced_by yet).\n',
|
|
269
|
+
}),
|
|
270
|
+
},
|
|
271
|
+
{
|
|
272
|
+
name: 'accepts a dated ADR record (docs/decisions/ is excluded)',
|
|
273
|
+
expect: 'accept',
|
|
274
|
+
run: () =>
|
|
275
|
+
run({
|
|
276
|
+
'docs/a.md': CLEAN,
|
|
277
|
+
'docs/decisions/ADR-001-x.md': '86 rules were undeclared on 2026-08-12.\n',
|
|
278
|
+
}),
|
|
279
|
+
},
|
|
280
|
+
{
|
|
281
|
+
name: 'accepts a rule count with no enforcement sense ("2 rules" in a concepts page)',
|
|
282
|
+
expect: 'accept',
|
|
283
|
+
run: () => run({ 'docs/a.md': 'The kernel splits into 2 rules and a router.\n' }),
|
|
284
|
+
},
|
|
285
|
+
{
|
|
286
|
+
name: 'rejects a moved scan root rather than reporting clean (exit 2)',
|
|
287
|
+
expect: 'reject',
|
|
288
|
+
run: () =>
|
|
289
|
+
runGateCli(
|
|
290
|
+
DEFAULT_ROOT,
|
|
291
|
+
SELF,
|
|
292
|
+
['--quiet', '--root', path.join(DEFAULT_ROOT, 'no-such-root')],
|
|
293
|
+
DEFAULT_ROOT,
|
|
294
|
+
),
|
|
295
|
+
},
|
|
296
|
+
];
|
|
297
|
+
|
|
298
|
+
try {
|
|
299
|
+
return runSelfTest({
|
|
300
|
+
gate: 'check_enforcement_denominator',
|
|
301
|
+
cases,
|
|
302
|
+
minCases: SELF_TEST_MIN_CASES,
|
|
303
|
+
minRejectCases: SELF_TEST_MIN_REJECT,
|
|
304
|
+
});
|
|
305
|
+
} finally {
|
|
306
|
+
for (const d of made) fs.rmSync(d, { recursive: true, force: true });
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
export function main(argv?: readonly string[]): number {
|
|
311
|
+
const args = argv ?? process.argv.slice(2);
|
|
312
|
+
if (args.includes('--self-test')) return selfTest();
|
|
313
|
+
const quiet = args.includes('--quiet');
|
|
314
|
+
const rootIdx = args.indexOf('--root');
|
|
315
|
+
const root = rootIdx >= 0 ? (args[rootIdx + 1] ?? DEFAULT_ROOT) : DEFAULT_ROOT;
|
|
316
|
+
|
|
317
|
+
const { code, findings, scanned } = check(root);
|
|
318
|
+
if (code === 2) return 2;
|
|
319
|
+
|
|
320
|
+
if (findings.length > 0) {
|
|
321
|
+
process.stdout.write('❌ hand-written enforcement count(s) in a published doc:\n\n');
|
|
322
|
+
for (const f of findings) {
|
|
323
|
+
const why =
|
|
324
|
+
f.kind === 'bare-marker' ? `\`${MARKER}\` with no reason` : 'hand-written count';
|
|
325
|
+
process.stdout.write(` ${f.file}:${String(f.line)} — ${why}\n ${f.excerpt}\n`);
|
|
326
|
+
}
|
|
327
|
+
process.stdout.write(
|
|
328
|
+
'\nExactly one enforcement denominator is quotable, and it comes from\n' +
|
|
329
|
+
'`check_enforcement_coverage` — which resolves rather than counts, and prints\n' +
|
|
330
|
+
'its denominator with the frame that produced it. `docs/proof.md` § 4b projects\n' +
|
|
331
|
+
'that output; cite the projection instead of restating a number. A figure that\n' +
|
|
332
|
+
'is right today is how the plurality returned every previous time.\n' +
|
|
333
|
+
`If the number is a dated record rather than a live claim, say so on the line:\n` +
|
|
334
|
+
` <!-- ${MARKER} <reason> -->\n`,
|
|
335
|
+
);
|
|
336
|
+
return 1;
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
if (!quiet) {
|
|
340
|
+
process.stdout.write(
|
|
341
|
+
`✅ one citable enforcement denominator: ${String(scanned)} published doc(s) restate none of it.\n`,
|
|
342
|
+
);
|
|
343
|
+
}
|
|
344
|
+
return 0;
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
function _isCliEntry(): boolean {
|
|
348
|
+
if (process.argv[1] === undefined) return false;
|
|
349
|
+
const argvUrl = pathToFileURL(path.resolve(process.argv[1])).href;
|
|
350
|
+
if (import.meta.url === argvUrl) return true;
|
|
351
|
+
try {
|
|
352
|
+
return (
|
|
353
|
+
fs.realpathSync(fileURLToPath(import.meta.url)) ===
|
|
354
|
+
fs.realpathSync(path.resolve(process.argv[1]))
|
|
355
|
+
);
|
|
356
|
+
} catch {
|
|
357
|
+
return false;
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
if (_isCliEntry() || process.argv[1] === _HERE) {
|
|
362
|
+
process.exit(main());
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
export { SCAN_ROOTS, EXCLUDED_PREFIXES, MARKER };
|
|
@@ -152,6 +152,7 @@ import { reportScanned, DeadScopeError } from './_lib/scan_scope.js';
|
|
|
152
152
|
import { GateLedger } from './_lib/gate_ledger.js';
|
|
153
153
|
import { resolveBaseRef } from './_lib/ratchet_base_ref.js';
|
|
154
154
|
import { materialiseSubtree } from './_lib/base_tree.js';
|
|
155
|
+
import { SKILLS_POSIX, measureSkillEstate } from './_lib/skill_estate.js';
|
|
155
156
|
import { runGateCli, runSelfTest, type SelfTestCase } from './_lib/gate_self_test.js';
|
|
156
157
|
|
|
157
158
|
const GATE = 'check_estate_count';
|
|
@@ -171,11 +172,35 @@ export interface EstateCounts {
|
|
|
171
172
|
active_roadmaps: number;
|
|
172
173
|
later_roadmaps: number;
|
|
173
174
|
open_blockers: number;
|
|
175
|
+
/**
|
|
176
|
+
* Maintained `SKILL.md` files — `lifecycle: deprecated` excluded.
|
|
177
|
+
*
|
|
178
|
+
* A FOURTH corpus on the same machinery, added 2026-08-24 on AI council 2/2
|
|
179
|
+
* over the alternative of a second budget file and a second gate: the
|
|
180
|
+
* floor-from-the-base-ref machinery is the expensive part and should not be
|
|
181
|
+
* written twice, and a second ratchet is a second place to forget.
|
|
182
|
+
*/
|
|
183
|
+
skill_count: number;
|
|
184
|
+
/**
|
|
185
|
+
* Exact-BPE tokens across those skills' `description:` fields.
|
|
186
|
+
*
|
|
187
|
+
* The second DIMENSION, not a companion figure. A count ratchet alone is
|
|
188
|
+
* gameable by merging four large skills into one file: the count falls, the
|
|
189
|
+
* payload a host must carry does not. `0` here means UNRESOLVED, never
|
|
190
|
+
* "no tokens" — see `tokensExact`.
|
|
191
|
+
*/
|
|
192
|
+
skill_description_tokens: number;
|
|
174
193
|
}
|
|
175
194
|
|
|
176
195
|
export type MetricName = keyof EstateCounts;
|
|
177
196
|
|
|
178
|
-
export const METRICS: readonly MetricName[] = [
|
|
197
|
+
export const METRICS: readonly MetricName[] = [
|
|
198
|
+
'active_roadmaps',
|
|
199
|
+
'later_roadmaps',
|
|
200
|
+
'open_blockers',
|
|
201
|
+
'skill_count',
|
|
202
|
+
'skill_description_tokens',
|
|
203
|
+
];
|
|
179
204
|
|
|
180
205
|
export interface EstateBudget {
|
|
181
206
|
/**
|
|
@@ -247,6 +272,16 @@ export interface EstateVerdict {
|
|
|
247
272
|
authorisedGrowth: GrowthFinding[];
|
|
248
273
|
/** The claims found in this change's diff, with their reasons. */
|
|
249
274
|
claims: GrowthClaim[];
|
|
275
|
+
/**
|
|
276
|
+
* Metrics dropped from the compare, each with its reason.
|
|
277
|
+
*
|
|
278
|
+
* Never empty-and-silent: a skill metric drops when the base ref carries no
|
|
279
|
+
* `src/skills` (an old tag, a shallow clone) or when the tokeniser resolved
|
|
280
|
+
* on one side and not the other. Comparing an exact reading against a proxy
|
|
281
|
+
* one would move the number by more than the growth this gate exists to
|
|
282
|
+
* catch, so the metric is stated unavailable rather than guessed.
|
|
283
|
+
*/
|
|
284
|
+
skippedMetrics: { metric: MetricName; reason: string }[];
|
|
250
285
|
/** `null` when the diff half could not run; the reason is printed either way. */
|
|
251
286
|
offsets: OffsetLedger | null;
|
|
252
287
|
offsetSkipReason: string | null;
|
|
@@ -342,13 +377,26 @@ export function countEstate(repoRoot: string): EstateCounts {
|
|
|
342
377
|
const stats = collect(roadmapRoot);
|
|
343
378
|
const openOf = (rows: readonly { open_blockers: readonly unknown[] }[]): number =>
|
|
344
379
|
rows.reduce((n, r) => n + r.open_blockers.length, 0);
|
|
380
|
+
const skills = measureSkillEstate(repoRoot);
|
|
345
381
|
return {
|
|
346
382
|
active_roadmaps: stats.length,
|
|
347
383
|
later_roadmaps: countIn(roadmapRoot, 'later'),
|
|
348
384
|
open_blockers: openOf(stats) + openOf(laterRoadmaps(roadmapRoot)),
|
|
385
|
+
skill_count: skills.skill_count,
|
|
386
|
+
// 0 stands for unresolved. `skillTokensExact` below is what the caller
|
|
387
|
+
// reads to tell that apart from a genuinely empty corpus, and the
|
|
388
|
+
// verdict skips the metric rather than comparing an exact reading
|
|
389
|
+
// against a proxy one — they differ by more than the growth a ratchet
|
|
390
|
+
// is trying to catch.
|
|
391
|
+
skill_description_tokens: skills.skill_description_tokens ?? 0,
|
|
349
392
|
};
|
|
350
393
|
}
|
|
351
394
|
|
|
395
|
+
/** Did the tokeniser resolve under `root`? A ratchet must not mix the two modes. */
|
|
396
|
+
export function skillTokensExact(root: string): boolean {
|
|
397
|
+
return measureSkillEstate(root).skill_description_tokens !== null;
|
|
398
|
+
}
|
|
399
|
+
|
|
352
400
|
/** `agents/roadmaps/<name>.md` — the active top level, never a subdirectory. */
|
|
353
401
|
function isActiveTopLevel(rel: string): boolean {
|
|
354
402
|
const norm = rel.split(path.sep).join('/');
|
|
@@ -506,19 +554,57 @@ export function evaluate(
|
|
|
506
554
|
// property, and unlike a number nobody has to remember to update it.
|
|
507
555
|
let floor: EstateCounts | null = null;
|
|
508
556
|
let floorSkipReason: string | null = null;
|
|
557
|
+
/** Set when the base ref carries no `src/skills` — the skill metrics drop. */
|
|
558
|
+
let skillFloorSkipReason: string | null = null;
|
|
559
|
+
/** Set when either side's tokeniser did not resolve — that ONE metric drops. */
|
|
560
|
+
let skillTokenSkipReason: string | null = null;
|
|
561
|
+
if (!skillTokensExact(repoRoot)) {
|
|
562
|
+
skillTokenSkipReason =
|
|
563
|
+
'the tokeniser did not resolve at HEAD; an exact reading may not be compared ' +
|
|
564
|
+
'against a proxy one';
|
|
565
|
+
}
|
|
509
566
|
if (baseRef === null || baseRef === undefined) {
|
|
510
567
|
floorSkipReason =
|
|
511
568
|
'no base ref resolved (no origin/main, no merge-commit parent) — the floor cannot be measured';
|
|
512
569
|
} else {
|
|
513
570
|
const base = materialiseSubtree(repoRoot, baseRef, ROADMAPS_POSIX);
|
|
571
|
+
// TWO subtrees, because the estate now spans two corpora and the floor
|
|
572
|
+
// must be measured on the base ref's own tree for BOTH. Materialised
|
|
573
|
+
// separately rather than widening the first call: `materialiseSubtree`
|
|
574
|
+
// takes one prefix, and the roadmap tree must stay readable even when
|
|
575
|
+
// the skills read fails (a `src/skills`-less base ref is a real state —
|
|
576
|
+
// an old tag, a shallow clone), in which case the skill metrics skip and
|
|
577
|
+
// the roadmap metrics still ratchet.
|
|
578
|
+
const baseSkills = materialiseSubtree(repoRoot, baseRef, SKILLS_POSIX);
|
|
514
579
|
try {
|
|
515
580
|
if (base.error !== null || base.files === 0) {
|
|
516
581
|
floorSkipReason = `could not read ${ROADMAPS_POSIX} at ${baseRef} — ${base.error ?? 'no files'}`;
|
|
517
582
|
} else {
|
|
518
|
-
|
|
583
|
+
const roadmapFloor = countEstate(base.root);
|
|
584
|
+
if (baseSkills.error !== null || baseSkills.files === 0) {
|
|
585
|
+
// Roadmap floor stands; the skill floor is stated as
|
|
586
|
+
// unavailable and its metrics are dropped from the compare.
|
|
587
|
+
floor = roadmapFloor;
|
|
588
|
+
skillFloorSkipReason =
|
|
589
|
+
`could not read ${SKILLS_POSIX} at ${baseRef} — ` +
|
|
590
|
+
`${baseSkills.error ?? 'no files'}`;
|
|
591
|
+
} else {
|
|
592
|
+
const s = measureSkillEstate(baseSkills.root);
|
|
593
|
+
floor = {
|
|
594
|
+
...roadmapFloor,
|
|
595
|
+
skill_count: s.skill_count,
|
|
596
|
+
skill_description_tokens: s.skill_description_tokens ?? 0,
|
|
597
|
+
};
|
|
598
|
+
if (s.skill_description_tokens === null) {
|
|
599
|
+
skillTokenSkipReason =
|
|
600
|
+
`the tokeniser did not resolve at ${baseRef}; an exact reading may ` +
|
|
601
|
+
'not be compared against a proxy one';
|
|
602
|
+
}
|
|
603
|
+
}
|
|
519
604
|
}
|
|
520
605
|
} finally {
|
|
521
606
|
fs.rmSync(base.root, { recursive: true, force: true });
|
|
607
|
+
fs.rmSync(baseSkills.root, { recursive: true, force: true });
|
|
522
608
|
}
|
|
523
609
|
}
|
|
524
610
|
|
|
@@ -571,11 +657,32 @@ export function evaluate(
|
|
|
571
657
|
active_roadmaps: offsets?.exempt.length ?? 0,
|
|
572
658
|
later_roadmaps: offsets?.parked.length ?? 0,
|
|
573
659
|
open_blockers: 0,
|
|
660
|
+
// The skill corpus gets NO allowance, and that is the whole point of the
|
|
661
|
+
// metric: the defect it addresses is a corpus that grew +8 in one release
|
|
662
|
+
// with nothing objecting. An addition takes the `estate_growth_exempt`
|
|
663
|
+
// claim path — a recorded reason in the diff — or it fails.
|
|
664
|
+
skill_count: 0,
|
|
665
|
+
skill_description_tokens: 0,
|
|
666
|
+
};
|
|
667
|
+
|
|
668
|
+
/** Metrics dropped from the compare, with the reason, never silently. */
|
|
669
|
+
const skippedMetrics: { metric: MetricName; reason: string }[] = [];
|
|
670
|
+
const skipMetric = (metric: MetricName): boolean => {
|
|
671
|
+
if (skillFloorSkipReason !== null && (metric === 'skill_count' || metric === 'skill_description_tokens')) {
|
|
672
|
+
skippedMetrics.push({ metric, reason: skillFloorSkipReason });
|
|
673
|
+
return true;
|
|
674
|
+
}
|
|
675
|
+
if (skillTokenSkipReason !== null && metric === 'skill_description_tokens') {
|
|
676
|
+
skippedMetrics.push({ metric, reason: skillTokenSkipReason });
|
|
677
|
+
return true;
|
|
678
|
+
}
|
|
679
|
+
return false;
|
|
574
680
|
};
|
|
575
681
|
|
|
576
682
|
const over: GrowthFinding[] = [];
|
|
577
683
|
if (floor !== null) {
|
|
578
684
|
for (const metric of METRICS) {
|
|
685
|
+
if (skipMetric(metric)) continue;
|
|
579
686
|
const live = counts[metric];
|
|
580
687
|
const allowed = floor[metric] + allowance[metric];
|
|
581
688
|
if (live > allowed) {
|
|
@@ -596,6 +703,7 @@ export function evaluate(
|
|
|
596
703
|
growth,
|
|
597
704
|
authorisedGrowth,
|
|
598
705
|
claims,
|
|
706
|
+
skippedMetrics,
|
|
599
707
|
offsets,
|
|
600
708
|
offsetSkipReason,
|
|
601
709
|
unpaid,
|
|
@@ -1010,8 +1118,12 @@ export function main(argv: string[] = process.argv.slice(2)): number {
|
|
|
1010
1118
|
|
|
1011
1119
|
for (const g of verdict.growth) {
|
|
1012
1120
|
const allow = g.allowance > 0 ? ` (+${String(g.allowance)} allowed here)` : '';
|
|
1121
|
+
// Two corpora share this gate, so the line names which one grew. It used
|
|
1122
|
+
// to say "the roadmap estate" unconditionally, which was already the
|
|
1123
|
+
// wrong noun for `skill_count` the moment that metric landed.
|
|
1124
|
+
const corpus = g.metric.startsWith('skill_') ? 'the skill estate' : 'the roadmap estate';
|
|
1013
1125
|
process.stderr.write(
|
|
1014
|
-
`❌
|
|
1126
|
+
`❌ ${corpus} grew: ${g.metric} ${String(g.floor)} → ${String(g.live)}${allow}.\n` +
|
|
1015
1127
|
` The floor is the measurement at ${verdict.floorRef ?? 'the base ref'}, not a number in a\n` +
|
|
1016
1128
|
' config — so there is no number to edit and nothing to walk. The estate does not\n' +
|
|
1017
1129
|
' walk down by itself, which is the defect this ratchet exists for. Either close,\n' +
|
|
@@ -1022,6 +1134,13 @@ export function main(argv: string[] = process.argv.slice(2)): number {
|
|
|
1022
1134
|
);
|
|
1023
1135
|
}
|
|
1024
1136
|
|
|
1137
|
+
// A dropped metric is REPORTED, never silent: a reader must be able to tell
|
|
1138
|
+
// "within its ratchet" from "within the ratchet of the metrics that could be
|
|
1139
|
+
// measured". This is the same distinction the floor-skip reason above keeps.
|
|
1140
|
+
for (const s of verdict.skippedMetrics) {
|
|
1141
|
+
process.stdout.write(` ⏭️ ${s.metric} not compared — ${s.reason}\n`);
|
|
1142
|
+
}
|
|
1143
|
+
|
|
1025
1144
|
if (verdict.unpaid > 0 && verdict.offsets !== null) {
|
|
1026
1145
|
process.stderr.write(
|
|
1027
1146
|
`❌ ${String(verdict.unpaid)} new active roadmap(s) with no offset in the same change.\n` +
|
|
@@ -49,6 +49,7 @@ import process from 'node:process';
|
|
|
49
49
|
import { fileURLToPath, pathToFileURL } from 'node:url';
|
|
50
50
|
|
|
51
51
|
import * as yaml from 'js-yaml';
|
|
52
|
+
import { asOf } from './_lib/as_of.js';
|
|
52
53
|
import { checkRatchet } from './_lib/gate_baseline.js';
|
|
53
54
|
import { GateLedger, type GateSkipReason } from './_lib/gate_ledger.js';
|
|
54
55
|
import { runCountedProbe } from './_lib/counted_probe.js';
|
|
@@ -979,7 +980,7 @@ function run_canary_mode(specs: readonly GateSpec[], argv: readonly string[]): n
|
|
|
979
980
|
process.stdout.write(` ❌ DISAGREEMENT [${d.kind}] ${d.gate}: ${d.detail}\n`);
|
|
980
981
|
}
|
|
981
982
|
|
|
982
|
-
const cycleId = `gate-surface-${
|
|
983
|
+
const cycleId = `gate-surface-${asOf().toISOString().slice(0, 10)}`;
|
|
983
984
|
const li = argv.indexOf('--ledger');
|
|
984
985
|
if (li >= 0 && argv[li + 1] !== undefined) {
|
|
985
986
|
const out = path.resolve(REPO_ROOT, argv[li + 1] as string);
|
|
@@ -28,6 +28,18 @@
|
|
|
28
28
|
* A hook fix that cannot reach the agent that wrote it is indistinguishable
|
|
29
29
|
* from no fix, and nothing said so. This gate says so.
|
|
30
30
|
*
|
|
31
|
+
* WHAT IT DOES NOT DO — ORDERING IS NOT EQUIVALENCE. This gate compares
|
|
32
|
+
* mtimes, so `touch dist/hooks/dispatch.js` makes every source look older and
|
|
33
|
+
* this gate green while the executing bytes are stale. Demonstrated on this tree
|
|
34
|
+
* rather than argued (2026-08-23): a one-constant edit to
|
|
35
|
+
* `block_unauthorized_git.ts` plus a `touch` on the bundle left THIS gate at
|
|
36
|
+
* exit 0 while `check_hook_bundle_content` exited 1 with executing
|
|
37
|
+
* `sha256 ce21579b7c14` against rebuilt `ac83e2f51118` — identical byte count,
|
|
38
|
+
* different bytes. That is why the success line below says "ordering" and names
|
|
39
|
+
* the digest gate instead of claiming freshness outright, and why preflight runs
|
|
40
|
+
* the two together (`taskfiles/ci-fast.yml`). The content comparison is NOT
|
|
41
|
+
* duplicated here: one home per invariant.
|
|
42
|
+
*
|
|
31
43
|
* WHAT IT DOES NOT DO: it never builds. Building into a live hook path is a
|
|
32
44
|
* documented hazard in this repo (an esbuild run that overwrites the
|
|
33
45
|
* dispatcher a running hook is executing can wedge the tool loop), so the
|
|
@@ -169,7 +181,7 @@ export function main(argv: string[] = process.argv.slice(2)): number {
|
|
|
169
181
|
if (r.stale.length === 0) {
|
|
170
182
|
if (!quiet) {
|
|
171
183
|
process.stdout.write(
|
|
172
|
-
`✅ OK hook bundle: fresh (built ${stamp(r.bundleMtimeMs)}, ${String(r.checked)} bundled source(s) checked)\n`,
|
|
184
|
+
`✅ OK hook bundle: ordering fresh (built ${stamp(r.bundleMtimeMs)}, ${String(r.checked)} bundled source(s) checked) — byte-equivalence is check_hook_bundle_content's\n`,
|
|
173
185
|
);
|
|
174
186
|
}
|
|
175
187
|
return 0;
|
|
@@ -37,6 +37,7 @@ import { fileURLToPath, pathToFileURL } from 'node:url';
|
|
|
37
37
|
// tolerantly (try/except → None) so the project-local linter still runs if the
|
|
38
38
|
// _lib package layout shifts; the TS twins always exist, so a static import is
|
|
39
39
|
// byte-faithful for behaviour (the only observable effect is the --global path).
|
|
40
|
+
import { asOf } from './_lib/as_of.js';
|
|
40
41
|
import * as _kg from './_lib/knowledge_global.js';
|
|
41
42
|
import * as _kgr from './_lib/knowledge_global_redaction.js';
|
|
42
43
|
import { assertScanned } from './_lib/scan_scope.js';
|
|
@@ -485,7 +486,7 @@ function _maxDate(parsed: PyDate[]): PyDate {
|
|
|
485
486
|
}
|
|
486
487
|
|
|
487
488
|
function _todayUtcDate(): PyDate {
|
|
488
|
-
const now =
|
|
489
|
+
const now = asOf();
|
|
489
490
|
return { year: now.getUTCFullYear(), month: now.getUTCMonth() + 1, day: now.getUTCDate() };
|
|
490
491
|
}
|
|
491
492
|
|
|
@@ -29,6 +29,7 @@ import process from 'node:process';
|
|
|
29
29
|
import { fileURLToPath } from 'node:url';
|
|
30
30
|
import YAML from 'yaml';
|
|
31
31
|
|
|
32
|
+
import { asOf } from './_lib/as_of.js';
|
|
32
33
|
import { assertScanned } from './_lib/scan_scope.js';
|
|
33
34
|
|
|
34
35
|
const PROG = 'check_knowledge_pages.ts';
|
|
@@ -72,7 +73,7 @@ function bodyLineCount(body: string): number {
|
|
|
72
73
|
}
|
|
73
74
|
|
|
74
75
|
/** Lint a single page's already-read content. Pure — no filesystem access — for direct unit testing. */
|
|
75
|
-
export function lintPage(relPath: string, content: string, today: Date =
|
|
76
|
+
export function lintPage(relPath: string, content: string, today: Date = asOf()): Warning[] {
|
|
76
77
|
const warnings: Warning[] = [];
|
|
77
78
|
const fm = readFrontmatter(content);
|
|
78
79
|
|
|
@@ -145,7 +146,7 @@ function countPages(knowledgeRoot: string): number {
|
|
|
145
146
|
);
|
|
146
147
|
}
|
|
147
148
|
|
|
148
|
-
export function lintAll(knowledgeRoot: string, today: Date =
|
|
149
|
+
export function lintAll(knowledgeRoot: string, today: Date = asOf()): Warning[] {
|
|
149
150
|
const warnings: Warning[] = [];
|
|
150
151
|
for (const dir of TYPED_DIRS) {
|
|
151
152
|
const scanDir = path.join(knowledgeRoot, dir);
|