@event4u/agent-config 14.10.0 → 14.11.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 +335 -0
- 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/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/alerting-doctrine/evals/triggers.json +17 -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-review/SKILL.md +11 -0
- package/dist/agent-src/skills/command-routing/SKILL.md +6 -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 +20 -3
- package/dist/agent-src/skills/fe-design/SKILL.md +74 -41
- package/dist/agent-src/skills/fe-design/evals/triggers.json +65 -53
- 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/evals/triggers.json +17 -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/monorepo-workspace/evals/triggers.json +17 -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/operational-readiness/evals/triggers.json +17 -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/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 +52 -21
- 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/server-hardening/evals/triggers.json +17 -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/spreadsheet-authoring/SKILL.md +3 -0
- package/dist/agent-src/skills/storybook-workshop/SKILL.md +194 -0
- package/dist/agent-src/skills/storybook-workshop/evals/triggers.json +17 -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 +9 -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/skills/workspace-link/evals/triggers.json +17 -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/uiAudit.js.map +1 -0
- package/dist/cli/commands/uiRender.js +206 -0
- package/dist/cli/commands/uiRender.js.map +1 -0
- package/dist/cli/main.js +22 -1
- package/dist/cli/main.js.map +1 -1
- package/dist/cli/mcp/content.js +64 -1
- package/dist/cli/mcp/content.js.map +1 -1
- package/dist/cli/mcp/dispatch.js +175 -10
- package/dist/cli/mcp/dispatch.js.map +1 -1
- package/dist/cli/registry.js +3 -0
- package/dist/cli/registry.js.map +1 -1
- package/dist/cli-delegate/{chunk-H4VIVD4C.js → chunk-236PNQZK.js} +413 -391
- 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-PLSG6UL5.js → chunk-K4FFODTS.js} +341 -204
- package/dist/cli-delegate/{chunk-YM4GZDJG.js → chunk-L43NCYPB.js} +5 -0
- 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 +359 -124
- 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 +2337 -1436
- package/dist/install/install.mjs +795 -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/lean_projection_mode.js.map +1 -0
- package/dist/scripts/_lib/scoped_projection.js +84 -0
- package/dist/scripts/_lib/scoped_projection.js.map +1 -1
- package/dist/scripts/_lib/ui_surface.js +89 -0
- package/dist/scripts/_lib/ui_surface.js.map +1 -0
- package/dist/scripts/condense.js +6 -10
- package/dist/scripts/condense.js.map +1 -1
- package/dist/scripts/project_thin_rules.js +40 -2
- package/dist/scripts/project_thin_rules.js.map +1 -1
- package/dist/server/schemas/settings.js +3 -0
- package/dist/server/schemas/settings.js.map +1 -1
- package/dist/shared/skillRanking.js +159 -0
- package/dist/shared/skillRanking.js.map +1 -0
- package/docs/contracts/provider-lifecycle.md +47 -18
- package/docs/contracts/settings-classes.md +14 -4
- package/docs/guidelines/agent-infra/context-hygiene-mechanics.md +49 -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/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/llms.txt +50 -39
- package/package.json +1 -1
- 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 +28 -0
- package/src/config/assurance-capability-registry.json +223 -0
- package/src/config/assurance-threshold-budget.json +65 -0
- package/src/config/ci-local-parity.yml +14 -0
- package/src/config/discovery/unassigned-artefacts.yml +2 -0
- package/src/config/dispatch-economy-metrics.json +4 -2
- package/src/config/evaluator-budgets.json +14 -14
- package/src/config/gate-coverage.yml +207 -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 +4 -2
- package/src/config/quorum-attendance-budget.json +12 -4
- 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/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/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/transcript_reads.ts +207 -0
- package/src/scripts/_lib/ui_authority.test.ts +251 -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/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_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_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_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_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/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/design_slop_rules.test.ts +7 -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 +97 -16
- package/src/scripts/hooks/concern_registry.ts +4 -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/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 +2 -1
- 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_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/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/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/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/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 +5 -0
- package/src/shared/skillRanking.ts +183 -0
|
@@ -65,6 +65,19 @@ const COMPLEXITY_PAT = /^complexity:\s*(lightweight|structural)\s*$/m;
|
|
|
65
65
|
const EXEC_MODE_PAT = /^execution:[^\S\n]*\n(?:[ \t]+(?!mode:).*\n)*[ \t]+mode:[ \t]*([^\s#]+)/m;
|
|
66
66
|
const EXEC_MODE_VALUES = new Set(['autonomous', 'phase-checkpoints', 'interactive']);
|
|
67
67
|
|
|
68
|
+
/**
|
|
69
|
+
* `relates:` relations (templates/roadmaps.md rule 18) — a CLOSED set.
|
|
70
|
+
*
|
|
71
|
+
* An open vocabulary here degrades into free-text notes nothing can read, which
|
|
72
|
+
* is the state `depends:` was in when its adoption measured 0/22. Four values,
|
|
73
|
+
* and an unknown one is a hard problem rather than a warning: the field feeds a
|
|
74
|
+
* decision (order, and whether a sibling supersedes this roadmap), so a value no
|
|
75
|
+
* reader understands is worse than an absent field.
|
|
76
|
+
*/
|
|
77
|
+
const RELATES_RELATIONS = new Set(['extends', 'supersedes', 'depends', 'disjoint']);
|
|
78
|
+
// The `relation:` line under each `- slug:` row inside the `relates:` block.
|
|
79
|
+
const RELATES_RELATION_PAT = /^[ \t]+relation:[ \t]*([^\s#]+)/gm;
|
|
80
|
+
|
|
68
81
|
// Plate / horizon detection — template rule 16 forbids time-boxed plates.
|
|
69
82
|
const PLATE_PATS: ReadonlyArray<readonly [RegExp, string]> = [
|
|
70
83
|
[/^##\s+Horizon\b/im, "'## Horizon' section header"],
|
|
@@ -211,6 +224,7 @@ function lint_roadmap(
|
|
|
211
224
|
_check_no_plate(text, problems);
|
|
212
225
|
}
|
|
213
226
|
_check_execution_mode(fm, problems);
|
|
227
|
+
_check_relates(fm, problems);
|
|
214
228
|
if (warnings) {
|
|
215
229
|
_check_autonomous_authoring(text, fm, warnings);
|
|
216
230
|
_check_human_gate_steps(text, warnings);
|
|
@@ -443,6 +457,47 @@ function _check_external_population_gates(text: string, warnings: string[]): voi
|
|
|
443
457
|
}
|
|
444
458
|
}
|
|
445
459
|
|
|
460
|
+
/**
|
|
461
|
+
* Validate a declared `relates:` block. Absent is valid here — requiring the
|
|
462
|
+
* block is `check_roadmap_trackable`'s ratchet, not this linter's job. This one
|
|
463
|
+
* only judges a declaration that IS present, exactly as `_check_execution_mode`
|
|
464
|
+
* does above.
|
|
465
|
+
*/
|
|
466
|
+
export function _check_relates(fm: string, problems: string[]): void {
|
|
467
|
+
if (!fm || !/^relates:/m.test(fm)) return;
|
|
468
|
+
const inline_empty = /^relates:[^\S\n]*\[[^\S\n]*\][^\S\n]*(?:#[^\n]*)?$/m.test(fm);
|
|
469
|
+
RELATES_RELATION_PAT.lastIndex = 0;
|
|
470
|
+
const values: string[] = [];
|
|
471
|
+
let m: RegExpExecArray | null;
|
|
472
|
+
while ((m = RELATES_RELATION_PAT.exec(fm)) !== null) {
|
|
473
|
+
values.push(m[1]!.replace(/^['"]|['"]$/g, ''));
|
|
474
|
+
}
|
|
475
|
+
for (const v of values) {
|
|
476
|
+
if (!RELATES_RELATIONS.has(v)) {
|
|
477
|
+
problems.push(
|
|
478
|
+
`unknown relates[].relation '${v}' — allowed: extends | supersedes | ` +
|
|
479
|
+
'depends | disjoint (templates/roadmaps.md rule 18)',
|
|
480
|
+
);
|
|
481
|
+
}
|
|
482
|
+
}
|
|
483
|
+
if (!inline_empty && values.length === 0) {
|
|
484
|
+
problems.push(
|
|
485
|
+
"'relates:' present but no 'relation:' key found — every row needs " +
|
|
486
|
+
"slug + relation, or write 'relates: []' with the probe's scanned: line " +
|
|
487
|
+
'(templates/roadmaps.md rule 18)',
|
|
488
|
+
);
|
|
489
|
+
}
|
|
490
|
+
// A `depends` row that does not mirror into `depends:` splits the set
|
|
491
|
+
// contract's edge source in two, which rule 18 forbids in as many words.
|
|
492
|
+
if (values.includes('depends') && !/^depends:/m.test(fm)) {
|
|
493
|
+
problems.push(
|
|
494
|
+
"relates[].relation: depends declared but no 'depends:' key mirrors it — " +
|
|
495
|
+
'the set contract reads `depends:` and only `depends:` ' +
|
|
496
|
+
'(templates/roadmaps.md rule 18)',
|
|
497
|
+
);
|
|
498
|
+
}
|
|
499
|
+
}
|
|
500
|
+
|
|
446
501
|
function _check_execution_mode(fm: string, problems: string[]): void {
|
|
447
502
|
if (!fm || !/^execution:/m.test(fm)) {
|
|
448
503
|
// Absent is VALID and stays valid — but it no longer means "interactive".
|
|
@@ -708,6 +763,7 @@ if (_isCliEntry() || process.argv[1] === _HERE) {
|
|
|
708
763
|
}
|
|
709
764
|
|
|
710
765
|
export {
|
|
766
|
+
RELATES_RELATIONS,
|
|
711
767
|
REPO_ROOT,
|
|
712
768
|
ROADMAP_GLOB,
|
|
713
769
|
LIGHTWEIGHT_LINE_CAP,
|
|
@@ -84,11 +84,25 @@ function _declaration(fm: Record<string, string | string[]>): string[] | null {
|
|
|
84
84
|
return list.length === 0 ? null : list;
|
|
85
85
|
}
|
|
86
86
|
|
|
87
|
-
/**
|
|
88
|
-
|
|
87
|
+
/**
|
|
88
|
+
* The body must state the gap in prose — the honesty convention.
|
|
89
|
+
*
|
|
90
|
+
* BOTH spellings are accepted, and that is not leniency. The bare `none` was
|
|
91
|
+
* retired for `instruction-only: <reason>` on 2026-08-23 (one rule still carries
|
|
92
|
+
* it: `non-destructive-by-default`, a kernel rule `block_kernel_rule_writes`
|
|
93
|
+
* denies the agent write to). A body-check that knew only the old word would
|
|
94
|
+
* fail a NEW rule that spelled the declaration the new way and said so in prose —
|
|
95
|
+
* the rename would have made the honesty convention unsatisfiable for exactly
|
|
96
|
+
* the rules adopting it.
|
|
97
|
+
*/
|
|
98
|
+
function _bodyStatesGap(text: string): boolean {
|
|
89
99
|
const end = text.indexOf('\n---\n', 4);
|
|
90
100
|
const body = end === -1 ? text : text.slice(end + 5);
|
|
91
|
-
return
|
|
101
|
+
return (
|
|
102
|
+
body.includes('enforced_by: none') ||
|
|
103
|
+
body.includes('`enforced_by: none`') ||
|
|
104
|
+
body.includes('instruction-only')
|
|
105
|
+
);
|
|
92
106
|
}
|
|
93
107
|
|
|
94
108
|
function _readBaseline(root: string): string[] | null {
|
|
@@ -144,11 +158,14 @@ function _scan(root: string, baseline: ReadonlySet<string>, ledger: GateLedger |
|
|
|
144
158
|
// shape validate_frontmatter uses for obligation_frequency. Their
|
|
145
159
|
// projected bytes are stability-gated, so requiring a prose line here
|
|
146
160
|
// would force an un-editable edit.
|
|
147
|
-
|
|
161
|
+
const declaresGap =
|
|
162
|
+
decl.includes('none') || decl.some((d) => d.startsWith('instruction-only'));
|
|
163
|
+
if (declaresGap && !_bodyStatesGap(text) && !is_kernel_rule(file)) {
|
|
148
164
|
const f =
|
|
149
|
-
`src/rules/${file} declares
|
|
150
|
-
`in its body — the honesty convention is one prose line naming \`
|
|
151
|
-
`reader of the rule sees the gap, not
|
|
165
|
+
`src/rules/${file} declares a model-carried gap in frontmatter but never states it ` +
|
|
166
|
+
`in its body — the honesty convention is one prose line naming \`instruction-only\` ` +
|
|
167
|
+
`(or the retired \`enforced_by: none\`), so a reader of the rule sees the gap, not ` +
|
|
168
|
+
`only a machine.`;
|
|
152
169
|
findings.push(f);
|
|
153
170
|
ledger?.fail(file, f);
|
|
154
171
|
continue;
|
|
@@ -0,0 +1,321 @@
|
|
|
1
|
+
#!/usr/bin/env -S npx tsx
|
|
2
|
+
/**
|
|
3
|
+
* Gate — a rule that declares `norm` stays inside the budget it declared.
|
|
4
|
+
*
|
|
5
|
+
* `road-to-standing-payload-diet` Phase 1 step 1.2.
|
|
6
|
+
*
|
|
7
|
+
* ## What `norm` pins, and why nothing pinned it before
|
|
8
|
+
*
|
|
9
|
+
* A rule file mixes three things at one uniform standing cost: the obligation
|
|
10
|
+
* (an Iron Law and its clauses), the routing (pointers to skills and
|
|
11
|
+
* guidelines), and the rationale (why the rule exists, what it measured, what it
|
|
12
|
+
* declines to claim). All three are re-sent on every session and every spawn.
|
|
13
|
+
* Only the first two have to be. Before this gate, `norm` appeared nowhere in
|
|
14
|
+
* `src/rules/` and nowhere in `rule.schema.json` (0 hits, measured 2026-08-23),
|
|
15
|
+
* so nothing objected when a rule grew by 200 lines of rationale.
|
|
16
|
+
*
|
|
17
|
+
* `norm.tokens` is the declared exact-BPE ceiling for the rule body below the
|
|
18
|
+
* frontmatter; `norm.remainder` names where the non-normative prose went. Both
|
|
19
|
+
* are required together, and the pairing is the point rather than tidiness: a
|
|
20
|
+
* pin with no destination is a licence to delete, and `preservation-guard`
|
|
21
|
+
* forbids deleting a passage during a transformation. The schema enforces the
|
|
22
|
+
* pairing; this gate enforces the number.
|
|
23
|
+
*
|
|
24
|
+
* ## Three deliberate properties
|
|
25
|
+
*
|
|
26
|
+
* 1. **Opt-in, and the opt-out count is the published metric.** Rules without
|
|
27
|
+
* `norm` are SKIPPED and counted, and the count is printed on the green path.
|
|
28
|
+
* A required key would have redded every rule file on the day it landed,
|
|
29
|
+
* which is the gate-that-teaches-you-to-ignore-it failure
|
|
30
|
+
* `src/config/preamble-payload-budget.json` warns about in its own
|
|
31
|
+
* `_comment`. So the un-pinned fraction is a number rather than an unknown.
|
|
32
|
+
* 2. **Exact tokenizer, or refuse to judge.** `js-tiktoken` is a devDependency
|
|
33
|
+
* and can be absent. Where it is, this gate does NOT fall back to the
|
|
34
|
+
* `chars/4` proxy and pass anyway — a pin enforced in a different unit from
|
|
35
|
+
* the one it was derived in is enforced against a number nobody can
|
|
36
|
+
* reproduce. It exits 2 and says so.
|
|
37
|
+
* 3. **`assertScanned` posture.** Zero rule files is exit 3, not green. This
|
|
38
|
+
* repo has shipped gates that scanned an emptied tree and certified coverage
|
|
39
|
+
* that did not exist.
|
|
40
|
+
*
|
|
41
|
+
* ## What it deliberately does NOT check
|
|
42
|
+
*
|
|
43
|
+
* Whether the body that remains is *genuinely* normative. That is a human read.
|
|
44
|
+
* The gate checks a declared number against a measured one, and the schema
|
|
45
|
+
* checks that a destination exists; `check_references` checks the destination
|
|
46
|
+
* resolves. None of the three can tell obligation from rationale, and claiming
|
|
47
|
+
* otherwise would be the coverage inflation this tree keeps removing.
|
|
48
|
+
*
|
|
49
|
+
* Modes: `--quiet` verdict only · `--json` machine-readable · `--self-test`.
|
|
50
|
+
*
|
|
51
|
+
* Exit codes: 0 every pin honoured · 1 a pin exceeded · 2 no exact tokenizer or
|
|
52
|
+
* a usage error · 3 dead scan scope.
|
|
53
|
+
*/
|
|
54
|
+
|
|
55
|
+
import * as fs from 'node:fs';
|
|
56
|
+
import * as path from 'node:path';
|
|
57
|
+
import process from 'node:process';
|
|
58
|
+
import { fileURLToPath, pathToFileURL } from 'node:url';
|
|
59
|
+
|
|
60
|
+
import { parse as parseYaml } from 'yaml';
|
|
61
|
+
|
|
62
|
+
import { GateLedger } from './_lib/gate_ledger.js';
|
|
63
|
+
import { runGateCli, runSelfTest, type SelfTestCase } from './_lib/gate_self_test.js';
|
|
64
|
+
import { strip_frontmatter } from './_lib/preservation_migration.js';
|
|
65
|
+
import { DeadScopeError, reportScanned } from './_lib/scan_scope.js';
|
|
66
|
+
import { gpt_tokens, method_note, TIKTOKEN_AVAILABLE } from './_lib/token_count.js';
|
|
67
|
+
|
|
68
|
+
const PROG = 'lint_rule_norm_pin';
|
|
69
|
+
const _HERE = fileURLToPath(import.meta.url);
|
|
70
|
+
const REPO_ROOT = path.resolve(path.dirname(_HERE), '..', '..');
|
|
71
|
+
const RULES_DIR = path.join(REPO_ROOT, 'src', 'rules');
|
|
72
|
+
const SCRIPT_REL = 'src/scripts/lint_rule_norm_pin.ts';
|
|
73
|
+
const SELF_TEST_MIN_CASES = 5;
|
|
74
|
+
const SELF_TEST_MIN_REJECT = 3;
|
|
75
|
+
|
|
76
|
+
export interface NormPin {
|
|
77
|
+
readonly tokens: number;
|
|
78
|
+
readonly remainder: readonly string[];
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
export interface Finding {
|
|
82
|
+
readonly rule: string;
|
|
83
|
+
readonly declared: number;
|
|
84
|
+
readonly measured: number;
|
|
85
|
+
readonly over: number;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
export interface Verdict {
|
|
89
|
+
readonly pinned: Finding[];
|
|
90
|
+
readonly violations: Finding[];
|
|
91
|
+
readonly unpinned: string[];
|
|
92
|
+
readonly method: string;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/** The `norm` block of one rule file, or `null` when it declares none. */
|
|
96
|
+
export function readNormPin(text: string): NormPin | null {
|
|
97
|
+
const m = /^---\n([\s\S]*?)\n---\n/.exec(text);
|
|
98
|
+
if (m === null) return null;
|
|
99
|
+
let fm: unknown;
|
|
100
|
+
try {
|
|
101
|
+
fm = parseYaml(m[1] ?? '');
|
|
102
|
+
} catch {
|
|
103
|
+
return null;
|
|
104
|
+
}
|
|
105
|
+
if (typeof fm !== 'object' || fm === null) return null;
|
|
106
|
+
const raw = (fm as Record<string, unknown>)['norm'];
|
|
107
|
+
if (typeof raw !== 'object' || raw === null) return null;
|
|
108
|
+
const block = raw as Record<string, unknown>;
|
|
109
|
+
const tokens = block['tokens'];
|
|
110
|
+
const remainder = block['remainder'];
|
|
111
|
+
if (typeof tokens !== 'number' || !Number.isInteger(tokens) || tokens < 1) return null;
|
|
112
|
+
if (!Array.isArray(remainder) || remainder.length === 0) return null;
|
|
113
|
+
return { tokens, remainder: remainder.map(String) };
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Exact-BPE size of the rule body BELOW the frontmatter.
|
|
118
|
+
*
|
|
119
|
+
* The frontmatter is excluded because it is not prose a reader consumes and
|
|
120
|
+
* because including it would make a pin move when an unrelated trigger is added.
|
|
121
|
+
*/
|
|
122
|
+
export function measureBody(text: string): number {
|
|
123
|
+
return gpt_tokens(strip_frontmatter(text)).tokens;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
export function check(dir: string = RULES_DIR): Verdict {
|
|
127
|
+
let entries: string[];
|
|
128
|
+
try {
|
|
129
|
+
entries = fs.readdirSync(dir).filter((f) => f.endsWith('.md')).sort();
|
|
130
|
+
} catch {
|
|
131
|
+
entries = [];
|
|
132
|
+
}
|
|
133
|
+
const pinned: Finding[] = [];
|
|
134
|
+
const violations: Finding[] = [];
|
|
135
|
+
const unpinned: string[] = [];
|
|
136
|
+
for (const name of entries) {
|
|
137
|
+
const text = fs.readFileSync(path.join(dir, name), 'utf-8');
|
|
138
|
+
const pin = readNormPin(text);
|
|
139
|
+
if (pin === null) {
|
|
140
|
+
unpinned.push(name);
|
|
141
|
+
continue;
|
|
142
|
+
}
|
|
143
|
+
const measured = measureBody(text);
|
|
144
|
+
const finding: Finding = {
|
|
145
|
+
rule: name,
|
|
146
|
+
declared: pin.tokens,
|
|
147
|
+
measured,
|
|
148
|
+
over: measured - pin.tokens,
|
|
149
|
+
};
|
|
150
|
+
pinned.push(finding);
|
|
151
|
+
if (finding.over > 0) violations.push(finding);
|
|
152
|
+
}
|
|
153
|
+
return { pinned, violations, unpinned, method: method_note() };
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
export function main(argv: readonly string[] = process.argv.slice(2)): number {
|
|
157
|
+
if (argv.includes('--self-test')) return selfTest();
|
|
158
|
+
const unknown = argv.filter((a) => a !== '--quiet' && a !== '--json');
|
|
159
|
+
if (unknown.length > 0) {
|
|
160
|
+
process.stderr.write(`${PROG}: unknown argument(s): ${unknown.join(' ')}\n`);
|
|
161
|
+
return 2;
|
|
162
|
+
}
|
|
163
|
+
const quiet = argv.includes('--quiet');
|
|
164
|
+
const json = argv.includes('--json');
|
|
165
|
+
|
|
166
|
+
if (!TIKTOKEN_AVAILABLE) {
|
|
167
|
+
process.stderr.write(
|
|
168
|
+
`${PROG}: no exact tokenizer available (js-tiktoken absent). A \`norm\` pin is ` +
|
|
169
|
+
'derived in exact BPE, so enforcing it against the chars/4 proxy would hold ' +
|
|
170
|
+
'the author to a number they cannot reproduce. Install devDependencies and ' +
|
|
171
|
+
're-run; this gate does NOT fall back and pass.\n',
|
|
172
|
+
);
|
|
173
|
+
return 2;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
const v = check();
|
|
177
|
+
const ledger = new GateLedger(PROG);
|
|
178
|
+
ledger.plan([...v.pinned.map((f) => f.rule), ...v.unpinned]);
|
|
179
|
+
for (const f of v.pinned) {
|
|
180
|
+
if (f.over > 0) ledger.fail(f.rule, `${String(f.measured)} > ${String(f.declared)}`);
|
|
181
|
+
else ledger.complete(f.rule);
|
|
182
|
+
}
|
|
183
|
+
for (const name of v.unpinned) ledger.skip(name, 'declared_exemption');
|
|
184
|
+
|
|
185
|
+
if (json) {
|
|
186
|
+
process.stdout.write(`${JSON.stringify(v, null, 2)}\n`);
|
|
187
|
+
} else if (!quiet) {
|
|
188
|
+
process.stdout.write(`${PROG} · ${v.method}\n`);
|
|
189
|
+
for (const f of v.pinned) {
|
|
190
|
+
const mark = f.over > 0 ? '❌' : '✅';
|
|
191
|
+
const room = f.over > 0 ? `+${String(f.over)} over` : `${String(-f.over)} tok of room`;
|
|
192
|
+
process.stdout.write(
|
|
193
|
+
` ${mark} ${f.rule.padEnd(42)} ${String(f.measured).padStart(6)} / ` +
|
|
194
|
+
`${String(f.declared).padStart(6)} pinned (${room})\n`,
|
|
195
|
+
);
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
try {
|
|
200
|
+
reportScanned({
|
|
201
|
+
gate: PROG,
|
|
202
|
+
scanned: v.pinned.length + v.unpinned.length,
|
|
203
|
+
units: 'rule file(s)',
|
|
204
|
+
roots: ['src/rules'],
|
|
205
|
+
});
|
|
206
|
+
} catch (err) {
|
|
207
|
+
if (err instanceof DeadScopeError) {
|
|
208
|
+
process.stderr.write(`❌ ${err.message}\n`);
|
|
209
|
+
return 3;
|
|
210
|
+
}
|
|
211
|
+
throw err;
|
|
212
|
+
}
|
|
213
|
+
ledger.report();
|
|
214
|
+
|
|
215
|
+
// The un-pinned count is this phase's own progress metric, so it is printed
|
|
216
|
+
// on the GREEN path too — a number only visible on failure is not a metric.
|
|
217
|
+
process.stdout.write(
|
|
218
|
+
`${PROG}: ${String(v.pinned.length)} rule(s) declare \`norm\`, ` +
|
|
219
|
+
`${String(v.unpinned.length)} do not (un-pinned remainder).\n`,
|
|
220
|
+
);
|
|
221
|
+
if (v.violations.length > 0) {
|
|
222
|
+
process.stdout.write(
|
|
223
|
+
`❌ ${PROG}: ${String(v.violations.length)} rule(s) exceed the \`norm\` budget they ` +
|
|
224
|
+
'declared. Either move more prose to the `remainder` destination, or raise the ' +
|
|
225
|
+
'pin in the same commit with the measurement that justifies it — never silently.\n',
|
|
226
|
+
);
|
|
227
|
+
return 1;
|
|
228
|
+
}
|
|
229
|
+
process.stdout.write(`✅ ${PROG}: every declared \`norm\` pin is honoured.\n`);
|
|
230
|
+
return 0;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
/**
|
|
234
|
+
* Prove the gate discriminates.
|
|
235
|
+
*
|
|
236
|
+
* The reject cases exercise the three ways it must refuse: a pin genuinely
|
|
237
|
+
* exceeded, a dead scan root, and a usage error. The accept cases prove an
|
|
238
|
+
* honoured pin and an un-pinned corpus both pass — the second matters because
|
|
239
|
+
* the opt-in design means most runs see no pin at all, and a gate that reddened
|
|
240
|
+
* on "nobody opted in" would have been abandoned in a week.
|
|
241
|
+
*/
|
|
242
|
+
function selfTest(): number {
|
|
243
|
+
const tmp = fs.mkdtempSync(path.join(REPO_ROOT, '.norm-pin-selftest-'));
|
|
244
|
+
const fixture = (name: string, body: string, pin: string | null): void => {
|
|
245
|
+
const fm = pin === null ? '' : `norm:\n tokens: ${pin}\n remainder:\n - docs/x.md\n`;
|
|
246
|
+
fs.writeFileSync(path.join(tmp, name), `---\ntype: auto\n${fm}---\n\n${body}\n`);
|
|
247
|
+
};
|
|
248
|
+
// ~120 tokens of prose: comfortably over a pin of 5, comfortably under 4000.
|
|
249
|
+
const body = 'The obligation is stated here. '.repeat(24);
|
|
250
|
+
try {
|
|
251
|
+
const cases: SelfTestCase[] = [
|
|
252
|
+
{
|
|
253
|
+
name: 'pin exceeded → exit 1',
|
|
254
|
+
expect: 'reject',
|
|
255
|
+
run: () => {
|
|
256
|
+
fixture('over.md', body, '5');
|
|
257
|
+
const v = check(tmp);
|
|
258
|
+
fs.rmSync(path.join(tmp, 'over.md'));
|
|
259
|
+
return v.violations.length > 0 ? 1 : 0;
|
|
260
|
+
},
|
|
261
|
+
},
|
|
262
|
+
{
|
|
263
|
+
name: 'dead scan root → exit 3',
|
|
264
|
+
expect: 'reject',
|
|
265
|
+
run: () => {
|
|
266
|
+
const v = check(path.join(tmp, 'no-such-dir'));
|
|
267
|
+
try {
|
|
268
|
+
reportScanned({
|
|
269
|
+
gate: PROG,
|
|
270
|
+
scanned: v.pinned.length + v.unpinned.length,
|
|
271
|
+
units: 'rule file(s)',
|
|
272
|
+
roots: ['src/rules'],
|
|
273
|
+
});
|
|
274
|
+
} catch (err) {
|
|
275
|
+
return err instanceof DeadScopeError ? 3 : 1;
|
|
276
|
+
}
|
|
277
|
+
return 0;
|
|
278
|
+
},
|
|
279
|
+
},
|
|
280
|
+
{
|
|
281
|
+
name: 'unknown argument → exit 2',
|
|
282
|
+
expect: 'reject',
|
|
283
|
+
run: () => runGateCli(REPO_ROOT, SCRIPT_REL, ['--nonsense'], REPO_ROOT),
|
|
284
|
+
},
|
|
285
|
+
{
|
|
286
|
+
name: 'pin honoured → exit 0',
|
|
287
|
+
expect: 'accept',
|
|
288
|
+
run: () => {
|
|
289
|
+
fixture('under.md', body, '4000');
|
|
290
|
+
const v = check(tmp);
|
|
291
|
+
fs.rmSync(path.join(tmp, 'under.md'));
|
|
292
|
+
return v.violations.length > 0 ? 1 : 0;
|
|
293
|
+
},
|
|
294
|
+
},
|
|
295
|
+
{
|
|
296
|
+
name: 'no rule declares a pin → still exit 0',
|
|
297
|
+
expect: 'accept',
|
|
298
|
+
run: () => {
|
|
299
|
+
fixture('bare.md', body, null);
|
|
300
|
+
const v = check(tmp);
|
|
301
|
+
const ok = v.pinned.length === 0 && v.unpinned.length === 1;
|
|
302
|
+
fs.rmSync(path.join(tmp, 'bare.md'));
|
|
303
|
+
return ok ? 0 : 1;
|
|
304
|
+
},
|
|
305
|
+
},
|
|
306
|
+
];
|
|
307
|
+
return runSelfTest({ gate: PROG, cases, minCases: SELF_TEST_MIN_CASES, minRejectCases: SELF_TEST_MIN_REJECT });
|
|
308
|
+
} finally {
|
|
309
|
+
fs.rmSync(tmp, { recursive: true, force: true });
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
function invokedDirectly(): boolean {
|
|
314
|
+
const entry = process.argv[1];
|
|
315
|
+
if (entry === undefined) return false;
|
|
316
|
+
return import.meta.url === pathToFileURL(path.resolve(entry)).href;
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
if (invokedDirectly()) {
|
|
320
|
+
process.exit(main());
|
|
321
|
+
}
|
|
@@ -4,7 +4,19 @@
|
|
|
4
4
|
* ("NEVER BULK-DUMP CONTEXT INTO A SUBAGENT") deterministic
|
|
5
5
|
* (road-to-lean-agent-init Phase 3).
|
|
6
6
|
*
|
|
7
|
-
*
|
|
7
|
+
* WIDENED 2026-08-23 (road-to-review-independence step 0.4) to a THIRD surface: the
|
|
8
|
+
* SHIPPED prompt templates under `src/skills/subagent-orchestration/prompts/`. The gate
|
|
9
|
+
* made the "NEVER BULK-DUMP CONTEXT INTO A SUBAGENT" Iron Law deterministic over test
|
|
10
|
+
* fixtures and golden transcripts — i.e. over the places a violation is *simulated* —
|
|
11
|
+
* while the templates that actually construct a spawn brief in production sat outside
|
|
12
|
+
* it. Eight diff-payload placeholder sites across five of those files, plus two further
|
|
13
|
+
* placeholder shapes in two more, were unscanned.
|
|
14
|
+
*
|
|
15
|
+
* Still WARN-ONLY, exactly as before: this surface is prose with placeholders, and a
|
|
16
|
+
* placeholder is not yet a payload. What the widening buys is that a template growing a
|
|
17
|
+
* bulk-dump shape is now visible rather than invisible.
|
|
18
|
+
*
|
|
19
|
+
* Scans three surfaces for spawn-brief-shaped payloads: (a) JSON fixtures
|
|
8
20
|
* matching `tests/fixtures/**\/*spawn*.json`; (b) fenced code blocks in
|
|
9
21
|
* `tests/reasoning-layer-eval/golden-transcripts/*.md` that either parse as
|
|
10
22
|
* JSON with both a `task` and a `knowledge_refs` key, or are introduced by
|
|
@@ -41,7 +53,7 @@ import * as fs from 'node:fs';
|
|
|
41
53
|
import * as path from 'node:path';
|
|
42
54
|
import { fileURLToPath, pathToFileURL } from 'node:url';
|
|
43
55
|
|
|
44
|
-
import {
|
|
56
|
+
import { reportScanned, DeadScopeError } from './_lib/scan_scope.js';
|
|
45
57
|
|
|
46
58
|
const _HERE = path.dirname(fileURLToPath(import.meta.url));
|
|
47
59
|
const REPO_ROOT = path.resolve(_HERE, '..', '..');
|
|
@@ -219,6 +231,22 @@ function scanRepo(repoRoot: string): Finding[] {
|
|
|
219
231
|
}
|
|
220
232
|
}
|
|
221
233
|
|
|
234
|
+
// The shipped templates — step 0.4's surface. Counted the same way as the other two
|
|
235
|
+
// (the walk, not the filter), so "no violations" and "no files read" stay
|
|
236
|
+
// distinguishable; that distinction is why `scanned` is incremented before any
|
|
237
|
+
// content test in all three loops.
|
|
238
|
+
const templatesDir = path.join(repoRoot, 'src', 'skills', 'subagent-orchestration', 'prompts');
|
|
239
|
+
if (fs.existsSync(templatesDir)) {
|
|
240
|
+
for (const entry of fs.readdirSync(templatesDir, { withFileTypes: true })) {
|
|
241
|
+
if (entry.isFile() && entry.name.endsWith('.md')) {
|
|
242
|
+
scanned += 1;
|
|
243
|
+
findings.push(
|
|
244
|
+
...scanMarkdownTranscript(path.join(templatesDir, entry.name), repoRoot),
|
|
245
|
+
);
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
|
|
222
250
|
const transcriptsDir = path.join(repoRoot, 'tests', 'reasoning-layer-eval', 'golden-transcripts');
|
|
223
251
|
if (fs.existsSync(transcriptsDir)) {
|
|
224
252
|
for (const entry of fs.readdirSync(transcriptsDir, { withFileTypes: true })) {
|
|
@@ -229,11 +257,20 @@ function scanRepo(repoRoot: string): Finding[] {
|
|
|
229
257
|
}
|
|
230
258
|
}
|
|
231
259
|
|
|
232
|
-
assertScanned
|
|
260
|
+
// `reportScanned`, not `assertScanned`: step 0.4's verify compares the scanned count
|
|
261
|
+
// against the pre-change one, and a count the gate never prints cannot be compared.
|
|
262
|
+
// The helper's own docstring makes the same point — "a count only visible without
|
|
263
|
+
// `--quiet` is not a count, since CI passes `--quiet`" — so the line goes to stdout
|
|
264
|
+
// unconditionally.
|
|
265
|
+
reportScanned({
|
|
233
266
|
gate: 'lint_spawn_payload',
|
|
234
267
|
scanned,
|
|
235
|
-
units: 'fixture / transcript file(s)',
|
|
236
|
-
roots: [
|
|
268
|
+
units: 'fixture / transcript / template file(s)',
|
|
269
|
+
roots: [
|
|
270
|
+
'tests/fixtures',
|
|
271
|
+
'tests/reasoning-layer-eval/golden-transcripts',
|
|
272
|
+
'src/skills/subagent-orchestration/prompts',
|
|
273
|
+
],
|
|
237
274
|
});
|
|
238
275
|
return findings;
|
|
239
276
|
}
|
|
@@ -30,6 +30,7 @@ import * as fs from 'node:fs';
|
|
|
30
30
|
import * as path from 'node:path';
|
|
31
31
|
import { fileURLToPath, pathToFileURL } from 'node:url';
|
|
32
32
|
|
|
33
|
+
import { asOf } from './_lib/as_of.js';
|
|
33
34
|
import { GateLedger } from './_lib/gate_ledger.js';
|
|
34
35
|
import { assertScanned, DeadScopeError } from './_lib/scan_scope.js';
|
|
35
36
|
|
|
@@ -132,7 +133,7 @@ function _now(): Date {
|
|
|
132
133
|
const parsed = Date.parse(`${flag.slice('--now='.length)}T00:00:00Z`);
|
|
133
134
|
if (!Number.isNaN(parsed)) return new Date(parsed);
|
|
134
135
|
}
|
|
135
|
-
return
|
|
136
|
+
return asOf();
|
|
136
137
|
}
|
|
137
138
|
|
|
138
139
|
function main(): number {
|
|
@@ -420,6 +420,15 @@ async function _run_http_leg(target: string): Promise<number> {
|
|
|
420
420
|
return failed;
|
|
421
421
|
}
|
|
422
422
|
|
|
423
|
+
/**
|
|
424
|
+
* The turnkey stdio surface's tool names, code-point sorted and joined.
|
|
425
|
+
* Kept as a literal rather than imported from `src/cli/` so this maintainer
|
|
426
|
+
* script does not take a build dependency on the CLI bundle; the CLI-side
|
|
427
|
+
* source of truth is `LITE_TOOLS` in `src/cli/mcp/dispatch.ts`, and
|
|
428
|
+
* `tests/scripts/mcp_lite_tools.test.ts` pins that side.
|
|
429
|
+
*/
|
|
430
|
+
const LITE_TOOL_NAMES_EXPECTED = 'read_skill,suggest_skill_for_task';
|
|
431
|
+
|
|
423
432
|
/** ALL skill+command prompt metas (uncapped — for full-set parity). */
|
|
424
433
|
function _local_prompts_all(): Record<string, unknown>[] {
|
|
425
434
|
const [prompts] = load_all_prompts();
|
|
@@ -438,7 +447,8 @@ function _local_resources_all(): Record<string, unknown>[] {
|
|
|
438
447
|
* Compares the FULL SUBSET the turnkey surface serves (skill/command prompts,
|
|
439
448
|
* rule/guideline resources — contexts excluded by design) via cursor
|
|
440
449
|
* pagination, on name/kind/uri keys, and asserts the read-only boundary
|
|
441
|
-
* (
|
|
450
|
+
* (the two read-only discovery tools and nothing else). Skips with a note if
|
|
451
|
+
* the binary isn't built.
|
|
442
452
|
*/
|
|
443
453
|
function _run_node_leg(cli: string): number {
|
|
444
454
|
if (!_exists(cli)) {
|
|
@@ -473,13 +483,29 @@ function _run_node_leg(cli: string): number {
|
|
|
473
483
|
_subset_resources(_normalize_resources({ resources: _local_resources_all() })),
|
|
474
484
|
_subset_resources(_normalize_resources({ resources: nodeResources })),
|
|
475
485
|
);
|
|
476
|
-
|
|
486
|
+
// Phase 1.1 of `road-to-skill-delivery-over-mcp`: the turnkey surface now
|
|
487
|
+
// serves exactly two read-only discovery tools, and this leg is where risk 6
|
|
488
|
+
// ("two implementations diverge silently") stops being a claim. Both names
|
|
489
|
+
// are checked, not counted — a count would pass on the wrong pair.
|
|
490
|
+
//
|
|
491
|
+
// `suggest_skill_for_task` is shared with the kernel and both now compute
|
|
492
|
+
// their score through the single `src/shared/skillRanking.ts` formula.
|
|
493
|
+
// `read_skill` is lite-only and deliberately NARROWER than the kernel's
|
|
494
|
+
// `read_resource_body`: it resolves a skill NAME through the content tree's
|
|
495
|
+
// uri map and can reach nothing else.
|
|
496
|
+
const nodeToolNames = nodeTools
|
|
497
|
+
.map((t) => String(t.name ?? ''))
|
|
498
|
+
.sort(_cmpCodePoints)
|
|
499
|
+
.join(',');
|
|
500
|
+
if (nodeToolNames !== LITE_TOOL_NAMES_EXPECTED) {
|
|
477
501
|
process.stdout.write(
|
|
478
|
-
`❌ node tools/list: expected
|
|
502
|
+
`❌ node tools/list: expected exactly [${LITE_TOOL_NAMES_EXPECTED}], got [${nodeToolNames}]\n`,
|
|
479
503
|
);
|
|
480
504
|
failed += 1;
|
|
481
505
|
} else {
|
|
482
|
-
process.stdout.write(
|
|
506
|
+
process.stdout.write(
|
|
507
|
+
`✅ node tools/list: ${LITE_TOOL_NAMES_EXPECTED} (read-only discovery, ADR-085 + Phase 1.1)\n`,
|
|
508
|
+
);
|
|
483
509
|
}
|
|
484
510
|
process.stdout.write(
|
|
485
511
|
`${`${failed ? '' : 'node-stdio parity OK '}(${path.basename(cli)})`.trim()}\n`,
|