@event4u/agent-config 14.10.0 → 14.12.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.augment-plugin/marketplace.json +3 -3
- package/.augment-plugin/plugin.json +1 -1
- package/.claude-plugin/marketplace.json +1 -1
- package/CHANGELOG.md +161 -208
- package/README.md +1 -1
- package/dist/agent-src/commands/design.md +88 -0
- package/dist/agent-src/commands/project/analyze.md +47 -0
- package/dist/agent-src/commands/review/changes.md +67 -6
- package/dist/agent-src/commands/roadmap/create.md +49 -0
- package/dist/agent-src/commands/roadmap/next.md +27 -11
- package/dist/agent-src/commands/roadmap/process-full.md +14 -0
- package/dist/agent-src/commands/video/from-script.md +60 -3
- package/dist/agent-src/commands/video/stitch.md +14 -0
- package/dist/agent-src/contexts/communication/rules-auto/guidelines-mechanics.md +1 -0
- package/dist/agent-src/contexts/execution/evidence-discipline.md +26 -0
- package/dist/agent-src/contexts/execution/roadmap-process-loop.md +154 -2
- package/dist/agent-src/rules/active-remediation.md +3 -3
- package/dist/agent-src/rules/code-provenance.md +2 -2
- package/dist/agent-src/rules/context-hygiene.md +13 -33
- package/dist/agent-src/rules/council-availability.md +2 -2
- package/dist/agent-src/rules/decision-revisit-gate.md +3 -1
- package/dist/agent-src/rules/design-fidelity.md +18 -0
- package/dist/agent-src/rules/design-review-after-ui-write.md +2 -2
- package/dist/agent-src/rules/evaluator-independence.md +56 -44
- package/dist/agent-src/rules/fix-what-you-see.md +9 -1
- package/dist/agent-src/rules/framework-neutrality-in-generic-skills.md +1 -1
- package/dist/agent-src/rules/minimal-safe-diff.md +14 -20
- package/dist/agent-src/rules/missing-skill-recovery.md +13 -1
- package/dist/agent-src/rules/playbook-precedence.md +105 -0
- package/dist/agent-src/rules/recurring-criticism.md +3 -1
- package/dist/agent-src/rules/roadmap-progress-sync.md +14 -13
- package/dist/agent-src/rules/scale-discipline.md +24 -0
- package/dist/agent-src/rules/security-sensitive-stop.md +2 -2
- package/dist/agent-src/rules/settings-ask-protocol.md +2 -2
- package/dist/agent-src/rules/ui-audit-gate.md +27 -15
- package/dist/agent-src/rules/untrusted-input-defense.md +2 -2
- package/dist/agent-src/skills/accessibility-auditor/SKILL.md +19 -0
- package/dist/agent-src/skills/adr-create/SKILL.md +7 -0
- package/dist/agent-src/skills/agents-md-thin-root/SKILL.md +33 -0
- package/dist/agent-src/skills/ai-council/references/advanced-modes.md +17 -3
- package/dist/agent-src/skills/ai-council/references/output-and-synthesis.md +31 -0
- package/dist/agent-src/skills/ai-council/references/procedure.md +19 -0
- package/dist/agent-src/skills/alerting-doctrine/SKILL.md +225 -0
- package/dist/agent-src/skills/authz-review/SKILL.md +0 -1
- package/dist/agent-src/skills/blast-radius-analyzer/SKILL.md +32 -0
- package/dist/agent-src/skills/brand/SKILL.md +3 -0
- package/dist/agent-src/skills/brand-asset-generation/SKILL.md +3 -0
- package/dist/agent-src/skills/brand-audit/SKILL.md +3 -0
- package/dist/agent-src/skills/brand-identity/SKILL.md +3 -0
- package/dist/agent-src/skills/brand-strategy/SKILL.md +3 -0
- package/dist/agent-src/skills/brand-to-tokens/SKILL.md +3 -0
- package/dist/agent-src/skills/check-refs/SKILL.md +3 -0
- package/dist/agent-src/skills/code-refactoring/SKILL.md +45 -1
- package/dist/agent-src/skills/code-review/SKILL.md +75 -5
- package/dist/agent-src/skills/command-routing/SKILL.md +6 -0
- package/dist/agent-src/skills/command-writing/SKILL.md +35 -0
- package/dist/agent-src/skills/condense-memory/SKILL.md +3 -0
- package/dist/agent-src/skills/context-authoring/SKILL.md +1 -1
- package/dist/agent-src/skills/conventional-commits-writing/SKILL.md +3 -0
- package/dist/agent-src/skills/copilot-agents-optimization/SKILL.md +10 -0
- package/dist/agent-src/skills/corpus-grounding/SKILL.md +3 -0
- package/dist/agent-src/skills/design-intelligence/SKILL.md +3 -0
- package/dist/agent-src/skills/design-intelligence/data/landing.csv +36 -35
- package/dist/agent-src/skills/design-intelligence/data/stacks/threejs.csv +1 -0
- package/dist/agent-src/skills/design-review/SKILL.md +79 -1
- package/dist/agent-src/skills/design-review/references/verification-automation.md +41 -0
- package/dist/agent-src/skills/design-system-capture/SKILL.md +35 -40
- package/dist/agent-src/skills/design-system-capture/references/import-procedure.md +50 -0
- package/dist/agent-src/skills/design-tokens/SKILL.md +3 -0
- package/dist/agent-src/skills/design-variations/SKILL.md +3 -0
- package/dist/agent-src/skills/developer-like-execution/SKILL.md +3 -0
- package/dist/agent-src/skills/estimate-ticket/SKILL.md +3 -0
- package/dist/agent-src/skills/existing-ui-audit/SKILL.md +28 -4
- package/dist/agent-src/skills/fe-design/SKILL.md +74 -41
- package/dist/agent-src/skills/fe-design/references/craft-floor.md +52 -0
- package/dist/agent-src/skills/fe-design/references/source-led-port.md +36 -0
- package/dist/agent-src/skills/file-editor/SKILL.md +5 -0
- package/dist/agent-src/skills/finishing-a-development-branch/SKILL.md +2 -2
- package/dist/agent-src/skills/git-workflow/SKILL.md +3 -0
- package/dist/agent-src/skills/html-deck/SKILL.md +3 -0
- package/dist/agent-src/skills/iconography/SKILL.md +3 -0
- package/dist/agent-src/skills/image-editing/SKILL.md +3 -0
- package/dist/agent-src/skills/image-generation/SKILL.md +3 -0
- package/dist/agent-src/skills/image-provider-routing/SKILL.md +3 -0
- package/dist/agent-src/skills/incident-commander/SKILL.md +10 -0
- package/dist/agent-src/skills/js-library-packaging/SKILL.md +173 -0
- package/dist/agent-src/skills/js-library-packaging/scripts/check_package_surface.ts +270 -0
- package/dist/agent-src/skills/laravel-migration/SKILL.md +3 -0
- package/dist/agent-src/skills/learning-to-rule-or-skill/SKILL.md +3 -0
- package/dist/agent-src/skills/lint-skills/SKILL.md +3 -0
- package/dist/agent-src/skills/llm-provider-knowledge/SKILL.md +3 -0
- package/dist/agent-src/skills/logging-monitoring/SKILL.md +234 -51
- package/dist/agent-src/skills/logo-generation/SKILL.md +3 -0
- package/dist/agent-src/skills/md-language-check/SKILL.md +3 -0
- package/dist/agent-src/skills/monorepo-workspace/SKILL.md +149 -0
- package/dist/agent-src/skills/motion-choreographer/SKILL.md +6 -0
- package/dist/agent-src/skills/multi-tenancy/SKILL.md +4 -0
- package/dist/agent-src/skills/operational-readiness/SKILL.md +184 -0
- package/dist/agent-src/skills/override-management/SKILL.md +3 -0
- package/dist/agent-src/skills/persona-improvement/SKILL.md +3 -0
- package/dist/agent-src/skills/pest-testing/SKILL.md +3 -0
- package/dist/agent-src/skills/playbook-authoring/SKILL.md +162 -0
- package/dist/agent-src/skills/playwright-testing/SKILL.md +3 -0
- package/dist/agent-src/skills/privacy-review/SKILL.md +3 -0
- package/dist/agent-src/skills/project-analysis-core/SKILL.md +23 -0
- package/dist/agent-src/skills/prompt-engineering-image/SKILL.md +3 -0
- package/dist/agent-src/skills/quality-tools/SKILL.md +5 -0
- package/dist/agent-src/skills/react-shadcn-ui/SKILL.md +81 -33
- package/dist/agent-src/skills/readme-reviewer/SKILL.md +3 -0
- package/dist/agent-src/skills/readme-writing/SKILL.md +3 -0
- package/dist/agent-src/skills/readme-writing-package/SKILL.md +3 -0
- package/dist/agent-src/skills/receiving-code-review/SKILL.md +2 -2
- package/dist/agent-src/skills/refine-prompt/SKILL.md +3 -0
- package/dist/agent-src/skills/refine-ticket/SKILL.md +3 -0
- package/dist/agent-src/skills/requesting-code-review/SKILL.md +2 -2
- package/dist/agent-src/skills/review-routing/SKILL.md +2 -2
- package/dist/agent-src/skills/roadmap-writing/SKILL.md +23 -41
- package/dist/agent-src/skills/roadmap-writing/references/follow-up-roadmap-shape.md +47 -0
- package/dist/agent-src/skills/rtk-output-filtering/SKILL.md +22 -6
- package/dist/agent-src/skills/runway-cognition/SKILL.md +3 -0
- package/dist/agent-src/skills/scene-expander/scene-blueprint.schema.yaml +26 -0
- package/dist/agent-src/skills/secrets-management/SKILL.md +4 -0
- package/dist/agent-src/skills/server-hardening/SKILL.md +159 -0
- package/dist/agent-src/skills/skill-improvement-pipeline/SKILL.md +3 -0
- package/dist/agent-src/skills/skill-management/SKILL.md +3 -0
- package/dist/agent-src/skills/skill-reviewer/SKILL.md +3 -0
- package/dist/agent-src/skills/skill-writing/SKILL.md +6 -0
- package/dist/agent-src/skills/skill-writing/references/procedure.md +24 -2
- package/dist/agent-src/skills/spreadsheet-authoring/SKILL.md +3 -0
- package/dist/agent-src/skills/storybook-workshop/SKILL.md +203 -0
- package/dist/agent-src/skills/storybook-workshop/scripts/story_contrast_floor.ts +134 -0
- package/dist/agent-src/skills/subagent-orchestration/SKILL.md +1 -1
- package/dist/agent-src/skills/subagent-orchestration/prompts/README.md +25 -0
- package/dist/agent-src/skills/supply-chain-intake/SKILL.md +12 -0
- package/dist/agent-src/skills/systematic-debugging/SKILL.md +1 -1
- package/dist/agent-src/skills/terraform/SKILL.md +3 -0
- package/dist/agent-src/skills/test-driven-development/SKILL.md +1 -1
- package/dist/agent-src/skills/threat-modeling/SKILL.md +0 -3
- package/dist/agent-src/skills/token-optimizer/SKILL.md +3 -0
- package/dist/agent-src/skills/typography-system/SKILL.md +3 -0
- package/dist/agent-src/skills/ui-component-architect/SKILL.md +17 -1
- package/dist/agent-src/skills/upstream-contribute/SKILL.md +3 -0
- package/dist/agent-src/skills/validate-feature-fit/SKILL.md +3 -0
- package/dist/agent-src/skills/verify-completion-evidence/SKILL.md +2 -2
- package/dist/agent-src/skills/wireframe/SKILL.md +3 -0
- package/dist/agent-src/skills/wireframe/references/story-beat-ledger.schema.json +115 -0
- package/dist/agent-src/skills/workspace-link/SKILL.md +131 -0
- package/dist/agent-src/templates/agents/agent-project-settings.example.yml +1 -1
- package/dist/agent-src/templates/playbook.md +75 -0
- package/dist/agent-src/templates/roadmaps.md +37 -0
- package/dist/agent-src/templates/scripts/check_playbook_invokes.ts +231 -0
- package/dist/agent-src/templates/scripts/work_engine/directives/ui/apply.ts +24 -0
- package/dist/agent-src/templates/scripts/work_engine/directives/ui/polish.ts +2 -0
- package/dist/agent-src/templates/scripts/work_engine/directives/ui/review.ts +216 -0
- package/dist/agent-src/templates/scripts/work_engine/directives/ui/scaffold.ts +159 -0
- package/dist/agent-src/templates/scripts/work_engine/directives/ui/stack_bundles.ts +73 -4
- package/dist/agent-src/templates/scripts/work_engine/stack/detect.ts +325 -40
- package/dist/cli/commands/uiAudit.js +221 -0
- package/dist/cli/commands/uiRender.js +206 -0
- package/dist/cli/main.js +22 -1
- package/dist/cli/mcp/content.js +64 -1
- package/dist/cli/mcp/dispatch.js +175 -10
- package/dist/cli/registry.js +3 -0
- package/dist/cli-delegate/{chunk-G23AT6GD.js → chunk-DMSZHXZS.js} +57 -1
- package/dist/cli-delegate/{chunk-77GR3VD4.js → chunk-FF7WAFMR.js} +58 -3
- package/dist/cli-delegate/{chunk-YM4GZDJG.js → chunk-JCW7ZLHK.js} +10 -0
- package/dist/cli-delegate/{chunk-H4VIVD4C.js → chunk-JJA2QEWA.js} +413 -391
- package/dist/cli-delegate/{chunk-PLSG6UL5.js → chunk-K4FFODTS.js} +341 -204
- package/dist/cli-delegate/{chunk-B2ERU2VA.js → chunk-WOKWX5PL.js} +1 -1
- package/dist/cli-delegate/cmd_brand_status.js +8 -6
- package/dist/cli-delegate/cmd_conformance.js +3 -3
- package/dist/cli-delegate/cmd_doctor.js +3 -3
- package/dist/cli-delegate/cmd_export.js +4 -4
- package/dist/cli-delegate/cmd_handoff.js +1 -1
- package/dist/cli-delegate/cmd_preflight.js +2 -2
- package/dist/cli-delegate/cmd_prune.js +4 -4
- package/dist/cli-delegate/cmd_session_recycle.js +70 -9
- package/dist/cli-delegate/cmd_settings_migrate.js +4 -4
- package/dist/cli-delegate/cmd_settings_set.js +1 -1
- package/dist/cli-delegate/cmd_sync.js +4 -4
- package/dist/cli-delegate/cmd_uninstall.js +4 -4
- package/dist/cli-delegate/cmd_validate.js +4 -4
- package/dist/discovery/deprecation-report.md +1 -1
- package/dist/discovery/discovery-manifest.json +362 -127
- package/dist/discovery/discovery-manifest.json.sha256 +1 -1
- package/dist/discovery/discovery-manifest.summary.md +4 -4
- package/dist/discovery/dormancy-report.md +1 -1
- package/dist/discovery/orphan-report.md +1 -1
- package/dist/discovery/packs.json +18 -8
- package/dist/discovery/trust-report.md +3 -3
- package/dist/discovery/workspaces.json +16 -6
- package/dist/hooks/dispatch.js +2575 -1472
- package/dist/install/install.mjs +800 -708
- package/dist/mcp/registry-manifest.json +3 -3
- package/dist/mcp/server.json +2 -2
- package/dist/mcp/server.mjs +1685 -1250
- package/dist/router.json +1 -1
- package/dist/scripts/_lib/lean_projection_mode.js +40 -0
- package/dist/scripts/_lib/scoped_projection.js +84 -0
- package/dist/scripts/_lib/ui_surface.js +89 -0
- package/dist/scripts/condense.js +6 -10
- package/dist/scripts/project_thin_rules.js +40 -2
- package/dist/server/schemas/settings.js +6 -0
- package/dist/shared/skillRanking.js +159 -0
- package/docs/contracts/provider-lifecycle.md +47 -18
- package/docs/contracts/settings-classes.md +35 -5
- package/docs/guidelines/agent-infra/context-hygiene-mechanics.md +49 -0
- package/docs/guidelines/agent-infra/downstream-changes-mechanics.md +91 -0
- package/docs/guidelines/agent-infra/evaluator-independence-mechanics.md +92 -0
- package/docs/guidelines/agent-infra/minimal-safe-diff-mechanics.md +45 -1
- package/docs/guidelines/agent-infra/roadmap-deferred-resolution-provenance.md +54 -0
- package/docs/guidelines/code-clarity.md +21 -0
- package/docs/guidelines/design-antipatterns.md +4 -2
- package/docs/guidelines/design-asset-discipline.md +38 -0
- package/docs/guidelines/design-fidelity-mechanics.md +45 -29
- package/docs/guidelines/design-handover-extraction.md +35 -5
- package/docs/guidelines/design-modes.md +41 -1
- package/docs/guidelines/monorepo-antipatterns.md +141 -0
- package/docs/guidelines/redundancy-taxonomy.md +180 -0
- package/llms.txt +50 -39
- package/package.json +6 -2
- package/src/agent-src/templates/scripts/check_playbook_invokes.ts +231 -0
- package/src/agent-src/templates/scripts/work_engine/directives/ui/apply.ts +24 -0
- package/src/agent-src/templates/scripts/work_engine/directives/ui/polish.ts +2 -0
- package/src/agent-src/templates/scripts/work_engine/directives/ui/review.ts +216 -0
- package/src/agent-src/templates/scripts/work_engine/directives/ui/scaffold.ts +159 -0
- package/src/agent-src/templates/scripts/work_engine/directives/ui/stack_bundles.ts +73 -4
- package/src/agent-src/templates/scripts/work_engine/stack/detect.ts +325 -40
- package/src/config/agent-settings.template.yml +44 -0
- package/src/config/assurance-capability-registry.json +223 -0
- package/src/config/assurance-threshold-budget.json +65 -0
- package/src/config/budgets.yml +19 -0
- package/src/config/ci-local-parity.yml +29 -0
- package/src/config/discovery/prompt-patterns.yml +56 -0
- package/src/config/discovery/unassigned-artefacts.yml +2 -0
- package/src/config/dispatch-economy-metrics.json +4 -2
- package/src/config/estate-count-budget.json +8 -3
- package/src/config/evaluator-budgets.json +14 -14
- package/src/config/gate-coverage.yml +392 -8
- package/src/config/gate-violation-baselines.json +76 -72
- package/src/config/hook-latency-budget.json +1 -0
- package/src/config/hook-token-budget.json +137 -125
- package/src/config/pack-size-budget.json +39 -10
- package/src/config/preamble-payload-budget.json +97 -71
- package/src/config/quorum-attendance-budget.json +12 -4
- package/src/config/routing-coverage-seed.json +29 -0
- package/src/config/rule-activation-census.json +7 -3
- package/src/config/rule-enforcement-baseline.json +0 -1
- package/src/config/rule-stub-ceilings.json +112 -91
- package/src/config/suggestion-capture.json +28 -0
- package/src/config/surface-matrix.yml +21 -2
- package/src/config/web-launch-readiness.json +188 -0
- package/src/scripts/_cli/cmd_doctor.ts +15 -16
- package/src/scripts/_cli/doctor_install_mode.ts +49 -0
- package/src/scripts/_cli/doctor_overrides.ts +154 -0
- package/src/scripts/_dispatch.bash +17 -0
- package/src/scripts/_lib/as_of.ts +412 -0
- package/src/scripts/_lib/exec_evidence.ts +7 -0
- package/src/scripts/_lib/gate_baseline.ts +150 -1
- package/src/scripts/_lib/hook_settings.ts +33 -0
- package/src/scripts/_lib/host_listing_model.ts +192 -0
- package/src/scripts/_lib/lean_projection_mode.ts +44 -0
- package/src/scripts/_lib/mcp_bridge.ts +199 -0
- package/src/scripts/_lib/review_independence.ts +62 -10
- package/src/scripts/_lib/rule_injection.ts +239 -0
- package/src/scripts/_lib/run_checkpoint.ts +54 -1
- package/src/scripts/_lib/scoped_projection.ts +96 -0
- package/src/scripts/_lib/session_register.ts +44 -2
- package/src/scripts/_lib/skill_catalogue.ts +38 -2
- package/src/scripts/_lib/skill_estate.ts +115 -0
- package/src/scripts/_lib/transcript_reads.ts +207 -0
- package/src/scripts/_lib/ui_authority.ts +343 -0
- package/src/scripts/ai-video/adapters/fal.sh +8 -3
- package/src/scripts/ai-video/adapters/gemini-veo.sh +10 -0
- package/src/scripts/ai-video/adapters/higgsfield.sh +10 -2
- package/src/scripts/ai-video/adapters/kling.sh +10 -0
- package/src/scripts/ai-video/adapters/sora.sh +10 -0
- package/src/scripts/ai-video/lib/calibrate-cost.sh +145 -0
- package/src/scripts/ai-video/lib/model-capabilities/README.md +53 -7
- package/src/scripts/ai-video/lib/model-capabilities/comfyui.json +15 -3
- package/src/scripts/ai-video/lib/model-capabilities/fal.json +36 -6
- package/src/scripts/ai-video/lib/model-capabilities/gemini-veo.json +23 -0
- package/src/scripts/ai-video/lib/model-capabilities/higgsfield.json +23 -0
- package/src/scripts/ai-video/lib/model-capabilities/kling.json +23 -0
- package/src/scripts/ai-video/lib/model-capabilities/musetalk.json +8 -2
- package/src/scripts/ai-video/lib/model-capabilities/replicate.json +36 -6
- package/src/scripts/ai-video/lib/model-capabilities/sora.json +45 -0
- package/src/scripts/ai-video/lib/model-capabilities/syncso.json +8 -2
- package/src/scripts/ai-video/lib/parse-blueprint.sh +52 -5
- package/src/scripts/ai-video/lib/resume-scan.sh +92 -3
- package/src/scripts/ai-video/lib/seam-plan.sh +212 -0
- package/src/scripts/ai-video/smoke-trace.sh +450 -2
- package/src/scripts/ai-video/stitch.sh +191 -10
- package/src/scripts/ai-video/test-pipeline.sh +84 -6
- package/src/scripts/ai_council/argument_exhaustion.ts +130 -0
- package/src/scripts/ai_council/cli_agency_bounds.ts +139 -0
- package/src/scripts/ai_council/cli_least_agency_canary.ts +347 -0
- package/src/scripts/ai_council/clients.ts +3 -2
- package/src/scripts/ai_council/consensus.ts +63 -6
- package/src/scripts/ai_council/events_log.ts +46 -1
- package/src/scripts/ai_council/orchestrator.ts +103 -108
- package/src/scripts/ai_council/orchestrator_results.ts +166 -0
- package/src/scripts/ai_council/prompts.ts +12 -5
- package/src/scripts/ai_council/quorum.ts +82 -1
- package/src/scripts/ai_council/quorum_wiring.ts +82 -5
- package/src/scripts/ai_council/stance_tally.ts +22 -0
- package/src/scripts/bench_hook_latency.ts +62 -0
- package/src/scripts/build_proof.ts +12 -1
- package/src/scripts/capture_skill_catalogue.ts +21 -0
- package/src/scripts/check_always_budget.ts +2 -1
- package/src/scripts/check_augmentignore.ts +2 -1
- package/src/scripts/check_beta_review_markers.ts +2 -1
- package/src/scripts/check_bundle_path_leakage.ts +162 -7
- package/src/scripts/check_command_examples.ts +557 -0
- package/src/scripts/check_composite_arming.ts +364 -0
- package/src/scripts/check_corpus_staleness.ts +2 -1
- package/src/scripts/check_council_pin_staleness.ts +3 -1
- package/src/scripts/check_enforcement_coverage.ts +116 -3
- package/src/scripts/check_enforcement_denominator.ts +365 -0
- package/src/scripts/check_estate_count.ts +122 -3
- package/src/scripts/check_gate_coverage.ts +2 -1
- package/src/scripts/check_hook_bundle_freshness.ts +13 -1
- package/src/scripts/check_knowledge_cards.ts +2 -1
- package/src/scripts/check_knowledge_pages.ts +3 -2
- package/src/scripts/check_memory.ts +2 -1
- package/src/scripts/check_no_automerge_key.ts +287 -0
- package/src/scripts/check_pack_conformance_fixture.ts +565 -0
- package/src/scripts/check_preamble_payload_budget.ts +30 -3
- package/src/scripts/check_proposal.ts +2 -1
- package/src/scripts/check_reach_staleness.ts +2 -1
- package/src/scripts/check_release_adjacent_health.ts +2 -1
- package/src/scripts/check_release_pr_shape.ts +5 -0
- package/src/scripts/check_review_schema.ts +34 -1
- package/src/scripts/check_roadmap_trackable.ts +48 -3
- package/src/scripts/check_routing_coverage.ts +352 -0
- package/src/scripts/check_score_contract.ts +505 -0
- package/src/scripts/check_skill_admissions.ts +514 -0
- package/src/scripts/check_source_size_budget.ts +2 -1
- package/src/scripts/check_standing_payload_delta.ts +505 -0
- package/src/scripts/check_trigger_evals.ts +2 -1
- package/src/scripts/check_web_launch_readiness.ts +705 -0
- package/src/scripts/classify_change_risk.ts +281 -0
- package/src/scripts/compute_skill_tiers.ts +186 -0
- package/src/scripts/condense.ts +8 -13
- package/src/scripts/council_attendance_metrics.ts +183 -0
- package/src/scripts/council_cli.ts +10 -8
- package/src/scripts/council_parse_rate.ts +116 -0
- package/src/scripts/derive_playbooks.ts +406 -0
- package/src/scripts/description_route_check.ts +494 -0
- package/src/scripts/design_slop_rules.ts +56 -2
- package/src/scripts/dispatch_r2_reviewer.ts +16 -0
- package/src/scripts/frontend_corpus_hash.ts +116 -0
- package/src/scripts/grade_target_readiness.ts +478 -0
- package/src/scripts/hook_manifest.json +1 -1
- package/src/scripts/hook_manifest.yaml +124 -16
- package/src/scripts/hooks/concern_registry.ts +6 -0
- package/src/scripts/hooks/design_pass_hook.ts +356 -0
- package/src/scripts/hooks/rtk_wrap_hook.ts +30 -7
- package/src/scripts/hooks/rule_inject_hook.ts +318 -0
- package/src/scripts/hooks/suggestion_capture_hook.ts +368 -0
- package/src/scripts/hot_context_hook.ts +74 -7
- package/src/scripts/install.ts +40 -89
- package/src/scripts/lint_adapter_tier.ts +663 -0
- package/src/scripts/lint_archived_skills.ts +93 -0
- package/src/scripts/lint_budget_ownership.ts +56 -5
- package/src/scripts/lint_deterministic_time.ts +470 -0
- package/src/scripts/lint_framework_leakage.ts +5 -0
- package/src/scripts/lint_handoffs.ts +525 -1
- package/src/scripts/lint_judge_prompt_expectation.ts +155 -0
- package/src/scripts/lint_marketplace.ts +88 -0
- package/src/scripts/lint_media_policy_linkage.ts +140 -1
- package/src/scripts/lint_one_off_age.ts +6 -1
- package/src/scripts/lint_override_kernel_guard.ts +87 -5
- package/src/scripts/lint_roadmap_complexity.ts +56 -0
- package/src/scripts/lint_rule_enforcement_declaration.ts +24 -7
- package/src/scripts/lint_rule_norm_pin.ts +321 -0
- package/src/scripts/lint_skill_trigger_corpus.ts +349 -0
- package/src/scripts/lint_spawn_payload.ts +42 -5
- package/src/scripts/lint_symptom_intake.ts +2 -1
- package/src/scripts/mcp_parity_smoke.ts +30 -4
- package/src/scripts/mcp_render.ts +66 -1
- package/src/scripts/mcp_tool_fingerprint.ts +241 -0
- package/src/scripts/measure_risk_class_drift.ts +140 -0
- package/src/scripts/measure_skill_ranker_baseline.ts +212 -0
- package/src/scripts/media/lib/adapter-common.sh +211 -1
- package/src/scripts/media/lib/adapter-contract.md +74 -6
- package/src/scripts/model_rule_injection.ts +907 -0
- package/src/scripts/pack_install_smoke.ts +363 -0
- package/src/scripts/pr_conflict_census.ts +187 -0
- package/src/scripts/project_thin_rules.ts +45 -2
- package/src/scripts/release.ts +66 -860
- package/src/scripts/release_drill.ts +59 -3
- package/src/scripts/release_env.ts +298 -0
- package/src/scripts/release_publication.ts +720 -0
- package/src/scripts/report_pack_delta.ts +204 -0
- package/src/scripts/roadmap_context.ts +778 -0
- package/src/scripts/schemas/fidelity-measurement-sheet.schema.json +169 -0
- package/src/scripts/schemas/rule.schema.json +24 -2
- package/src/scripts/schemas/skill.schema.json +39 -0
- package/src/scripts/schemas/ui-authority.schema.json +114 -0
- package/src/scripts/select_analysis_mode.ts +112 -0
- package/src/scripts/session_register_hook.ts +29 -3
- package/src/scripts/sessions_cli.ts +67 -3
- package/src/scripts/skill_tools/score_skill_relevance.ts +36 -53
- package/src/scripts/sync_pr_branch.ts +40 -1
- package/src/scripts/token_sink_report.ts +239 -0
- package/src/scripts/trigger_coverage.ts +122 -3
- package/src/scripts/update_counts.ts +7 -3
- package/src/scripts/validate_frontmatter.ts +66 -0
- package/src/server/schemas/settings.ts +10 -0
- package/src/shared/skillRanking.ts +183 -0
- package/dist/agent-src/skills/accessibility-auditor/evals/evals.json +0 -15
- package/dist/agent-src/skills/agent-security-review/evals/triggers.json +0 -52
- package/dist/agent-src/skills/ai-code-blindspots/evals/triggers.json +0 -52
- package/dist/agent-src/skills/analysis-skill-router/evals/evals.json +0 -13
- package/dist/agent-src/skills/brand/evals/triggers.json +0 -17
- package/dist/agent-src/skills/brand-asset-generation/evals/triggers.json +0 -17
- package/dist/agent-src/skills/brand-audit/evals/triggers.json +0 -17
- package/dist/agent-src/skills/brand-identity/evals/triggers.json +0 -17
- package/dist/agent-src/skills/brand-strategy/evals/triggers.json +0 -17
- package/dist/agent-src/skills/brand-to-tokens/evals/triggers.json +0 -17
- package/dist/agent-src/skills/bug-analyzer/evals/evals.json +0 -13
- package/dist/agent-src/skills/canvas-design/evals/triggers.json +0 -17
- package/dist/agent-src/skills/character-consistency/evals/evals.json +0 -16
- package/dist/agent-src/skills/code-intelligence/evals/triggers.json +0 -52
- package/dist/agent-src/skills/code-review/evals/evals.json +0 -100
- package/dist/agent-src/skills/command-routing/evals/evals.json +0 -14
- package/dist/agent-src/skills/complexity-first-planning/evals/triggers.json +0 -17
- package/dist/agent-src/skills/contract-review/evals/triggers.json +0 -17
- package/dist/agent-src/skills/conventional-commits-writing/evals/evals.json +0 -15
- package/dist/agent-src/skills/corpus-grounding/evals/triggers.json +0 -17
- package/dist/agent-src/skills/dashboard-design/evals/evals.json +0 -16
- package/dist/agent-src/skills/dcf-modeling/evals/domain-truth.json +0 -29
- package/dist/agent-src/skills/dcf-modeling/evals/evals.json +0 -20
- package/dist/agent-src/skills/decision-record/evals/evals.json +0 -20
- package/dist/agent-src/skills/decision-record/evals/triggers.json +0 -87
- package/dist/agent-src/skills/design-intelligence/evals/evals.json +0 -14
- package/dist/agent-src/skills/design-intelligence/evals/triggers.json +0 -17
- package/dist/agent-src/skills/design-system-capture/evals/evals.json +0 -15
- package/dist/agent-src/skills/design-tokens/evals/triggers.json +0 -17
- package/dist/agent-src/skills/design-variations/evals/triggers.json +0 -17
- package/dist/agent-src/skills/developer-like-execution/evals/evals.json +0 -16
- package/dist/agent-src/skills/doc-coauthoring/evals/evals.json +0 -16
- package/dist/agent-src/skills/doc-coauthoring/evals/triggers.json +0 -17
- package/dist/agent-src/skills/docx-authoring/evals/triggers.json +0 -52
- package/dist/agent-src/skills/dpa-review/evals/triggers.json +0 -17
- package/dist/agent-src/skills/editorial-calendar/evals/domain-truth.json +0 -16
- package/dist/agent-src/skills/editorial-calendar/evals/evals.json +0 -16
- package/dist/agent-src/skills/eloquent/evals/triggers.json +0 -17
- package/dist/agent-src/skills/estimate-ticket/evals/evals.json +0 -16
- package/dist/agent-src/skills/estimate-ticket/evals/output-schema.yml +0 -20
- package/dist/agent-src/skills/estimate-ticket/evals/triggers.json +0 -19
- package/dist/agent-src/skills/evaluate-llm-feature/evals/triggers.json +0 -52
- package/dist/agent-src/skills/existing-ui-audit/evals/triggers.json +0 -47
- package/dist/agent-src/skills/experiment-loop/evals/output-schema.yml +0 -27
- package/dist/agent-src/skills/experiment-loop/evals/triggers.json +0 -17
- package/dist/agent-src/skills/fe-design/evals/triggers.json +0 -55
- package/dist/agent-src/skills/forecasting/evals/domain-truth.json +0 -29
- package/dist/agent-src/skills/forecasting/evals/evals.json +0 -20
- package/dist/agent-src/skills/forensics-report/evals/triggers.json +0 -17
- package/dist/agent-src/skills/frontend-render-security/evals/triggers.json +0 -52
- package/dist/agent-src/skills/fundraising-narrative/evals/domain-truth.json +0 -16
- package/dist/agent-src/skills/fundraising-narrative/evals/evals.json +0 -16
- package/dist/agent-src/skills/gated-reach/evals/triggers.json +0 -72
- package/dist/agent-src/skills/github-ci/evals/evals.json +0 -25
- package/dist/agent-src/skills/history-design/evals/triggers.json +0 -17
- package/dist/agent-src/skills/html-deck/evals/triggers.json +0 -17
- package/dist/agent-src/skills/humanizer/evals/strip_fixtures.json +0 -57
- package/dist/agent-src/skills/humanizer/evals/triggers.json +0 -17
- package/dist/agent-src/skills/iconography/evals/triggers.json +0 -17
- package/dist/agent-src/skills/image-analyser/evals/triggers.json +0 -17
- package/dist/agent-src/skills/image-creator/evals/triggers.json +0 -17
- package/dist/agent-src/skills/image-editing/evals/triggers.json +0 -17
- package/dist/agent-src/skills/image-generation/evals/triggers.json +0 -17
- package/dist/agent-src/skills/image-provider-routing/evals/triggers.json +0 -17
- package/dist/agent-src/skills/incident-commander/evals/domain-truth.json +0 -16
- package/dist/agent-src/skills/incident-commander/evals/evals.json +0 -20
- package/dist/agent-src/skills/judge-artifact-completeness/evals/triggers.json +0 -17
- package/dist/agent-src/skills/judge-injection-defense/evals/triggers.json +0 -17
- package/dist/agent-src/skills/judge-synthesis/evals/triggers.json +0 -17
- package/dist/agent-src/skills/launch-readiness/evals/evals.json +0 -21
- package/dist/agent-src/skills/learning-tutor/evals/triggers.json +0 -52
- package/dist/agent-src/skills/legal-intake-triage/evals/triggers.json +0 -17
- package/dist/agent-src/skills/legal-practice-profile/evals/triggers.json +0 -17
- package/dist/agent-src/skills/license-compliance-audit/evals/triggers.json +0 -52
- package/dist/agent-src/skills/license-compliance-borrow-check/evals/triggers.json +0 -52
- package/dist/agent-src/skills/license-compliance-credits/evals/triggers.json +0 -52
- package/dist/agent-src/skills/llm-provider-knowledge/evals/triggers.json +0 -20
- package/dist/agent-src/skills/logging-monitoring/evals/evals.json +0 -16
- package/dist/agent-src/skills/logo-generation/evals/triggers.json +0 -17
- package/dist/agent-src/skills/messaging-architecture/evals/domain-truth.json +0 -16
- package/dist/agent-src/skills/messaging-architecture/evals/evals.json +0 -16
- package/dist/agent-src/skills/nda-triage/evals/triggers.json +0 -17
- package/dist/agent-src/skills/pdf-tools/evals/triggers.json +0 -52
- package/dist/agent-src/skills/perf-feedback-craft/evals/evals.json +0 -16
- package/dist/agent-src/skills/persona-improvement/evals/triggers.json +0 -52
- package/dist/agent-src/skills/php-coder/evals/triggers.json +0 -17
- package/dist/agent-src/skills/prediction-pool-optimizer/evals/triggers.json +0 -21
- package/dist/agent-src/skills/prompt-engineering-image/evals/triggers.json +0 -17
- package/dist/agent-src/skills/prompt-engineering-patterns/evals/evals.json +0 -16
- package/dist/agent-src/skills/prompt-validator/evals/triggers.json +0 -17
- package/dist/agent-src/skills/quality-tools/evals/evals.json +0 -15
- package/dist/agent-src/skills/reasoning-orchestrator/evals/triggers.json +0 -17
- package/dist/agent-src/skills/refine-prompt/evals/evals.json +0 -16
- package/dist/agent-src/skills/refine-ticket/evals/evals.json +0 -16
- package/dist/agent-src/skills/refine-ticket/evals/output-schema.yml +0 -16
- package/dist/agent-src/skills/refine-ticket/evals/triggers.json +0 -17
- package/dist/agent-src/skills/release-comms/evals/evals.json +0 -16
- package/dist/agent-src/skills/rice-prioritization/evals/evals.json +0 -20
- package/dist/agent-src/skills/runway-cognition/evals/domain-truth.json +0 -29
- package/dist/agent-src/skills/runway-cognition/evals/evals.json +0 -20
- package/dist/agent-src/skills/scenario-modeling/evals/domain-truth.json +0 -29
- package/dist/agent-src/skills/scenario-modeling/evals/evals.json +0 -20
- package/dist/agent-src/skills/schema-review/evals/triggers.json +0 -17
- package/dist/agent-src/skills/screenshot-hygiene/evals/triggers.json +0 -52
- package/dist/agent-src/skills/security-maturity-assessment/evals/triggers.json +0 -52
- package/dist/agent-src/skills/skill-writing/evals/triggers.json +0 -17
- package/dist/agent-src/skills/spreadsheet-authoring/evals/triggers.json +0 -47
- package/dist/agent-src/skills/subagent-orchestration/evals/evals.json +0 -60
- package/dist/agent-src/skills/supply-chain-intake/evals/triggers.json +0 -52
- package/dist/agent-src/skills/systematic-debugging/evals/evals.json +0 -20
- package/dist/agent-src/skills/test-case-discovery/evals/triggers.json +0 -52
- package/dist/agent-src/skills/test-driven-development/evals/evals.json +0 -16
- package/dist/agent-src/skills/threat-modeling/evals/evals.json +0 -21
- package/dist/agent-src/skills/typography-system/evals/evals.json +0 -14
- package/dist/agent-src/skills/typography-system/evals/triggers.json +0 -17
- package/dist/agent-src/skills/unit-economics-modeling/evals/domain-truth.json +0 -40
- package/dist/agent-src/skills/unit-economics-modeling/evals/evals.json +0 -24
- package/dist/agent-src/skills/verify-completion-evidence/evals/evals.json +0 -16
- package/dist/agent-src/skills/verify-repair-loop/evals/output-schema.yml +0 -20
- package/dist/agent-src/skills/verify-repair-loop/evals/triggers.json +0 -17
- package/dist/agent-src/skills/vision-articulation/evals/evals.json +0 -16
- package/dist/agent-src/skills/voice-and-tone-design/evals/evals.json +0 -16
- package/dist/agent-src/skills/wireframe/evals/triggers.json +0 -17
- package/dist/agent-src/skills/worktree-lifecycle/evals/evals.json +0 -38
- package/dist/agent-src/skills/worktree-lifecycle/evals/triggers.json +0 -52
- package/dist/cli/agent-config.js.map +0 -1
- package/dist/cli/bash/runBash.js.map +0 -1
- package/dist/cli/commands/commands.js.map +0 -1
- package/dist/cli/commands/config.js.map +0 -1
- package/dist/cli/commands/doctorShell.js.map +0 -1
- package/dist/cli/commands/mcpServer.js.map +0 -1
- package/dist/cli/commands/packs.js.map +0 -1
- package/dist/cli/commands/profiles.js.map +0 -1
- package/dist/cli/commands/recordTriggerEval.js.map +0 -1
- package/dist/cli/commands/rtkDetect.js.map +0 -1
- package/dist/cli/commands/settings.js.map +0 -1
- package/dist/cli/commands/uiServe.js.map +0 -1
- package/dist/cli/commands/versions.js.map +0 -1
- package/dist/cli/commands/workspaces.js.map +0 -1
- package/dist/cli/configRoot.js.map +0 -1
- package/dist/cli/discovery/loadManifest.js.map +0 -1
- package/dist/cli/firstRunNotice.js.map +0 -1
- package/dist/cli/help.js.map +0 -1
- package/dist/cli/initRouting.js.map +0 -1
- package/dist/cli/log/logger.js.map +0 -1
- package/dist/cli/main.js.map +0 -1
- package/dist/cli/mcp/content.js.map +0 -1
- package/dist/cli/mcp/dispatch.js.map +0 -1
- package/dist/cli/mcp/stdio.js.map +0 -1
- package/dist/cli/paths.js.map +0 -1
- package/dist/cli/python/knowledge_ingest.js.map +0 -1
- package/dist/cli/python/workspace_analytics.js.map +0 -1
- package/dist/cli/python/workspace_crypto.js.map +0 -1
- package/dist/cli/python/workspace_documents.js.map +0 -1
- package/dist/cli/python/workspace_drive.js.map +0 -1
- package/dist/cli/python/workspace_drive_health.js.map +0 -1
- package/dist/cli/python/workspace_explain.js.map +0 -1
- package/dist/cli/python/workspace_hosts.js.map +0 -1
- package/dist/cli/python/workspace_inbox.js.map +0 -1
- package/dist/cli/python/workspace_render.js.map +0 -1
- package/dist/cli/python/workspace_roles.js.map +0 -1
- package/dist/cli/python/workspace_secrets.js.map +0 -1
- package/dist/cli/python/workspace_sessions.js.map +0 -1
- package/dist/cli/python/workspace_skills.js.map +0 -1
- package/dist/cli/registry.js.map +0 -1
- package/dist/install/agentSwitchDetection.js.map +0 -1
- package/dist/install/agentSwitchProfile.js.map +0 -1
- package/dist/install/atomic.js.map +0 -1
- package/dist/install/claudePathsPlan.js.map +0 -1
- package/dist/install/conflict.js.map +0 -1
- package/dist/install/detect.js.map +0 -1
- package/dist/install/emit_host_rules_cli.js.map +0 -1
- package/dist/install/globalRuleLayers.js.map +0 -1
- package/dist/install/hostLayerFingerprint.js.map +0 -1
- package/dist/install/partitionEligibility.js.map +0 -1
- package/dist/install/paths.js.map +0 -1
- package/dist/install/plan.js.map +0 -1
- package/dist/install/preflight.js.map +0 -1
- package/dist/install/rtkDetection.js.map +0 -1
- package/dist/install/ruleInScope.js.map +0 -1
- package/dist/install/ruleLayerPartition.js.map +0 -1
- package/dist/install/rule_scope.js.map +0 -1
- package/dist/install/rule_scope_cli.js.map +0 -1
- package/dist/install/selectedTools.js.map +0 -1
- package/dist/install/toolDetection.js.map +0 -1
- package/dist/install/txlog.js.map +0 -1
- package/dist/install/types.js.map +0 -1
- package/dist/install/wizard-plan.js.map +0 -1
- package/dist/install/wizardDismissals.js.map +0 -1
- package/dist/scripts/_lib/agent_settings.js.map +0 -1
- package/dist/scripts/_lib/agent_src.js.map +0 -1
- package/dist/scripts/_lib/claude_builtin_names.js.map +0 -1
- package/dist/scripts/_lib/claude_plugin.js.map +0 -1
- package/dist/scripts/_lib/claude_settings_hooks.js.map +0 -1
- package/dist/scripts/_lib/compile_time_toggles.js.map +0 -1
- package/dist/scripts/_lib/environment_detector.js.map +0 -1
- package/dist/scripts/_lib/host_launch.js.map +0 -1
- package/dist/scripts/_lib/install_layout.js.map +0 -1
- package/dist/scripts/_lib/installed_lock.js.map +0 -1
- package/dist/scripts/_lib/model_tier.js.map +0 -1
- package/dist/scripts/_lib/prune_empty_dirs.js.map +0 -1
- package/dist/scripts/_lib/scoped_projection.js.map +0 -1
- package/dist/scripts/_lib/script_output.js.map +0 -1
- package/dist/scripts/_lib/spawn_env.js.map +0 -1
- package/dist/scripts/_lib/surface_tiers.js.map +0 -1
- package/dist/scripts/_lib/token_count.js.map +0 -1
- package/dist/scripts/_lib/trigger_eval_floors.js.map +0 -1
- package/dist/scripts/_lib/user_global_paths.js.map +0 -1
- package/dist/scripts/ai_council/modes.js.map +0 -1
- package/dist/scripts/ai_council/transport_resolver.js.map +0 -1
- package/dist/scripts/condense.js.map +0 -1
- package/dist/scripts/project_thin_rules.js.map +0 -1
- package/dist/server/app.js.map +0 -1
- package/dist/server/io/atomicMultiWrite.js.map +0 -1
- package/dist/server/io/atomicWrite.js.map +0 -1
- package/dist/server/io/sharedWriteCheck.js.map +0 -1
- package/dist/server/io/substituteTemplate.js.map +0 -1
- package/dist/server/io/yamlIO.js.map +0 -1
- package/dist/server/nicknameResolver.js.map +0 -1
- package/dist/server/port.js.map +0 -1
- package/dist/server/routes/discovery.js.map +0 -1
- package/dist/server/routes/install.js.map +0 -1
- package/dist/server/routes/ping.js.map +0 -1
- package/dist/server/routes/schema.js.map +0 -1
- package/dist/server/routes/settings.js.map +0 -1
- package/dist/server/routes/settingsChanges.js.map +0 -1
- package/dist/server/routes/userMd.js.map +0 -1
- package/dist/server/routes/wizard.js.map +0 -1
- package/dist/server/routes/workspace.js.map +0 -1
- package/dist/server/schemas/settings.js.map +0 -1
- package/dist/server/serverInfo.js.map +0 -1
- package/dist/server/token.js.map +0 -1
- package/dist/server/writeRoot.js.map +0 -1
- package/dist/shared/capabilities.js.map +0 -1
- package/dist/shared/interactiveContext.js.map +0 -1
- package/dist/shared/nicknamePrefill.js.map +0 -1
- package/dist/shared/settingsAsks.js.map +0 -1
- package/dist/shared/settingsCarveOut.js.map +0 -1
- package/dist/shared/settingsClasses.js.map +0 -1
- package/dist/shared/settingsConsent.js.map +0 -1
- package/dist/shared/settingsSurface.js.map +0 -1
- package/dist/shared/userMd/formAdapter.js.map +0 -1
- package/dist/shared/userMd/schema.js.map +0 -1
- package/dist/shared/userMd/utils.js.map +0 -1
- package/dist/ui/assets/index-Cxgy63kz.js.map +0 -1
- package/src/scripts/_lib/adr_frontmatter.test.ts +0 -365
- package/src/scripts/_lib/adversarial_council_gate.test.ts +0 -112
- package/src/scripts/_lib/adversarial_reconcile.test.ts +0 -197
- package/src/scripts/_lib/auto_dispatch.corpus.test.ts +0 -150
- package/src/scripts/_lib/secret_detector.test.ts +0 -108
- package/src/scripts/_lib/secret_detector_adversarial.test.ts +0 -116
- package/src/scripts/_lib/untrusted_content.test.ts +0 -175
- package/src/scripts/check_secret_leak.test.ts +0 -90
- package/src/scripts/design_slop_rules.test.ts +0 -239
- package/src/scripts/self_review_gate.test.ts +0 -296
- package/src/shared/capabilities.test.ts +0 -43
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* frontend_corpus_hash — freeze and verify the frontend benchmark corpus.
|
|
3
|
+
*
|
|
4
|
+
* Step 0.2 of `road-to-frontend-power` registers a labelled frontend population
|
|
5
|
+
* and requires its hash to be committed BEFORE any commit that moves the
|
|
6
|
+
* detector engine. Risk 6 of that roadmap names the failure the hash guards
|
|
7
|
+
* against: "One effort ships both the engine and the corpus that scores it."
|
|
8
|
+
*
|
|
9
|
+
* The hash is the weaker half of that mitigation and this header says so
|
|
10
|
+
* plainly: it pins the population against LATER edits, so a number published
|
|
11
|
+
* against `<digest>` cannot be re-scored on a quietly-different corpus. It says
|
|
12
|
+
* nothing about who authored the corpus in the first place. The authorship
|
|
13
|
+
* caveat — and the resulting rule that no detector row may be promoted to
|
|
14
|
+
* `backed` against this population — lives in
|
|
15
|
+
* `tests/eval/frontend-corpus/README.md` and is not restated here.
|
|
16
|
+
*
|
|
17
|
+
* Determinism: files are enumerated depth-first with a sorted directory walk,
|
|
18
|
+
* paths are emitted POSIX-style relative to the corpus root, and content is
|
|
19
|
+
* hashed as raw bytes. `CORPUS.sha256` itself is excluded, so `--write`
|
|
20
|
+
* followed by `--check` is stable.
|
|
21
|
+
*
|
|
22
|
+
* Not a CI gate, deliberately. `tests/eval/frontend-corpus.test.ts` runs the
|
|
23
|
+
* `--check` path, which is the enforcement surface; a fourth ratchet-tripping
|
|
24
|
+
* gate script for a manifest one test can assert would cost more than it buys.
|
|
25
|
+
*
|
|
26
|
+
* Exit 0 = manifest matches (or was written). Exit 1 = drift.
|
|
27
|
+
*/
|
|
28
|
+
|
|
29
|
+
import * as crypto from 'node:crypto';
|
|
30
|
+
import * as fs from 'node:fs';
|
|
31
|
+
import * as path from 'node:path';
|
|
32
|
+
import { fileURLToPath, pathToFileURL } from 'node:url';
|
|
33
|
+
|
|
34
|
+
const _HERE = fileURLToPath(import.meta.url);
|
|
35
|
+
const REPO = path.resolve(path.dirname(_HERE), '..', '..');
|
|
36
|
+
export const CORPUS_ROOT = path.join(REPO, 'tests', 'eval', 'frontend-corpus');
|
|
37
|
+
export const MANIFEST_NAME = 'CORPUS.sha256';
|
|
38
|
+
/** Subtrees carrying corpus content. Anything else at the root is prose. */
|
|
39
|
+
const CONTENT_DIRS = ['cases', 'near-miss'] as const;
|
|
40
|
+
|
|
41
|
+
/** Depth-first, sorted, POSIX-relative file list under `root`. */
|
|
42
|
+
export function walk(root: string, rel = ''): string[] {
|
|
43
|
+
const abs = rel ? path.join(root, rel) : root;
|
|
44
|
+
if (!fs.existsSync(abs)) return [];
|
|
45
|
+
const out: string[] = [];
|
|
46
|
+
for (const name of fs.readdirSync(abs).sort()) {
|
|
47
|
+
const childRel = rel ? `${rel}/${name}` : name;
|
|
48
|
+
if (fs.statSync(path.join(root, childRel)).isDirectory()) out.push(...walk(root, childRel));
|
|
49
|
+
else if (childRel !== MANIFEST_NAME) out.push(childRel);
|
|
50
|
+
}
|
|
51
|
+
return out;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Pure core: the manifest text for a set of (path, bytes) pairs. Pure so the
|
|
56
|
+
* ordering guarantee is testable without a corpus on disk.
|
|
57
|
+
*/
|
|
58
|
+
export function manifestText(entries: ReadonlyArray<readonly [string, Buffer]>): string {
|
|
59
|
+
const lines = entries.map(
|
|
60
|
+
([p, bytes]) => `${crypto.createHash('sha256').update(bytes).digest('hex')} ${p}`,
|
|
61
|
+
);
|
|
62
|
+
const roll = crypto.createHash('sha256').update(lines.join('\n')).digest('hex');
|
|
63
|
+
return [
|
|
64
|
+
'# frontend benchmark corpus — sha256 manifest',
|
|
65
|
+
'# Produced by src/scripts/frontend_corpus_hash.ts. Do not hand-edit.',
|
|
66
|
+
`# files: ${lines.length}`,
|
|
67
|
+
`# corpus: ${roll}`,
|
|
68
|
+
...lines,
|
|
69
|
+
'',
|
|
70
|
+
].join('\n');
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export function buildManifest(root: string = CORPUS_ROOT): string {
|
|
74
|
+
const files = CONTENT_DIRS.flatMap((d) => walk(root, d));
|
|
75
|
+
return manifestText(files.map((p) => [p, fs.readFileSync(path.join(root, p))] as const));
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/** The rolling `# corpus:` digest — the value a published number cites. */
|
|
79
|
+
export function corpusDigest(text: string): string | null {
|
|
80
|
+
return /^# corpus: ([0-9a-f]{64})$/m.exec(text)?.[1] ?? null;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
function main(argv: readonly string[]): number {
|
|
84
|
+
const manifestPath = path.join(CORPUS_ROOT, MANIFEST_NAME);
|
|
85
|
+
const built = buildManifest();
|
|
86
|
+
const digest = corpusDigest(built);
|
|
87
|
+
|
|
88
|
+
if (argv.includes('--write')) {
|
|
89
|
+
fs.writeFileSync(manifestPath, built);
|
|
90
|
+
process.stdout.write(`✅ wrote ${MANIFEST_NAME} — corpus ${digest}\n`);
|
|
91
|
+
return 0;
|
|
92
|
+
}
|
|
93
|
+
if (argv.includes('--check')) {
|
|
94
|
+
if (!fs.existsSync(manifestPath)) {
|
|
95
|
+
console.error(`❌ ${MANIFEST_NAME} is missing — run with --write`);
|
|
96
|
+
return 1;
|
|
97
|
+
}
|
|
98
|
+
const onDisk = fs.readFileSync(manifestPath, 'utf8');
|
|
99
|
+
if (onDisk !== built) {
|
|
100
|
+
console.error(
|
|
101
|
+
`❌ corpus drift — manifest says ${corpusDigest(onDisk)}, tree hashes to ${digest}.\n` +
|
|
102
|
+
' A case changed without a rehash. Rerun with --write, and re-publish any\n' +
|
|
103
|
+
' number that cited the old digest rather than carrying it over.',
|
|
104
|
+
);
|
|
105
|
+
return 1;
|
|
106
|
+
}
|
|
107
|
+
process.stdout.write(`✅ corpus matches manifest — ${digest}\n`);
|
|
108
|
+
return 0;
|
|
109
|
+
}
|
|
110
|
+
process.stdout.write(built);
|
|
111
|
+
return 0;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
if (process.argv[1] && pathToFileURL(process.argv[1]).href === import.meta.url) {
|
|
115
|
+
process.exit(main(process.argv.slice(2)));
|
|
116
|
+
}
|
|
@@ -0,0 +1,478 @@
|
|
|
1
|
+
#!/usr/bin/env tsx
|
|
2
|
+
/**
|
|
3
|
+
* Grade a TARGET repository's assurance readiness — the matrix `/project:analyze` prints.
|
|
4
|
+
*
|
|
5
|
+
* WHY A SCRIPT AND NOT PROSE. `road-to-target-project-assurance-readiness`
|
|
6
|
+
* Phase 1 asks for detection asserted "by a vitest spec", and a gather list
|
|
7
|
+
* written in a command's markdown cannot be asserted by anything. So the
|
|
8
|
+
* detection is here and the command invokes it; the command keeps the narrative.
|
|
9
|
+
*
|
|
10
|
+
* THE ANTI-VANITY RULE IS STRUCTURAL, NOT A STYLE NOTE. Ten dimensions are
|
|
11
|
+
* graded 0 Absent / 1 Present / 2 Enforced-in-CI / 3 Independent-and-diff-scoped,
|
|
12
|
+
* and the verdict is `min` over the FOUR knockout dimensions, reported as
|
|
13
|
+
* `L<n> — bound by <dimension>`. **No aggregate number is ever emitted** — no
|
|
14
|
+
* percentage, no x/100, no mean. A single score is the vanity metric the source
|
|
15
|
+
* report's own anti-vanity rule forbids, and `renderMatrix` carries a test that
|
|
16
|
+
* greps its own output for `%` and `/100`.
|
|
17
|
+
*
|
|
18
|
+
* NOT-DETECTABLE IS NOT ZERO, AND ON A KNOCKOUT IT BINDS. A `0` claims the target
|
|
19
|
+
* lacks something. `not detectable` says this tool cannot tell — a different fact,
|
|
20
|
+
* and the honest one for a Python target, because `quality-tools` routes PHP and
|
|
21
|
+
* JS/TS only. An undetectable KNOCKOUT binds at L0 with its reason printed, so the
|
|
22
|
+
* gap is visible rather than flattering.
|
|
23
|
+
*
|
|
24
|
+
* SCOPE — this grades, it does not install. Whether a missing gate then gets
|
|
25
|
+
* created in the target is a successor roadmap's problem
|
|
26
|
+
* (`stubs/road-to-target-project-bootstrap-enforce.md`).
|
|
27
|
+
*
|
|
28
|
+
* Exit codes:
|
|
29
|
+
* 0 — a matrix was produced (any level, including L0 — a low grade is a
|
|
30
|
+
* finding about the target, never a failure of this gate)
|
|
31
|
+
* 1 — nothing was gradeable (no target root)
|
|
32
|
+
* 2 — the gate could not run (bad args)
|
|
33
|
+
*/
|
|
34
|
+
import * as fs from 'node:fs';
|
|
35
|
+
import * as os from 'node:os';
|
|
36
|
+
import * as path from 'node:path';
|
|
37
|
+
import { fileURLToPath, pathToFileURL } from 'node:url';
|
|
38
|
+
|
|
39
|
+
import { GateLedger } from './_lib/gate_ledger.js';
|
|
40
|
+
import { runGateCli, runSelfTest, type SelfTestCase } from './_lib/gate_self_test.js';
|
|
41
|
+
import { DeadScopeError, reportScanned } from './_lib/scan_scope.js';
|
|
42
|
+
|
|
43
|
+
const _HERE = fileURLToPath(import.meta.url);
|
|
44
|
+
const REPO_ROOT = path.resolve(path.dirname(_HERE), '..', '..');
|
|
45
|
+
const SELF = 'src/scripts/grade_target_readiness.ts';
|
|
46
|
+
|
|
47
|
+
const SELF_TEST_MIN_CASES = 6;
|
|
48
|
+
const SELF_TEST_MIN_REJECT = 2;
|
|
49
|
+
|
|
50
|
+
/** 0 Absent · 1 Present · 2 Enforced-in-CI · 3 Independent-and-diff-scoped. */
|
|
51
|
+
export type Grade = 0 | 1 | 2 | 3;
|
|
52
|
+
|
|
53
|
+
/** `null` means "this tool cannot tell", which is NOT a zero. */
|
|
54
|
+
export interface DimensionResult {
|
|
55
|
+
id: string;
|
|
56
|
+
label: string;
|
|
57
|
+
knockout: boolean;
|
|
58
|
+
grade: Grade | null;
|
|
59
|
+
/** Required when `grade` is null: why detection is impossible, not merely absent. */
|
|
60
|
+
notDetectable?: string;
|
|
61
|
+
evidence: string;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export interface Matrix {
|
|
65
|
+
level: Grade | 0;
|
|
66
|
+
boundBy: string;
|
|
67
|
+
boundReason?: string;
|
|
68
|
+
dimensions: DimensionResult[];
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// ── primitive probes ───────────────────────────────────────────────────────
|
|
72
|
+
|
|
73
|
+
const _exists = (root: string, ...rel: string[]): boolean =>
|
|
74
|
+
rel.some((r) => fs.existsSync(path.join(root, r)));
|
|
75
|
+
|
|
76
|
+
function _glob1(root: string, dir: string, re: RegExp): boolean {
|
|
77
|
+
const d = path.join(root, dir);
|
|
78
|
+
try {
|
|
79
|
+
return fs.readdirSync(d).some((f) => re.test(f));
|
|
80
|
+
} catch {
|
|
81
|
+
return false;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
function _readIfAny(root: string, ...rel: string[]): string {
|
|
86
|
+
for (const r of rel) {
|
|
87
|
+
try {
|
|
88
|
+
return fs.readFileSync(path.join(root, r), 'utf-8');
|
|
89
|
+
} catch {
|
|
90
|
+
/* next */
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
return '';
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/** Every workflow file's text, concatenated. Empty when there is no CI at all. */
|
|
97
|
+
function _ciText(root: string): string {
|
|
98
|
+
const d = path.join(root, '.github', 'workflows');
|
|
99
|
+
let out = '';
|
|
100
|
+
try {
|
|
101
|
+
for (const f of fs.readdirSync(d)) {
|
|
102
|
+
if (/\.ya?ml$/.test(f)) out += `${fs.readFileSync(path.join(d, f), 'utf-8')}\n`;
|
|
103
|
+
}
|
|
104
|
+
} catch {
|
|
105
|
+
/* no CI */
|
|
106
|
+
}
|
|
107
|
+
return out;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Is this a Python-primary target?
|
|
112
|
+
*
|
|
113
|
+
* Load-bearing for dimension 4: `quality-tools` routes PHP and JS/TS only, so on
|
|
114
|
+
* a Python target the static-analysis dimension is NOT DETECTABLE rather than 0.
|
|
115
|
+
*/
|
|
116
|
+
export function isPythonTarget(root: string): boolean {
|
|
117
|
+
const py = _exists(root, 'pyproject.toml', 'setup.cfg', 'requirements.txt', 'setup.py');
|
|
118
|
+
const other = _exists(root, 'composer.json', 'package.json');
|
|
119
|
+
return py && !other;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// ── the ten dimensions ─────────────────────────────────────────────────────
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Grade one dimension. `ci` decides 1 → 2: a thing that exists is `Present`; a
|
|
126
|
+
* thing CI runs in a job that is not `continue-on-error` is `Enforced-in-CI`.
|
|
127
|
+
*/
|
|
128
|
+
function _graded(present: boolean, enforced: boolean, diffScoped = false): Grade {
|
|
129
|
+
if (!present) return 0;
|
|
130
|
+
if (diffScoped && enforced) return 3;
|
|
131
|
+
return enforced ? 2 : 1;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/** A CI job that cannot fail the build enforces nothing. */
|
|
135
|
+
function _ciBlocks(ci: string, ...needles: string[]): boolean {
|
|
136
|
+
if (ci === '') return false;
|
|
137
|
+
const mentions = needles.some((n) => ci.toLowerCase().includes(n.toLowerCase()));
|
|
138
|
+
if (!mentions) return false;
|
|
139
|
+
// Coarse but honest: a workflow that marks EVERY job continue-on-error
|
|
140
|
+
// enforces nothing. Per-job attribution needs a YAML parse and is the
|
|
141
|
+
// successor roadmap's problem; stated rather than silently approximated.
|
|
142
|
+
const allSoft = /continue-on-error:\s*true/.test(ci) && !/continue-on-error:\s*false/.test(ci);
|
|
143
|
+
return !allSoft;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
export function grade(root: string): Matrix {
|
|
147
|
+
const ci = _ciText(root);
|
|
148
|
+
const hasCi = ci !== '';
|
|
149
|
+
const py = isPythonTarget(root);
|
|
150
|
+
const pyproject = _readIfAny(root, 'pyproject.toml');
|
|
151
|
+
|
|
152
|
+
const dims: DimensionResult[] = [];
|
|
153
|
+
|
|
154
|
+
// 1. behaviour contract
|
|
155
|
+
const contract = _exists(root, 'AGENTS.md', 'openapi.yaml', 'openapi.yml', 'CONTRACT.md');
|
|
156
|
+
dims.push({
|
|
157
|
+
id: 'behaviour-contract',
|
|
158
|
+
label: 'behaviour contract',
|
|
159
|
+
knockout: false,
|
|
160
|
+
grade: _graded(contract, false),
|
|
161
|
+
evidence: contract ? 'AGENTS.md / OpenAPI / CONTRACT.md present' : 'none found',
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
// 2. test presence & types — KNOCKOUT
|
|
165
|
+
const testCfg =
|
|
166
|
+
_exists(root, 'vitest.config.ts', 'vitest.config.js', 'jest.config.js', 'jest.config.ts',
|
|
167
|
+
'phpunit.xml', 'phpunit.xml.dist', 'pest.php', 'pytest.ini', 'tox.ini') ||
|
|
168
|
+
/\[tool\.pytest/.test(pyproject);
|
|
169
|
+
dims.push({
|
|
170
|
+
id: 'test-presence',
|
|
171
|
+
label: 'test presence & types',
|
|
172
|
+
knockout: true,
|
|
173
|
+
grade: _graded(testCfg, _ciBlocks(ci, 'vitest', 'jest', 'phpunit', 'pest', 'pytest', 'npm test', 'task test')),
|
|
174
|
+
evidence: testCfg ? 'a test-runner config is present' : 'no test-runner config',
|
|
175
|
+
});
|
|
176
|
+
|
|
177
|
+
// 3. test strength — mutation or property-based
|
|
178
|
+
const mutation =
|
|
179
|
+
_glob1(root, '.', /^stryker\.conf\./) || _exists(root, 'infection.json', 'infection.json.dist') ||
|
|
180
|
+
/\[tool\.mutmut\]/.test(pyproject) || /\[mutmut\]/.test(_readIfAny(root, 'setup.cfg'));
|
|
181
|
+
const property =
|
|
182
|
+
/fast-check/.test(_readIfAny(root, 'package.json')) || /hypothesis/.test(pyproject + _readIfAny(root, 'requirements.txt'));
|
|
183
|
+
dims.push({
|
|
184
|
+
id: 'test-strength',
|
|
185
|
+
label: 'test strength',
|
|
186
|
+
knockout: false,
|
|
187
|
+
grade: _graded(mutation || property, _ciBlocks(ci, 'stryker', 'infection', 'mutmut')),
|
|
188
|
+
evidence: mutation ? 'mutation config present' : property ? 'property-based library present' : 'neither mutation nor property testing',
|
|
189
|
+
});
|
|
190
|
+
|
|
191
|
+
// 4. static analysis & types — KNOCKOUT, and the not-detectable case
|
|
192
|
+
if (py) {
|
|
193
|
+
dims.push({
|
|
194
|
+
id: 'static-analysis',
|
|
195
|
+
label: 'static analysis & types',
|
|
196
|
+
knockout: true,
|
|
197
|
+
grade: null,
|
|
198
|
+
notDetectable: 'quality-tools has no Python mode',
|
|
199
|
+
evidence: 'Python-primary target',
|
|
200
|
+
});
|
|
201
|
+
} else {
|
|
202
|
+
const sa = _exists(root, 'phpstan.neon', 'phpstan.neon.dist', 'psalm.xml', 'tsconfig.json');
|
|
203
|
+
dims.push({
|
|
204
|
+
id: 'static-analysis',
|
|
205
|
+
label: 'static analysis & types',
|
|
206
|
+
knockout: true,
|
|
207
|
+
grade: _graded(sa, _ciBlocks(ci, 'phpstan', 'psalm', 'tsc', 'typecheck')),
|
|
208
|
+
evidence: sa ? 'a static-analysis config is present' : 'no static-analysis config',
|
|
209
|
+
});
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
// 5. architecture gates
|
|
213
|
+
const arch = _glob1(root, '.', /^\.dependency-cruiser\./) || _exists(root, 'deptrac.yaml', 'deptrac.yml');
|
|
214
|
+
dims.push({
|
|
215
|
+
id: 'architecture-gates',
|
|
216
|
+
label: 'architecture gates',
|
|
217
|
+
knockout: false,
|
|
218
|
+
grade: _graded(arch, _ciBlocks(ci, 'dependency-cruiser', 'deptrac')),
|
|
219
|
+
evidence: arch ? 'a boundary-gate config is present' : 'no architecture gate',
|
|
220
|
+
});
|
|
221
|
+
|
|
222
|
+
// 6. security & supply chain — KNOCKOUT
|
|
223
|
+
const lock = _exists(root, 'package-lock.json', 'pnpm-lock.yaml', 'yarn.lock', 'composer.lock', 'poetry.lock', 'uv.lock');
|
|
224
|
+
const sast = _glob1(root, '.', /^\.semgrep/) || _exists(root, 'bandit.yaml', '.bandit');
|
|
225
|
+
const audit = _ciBlocks(ci, 'npm audit', 'pnpm audit', 'composer audit', 'pip-audit', 'semgrep', 'bandit');
|
|
226
|
+
dims.push({
|
|
227
|
+
id: 'security-supply-chain',
|
|
228
|
+
label: 'security & supply chain',
|
|
229
|
+
knockout: true,
|
|
230
|
+
grade: _graded(lock || sast, audit),
|
|
231
|
+
evidence: `${lock ? 'lockfile' : 'no lockfile'}; ${sast ? 'SAST config' : 'no SAST config'}; ${audit ? 'audit runs in CI' : 'no blocking audit step'}`,
|
|
232
|
+
});
|
|
233
|
+
|
|
234
|
+
// 7. CI enforcement — KNOCKOUT
|
|
235
|
+
const blockingJob = hasCi && !(/continue-on-error:\s*true/.test(ci) && !/continue-on-error:\s*false/.test(ci));
|
|
236
|
+
dims.push({
|
|
237
|
+
id: 'ci-enforcement',
|
|
238
|
+
label: 'CI enforcement',
|
|
239
|
+
knockout: true,
|
|
240
|
+
grade: hasCi ? (blockingJob ? 2 : 1) : 0,
|
|
241
|
+
evidence: !hasCi ? 'no workflows' : blockingJob ? 'at least one job can fail the build' : 'every job is continue-on-error',
|
|
242
|
+
});
|
|
243
|
+
|
|
244
|
+
// 8. independent verification
|
|
245
|
+
const owners = _exists(root, 'CODEOWNERS', '.github/CODEOWNERS', 'docs/CODEOWNERS');
|
|
246
|
+
dims.push({
|
|
247
|
+
id: 'independent-verification',
|
|
248
|
+
label: 'independent verification',
|
|
249
|
+
knockout: false,
|
|
250
|
+
grade: _graded(owners, false),
|
|
251
|
+
evidence: owners ? 'CODEOWNERS present' : 'no CODEOWNERS',
|
|
252
|
+
});
|
|
253
|
+
|
|
254
|
+
// 9. evidence & traceability
|
|
255
|
+
const adr = _exists(root, 'docs/adr', 'docs/decisions', 'adr');
|
|
256
|
+
dims.push({
|
|
257
|
+
id: 'evidence-traceability',
|
|
258
|
+
label: 'evidence & traceability',
|
|
259
|
+
knockout: false,
|
|
260
|
+
grade: _graded(adr, false),
|
|
261
|
+
evidence: adr ? 'a decision record directory exists' : 'no decision records',
|
|
262
|
+
});
|
|
263
|
+
|
|
264
|
+
// 10. runtime verification — never detectable, and deliberately NOT a knockout
|
|
265
|
+
dims.push({
|
|
266
|
+
id: 'runtime-verification',
|
|
267
|
+
label: 'runtime verification',
|
|
268
|
+
knockout: false,
|
|
269
|
+
grade: null,
|
|
270
|
+
notDetectable: 'needs a deploy platform this tool does not own',
|
|
271
|
+
evidence: 'out of scope by design (see the roadmap exclusion table)',
|
|
272
|
+
});
|
|
273
|
+
|
|
274
|
+
// ── the verdict: min over knockouts, undetectable binds at L0 ──────────
|
|
275
|
+
const knockouts = dims.filter((d) => d.knockout);
|
|
276
|
+
const undetectable = knockouts.find((d) => d.grade === null);
|
|
277
|
+
if (undetectable !== undefined) {
|
|
278
|
+
// `boundReason` is spread in conditionally rather than assigned
|
|
279
|
+
// `undefined`: under `exactOptionalPropertyTypes` an optional property
|
|
280
|
+
// and a property explicitly set to `undefined` are different types, and
|
|
281
|
+
// the second does not satisfy `boundReason?: string`.
|
|
282
|
+
return {
|
|
283
|
+
level: 0,
|
|
284
|
+
boundBy: undetectable.label,
|
|
285
|
+
...(undetectable.notDetectable === undefined ? {} : { boundReason: undetectable.notDetectable }),
|
|
286
|
+
dimensions: dims,
|
|
287
|
+
};
|
|
288
|
+
}
|
|
289
|
+
let level: Grade = 3;
|
|
290
|
+
let boundBy = knockouts[0]?.label ?? 'unknown';
|
|
291
|
+
for (const k of knockouts) {
|
|
292
|
+
const g = k.grade as Grade;
|
|
293
|
+
if (g < level) {
|
|
294
|
+
level = g;
|
|
295
|
+
boundBy = k.label;
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
return { level, boundBy, dimensions: dims };
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
// ── rendering ──────────────────────────────────────────────────────────────
|
|
302
|
+
|
|
303
|
+
const GRADE_WORD: Record<number, string> = { 0: 'Absent', 1: 'Present', 2: 'Enforced-in-CI', 3: 'Independent+diff-scoped' };
|
|
304
|
+
|
|
305
|
+
/**
|
|
306
|
+
* Render the matrix. Emits NO aggregate figure — no `%`, no `/100`, no mean.
|
|
307
|
+
* A test greps this function's own output for both, because the pressure to
|
|
308
|
+
* print one number is exactly what turns readiness into a vanity metric.
|
|
309
|
+
*/
|
|
310
|
+
export function renderMatrix(m: Matrix): string {
|
|
311
|
+
const L: string[] = [];
|
|
312
|
+
L.push('READINESS');
|
|
313
|
+
L.push(
|
|
314
|
+
m.boundReason !== undefined
|
|
315
|
+
? `L${String(m.level)} — bound by ${m.boundBy} (not detectable — ${m.boundReason})`
|
|
316
|
+
: `L${String(m.level)} — bound by ${m.boundBy}`,
|
|
317
|
+
);
|
|
318
|
+
L.push('');
|
|
319
|
+
for (const d of m.dimensions) {
|
|
320
|
+
const val = d.grade === null ? `not detectable — ${d.notDetectable ?? ''}` : `${String(d.grade)} ${GRADE_WORD[d.grade] ?? ''}`;
|
|
321
|
+
L.push(` ${d.knockout ? '!' : ' '} ${d.label.padEnd(28)} ${val}`);
|
|
322
|
+
}
|
|
323
|
+
L.push('');
|
|
324
|
+
L.push(' ! = knockout dimension. The level is the MINIMUM over knockouts;');
|
|
325
|
+
L.push(' an undetectable knockout binds at L0 with its reason shown.');
|
|
326
|
+
L.push(' No aggregate score is reported, by design.');
|
|
327
|
+
return L.join('\n');
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
// ── self-test ──────────────────────────────────────────────────────────────
|
|
331
|
+
|
|
332
|
+
function _mk(files: Record<string, string>): string {
|
|
333
|
+
const d = fs.mkdtempSync(path.join(os.tmpdir(), 'target-readiness-'));
|
|
334
|
+
for (const [rel, body] of Object.entries(files)) {
|
|
335
|
+
const p = path.join(d, rel);
|
|
336
|
+
fs.mkdirSync(path.dirname(p), { recursive: true });
|
|
337
|
+
fs.writeFileSync(p, body);
|
|
338
|
+
}
|
|
339
|
+
return d;
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
const BLOCKING_CI = 'jobs:\n t:\n steps:\n - run: npx vitest run\n - run: npx tsc --noEmit\n - run: npm audit\n';
|
|
343
|
+
|
|
344
|
+
export function selfTest(): number {
|
|
345
|
+
const made: string[] = [];
|
|
346
|
+
const mk = (f: Record<string, string>): string => {
|
|
347
|
+
const d = _mk(f);
|
|
348
|
+
made.push(d);
|
|
349
|
+
return d;
|
|
350
|
+
};
|
|
351
|
+
const cases: SelfTestCase[] = [
|
|
352
|
+
{
|
|
353
|
+
name: 'a bare directory grades L0 bound by a knockout, and does not crash',
|
|
354
|
+
expect: 'accept',
|
|
355
|
+
run: () => (grade(mk({ 'README.md': '#\n' })).level === 0 ? 0 : 1),
|
|
356
|
+
},
|
|
357
|
+
{
|
|
358
|
+
name: 'a Python target reports static analysis NOT DETECTABLE, never 0',
|
|
359
|
+
expect: 'accept',
|
|
360
|
+
run: () => {
|
|
361
|
+
const m = grade(mk({ 'pyproject.toml': '[tool.pytest.ini_options]\n' }));
|
|
362
|
+
const sa = m.dimensions.find((d) => d.id === 'static-analysis');
|
|
363
|
+
return sa?.grade === null && sa.notDetectable === 'quality-tools has no Python mode' ? 0 : 1;
|
|
364
|
+
},
|
|
365
|
+
},
|
|
366
|
+
{
|
|
367
|
+
name: 'an undetectable knockout BINDS at L0 with its reason',
|
|
368
|
+
expect: 'accept',
|
|
369
|
+
run: () => {
|
|
370
|
+
const m = grade(mk({ 'pyproject.toml': '[tool.pytest.ini_options]\n' }));
|
|
371
|
+
return m.level === 0 && m.boundBy === 'static analysis & types' && m.boundReason !== undefined ? 0 : 1;
|
|
372
|
+
},
|
|
373
|
+
},
|
|
374
|
+
{
|
|
375
|
+
name: 'CI enforcement at 0 binds even when everything else is enforced',
|
|
376
|
+
expect: 'accept',
|
|
377
|
+
run: () => {
|
|
378
|
+
const m = grade(mk({
|
|
379
|
+
'package.json': '{"devDependencies":{"fast-check":"1"}}',
|
|
380
|
+
'tsconfig.json': '{}',
|
|
381
|
+
'vitest.config.ts': '',
|
|
382
|
+
'package-lock.json': '{}',
|
|
383
|
+
'.semgrep.yml': '',
|
|
384
|
+
'deptrac.yaml': '',
|
|
385
|
+
'AGENTS.md': '#\n',
|
|
386
|
+
'CODEOWNERS': '* @o\n',
|
|
387
|
+
'docs/adr/ADR-1.md': '#\n',
|
|
388
|
+
}));
|
|
389
|
+
return m.level === 0 && m.boundBy === 'CI enforcement' ? 0 : 1;
|
|
390
|
+
},
|
|
391
|
+
},
|
|
392
|
+
{
|
|
393
|
+
name: 'the rendered matrix carries NO aggregate figure',
|
|
394
|
+
expect: 'accept',
|
|
395
|
+
run: () => {
|
|
396
|
+
const out = renderMatrix(grade(mk({ 'package.json': '{}', '.github/workflows/ci.yml': BLOCKING_CI })));
|
|
397
|
+
return /%|\/100/.test(out) ? 1 : 0;
|
|
398
|
+
},
|
|
399
|
+
},
|
|
400
|
+
{
|
|
401
|
+
name: 'rejects a missing target root rather than grading an empty tree',
|
|
402
|
+
expect: 'reject',
|
|
403
|
+
run: () => runGateCli(REPO_ROOT, SELF, ['--quiet', '--target', path.join(REPO_ROOT, 'no-such-target')], REPO_ROOT),
|
|
404
|
+
},
|
|
405
|
+
{
|
|
406
|
+
name: 'rejects a target argument that is a file, not a directory',
|
|
407
|
+
expect: 'reject',
|
|
408
|
+
run: () => runGateCli(REPO_ROOT, SELF, ['--quiet', '--target', path.join(REPO_ROOT, 'package.json')], REPO_ROOT),
|
|
409
|
+
},
|
|
410
|
+
];
|
|
411
|
+
try {
|
|
412
|
+
return runSelfTest({ gate: 'grade_target_readiness', cases, minCases: SELF_TEST_MIN_CASES, minRejectCases: SELF_TEST_MIN_REJECT });
|
|
413
|
+
} finally {
|
|
414
|
+
for (const d of made) fs.rmSync(d, { recursive: true, force: true });
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
function main(argv?: readonly string[]): number {
|
|
419
|
+
const args = argv ?? process.argv.slice(2);
|
|
420
|
+
if (args.includes('--self-test')) return selfTest();
|
|
421
|
+
const quiet = args.includes('--quiet');
|
|
422
|
+
const i = args.indexOf('--target');
|
|
423
|
+
const target = i >= 0 ? args[i + 1] : process.cwd();
|
|
424
|
+
if (target === undefined) {
|
|
425
|
+
process.stderr.write('grade_target_readiness: --target requires a directory\n');
|
|
426
|
+
return 2;
|
|
427
|
+
}
|
|
428
|
+
let stat: fs.Stats;
|
|
429
|
+
try {
|
|
430
|
+
stat = fs.statSync(target);
|
|
431
|
+
} catch {
|
|
432
|
+
process.stderr.write(`❌ target not found: ${target}\n`);
|
|
433
|
+
return 1;
|
|
434
|
+
}
|
|
435
|
+
if (!stat.isDirectory()) {
|
|
436
|
+
process.stderr.write(`❌ target is not a directory: ${target}\n`);
|
|
437
|
+
return 1;
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
const m = grade(target);
|
|
441
|
+
const ledger = new GateLedger('grade_target_readiness');
|
|
442
|
+
ledger.plan(m.dimensions.map((d) => d.id));
|
|
443
|
+
for (const d of m.dimensions) {
|
|
444
|
+
if (d.grade === null) ledger.outOfScope(d.id, 'not_applicable_kind');
|
|
445
|
+
else ledger.complete(d.id);
|
|
446
|
+
}
|
|
447
|
+
ledger.report();
|
|
448
|
+
try {
|
|
449
|
+
reportScanned({
|
|
450
|
+
gate: 'grade_target_readiness',
|
|
451
|
+
scanned: m.dimensions.length,
|
|
452
|
+
units: 'readiness dimension(s)',
|
|
453
|
+
roots: [target],
|
|
454
|
+
});
|
|
455
|
+
} catch (err) {
|
|
456
|
+
if (err instanceof DeadScopeError) {
|
|
457
|
+
process.stderr.write(`❌ ${err.message}\n`);
|
|
458
|
+
return 2;
|
|
459
|
+
}
|
|
460
|
+
throw err;
|
|
461
|
+
}
|
|
462
|
+
if (!quiet) process.stdout.write(`${renderMatrix(m)}\n`);
|
|
463
|
+
return 0;
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
function _isCliEntry(): boolean {
|
|
467
|
+
if (process.argv[1] === undefined) return false;
|
|
468
|
+
if (import.meta.url === pathToFileURL(path.resolve(process.argv[1])).href) return true;
|
|
469
|
+
try {
|
|
470
|
+
return fs.realpathSync(fileURLToPath(import.meta.url)) === fs.realpathSync(path.resolve(process.argv[1]));
|
|
471
|
+
} catch {
|
|
472
|
+
return false;
|
|
473
|
+
}
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
if (_isCliEntry() || process.argv[1] === _HERE) process.exit(main());
|
|
477
|
+
|
|
478
|
+
export { main };
|