@event4u/agent-config 14.9.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 +384 -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/async-python-patterns/SKILL.md +1 -1
- 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 +1 -1
- 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 +4 -1
- package/dist/agent-src/skills/context-authoring/SKILL.md +1 -1
- package/dist/agent-src/skills/conventional-commits-writing/SKILL.md +4 -1
- 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 +80 -2
- 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/discovery-interview/SKILL.md +1 -1
- package/dist/agent-src/skills/doc-coauthoring/SKILL.md +1 -1
- package/dist/agent-src/skills/docx-authoring/SKILL.md +1 -1
- package/dist/agent-src/skills/editorial-calendar/SKILL.md +1 -1
- 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/github-ci/SKILL.md +1 -1
- 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/judge-artifact-completeness/SKILL.md +1 -1
- package/dist/agent-src/skills/judge-injection-defense/SKILL.md +1 -1
- package/dist/agent-src/skills/laravel-migration/SKILL.md +3 -0
- package/dist/agent-src/skills/laravel-validation/SKILL.md +1 -1
- package/dist/agent-src/skills/learning-to-rule-or-skill/SKILL.md +3 -0
- package/dist/agent-src/skills/legal-intake-triage/SKILL.md +1 -1
- package/dist/agent-src/skills/legal-practice-profile/SKILL.md +1 -1
- 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/messaging-architecture/SKILL.md +1 -1
- package/dist/agent-src/skills/migration-architect/SKILL.md +1 -1
- package/dist/agent-src/skills/module-detect-on-the-fly/SKILL.md +1 -1
- package/dist/agent-src/skills/module-management/SKILL.md +1 -1
- 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 +7 -1
- package/dist/agent-src/skills/multi-tenancy/SKILL.md +4 -0
- package/dist/agent-src/skills/onboarding-program/SKILL.md +1 -1
- 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/perf-feedback-craft/SKILL.md +1 -1
- 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/prompt-optimizer/SKILL.md +1 -1
- 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 +3 -3
- 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/SKILL.md +1 -1
- package/dist/agent-src/skills/scene-expander/scene-blueprint.schema.yaml +26 -0
- package/dist/agent-src/skills/secrets-management/SKILL.md +5 -1
- 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/using-git-worktrees/SKILL.md +1 -1
- 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 +380 -145
- 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 +227 -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/preamble-payload-budget.json +71 -67
- 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/seating.ts +211 -0
- 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_pack_passport_reconciliation.ts +274 -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/generate_pack_manifests.ts +78 -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/pack.schema.json +62 -4
- package/src/scripts/schemas/rule.schema.json +24 -2
- package/src/scripts/schemas/skill.schema.json +41 -2
- 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/tighten_skill_descriptions.ts +264 -0
- 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
|
@@ -0,0 +1,364 @@
|
|
|
1
|
+
#!/usr/bin/env tsx
|
|
2
|
+
/**
|
|
3
|
+
* A1.2/A1.3 — answer the per-turn composite's arming question, and refuse to guess.
|
|
4
|
+
*
|
|
5
|
+
* `src/config/hook-latency-budget.json` → `per_turn_composite` ships
|
|
6
|
+
* `observe_only: true` with `p50_ci: null`, and its `arming_precondition` is
|
|
7
|
+
* **"at least 10 CI gate readings of the composite, from at least 2 distinct
|
|
8
|
+
* runner sessions"**. Until 2026-08-23 that precondition could not be evaluated
|
|
9
|
+
* at all: the bench printed the composite and stored nothing. This reads the
|
|
10
|
+
* store the bench now appends to and reports whether the precondition holds.
|
|
11
|
+
*
|
|
12
|
+
* IT NEVER WRITES `p50_ci`, AND THAT IS THE POINT. A2.1 is a MAINTAINER ACT
|
|
13
|
+
* gated by `b-composite-ceiling-value`. This script publishes a distribution to
|
|
14
|
+
* choose FROM; choosing is not its job, and a script that both measured and
|
|
15
|
+
* armed would be the agent setting its own ceiling.
|
|
16
|
+
*
|
|
17
|
+
* THREE REFUSALS, each from a recorded failure mode:
|
|
18
|
+
*
|
|
19
|
+
* 1. **A null composite is dropped, never extrapolated.** `perTurnComposite()`
|
|
20
|
+
* returns null rather than a number when a slot is missing from the run,
|
|
21
|
+
* because a composite over a subset reads LOW — and low is the direction that
|
|
22
|
+
* makes a ceiling look met. A record with `composite_ms: null` is counted as
|
|
23
|
+
* unusable and named, not averaged away.
|
|
24
|
+
* 2. **Never a bare boolean.** "not yet" always names the shortfall — which
|
|
25
|
+
* clause failed and by how much. `9 readings from 3 sessions` and `12 from 1`
|
|
26
|
+
* are both not-armable and fail for *different* reasons; a boolean loses that.
|
|
27
|
+
* Both are pinned as tests.
|
|
28
|
+
* 3. **Sessions are counted by identity, not by row.** The instability the floor
|
|
29
|
+
* exists to exclude was measured on ONE machine (a sibling metric read
|
|
30
|
+
* 44–157 % at n=12), so twelve readings from one session is exactly the shape
|
|
31
|
+
* the floor rejects. A bare counter cannot see it.
|
|
32
|
+
*
|
|
33
|
+
* Exit codes:
|
|
34
|
+
* 0 — the store was read and a verdict printed (armable OR not — "not yet" is
|
|
35
|
+
* a successful measurement, never a build failure)
|
|
36
|
+
* 1 — the store is unreadable or malformed
|
|
37
|
+
* 2 — bad args
|
|
38
|
+
*/
|
|
39
|
+
import * as fs from 'node:fs';
|
|
40
|
+
import * as os from 'node:os';
|
|
41
|
+
import * as path from 'node:path';
|
|
42
|
+
import { fileURLToPath, pathToFileURL } from 'node:url';
|
|
43
|
+
|
|
44
|
+
import { runGateCli, runSelfTest, type SelfTestCase } from './_lib/gate_self_test.js';
|
|
45
|
+
import { DeadScopeError, reportScanned } from './_lib/scan_scope.js';
|
|
46
|
+
|
|
47
|
+
const _HERE = fileURLToPath(import.meta.url);
|
|
48
|
+
const REPO_ROOT = path.resolve(path.dirname(_HERE), '..', '..');
|
|
49
|
+
const SELF = 'src/scripts/check_composite_arming.ts';
|
|
50
|
+
|
|
51
|
+
/** The tracked, append-only store the bench writes with `--record-composite`. */
|
|
52
|
+
export const STORE_REL = path.join('agents', 'evidence', 'hook-composite-readings.jsonl');
|
|
53
|
+
|
|
54
|
+
/** From `per_turn_composite.arming_precondition`. A STATED minimum, not a derived one. */
|
|
55
|
+
export const MIN_READINGS = 10;
|
|
56
|
+
export const MIN_SESSIONS = 2;
|
|
57
|
+
|
|
58
|
+
const SELF_TEST_MIN_CASES = 5;
|
|
59
|
+
const SELF_TEST_MIN_REJECT = 2;
|
|
60
|
+
|
|
61
|
+
export interface Reading {
|
|
62
|
+
/** null when a slot was missing from the run — unusable, never extrapolated. */
|
|
63
|
+
composite_ms: number | null;
|
|
64
|
+
parts?: Record<string, number>;
|
|
65
|
+
tool_calls?: number;
|
|
66
|
+
/** Distinguishes runner SESSIONS, not rows. See refusal 3. */
|
|
67
|
+
session: string;
|
|
68
|
+
platform?: string;
|
|
69
|
+
node?: string;
|
|
70
|
+
commit?: string;
|
|
71
|
+
recorded_at?: string;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export interface Verdict {
|
|
75
|
+
armable: boolean;
|
|
76
|
+
usable: number;
|
|
77
|
+
unusable: number;
|
|
78
|
+
sessions: string[];
|
|
79
|
+
/** Every clause that failed, each naming its shortfall. Empty iff armable. */
|
|
80
|
+
failures: string[];
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
export function parseStore(text: string): { readings: Reading[]; malformed: number } {
|
|
84
|
+
const readings: Reading[] = [];
|
|
85
|
+
let malformed = 0;
|
|
86
|
+
for (const line of text.split('\n')) {
|
|
87
|
+
const t = line.trim();
|
|
88
|
+
if (t === '') continue;
|
|
89
|
+
try {
|
|
90
|
+
const o = JSON.parse(t) as Partial<Reading>;
|
|
91
|
+
if (typeof o.session !== 'string' || !('composite_ms' in o)) {
|
|
92
|
+
malformed += 1;
|
|
93
|
+
continue;
|
|
94
|
+
}
|
|
95
|
+
readings.push({ ...o, session: o.session, composite_ms: o.composite_ms ?? null });
|
|
96
|
+
} catch {
|
|
97
|
+
malformed += 1;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
return { readings, malformed };
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
export function evaluate(readings: readonly Reading[]): Verdict {
|
|
104
|
+
const usable = readings.filter((r) => typeof r.composite_ms === 'number');
|
|
105
|
+
const unusable = readings.length - usable.length;
|
|
106
|
+
const sessions = [...new Set(usable.map((r) => r.session))].sort();
|
|
107
|
+
const failures: string[] = [];
|
|
108
|
+
if (usable.length < MIN_READINGS) {
|
|
109
|
+
failures.push(
|
|
110
|
+
`readings: ${String(usable.length)} usable of ${String(MIN_READINGS)} required ` +
|
|
111
|
+
`(short by ${String(MIN_READINGS - usable.length)})`,
|
|
112
|
+
);
|
|
113
|
+
}
|
|
114
|
+
if (sessions.length < MIN_SESSIONS) {
|
|
115
|
+
failures.push(
|
|
116
|
+
`sessions: ${String(sessions.length)} distinct of ${String(MIN_SESSIONS)} required ` +
|
|
117
|
+
`(short by ${String(MIN_SESSIONS - sessions.length)}) — the floor exists because the ` +
|
|
118
|
+
`instability it excludes was measured on ONE machine, so N readings from one session ` +
|
|
119
|
+
`cannot substitute`,
|
|
120
|
+
);
|
|
121
|
+
}
|
|
122
|
+
return { armable: failures.length === 0, usable: usable.length, unusable, sessions, failures };
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
function _quantile(sorted: readonly number[], q: number): number {
|
|
126
|
+
if (sorted.length === 0) return 0;
|
|
127
|
+
const i = Math.min(sorted.length - 1, Math.max(0, Math.ceil(q * sorted.length) - 1));
|
|
128
|
+
return sorted[i] as number;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* A1.3 — render the distribution to choose FROM. Writes no `p50_ci`.
|
|
133
|
+
*
|
|
134
|
+
* The pathology net is kept SEPARATE from the cap, per step 3 of the recorded
|
|
135
|
+
* arming procedure: one runner spike should be caught as a pathology rather than
|
|
136
|
+
* by lowering the cap for everyone.
|
|
137
|
+
*/
|
|
138
|
+
export function renderDistribution(readings: readonly Reading[], v: Verdict): string {
|
|
139
|
+
const vals = readings
|
|
140
|
+
.map((r) => r.composite_ms)
|
|
141
|
+
.filter((x): x is number => typeof x === 'number')
|
|
142
|
+
.sort((a, b) => a - b);
|
|
143
|
+
const L: string[] = [];
|
|
144
|
+
L.push('# Per-turn composite — distribution, not a decision');
|
|
145
|
+
L.push('');
|
|
146
|
+
L.push(`n = ${String(v.usable)} usable reading(s) across ${String(v.sessions.length)} session(s).`);
|
|
147
|
+
if (v.unusable > 0) {
|
|
148
|
+
L.push('');
|
|
149
|
+
L.push(
|
|
150
|
+
`**${String(v.unusable)} reading(s) were DROPPED as unusable** — a slot the definition ` +
|
|
151
|
+
'needs was missing from that run, so the composite would have read low, and low is the ' +
|
|
152
|
+
'direction that makes a ceiling look met. They are excluded, not averaged.',
|
|
153
|
+
);
|
|
154
|
+
}
|
|
155
|
+
L.push('');
|
|
156
|
+
L.push('| statistic | ms |');
|
|
157
|
+
L.push('|---|---|');
|
|
158
|
+
L.push(`| min | ${String(vals[0] ?? 0)} |`);
|
|
159
|
+
L.push(`| p50 | ${String(_quantile(vals, 0.5))} |`);
|
|
160
|
+
L.push(`| p95 | ${String(_quantile(vals, 0.95))} |`);
|
|
161
|
+
L.push(`| max | ${String(vals[vals.length - 1] ?? 0)} |`);
|
|
162
|
+
L.push(`| spread (max − min) | ${String((vals[vals.length - 1] ?? 0) - (vals[0] ?? 0))} |`);
|
|
163
|
+
L.push('');
|
|
164
|
+
L.push('## Per session');
|
|
165
|
+
L.push('');
|
|
166
|
+
L.push('| session | n | p50 | max |');
|
|
167
|
+
L.push('|---|---|---|---|');
|
|
168
|
+
for (const s of v.sessions) {
|
|
169
|
+
const sv = readings
|
|
170
|
+
.filter((r) => r.session === s && typeof r.composite_ms === 'number')
|
|
171
|
+
.map((r) => r.composite_ms as number)
|
|
172
|
+
.sort((a, b) => a - b);
|
|
173
|
+
L.push(`| \`${s}\` | ${String(sv.length)} | ${String(_quantile(sv, 0.5))} | ${String(sv[sv.length - 1] ?? 0)} |`);
|
|
174
|
+
}
|
|
175
|
+
L.push('');
|
|
176
|
+
L.push('## What a maintainer does with this — and what this file deliberately does NOT do');
|
|
177
|
+
L.push('');
|
|
178
|
+
L.push(
|
|
179
|
+
'This file writes **no `p50_ci`**. Setting it is step A2.1, a MAINTAINER ACT gated by ' +
|
|
180
|
+
'`b-composite-ceiling-value`. A script that both measured the distribution and armed the ' +
|
|
181
|
+
'ceiling from it would be the agent setting its own budget.',
|
|
182
|
+
);
|
|
183
|
+
L.push('');
|
|
184
|
+
L.push(
|
|
185
|
+
'Per step 2 of the recorded arming procedure, the cap is an **absolute** number derived from ' +
|
|
186
|
+
'this distribution, never a creep window — shared CI runners flap, which is why ' +
|
|
187
|
+
'`regression_gate.max_regression_pct` already sits at 200.',
|
|
188
|
+
);
|
|
189
|
+
L.push('');
|
|
190
|
+
L.push(
|
|
191
|
+
'Per step 3, the **pathology net stays separate from the cap**. Proposed shape, offered as a ' +
|
|
192
|
+
'starting point and not a recommendation: cap from the p50 with the recorded headroom ' +
|
|
193
|
+
'convention, and a separate net at roughly the observed max, so ONE spike is caught as a ' +
|
|
194
|
+
'pathology rather than by lowering the cap for every run.',
|
|
195
|
+
);
|
|
196
|
+
if (!v.armable) {
|
|
197
|
+
L.push('');
|
|
198
|
+
L.push('## NOT ARMABLE YET');
|
|
199
|
+
L.push('');
|
|
200
|
+
for (const f of v.failures) L.push(`- ${f}`);
|
|
201
|
+
L.push('');
|
|
202
|
+
L.push(
|
|
203
|
+
'The numbers above are printed anyway, because a distribution is informative before it is ' +
|
|
204
|
+
'sufficient — but they must not be read as a basis for a ceiling until every clause ' +
|
|
205
|
+
'above clears.',
|
|
206
|
+
);
|
|
207
|
+
}
|
|
208
|
+
return `${L.join('\n')}\n`;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
export function selfTest(): number {
|
|
212
|
+
const nine3 = Array.from({ length: 9 }, (_, i) => ({ composite_ms: 1000 + i, session: `s${String(i % 3)}` }));
|
|
213
|
+
const twelve1 = Array.from({ length: 12 }, (_, i) => ({ composite_ms: 1000 + i, session: 'only' }));
|
|
214
|
+
const ok = Array.from({ length: 10 }, (_, i) => ({ composite_ms: 1000 + i, session: `s${String(i % 2)}` }));
|
|
215
|
+
const cases: SelfTestCase[] = [
|
|
216
|
+
{
|
|
217
|
+
name: '9 readings from 3 sessions is NOT armable, and names the readings clause',
|
|
218
|
+
expect: 'accept',
|
|
219
|
+
run: () => {
|
|
220
|
+
const v = evaluate(nine3);
|
|
221
|
+
return !v.armable && v.failures.length === 1 && v.failures[0]?.startsWith('readings:') === true ? 0 : 1;
|
|
222
|
+
},
|
|
223
|
+
},
|
|
224
|
+
{
|
|
225
|
+
name: '12 readings from 1 session is NOT armable, and names the sessions clause',
|
|
226
|
+
expect: 'accept',
|
|
227
|
+
run: () => {
|
|
228
|
+
const v = evaluate(twelve1);
|
|
229
|
+
return !v.armable && v.failures.length === 1 && v.failures[0]?.startsWith('sessions:') === true ? 0 : 1;
|
|
230
|
+
},
|
|
231
|
+
},
|
|
232
|
+
{
|
|
233
|
+
name: '10 readings from 2 sessions IS armable',
|
|
234
|
+
expect: 'accept',
|
|
235
|
+
run: () => (evaluate(ok).armable ? 0 : 1),
|
|
236
|
+
},
|
|
237
|
+
{
|
|
238
|
+
name: 'a null composite is dropped, not counted toward the floor',
|
|
239
|
+
expect: 'accept',
|
|
240
|
+
run: () => {
|
|
241
|
+
const v = evaluate([...ok.slice(0, 9), { composite_ms: null, session: 'sX' }]);
|
|
242
|
+
return !v.armable && v.unusable === 1 && v.usable === 9 ? 0 : 1;
|
|
243
|
+
},
|
|
244
|
+
},
|
|
245
|
+
{
|
|
246
|
+
name: 'the published distribution writes no p50_ci',
|
|
247
|
+
expect: 'accept',
|
|
248
|
+
run: () => (/p50_ci/.test(renderDistribution(ok, evaluate(ok))) && !/writes \*\*no `p50_ci`\*\*/.test(renderDistribution(ok, evaluate(ok))) ? 1 : 0),
|
|
249
|
+
},
|
|
250
|
+
{
|
|
251
|
+
name: 'rejects a missing store rather than reporting armable',
|
|
252
|
+
expect: 'reject',
|
|
253
|
+
run: () => runGateCli(REPO_ROOT, SELF, ['--store', path.join(REPO_ROOT, 'no-such.jsonl')], REPO_ROOT),
|
|
254
|
+
},
|
|
255
|
+
{
|
|
256
|
+
name: 'rejects a malformed store rather than silently skipping every line',
|
|
257
|
+
expect: 'reject',
|
|
258
|
+
run: () => {
|
|
259
|
+
const d = fs.mkdtempSync(path.join(os.tmpdir(), 'arm-'));
|
|
260
|
+
const f = path.join(d, 's.jsonl');
|
|
261
|
+
fs.writeFileSync(f, 'not json\n{also not\n');
|
|
262
|
+
try {
|
|
263
|
+
return runGateCli(REPO_ROOT, SELF, ['--store', f], REPO_ROOT);
|
|
264
|
+
} finally {
|
|
265
|
+
fs.rmSync(d, { recursive: true, force: true });
|
|
266
|
+
}
|
|
267
|
+
},
|
|
268
|
+
},
|
|
269
|
+
];
|
|
270
|
+
return runSelfTest({ gate: 'check_composite_arming', cases, minCases: SELF_TEST_MIN_CASES, minRejectCases: SELF_TEST_MIN_REJECT });
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
function main(argv?: readonly string[]): number {
|
|
274
|
+
const args = argv ?? process.argv.slice(2);
|
|
275
|
+
if (args.includes('--self-test')) return selfTest();
|
|
276
|
+
const si = args.indexOf('--store');
|
|
277
|
+
const store = si >= 0 ? args[si + 1] : path.join(REPO_ROOT, STORE_REL);
|
|
278
|
+
if (store === undefined) {
|
|
279
|
+
process.stderr.write('check_composite_arming: --store requires a path\n');
|
|
280
|
+
return 2;
|
|
281
|
+
}
|
|
282
|
+
let text: string;
|
|
283
|
+
try {
|
|
284
|
+
text = fs.readFileSync(store, 'utf-8');
|
|
285
|
+
} catch {
|
|
286
|
+
process.stdout.write(
|
|
287
|
+
`❌ no composite store at ${path.relative(REPO_ROOT, store)}.\n` +
|
|
288
|
+
` The bench appends to it with \`--record-composite\`; until CI runs have\n` +
|
|
289
|
+
` accumulated readings there is nothing to evaluate. This is "not measured yet",\n` +
|
|
290
|
+
` which is NOT the same as "armable".\n`,
|
|
291
|
+
);
|
|
292
|
+
return 1;
|
|
293
|
+
}
|
|
294
|
+
const { readings, malformed } = parseStore(text);
|
|
295
|
+
if (malformed > 0 && readings.length === 0) {
|
|
296
|
+
process.stderr.write(
|
|
297
|
+
`❌ ${path.relative(REPO_ROOT, store)}: ${String(malformed)} malformed line(s) and no usable ` +
|
|
298
|
+
`record. A store that parses to nothing must not read as "no readings yet".\n`,
|
|
299
|
+
);
|
|
300
|
+
return 1;
|
|
301
|
+
}
|
|
302
|
+
// Scope assertion. The unit is a READING, and zero of them is a dead scope
|
|
303
|
+
// rather than "nothing to report": a store that parsed to no records reads
|
|
304
|
+
// identically to a store nobody has written, and the second must not pass as
|
|
305
|
+
// the first. The missing-file case above already exits 1; this catches the
|
|
306
|
+
// present-but-empty and parsed-to-nothing cases.
|
|
307
|
+
try {
|
|
308
|
+
reportScanned({
|
|
309
|
+
gate: 'check_composite_arming',
|
|
310
|
+
scanned: readings.length,
|
|
311
|
+
units: 'composite reading(s)',
|
|
312
|
+
roots: [path.relative(REPO_ROOT, store) || store],
|
|
313
|
+
});
|
|
314
|
+
} catch (err) {
|
|
315
|
+
if (err instanceof DeadScopeError) {
|
|
316
|
+
process.stderr.write(`❌ ${err.message}\n`);
|
|
317
|
+
return 1;
|
|
318
|
+
}
|
|
319
|
+
throw err;
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
const v = evaluate(readings);
|
|
323
|
+
|
|
324
|
+
if (args.includes('--publish')) {
|
|
325
|
+
const out = path.join(REPO_ROOT, 'agents', 'evidence', 'reports', 'per-turn-composite-distribution.md');
|
|
326
|
+
fs.mkdirSync(path.dirname(out), { recursive: true });
|
|
327
|
+
fs.writeFileSync(out, renderDistribution(readings, v), 'utf-8');
|
|
328
|
+
process.stdout.write(`✅ wrote ${path.relative(REPO_ROOT, out)} (n=${String(v.usable)}, sessions=${String(v.sessions.length)})\n`);
|
|
329
|
+
return 0;
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
if (malformed > 0) {
|
|
333
|
+
process.stdout.write(`⚠️ ${String(malformed)} malformed line(s) ignored (${String(readings.length)} parsed)\n`);
|
|
334
|
+
}
|
|
335
|
+
if (v.armable) {
|
|
336
|
+
process.stdout.write(
|
|
337
|
+
`✅ ARMABLE — ${String(v.usable)} usable reading(s) from ${String(v.sessions.length)} session(s) ` +
|
|
338
|
+
`(floor: ${String(MIN_READINGS)} / ${String(MIN_SESSIONS)}).\n` +
|
|
339
|
+
` Next is A2.1, a MAINTAINER ACT: run with --publish, then set p50_ci and flip\n` +
|
|
340
|
+
` observe_only. This script never writes either.\n`,
|
|
341
|
+
);
|
|
342
|
+
} else {
|
|
343
|
+
process.stdout.write(
|
|
344
|
+
`⏳ NOT YET — ${String(v.usable)} usable reading(s) from ${String(v.sessions.length)} session(s)` +
|
|
345
|
+
`${v.unusable > 0 ? `, ${String(v.unusable)} dropped as unusable` : ''}.\n`,
|
|
346
|
+
);
|
|
347
|
+
for (const f of v.failures) process.stdout.write(` · ${f}\n`);
|
|
348
|
+
}
|
|
349
|
+
return 0;
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
function _isCliEntry(): boolean {
|
|
353
|
+
if (process.argv[1] === undefined) return false;
|
|
354
|
+
if (import.meta.url === pathToFileURL(path.resolve(process.argv[1])).href) return true;
|
|
355
|
+
try {
|
|
356
|
+
return fs.realpathSync(fileURLToPath(import.meta.url)) === fs.realpathSync(path.resolve(process.argv[1]));
|
|
357
|
+
} catch {
|
|
358
|
+
return false;
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
if (_isCliEntry() || process.argv[1] === _HERE) process.exit(main());
|
|
363
|
+
|
|
364
|
+
export { main };
|
|
@@ -49,6 +49,7 @@ import * as os from 'node:os';
|
|
|
49
49
|
import * as path from 'node:path';
|
|
50
50
|
import { fileURLToPath, pathToFileURL } from 'node:url';
|
|
51
51
|
|
|
52
|
+
import { asOf } from './_lib/as_of.js';
|
|
52
53
|
import { GateLedger } from './_lib/gate_ledger.js';
|
|
53
54
|
import { runGateCli, runSelfTest } from './_lib/gate_self_test.js';
|
|
54
55
|
import { assertScanned, DeadScopeError } from './_lib/scan_scope.js';
|
|
@@ -126,7 +127,7 @@ export function days_between(fromStamp: number, toStamp: number): number {
|
|
|
126
127
|
}
|
|
127
128
|
|
|
128
129
|
/** Today as `YYYY-MM-DD` in UTC — the only place the clock is read. */
|
|
129
|
-
export function today_iso(now: Date =
|
|
130
|
+
export function today_iso(now: Date = asOf()): string {
|
|
130
131
|
return now.toISOString().slice(0, 10);
|
|
131
132
|
}
|
|
132
133
|
|
|
@@ -36,6 +36,7 @@ import * as fs from 'node:fs';
|
|
|
36
36
|
import * as os from 'node:os';
|
|
37
37
|
import * as path from 'node:path';
|
|
38
38
|
|
|
39
|
+
import { asOf, asOfBanner } from './_lib/as_of.js';
|
|
39
40
|
import { DeadScopeError, reportScanned } from './_lib/scan_scope.js';
|
|
40
41
|
import { runSelfTest, type SelfTestCase } from './_lib/gate_self_test.js';
|
|
41
42
|
|
|
@@ -234,7 +235,7 @@ function main(argv: string[]): number {
|
|
|
234
235
|
const today =
|
|
235
236
|
ti >= 0 && argv[ti + 1] !== undefined
|
|
236
237
|
? String(argv[ti + 1])
|
|
237
|
-
:
|
|
238
|
+
: asOf().toISOString().slice(0, 10);
|
|
238
239
|
if (epochDay(today) === null) {
|
|
239
240
|
process.stderr.write(`--today must be a real YYYY-MM-DD date (got ${today})\n`);
|
|
240
241
|
return 2;
|
|
@@ -253,6 +254,7 @@ function main(argv: string[]): number {
|
|
|
253
254
|
const bad = rows.filter((r) => r.verdict === 'stale' || r.verdict === 'future-date' || r.verdict === 'malformed');
|
|
254
255
|
const unstamped = rows.filter((r) => r.verdict === 'unstamped');
|
|
255
256
|
|
|
257
|
+
process.stdout.write(`${asOfBanner(ti >= 0 ? today : undefined)}\n`);
|
|
256
258
|
for (const r of rows) {
|
|
257
259
|
const age = r.age_days === null ? '—' : `${r.age_days}d`;
|
|
258
260
|
process.stdout.write(
|
|
@@ -38,6 +38,7 @@ import * as path from 'node:path';
|
|
|
38
38
|
import { fileURLToPath, pathToFileURL } from 'node:url';
|
|
39
39
|
|
|
40
40
|
import { assertScanned, DeadScopeError } from './_lib/scan_scope.js';
|
|
41
|
+
import { count as count_artefacts } from './update_counts.js';
|
|
41
42
|
import { KERNEL_RULE_ID_SET } from './_lib/kernel_rules.js';
|
|
42
43
|
import {
|
|
43
44
|
carrier_frequency_by_platform,
|
|
@@ -81,7 +82,7 @@ export type Resolution =
|
|
|
81
82
|
| 'observer' // instruments only — never blocks
|
|
82
83
|
| 'unwired' // declared script exists but nothing runs it ← the D1 class
|
|
83
84
|
| 'missing' // declared target does not exist at all
|
|
84
|
-
| 'none'; // honest, recorded gap
|
|
85
|
+
| 'none'; // honest, recorded gap — `instruction-only: <reason>`, or the retired bare `none`
|
|
85
86
|
|
|
86
87
|
/**
|
|
87
88
|
* Whether the carrier's firing set covers the obligation's — the question
|
|
@@ -91,7 +92,8 @@ export type Resolution =
|
|
|
91
92
|
* hook-capable platform.
|
|
92
93
|
* `gap` — at least one hook-capable platform where no declared carrier
|
|
93
94
|
* covers it. `gap_platforms` names them.
|
|
94
|
-
* `declared-gap` — the rule declares `
|
|
95
|
+
* `declared-gap` — the rule declares `instruction-only:` (or the retired `none`);
|
|
96
|
+
* the gap is stated in
|
|
95
97
|
* the rule's own text, so it is honest, not a defect.
|
|
96
98
|
* `unclassified` — no `obligation_frequency` to join against. The nine kernel
|
|
97
99
|
* rules sit here: `block_kernel_rule_writes.ts` denies agent
|
|
@@ -377,8 +379,32 @@ export function resolve_one(
|
|
|
377
379
|
exists: (rel: string) => boolean;
|
|
378
380
|
},
|
|
379
381
|
): { resolution: Resolution; note?: string } {
|
|
382
|
+
// `none` stays legal and counted — an honest gap beats a false claim — but it
|
|
383
|
+
// is the RETIRED spelling. `instruction-only: <reason>` is the same effective
|
|
384
|
+
// level with the triage record attached, because "nothing enforces this" and
|
|
385
|
+
// "nothing enforces this AND here is why that is the right call" are not the
|
|
386
|
+
// same statement, and only the second one survives review. The one remaining
|
|
387
|
+
// `none` is `non-destructive-by-default`, a kernel rule that
|
|
388
|
+
// `block_kernel_rule_writes` denies agent writes to — see
|
|
389
|
+
// `agents/roadmaps/stubs/road-to-kernel-instruction-only-migration.md`.
|
|
380
390
|
if (decl === 'none') return { resolution: 'none' };
|
|
381
391
|
|
|
392
|
+
if (decl === 'instruction-only' || decl.startsWith('instruction-only:')) {
|
|
393
|
+
const reason = decl.slice('instruction-only:'.length).trim();
|
|
394
|
+
if (decl === 'instruction-only' || reason === '') {
|
|
395
|
+
// A bare marker is not a triage record. `missing` is the honest slot:
|
|
396
|
+
// the declaration names a mechanism it never supplies, and `missing`
|
|
397
|
+
// is what the `--check` ratchet reds on.
|
|
398
|
+
return {
|
|
399
|
+
resolution: 'missing',
|
|
400
|
+
note:
|
|
401
|
+
'instruction-only declared with no reason — a reason is a triage record, ' +
|
|
402
|
+
'not a pass. State in one line why this obligation is model-carried.',
|
|
403
|
+
};
|
|
404
|
+
}
|
|
405
|
+
return { resolution: 'none' };
|
|
406
|
+
}
|
|
407
|
+
|
|
382
408
|
const idx = decl.indexOf(':');
|
|
383
409
|
const kind = decl.slice(0, idx);
|
|
384
410
|
const target = decl.slice(idx + 1);
|
|
@@ -471,7 +497,10 @@ export function join_frequency(
|
|
|
471
497
|
if (declared.length === 0) {
|
|
472
498
|
return { verdict: 'unmeasured', carrier_frequency: null, gap_platforms: [] };
|
|
473
499
|
}
|
|
474
|
-
|
|
500
|
+
// `instruction-only:` is the same declared gap as `none`, with its reason
|
|
501
|
+
// attached; a rule that spelled it the new way must not become a frequency
|
|
502
|
+
// finding for doing so.
|
|
503
|
+
if (declared.every((d) => d === 'none' || d.startsWith('instruction-only:'))) {
|
|
475
504
|
return { verdict: 'declared-gap', carrier_frequency: null, gap_platforms: [] };
|
|
476
505
|
}
|
|
477
506
|
|
|
@@ -599,6 +628,12 @@ export interface Summary {
|
|
|
599
628
|
frequency_gap: number;
|
|
600
629
|
/** Rules with no `obligation_frequency` to join — the nine kernel rules. */
|
|
601
630
|
frequency_unclassified: number;
|
|
631
|
+
/**
|
|
632
|
+
* The denominator every figure above is taken over, WITH its frame. See
|
|
633
|
+
* {@link denominator_frames} for why the frame ships even when the two
|
|
634
|
+
* populations agree.
|
|
635
|
+
*/
|
|
636
|
+
frames: DenominatorFrames;
|
|
602
637
|
}
|
|
603
638
|
|
|
604
639
|
export function summarise(rows: RuleCoverage[]): Summary {
|
|
@@ -617,9 +652,83 @@ export function summarise(rows: RuleCoverage[]): Summary {
|
|
|
617
652
|
blocking_pct: rows.length === 0 ? 0 : Math.round((blocking / rows.length) * 1000) / 10,
|
|
618
653
|
frequency_gap: count((r) => r.frequency_verdict === 'gap'),
|
|
619
654
|
frequency_unclassified: count((r) => r.frequency_verdict === 'unclassified'),
|
|
655
|
+
frames: denominator_frames(rows.length),
|
|
620
656
|
};
|
|
621
657
|
}
|
|
622
658
|
|
|
659
|
+
/**
|
|
660
|
+
* The denominator, WITH the frame that produced it.
|
|
661
|
+
*
|
|
662
|
+
* WHY A FRAME AND NOT JUST A NUMBER. Until 2026-08-23 the tree published five
|
|
663
|
+
* different figures for one property — `docs/proof.md` carried an 86 and an 89
|
|
664
|
+
* for "rules that declare no backstop" in two places, a frontmatter grep said
|
|
665
|
+
* 87 and an any-line grep said 82 — and a reader had no way to tell which was
|
|
666
|
+
* the answer. The cause was not arithmetic. It was that every figure was
|
|
667
|
+
* quoted without saying WHICH population it was taken over: the resolver was
|
|
668
|
+
* once scoped narrower than the governed-rule corpus, so "in-scope" and
|
|
669
|
+
* "governed total" were genuinely different numbers, and prose copied one under
|
|
670
|
+
* a heading that meant the other.
|
|
671
|
+
*
|
|
672
|
+
* They agree today, because the resolver now reads the whole of `src/rules/`.
|
|
673
|
+
* That agreement is exactly why the frame must still be printed: a silent
|
|
674
|
+
* agreement is indistinguishable from a silent conflation, and the next
|
|
675
|
+
* narrowing of either side would reintroduce the plurality with nothing
|
|
676
|
+
* reporting it. So the two frames are computed from INDEPENDENT sources — this
|
|
677
|
+
* resolver's own row count, and `update_counts.count('rules')`, the same
|
|
678
|
+
* function that keeps the published artefact counts honest — and their
|
|
679
|
+
* agreement is asserted rather than assumed.
|
|
680
|
+
*/
|
|
681
|
+
export interface DenominatorFrames {
|
|
682
|
+
/** Rules this resolver actually resolved. Every percentage uses this frame. */
|
|
683
|
+
in_scope: number;
|
|
684
|
+
/** The governed-rule total, counted independently by `update_counts`. */
|
|
685
|
+
governed_total: number;
|
|
686
|
+
/** `false` means the two populations have diverged and prose must say which. */
|
|
687
|
+
agree: boolean;
|
|
688
|
+
/** Where the in-scope frame comes from, for a reader re-deriving it. */
|
|
689
|
+
source: string;
|
|
690
|
+
}
|
|
691
|
+
|
|
692
|
+
export function denominator_frames(
|
|
693
|
+
in_scope: number,
|
|
694
|
+
governed = (): number => count_artefacts('rules'),
|
|
695
|
+
): DenominatorFrames {
|
|
696
|
+
let governed_total: number;
|
|
697
|
+
try {
|
|
698
|
+
governed_total = governed();
|
|
699
|
+
} catch {
|
|
700
|
+
// An unreadable second source is reported as a divergence, never as
|
|
701
|
+
// agreement: "I could not check" and "they match" must not print alike.
|
|
702
|
+
governed_total = -1;
|
|
703
|
+
}
|
|
704
|
+
return {
|
|
705
|
+
in_scope,
|
|
706
|
+
governed_total,
|
|
707
|
+
agree: governed_total === in_scope,
|
|
708
|
+
source: 'src/rules/*.md',
|
|
709
|
+
};
|
|
710
|
+
}
|
|
711
|
+
|
|
712
|
+
/** The one sanctioned sentence for the denominator. Prose quotes this, never a literal. */
|
|
713
|
+
export function denominator_line(f: DenominatorFrames): string {
|
|
714
|
+
if (f.governed_total < 0) {
|
|
715
|
+
return (
|
|
716
|
+
`denominator: ${String(f.in_scope)} rule(s), frame in-scope (${f.source}) — ` +
|
|
717
|
+
`governed-total UNAVAILABLE, so agreement is unverified`
|
|
718
|
+
);
|
|
719
|
+
}
|
|
720
|
+
if (f.agree) {
|
|
721
|
+
return (
|
|
722
|
+
`denominator: ${String(f.in_scope)} rule(s), frame in-scope (${f.source}) ` +
|
|
723
|
+
`== governed-total ${String(f.governed_total)}`
|
|
724
|
+
);
|
|
725
|
+
}
|
|
726
|
+
return (
|
|
727
|
+
`denominator: ${String(f.in_scope)} rule(s) in-scope (${f.source}) vs ` +
|
|
728
|
+
`${String(f.governed_total)} governed-total — FRAMES DIVERGE, name the frame on every figure`
|
|
729
|
+
);
|
|
730
|
+
}
|
|
731
|
+
|
|
623
732
|
function main(argv: string[]): number {
|
|
624
733
|
const as_json = argv.includes('--json');
|
|
625
734
|
const check = argv.includes('--check');
|
|
@@ -702,6 +811,10 @@ function main(argv: string[]): number {
|
|
|
702
811
|
` frequency: ${summary.frequency_gap} gap · ${summary.frequency_unclassified} unclassified ` +
|
|
703
812
|
`(kernel — block_kernel_rule_writes denies the field)`,
|
|
704
813
|
);
|
|
814
|
+
// The denominator is published WITH its frame, and it is the only sanctioned
|
|
815
|
+
// source for that number: `check_enforcement_denominator` reds when a
|
|
816
|
+
// tracked doc carries an enforcement count this resolver did not produce.
|
|
817
|
+
lines.push(` ${denominator_line(summary.frames)}`);
|
|
705
818
|
|
|
706
819
|
const gaps = rows.filter((r) => r.frequency_verdict === 'gap');
|
|
707
820
|
if (gaps.length > 0) {
|