@event4u/agent-config 16.1.0 → 16.3.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 +98 -257
- package/README.md +14 -12
- package/dist/agent-src/commands/analyze/inbox.md +1 -1
- package/dist/agent-src/commands/analyze/roadmap-repos.md +1 -1
- package/dist/agent-src/commands/bug/fix.md +17 -2
- package/dist/agent-src/commands/feature/plan.md +1 -1
- package/dist/agent-src/commands/feature/roadmap.md +1 -1
- package/dist/agent-src/commands/fix/ci.md +1 -1
- package/dist/agent-src/commands/implement-ticket.md +1 -1
- package/dist/agent-src/commands/jira-ticket.md +1 -1
- package/dist/agent-src/commands/roadmap/create.md +1 -1
- package/dist/agent-src/commands/roadmap/materialize.md +1 -1
- package/dist/agent-src/commands/roadmap/process-full.md +5 -5
- package/dist/agent-src/commands/roadmap/resolve-blockers.md +361 -0
- package/dist/agent-src/commands/roadmap/triage-parked.md +325 -0
- package/dist/agent-src/commands/roadmap.md +18 -4
- package/dist/agent-src/commands/tests/create.md +17 -3
- package/dist/agent-src/commands/tests/execute.md +22 -5
- package/dist/agent-src/commands/work.md +4 -0
- package/dist/agent-src/contexts/authority/decision-revisit-gate-enforcement.md +43 -0
- package/dist/agent-src/contexts/communication/rules-auto/design-fidelity-enforcement.md +24 -0
- package/dist/agent-src/contexts/execution/auto-dispatch-classification.md +6 -6
- package/dist/agent-src/contexts/execution/autonomy-mechanics.md +4 -8
- package/dist/agent-src/contexts/execution/roadmap-process-loop.md +32 -2
- package/dist/agent-src/contexts/execution/session-canary-enforcement-history.md +67 -0
- package/dist/agent-src/contexts/execution/toolchain-resolver.md +101 -7
- package/dist/agent-src/rules/active-remediation.md +1 -1
- package/dist/agent-src/rules/autonomous-execution.md +1 -0
- package/dist/agent-src/rules/broken-access-control.md +1 -0
- package/dist/agent-src/rules/command-suggestion-policy.md +1 -0
- package/dist/agent-src/rules/context-hygiene.md +1 -1
- package/dist/agent-src/rules/decision-revisit-gate.md +16 -33
- package/dist/agent-src/rules/design-fidelity.md +13 -16
- package/dist/agent-src/rules/doc-screenshot-hygiene.md +1 -0
- package/dist/agent-src/rules/domain-safety-disclaimer.md +1 -0
- package/dist/agent-src/rules/domain-safety-pii.md +1 -0
- package/dist/agent-src/rules/domain-safety-retention.md +1 -0
- package/dist/agent-src/rules/engineering-safety-floor.md +1 -0
- package/dist/agent-src/rules/evaluator-independence.md +3 -2
- package/dist/agent-src/rules/fast-path-marker-visibility.md +1 -0
- package/dist/agent-src/rules/finance-safety-floor.md +1 -0
- package/dist/agent-src/rules/git-history-discipline.md +1 -0
- package/dist/agent-src/rules/image-likeness-and-rights.md +1 -0
- package/dist/agent-src/rules/legal-safety-floor.md +3 -2
- package/dist/agent-src/rules/lethal-trifecta-guard.md +1 -0
- package/dist/agent-src/rules/low-impact-corpus-privacy-floor.md +1 -0
- package/dist/agent-src/rules/media-governance-routing.md +14 -17
- package/dist/agent-src/rules/persona-governance.md +2 -2
- package/dist/agent-src/rules/provider-lifecycle-discipline.md +1 -1
- package/dist/agent-src/rules/question-not-instruction.md +1 -0
- package/dist/agent-src/rules/roadmap-progress-sync.md +1 -1
- package/dist/agent-src/rules/runtime-safety.md +1 -0
- package/dist/agent-src/rules/secret-vcs-guard.md +1 -0
- package/dist/agent-src/rules/security-sensitive-stop.md +3 -2
- package/dist/agent-src/rules/session-canary.md +8 -62
- package/dist/agent-src/rules/settings-ask-protocol.md +1 -0
- package/dist/agent-src/rules/source-confidentiality.md +1 -0
- package/dist/agent-src/rules/strategy-safety-floor.md +1 -0
- package/dist/agent-src/rules/tool-safety.md +1 -0
- package/dist/agent-src/rules/ui-audit-gate.md +1 -2
- package/dist/agent-src/rules/untrusted-input-defense.md +1 -0
- package/dist/agent-src/rules/user-interrupt-priority.md +1 -0
- package/dist/agent-src/scripts/archive_completed_roadmaps.ts +115 -20
- package/dist/agent-src/scripts/deferral_carry.ts +339 -0
- package/dist/agent-src/scripts/update_roadmap_progress.ts +4 -1
- package/dist/agent-src/skills/accessibility-auditor/data/aria-patterns.csv +1 -1
- package/dist/agent-src/skills/accessibility-auditor/data/manifest.json +2 -2
- package/dist/agent-src/skills/api-design/data/manifest.json +2 -2
- package/dist/agent-src/skills/api-testing/SKILL.md +17 -0
- package/dist/agent-src/skills/code-intelligence/SKILL.md +14 -2
- package/dist/agent-src/skills/design-review/SKILL.md +30 -4
- package/dist/agent-src/skills/design-review/references/verification-automation.md +32 -0
- package/dist/agent-src/skills/design-system-capture/references/import-procedure.md +1 -1
- package/dist/agent-src/skills/existing-ui-audit/SKILL.md +18 -3
- package/dist/agent-src/skills/existing-ui-audit/references/component-taxonomy-detection.md +56 -0
- package/dist/agent-src/skills/fe-design/SKILL.md +1 -1
- package/dist/agent-src/skills/iconography/SKILL.md +1 -1
- package/dist/agent-src/skills/js-library-packaging/SKILL.md +2 -2
- package/dist/agent-src/skills/markitdown/SKILL.md +4 -0
- package/dist/agent-src/skills/monorepo-workspace/SKILL.md +1 -1
- package/dist/agent-src/skills/playwright-testing/SKILL.md +30 -6
- package/dist/agent-src/skills/quality-tools/SKILL.md +11 -1
- package/dist/agent-src/skills/quality-tools/references/go-tools.md +76 -0
- package/dist/agent-src/skills/quality-tools/references/python-tools.md +104 -0
- package/dist/agent-src/skills/review-routing/SKILL.md +2 -2
- package/dist/agent-src/skills/skill-improvement-pipeline/SKILL.md +1 -1
- package/dist/agent-src/skills/storybook-workshop/SKILL.md +3 -3
- package/dist/agent-src/skills/tailwind-engineer/SKILL.md +1 -1
- package/dist/agent-src/skills/test-case-discovery/SKILL.md +7 -0
- package/dist/agent-src/skills/test-driven-development/SKILL.md +17 -0
- package/dist/agent-src/skills/test-performance/SKILL.md +19 -1
- package/dist/agent-src/skills/ui-component-architect/SKILL.md +25 -2
- package/dist/agent-src/templates/agents/agent-project-settings.example.yml +1 -1
- package/dist/agent-src/templates/roadmaps.md +30 -0
- package/dist/agent-src/templates/scripts/work_engine/directives/ui/app_spec.ts +10 -4
- package/dist/agent-src/templates/scripts/work_engine/directives/ui/apply.ts +302 -21
- package/dist/agent-src/templates/scripts/work_engine/directives/ui/audit.ts +22 -3
- package/dist/agent-src/templates/scripts/work_engine/directives/ui/scaffold.ts +6 -1
- package/dist/agent-src/templates/scripts/work_engine/stack/runner.ts +774 -109
- package/dist/agent-src/templates/scripts/work_engine/state.ts +57 -7
- package/dist/agent-src/templates/scripts/work_engine/taxonomy/detect.ts +500 -0
- package/dist/agent-src/templates/scripts/work_engine/taxonomy/place.ts +183 -0
- package/dist/cli/python/knowledge_ingest.js +1 -1
- package/dist/cli/python/workspace_drive.js +1 -1
- package/dist/cli/registry.js +1 -1
- package/dist/cli-delegate/archive_completed_roadmaps.js +92 -12
- package/dist/cli-delegate/check_update_banner.js +12 -1
- package/dist/cli-delegate/chunk-523HCFYO.js +90 -0
- package/dist/cli-delegate/{chunk-M2DPGFZ4.js → chunk-6V6TA25H.js} +22 -152
- package/dist/cli-delegate/chunk-7IQE3D5S.js +191 -0
- package/dist/cli-delegate/{chunk-6KFEC3G7.js → chunk-CQWX336L.js} +1 -1
- package/dist/cli-delegate/chunk-DEIV7XP7.js +108 -0
- package/dist/cli-delegate/chunk-EEHDXSYD.js +2040 -0
- package/dist/cli-delegate/{chunk-P6ZHP5W2.js → chunk-GKE7ZVFA.js} +4 -4
- package/dist/cli-delegate/chunk-JQOM7TTM.js +1201 -0
- package/dist/cli-delegate/{chunk-UNCRJBT3.js → chunk-JQVYKIZA.js} +41 -0
- package/dist/cli-delegate/{chunk-FC75PGJE.js → chunk-JY2I2DXV.js} +12 -1
- package/dist/cli-delegate/chunk-KB5FZ655.js +208 -0
- package/dist/cli-delegate/{chunk-YUM5KURG.js → chunk-KR6EM23A.js} +235 -1455
- package/dist/cli-delegate/{chunk-LTYVIY76.js → chunk-LIYTLH6O.js} +1 -1
- package/dist/cli-delegate/chunk-NQ7WT43P.js +2729 -0
- package/dist/cli-delegate/chunk-NXEILF2K.js +2160 -0
- package/dist/cli-delegate/{chunk-5R7HOLAF.js → chunk-NYX3L2PZ.js} +1 -1
- package/dist/cli-delegate/{chunk-4E2W63DA.js → chunk-OKJUIAPS.js} +62 -1
- package/dist/cli-delegate/{chunk-QAJS5YWY.js → chunk-PHD7OOLE.js} +2 -1
- package/dist/cli-delegate/{chunk-RGNIWTEA.js → chunk-QLDHIPWR.js} +1 -1
- package/dist/cli-delegate/{chunk-HDVVGPQW.js → chunk-RQNNW7IF.js} +1405 -567
- package/dist/cli-delegate/{chunk-S3VFXMTM.js → chunk-S4UMZNES.js} +1 -1
- package/dist/cli-delegate/{chunk-6KM6ORRY.js → chunk-S4YWNRKO.js} +24 -8
- package/dist/cli-delegate/{chunk-GJCBB2UG.js → chunk-TRI6DQZ6.js} +3054 -325
- package/dist/cli-delegate/chunk-ULQRUR23.js +208 -0
- package/dist/cli-delegate/{chunk-NUHLI2RX.js → chunk-YCU3TIXH.js} +2 -0
- package/dist/cli-delegate/chunk-ZBZV2G5R.js +210 -0
- package/dist/cli-delegate/{chunk-WGXTVKCQ.js → chunk-ZUZKZYCN.js} +5 -3
- package/dist/cli-delegate/cmd_analyze_session.js +1 -1
- package/dist/cli-delegate/cmd_brand_status.js +1 -1
- package/dist/cli-delegate/cmd_conformance.js +1862 -809
- package/dist/cli-delegate/cmd_doctor.js +13 -6
- package/dist/cli-delegate/cmd_doctor_neighbours.js +23 -0
- package/dist/cli-delegate/cmd_explain.js +5 -5
- package/dist/cli-delegate/cmd_export.js +11 -8
- package/dist/cli-delegate/cmd_fleet.js +3 -3
- package/dist/cli-delegate/cmd_handoff.js +10 -7
- package/dist/cli-delegate/cmd_mcp_available.js +1 -1
- package/dist/cli-delegate/cmd_memory_get.js +3 -1
- package/dist/cli-delegate/cmd_migrate.js +2 -2
- package/dist/cli-delegate/cmd_packs_active.js +3 -3
- package/dist/cli-delegate/cmd_preflight.js +6 -6
- package/dist/cli-delegate/cmd_prune.js +11 -8
- package/dist/cli-delegate/cmd_refresh.js +2 -1
- package/dist/cli-delegate/cmd_route_audit.js +8 -6
- package/dist/cli-delegate/cmd_route_explain.js +4 -4
- package/dist/cli-delegate/cmd_session_recycle.js +4 -3
- package/dist/cli-delegate/cmd_settings_get.js +1 -1
- package/dist/cli-delegate/cmd_settings_migrate.js +11 -8
- package/dist/cli-delegate/cmd_settings_set.js +4 -4
- package/dist/cli-delegate/cmd_sync.js +11 -8
- package/dist/cli-delegate/cmd_uninstall.js +11 -8
- package/dist/cli-delegate/cmd_update.js +1 -1
- package/dist/cli-delegate/cmd_upgrade.js +3 -2
- package/dist/cli-delegate/cmd_validate.js +11 -8
- package/dist/cli-delegate/cmd_versions.js +1 -1
- package/dist/cli-delegate/deferral_carry.js +16 -0
- package/dist/cli-delegate/gate_execute.js +2 -2
- package/dist/cli-delegate/roadmap_gates.js +5 -5
- package/dist/cli-delegate/update_roadmap_progress.js +1 -1
- package/dist/discovery/deprecation-report.md +1 -1
- package/dist/discovery/discovery-manifest.json +132 -80
- package/dist/discovery/discovery-manifest.json.sha256 +1 -1
- package/dist/discovery/discovery-manifest.summary.md +3 -3
- package/dist/discovery/dormancy-report.md +1 -1
- package/dist/discovery/orphan-report.md +1 -1
- package/dist/discovery/packs.json +7 -5
- package/dist/discovery/trust-report.md +2 -2
- package/dist/discovery/workspaces.json +6 -4
- package/dist/hooks/dispatch.js +7972 -5186
- package/dist/hooks/dispatch.sha256 +1 -0
- package/dist/install/claudePathsPlan.js +47 -6
- package/dist/install/claudeRuleRewrite.js +7 -0
- package/dist/install/emit_host_rules_cli.js +39 -36
- package/dist/install/globalRuleScope.js +87 -0
- package/dist/install/host_rule_ownership.js +160 -0
- package/dist/install/install.mjs +2226 -1055
- package/dist/install/installThinLayer.js +261 -0
- package/dist/install/installedRuleLinks.js +176 -0
- package/dist/install/wizard-plan.js +24 -0
- package/dist/mcp/registry-manifest.json +3 -3
- package/dist/mcp/server.json +2 -2
- package/dist/mcp/server.mjs +40913 -34865
- package/dist/scripts/_lib/agent_settings.js +11 -0
- package/dist/scripts/_lib/claude_settings_hooks.js +10 -8
- package/dist/scripts/_lib/installed_layer.js +378 -0
- package/dist/scripts/_lib/lean_projection_mode.js +218 -15
- package/dist/scripts/_lib/rule_consequence_class.js +45 -0
- package/dist/scripts/_lib/rule_injection.js +67 -10
- package/dist/scripts/_lib/rule_law_section.js +122 -0
- package/dist/scripts/_lib/thin_rules.js +458 -0
- package/dist/scripts/_lib/windsurf_render.js +60 -0
- package/dist/scripts/condense.js +14 -26
- package/dist/scripts/project_thin_rules.js +14 -294
- package/dist/server/schemas/settings.js +29 -0
- package/dist/shared/skillRanking.js +74 -13
- package/dist/ui/assets/index-Cwq4d0hX.js +23 -0
- package/dist/ui/assets/index-Cyjy8bWO.css +1 -0
- package/dist/ui/index.html +2 -2
- package/docs/contracts/settings-classes.md +10 -6
- package/package.json +4 -4
- package/src/agent-src/scripts/archive_completed_roadmaps.ts +115 -20
- package/src/agent-src/scripts/deferral_carry.ts +339 -0
- package/src/agent-src/scripts/update_roadmap_progress.ts +4 -1
- package/src/agent-src/templates/scripts/work_engine/directives/ui/app_spec.ts +10 -4
- package/src/agent-src/templates/scripts/work_engine/directives/ui/apply.ts +302 -21
- package/src/agent-src/templates/scripts/work_engine/directives/ui/audit.ts +22 -3
- package/src/agent-src/templates/scripts/work_engine/directives/ui/scaffold.ts +6 -1
- package/src/agent-src/templates/scripts/work_engine/stack/runner.ts +774 -109
- package/src/agent-src/templates/scripts/work_engine/state.ts +57 -7
- package/src/agent-src/templates/scripts/work_engine/taxonomy/detect.ts +500 -0
- package/src/agent-src/templates/scripts/work_engine/taxonomy/place.ts +183 -0
- package/src/config/agent-settings.template.yml +91 -22
- package/src/config/ci-local-parity.yml +18 -0
- package/src/config/continuity-surface.json +9 -2
- package/src/config/evaluator-budgets.json +4 -4
- package/src/config/gate-coverage.yml +327 -3
- package/src/config/gate-violation-baselines.json +21 -9
- package/src/config/hook-bundle-budget.json +25 -0
- package/src/config/hook-latency-budget.json +21 -0
- package/src/config/hook-token-budget.json +8 -3
- package/src/config/host-instruction-limits.json +33 -0
- package/src/config/metric-registry.yml +114 -0
- package/src/config/placeholder-drift-budget.json +10 -0
- package/src/config/routing-coverage-seed.json +38 -3
- package/src/config/rule-activation-census.json +7 -3
- package/src/config/rule-consequence-class.json +161 -0
- package/src/config/rule-law-ceilings.json +99 -0
- package/src/install/claudePathsPlan.ts +46 -4
- package/src/install/claudeRuleRewrite.ts +10 -1
- package/src/install/emit_host_rules_cli.ts +43 -34
- package/src/install/globalRuleScope.ts +109 -0
- package/src/install/host_rule_ownership.ts +170 -0
- package/src/install/installThinLayer.ts +312 -0
- package/src/install/installedRuleLinks.ts +220 -0
- package/src/install/wizard-plan.ts +24 -0
- package/src/scripts/_cli/cmd_doctor.ts +28 -90
- package/src/scripts/_cli/cmd_doctor_neighbours.ts +293 -0
- package/src/scripts/_cli/doctor_execution.ts +100 -17
- package/src/scripts/_cli/doctor_network_posture.ts +226 -0
- package/src/scripts/_dispatch.bash +16 -2
- package/src/scripts/_lib/agent_settings.ts +11 -0
- package/src/scripts/_lib/body_portable.ts +102 -0
- package/src/scripts/_lib/cc_transcript.ts +132 -1
- package/src/scripts/_lib/claude_settings_hooks.ts +10 -8
- package/src/scripts/_lib/concern_sla_window.ts +200 -0
- package/src/scripts/_lib/estate_offsets.ts +241 -0
- package/src/scripts/_lib/exemption_shape.ts +143 -0
- package/src/scripts/_lib/fnv.ts +23 -0
- package/src/scripts/_lib/foreign_scan.ts +106 -0
- package/src/scripts/_lib/forge_protection.ts +114 -0
- package/src/scripts/_lib/forge_reader.ts +558 -0
- package/src/scripts/_lib/gitignore_block.ts +314 -0
- package/src/scripts/_lib/global_deploy_inventory.ts +32 -0
- package/src/scripts/_lib/graph_feeder_record.ts +214 -0
- package/src/scripts/_lib/hook_settings.ts +73 -0
- package/src/scripts/_lib/host_capability.ts +40 -19
- package/src/scripts/_lib/host_env_write.ts +111 -0
- package/src/scripts/_lib/host_hook_merge.ts +165 -0
- package/src/scripts/_lib/installed_layer.ts +538 -0
- package/src/scripts/_lib/json_merge.ts +82 -0
- package/src/scripts/_lib/json_pointers.ts +93 -11
- package/src/scripts/_lib/lean_projection_mode.ts +275 -15
- package/src/scripts/_lib/llm_proposer_transport.ts +14 -4
- package/src/scripts/_lib/machine_wake.ts +16 -3
- package/src/scripts/_lib/neighbour_census.ts +760 -0
- package/src/scripts/_lib/neighbour_scan.ts +122 -0
- package/src/scripts/_lib/neighbour_tool_use.ts +189 -0
- package/src/scripts/_lib/obligations.ts +119 -8
- package/src/scripts/_lib/probe_inputs.ts +271 -0
- package/src/scripts/_lib/prompt_shape.ts +46 -0
- package/src/scripts/_lib/read_surface_scan.ts +322 -0
- package/src/scripts/_lib/release_highlights.ts +2 -1
- package/src/scripts/_lib/release_migration_gate.ts +19 -3
- package/src/scripts/_lib/reserved_name_sweep.ts +73 -0
- package/src/scripts/_lib/retrieval_sanitize.ts +77 -16
- package/src/scripts/_lib/review_coverage.ts +134 -0
- package/src/scripts/_lib/rule_consequence_class.ts +71 -0
- package/src/scripts/_lib/rule_injection.ts +130 -10
- package/src/scripts/_lib/rule_law_section.ts +147 -0
- package/src/scripts/_lib/rule_layer_overlap.ts +58 -0
- package/src/scripts/_lib/shell_write_shapes.ts +108 -0
- package/src/scripts/_lib/skill_origin.ts +254 -0
- package/src/scripts/_lib/structural_hiding.ts +622 -0
- package/src/scripts/_lib/structured_ask.ts +64 -21
- package/src/scripts/_lib/thin_rules.ts +540 -0
- package/src/scripts/_lib/touched_file_quality.ts +434 -0
- package/src/scripts/_lib/turn_end_refusals.ts +600 -4
- package/src/scripts/_lib/turn_end_transcript.ts +216 -0
- package/src/scripts/_lib/verification_command.ts +324 -0
- package/src/scripts/_lib/verification_evidence.ts +647 -0
- package/src/scripts/_lib/verify_clause.ts +280 -0
- package/src/scripts/_lib/windsurf_render.ts +63 -0
- package/src/scripts/ai_council/cli_call_budget.ts +13 -5
- package/src/scripts/ai_council/clients.ts +26 -57
- package/src/scripts/ai_council/config.ts +1 -1
- package/src/scripts/ai_council/vendor_defaults.ts +45 -0
- package/src/scripts/ai_team/team_dispatch.ts +4 -0
- package/src/scripts/audit_skill_overlap.ts +261 -0
- package/src/scripts/before_complete_hook.ts +573 -25
- package/src/scripts/bench_hook_latency.ts +412 -5
- package/src/scripts/bench_touched_file_quality.ts +238 -0
- package/src/scripts/cache_realization_report.ts +61 -1
- package/src/scripts/check_argument_hint.ts +287 -0
- package/src/scripts/check_claims.ts +125 -1
- package/src/scripts/check_enforcement_coverage.ts +38 -9
- package/src/scripts/check_enforcement_matrix.ts +621 -22
- package/src/scripts/check_estate_count.ts +130 -153
- package/src/scripts/check_finding_dispositions.ts +138 -7
- package/src/scripts/check_generator_sync.ts +71 -0
- package/src/scripts/check_hook_bundle_composition.ts +370 -0
- package/src/scripts/check_host_docs_digest.ts +786 -0
- package/src/scripts/check_host_format_column.ts +559 -0
- package/src/scripts/check_input_references.ts +228 -0
- package/src/scripts/check_inputs_parity.ts +235 -0
- package/src/scripts/check_kernel_edit_ratified.ts +89 -9
- package/src/scripts/check_kill_switch_table.ts +294 -0
- package/src/scripts/check_memory.ts +7 -1
- package/src/scripts/check_placeholder_drift.ts +221 -0
- package/src/scripts/check_read_surface_coverage.ts +515 -0
- package/src/scripts/check_release_highlights.ts +10 -0
- package/src/scripts/check_release_holds.ts +2 -1
- package/src/scripts/check_release_pr_shape.ts +38 -15
- package/src/scripts/check_routing_coverage.ts +378 -11
- package/src/scripts/check_standing_rule_delivery.ts +33 -13
- package/src/scripts/check_static_parity.ts +17 -0
- package/src/scripts/check_verify_expectation_delta.ts +521 -0
- package/src/scripts/ci_settle.ts +145 -19
- package/src/scripts/closure_scan.ts +115 -1
- package/src/scripts/code_graph/detect.ts +127 -7
- package/src/scripts/code_graph/foreign.ts +194 -0
- package/src/scripts/code_graph/query.ts +217 -4
- package/src/scripts/code_graph/types.ts +26 -2
- package/src/scripts/code_graph/validate.ts +3 -1
- package/src/scripts/code_graph/verbs.ts +103 -0
- package/src/scripts/compile_hook_manifest.ts +90 -14
- package/src/scripts/condense.ts +14 -27
- package/src/scripts/estate_exemption_shape.ts +202 -0
- package/src/scripts/external_sources_denylist.json +29 -4
- package/src/scripts/generate_host_cost_table.ts +1 -1
- package/src/scripts/hook_manifest.json +1 -1
- package/src/scripts/hook_manifest.yaml +192 -14
- package/src/scripts/hooks/block_config_weakening.ts +294 -4
- package/src/scripts/hooks/block_kernel_rule_writes.ts +9 -78
- package/src/scripts/hooks/block_plumbing_writes.ts +342 -0
- package/src/scripts/hooks/bundle_integrity.ts +291 -0
- package/src/scripts/hooks/chain_nudge_hook.ts +1 -2
- package/src/scripts/hooks/code_graph_context_hook.ts +253 -25
- package/src/scripts/hooks/comment_discipline_hook.ts +1 -3
- package/src/scripts/hooks/concern_failure_policy.ts +280 -0
- package/src/scripts/hooks/concern_registry.ts +2 -0
- package/src/scripts/hooks/concern_timings.ts +94 -0
- package/src/scripts/hooks/delegation_nudge_hook.ts +1 -2
- package/src/scripts/hooks/design_pass_hook.ts +100 -9
- package/src/scripts/hooks/design_slop_hook.ts +1 -2
- package/src/scripts/hooks/dispatch_hook.ts +77 -71
- package/src/scripts/hooks/edit_shape_hook.ts +1 -2
- package/src/scripts/hooks/end_review_nudge_hook.ts +1 -1
- package/src/scripts/hooks/evidence_independence.ts +1 -2
- package/src/scripts/hooks/exit_codes.ts +129 -0
- package/src/scripts/hooks/host_lowering.json +1 -0
- package/src/scripts/hooks/host_lowering.ts +146 -3
- package/src/scripts/hooks/host_lowering.yaml +262 -46
- package/src/scripts/hooks/host_semantics.ts +30 -2
- package/src/scripts/hooks/injection_budget.ts +9 -2
- package/src/scripts/hooks/interruption_ledger_hook.ts +1 -2
- package/src/scripts/hooks/journal_record_hook.ts +1 -2
- package/src/scripts/hooks/memory_recall_hook.ts +1 -2
- package/src/scripts/hooks/obligation_settle_hook.ts +151 -5
- package/src/scripts/hooks/one_question_per_ask_hook.ts +43 -6
- package/src/scripts/hooks/orchestration_record_hook.ts +1 -2
- package/src/scripts/hooks/payload_stub.ts +10 -1
- package/src/scripts/hooks/permission_gate.ts +1 -2
- package/src/scripts/hooks/push_settle_hook.ts +1 -3
- package/src/scripts/hooks/replay_hook.ts +2 -1
- package/src/scripts/hooks/reread_guard_hook.ts +1 -2
- package/src/scripts/hooks/review_baseline_hook.ts +1 -2
- package/src/scripts/hooks/rtk_wrap_hook.ts +1 -2
- package/src/scripts/hooks/rule_inject_hook.ts +765 -68
- package/src/scripts/hooks/run_continuation_hook.ts +13 -15
- package/src/scripts/hooks/skill_route_hook.ts +1 -2
- package/src/scripts/hooks/source_first_gate_hook.ts +1 -2
- package/src/scripts/hooks/spawn_guard_shadow_hook.ts +1 -2
- package/src/scripts/hooks/subagent_ledger_hook.ts +1 -2
- package/src/scripts/hooks/suggestion_capture_hook.ts +1 -1
- package/src/scripts/hooks/table_fingerprint.ts +70 -0
- package/src/scripts/hooks/telemetry_flush_hook.ts +1 -2
- package/src/scripts/hooks/telemetry_usage_hook.ts +65 -10
- package/src/scripts/hooks/tool_result_bytes_hook.ts +93 -9
- package/src/scripts/hooks/turn_end_gate_hook.ts +421 -324
- package/src/scripts/hooks/ui_route_nudge_hook.ts +1 -2
- package/src/scripts/hooks_status.ts +112 -0
- package/src/scripts/injection_scan_hook.ts +7 -0
- package/src/scripts/install.ts +75 -189
- package/src/scripts/installed_layer_report.ts +103 -0
- package/src/scripts/language_mirror_hook.ts +15 -6
- package/src/scripts/learning_sidecar.ts +119 -8
- package/src/scripts/lint_deny_text.ts +419 -0
- package/src/scripts/lint_exit_codes.ts +262 -0
- package/src/scripts/lint_hook_manifest.ts +108 -0
- package/src/scripts/lint_major_migration_sections.ts +156 -26
- package/src/scripts/lint_pack_boundaries.ts +63 -5
- package/src/scripts/lint_roadmap_blockers.ts +78 -12
- package/src/scripts/lint_rule_law_section.ts +517 -0
- package/src/scripts/lint_skill_descriptions.ts +1 -1
- package/src/scripts/lint_skill_scripts_readonly.ts +1 -1
- package/src/scripts/lint_workflow_security.ts +161 -5
- package/src/scripts/mcp_server/consumer_tool_catalog.json +53 -0
- package/src/scripts/mcp_server/graph_tools.ts +72 -3
- package/src/scripts/mcp_server/prompts.ts +142 -1
- package/src/scripts/measure_routing_signal.ts +54 -16
- package/src/scripts/measure_skill_ranker_baseline.ts +515 -53
- package/src/scripts/measure_turn_end_gate.ts +193 -0
- package/src/scripts/memory_learn_hook.ts +91 -6
- package/src/scripts/memory_lookup.ts +1 -1
- package/src/scripts/model_rule_injection.ts +52 -5
- package/src/scripts/prepack-check.mjs +53 -0
- package/src/scripts/project_thin_rules.ts +34 -327
- package/src/scripts/release_publication.ts +13 -1
- package/src/scripts/report_evidence_temperature.ts +657 -0
- package/src/scripts/report_installed_rule_links.ts +157 -0
- package/src/scripts/report_invocation_surface.ts +383 -0
- package/src/scripts/report_label_agreement.ts +233 -0
- package/src/scripts/report_obligation_carriers.ts +699 -0
- package/src/scripts/report_obligation_mechanism.ts +230 -0
- package/src/scripts/report_obligation_writer_split.ts +236 -0
- package/src/scripts/report_single_token_triggers.ts +277 -0
- package/src/scripts/report_skill_menu_census.ts +208 -0
- package/src/scripts/report_skill_ranker_confusion.ts +442 -0
- package/src/scripts/report_standing_payload_by_host.ts +188 -15
- package/src/scripts/report_verification_record_coverage.ts +306 -0
- package/src/scripts/roadmap_verify_share.ts +213 -0
- package/src/scripts/rule_activation_census.ts +5 -2
- package/src/scripts/rule_trigger_eval.ts +9 -9
- package/src/scripts/schemas/command.schema.json +44 -0
- package/src/scripts/schemas/review-findings.schema.json +7 -2
- package/src/scripts/schemas/rule.schema.json +5 -0
- package/src/scripts/schemas/skill.schema.json +44 -0
- package/src/scripts/self_review_gate.ts +421 -17
- package/src/scripts/semantic_parity_census.ts +314 -0
- package/src/scripts/session_eol_report.ts +54 -1
- package/src/scripts/skill_tools/score_skill_relevance.ts +290 -25
- package/src/scripts/sweep_dead_scan_roots.ts +1 -1
- package/src/scripts/sweep_skill_ranker_signals.ts +129 -0
- package/src/scripts/sync_gitignore.ts +29 -235
- package/src/scripts/trigger_eval_grandfather.json +0 -7
- package/src/scripts/trigger_eval_rotation.ts +122 -27
- package/src/scripts/ui_conformance_probe.ts +156 -4
- package/src/scripts/update_prices.ts +85 -3
- package/src/scripts/write_bundle_digest.mjs +74 -0
- package/src/server/schemas/settings.ts +41 -0
- package/src/shared/skillRanking.ts +117 -11
- package/src/templates/consumer-settings/ONBOARDING.md +1 -0
- package/dist/cli-delegate/chunk-FXYUYU4N.js +0 -4416
- package/dist/cli-delegate/chunk-QJWAUMJW.js +0 -1072
- package/dist/cli-delegate/chunk-YDPILCOL.js +0 -152
- package/dist/ui/assets/index-DH1xc62v.js +0 -29
- package/dist/ui/assets/index-jSfMW8_t.css +0 -1
|
@@ -0,0 +1,521 @@
|
|
|
1
|
+
#!/usr/bin/env tsx
|
|
2
|
+
/**
|
|
3
|
+
* A `verify:` clause this change ADDS names what its command must produce.
|
|
4
|
+
*
|
|
5
|
+
* THE DEFECT. `verify: `cat notes.md`` is a legal, green, fully-conforming step
|
|
6
|
+
* field whose oracle cannot say no: the step gets flipped on a command that was
|
|
7
|
+
* never able to fail. The grammar that fixes it shipped in
|
|
8
|
+
* `_lib/verify_clause.ts` — the optional `-> 0` / `-> /regex/` tail — and
|
|
9
|
+
* `closure_scan` reports the unfalsifiable share as a number. Reporting is
|
|
10
|
+
* where it stopped. Measured over the active estate on 2026-10-01: 173 clauses,
|
|
11
|
+
* 99 naming a command, 34 naming an expectation, and all 34 authored in one
|
|
12
|
+
* round. The grammar exists and nothing asks anyone to use it.
|
|
13
|
+
*
|
|
14
|
+
* WHY DIFF-SCOPED, AND WHY THAT IS NOT A WEAKER VERSION OF ESTATE-SCOPED.
|
|
15
|
+
* Gating the estate would red 139 clauses across every roadmap active before
|
|
16
|
+
* this round, on a day nobody authored any of them. A gate that arrives red on
|
|
17
|
+
* most of its corpus is a backlog with an exit code, and the predictable end is
|
|
18
|
+
* that it gets weakened until it finds nothing. This reads only clauses the
|
|
19
|
+
* change under review ADDED or CHANGED, so the corpus is whatever the author is
|
|
20
|
+
* already writing, and the old clauses stay legal exactly as prose does.
|
|
21
|
+
*
|
|
22
|
+
* REPLAYED BEFORE IT WAS WRITTEN, not after. Over the last thirty merges on
|
|
23
|
+
* the trunk that touched a roadmap: 145 added command-bearing
|
|
24
|
+
* clauses, 96 already carrying an expectation, 49 bare — and **6 of the 30
|
|
25
|
+
* merges would have gone red**, 39 of the 49 sitting in a single bulk-authoring
|
|
26
|
+
* round. 20% is under the one-in-four share at which this ratchet was to be
|
|
27
|
+
* withdrawn as too costly. `--replay <n>` reproduces that table on demand,
|
|
28
|
+
* which is the whole measurement rather than a memory of it.
|
|
29
|
+
*
|
|
30
|
+
* THE POINTER CARVE-OUT, and it is measured rather than assumed. 8 of those 49
|
|
31
|
+
* bare clauses are not commands at all: a backticked FILE PATH or test id
|
|
32
|
+
* written after the label, which the shared parser reads as a command because
|
|
33
|
+
* that is what a backticked token looks like to it. Demanding `-> 0` from
|
|
34
|
+
* `docs/CLAIMS.md` teaches authors to paste a meaningless arrow, which is the
|
|
35
|
+
* failure this gate exists to prevent arriving through its own front door. So a
|
|
36
|
+
* single whitespace-free token ending in a source or document extension, with
|
|
37
|
+
* an optional `:line` suffix, is a POINTER and is not asked for an oracle.
|
|
38
|
+
* Anything containing a space is a command: `cat file.md` still has to answer.
|
|
39
|
+
*
|
|
40
|
+
* The carve-out lives HERE and not in the parser. Widening `verify_clause.ts`
|
|
41
|
+
* would change what `closure_scan` and the run-continuation hook see, and both
|
|
42
|
+
* were measured on the current grammar.
|
|
43
|
+
*
|
|
44
|
+
* THE ARROW IS NOT PARSED HERE AT ALL. This gate asks `parseVerifyClause`
|
|
45
|
+
* whether a clause carries an expectation and never looks at the arrow itself:
|
|
46
|
+
* a second arrow regex is how a grammar and its gate drift, and a drifted pair
|
|
47
|
+
* fails silently — an expectation simply stops being read and a conforming
|
|
48
|
+
* clause is refused. An earlier version re-exported `VERIFY_ARROW_SOURCE` so a
|
|
49
|
+
* test could assert equality with the parser's copy; a reviewer pointed out
|
|
50
|
+
* that comparing two equal STRINGS proves nothing about where either came
|
|
51
|
+
* from, and the re-export is gone. What is asserted instead is behavioural —
|
|
52
|
+
* the gate's verdict changes when the parser's grammar does, because the
|
|
53
|
+
* parser is the only thing that reads it.
|
|
54
|
+
*
|
|
55
|
+
* CLI:
|
|
56
|
+
* ./scripts-run src/scripts/check_verify_expectation_delta
|
|
57
|
+
* ./scripts-run src/scripts/check_verify_expectation_delta --base origin/main
|
|
58
|
+
* ./scripts-run src/scripts/check_verify_expectation_delta --replay 30
|
|
59
|
+
* ./scripts-run src/scripts/check_verify_expectation_delta --self-test
|
|
60
|
+
*
|
|
61
|
+
* Exit codes: 0 clean · 1 a bare clause was added · 2 usage error or no base ref.
|
|
62
|
+
*/
|
|
63
|
+
import { spawnSync } from 'node:child_process';
|
|
64
|
+
import * as fs from 'node:fs';
|
|
65
|
+
import * as os from 'node:os';
|
|
66
|
+
import * as path from 'node:path';
|
|
67
|
+
import process from 'node:process';
|
|
68
|
+
import { fileURLToPath, pathToFileURL } from 'node:url';
|
|
69
|
+
|
|
70
|
+
import { parseVerifyClause } from './_lib/verify_clause.js';
|
|
71
|
+
import { resolveBaseRef } from './_lib/ratchet_base_ref.js';
|
|
72
|
+
import { reportScanned, DeadScopeError } from './_lib/scan_scope.js';
|
|
73
|
+
import { runGateCli, runSelfTest, type SelfTestCase } from './_lib/gate_self_test.js';
|
|
74
|
+
|
|
75
|
+
const _HERE = path.resolve(fileURLToPath(import.meta.url));
|
|
76
|
+
const REPO_ROOT = path.resolve(path.dirname(_HERE), '..', '..');
|
|
77
|
+
const GATE = 'check_verify_expectation_delta';
|
|
78
|
+
const ROADMAPS_REL = 'agents/roadmaps';
|
|
79
|
+
const SCRIPT_REL = 'src/scripts/check_verify_expectation_delta.ts';
|
|
80
|
+
|
|
81
|
+
/** Declared here so a truncated case list is a visible diff, not a quiet pass. */
|
|
82
|
+
const SELF_TEST_MIN_CASES = 6;
|
|
83
|
+
const SELF_TEST_MIN_REJECT = 3;
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* A backticked value that points AT something rather than running.
|
|
87
|
+
*
|
|
88
|
+
* One token, no whitespace, a source or document extension, optionally a
|
|
89
|
+
* `:line` suffix. Measured at 8 of 49 bare clauses over thirty merges — a sixth
|
|
90
|
+
* of what an uncarved gate would have fired on.
|
|
91
|
+
*
|
|
92
|
+
* THE INVOCATION PREFIX IS EXCLUDED, and that is a review finding rather than a
|
|
93
|
+
* refinement: `./src/scripts/check.ts` ends in `.ts` and this pattern exempted
|
|
94
|
+
* it, while being exactly the shape a shebang-bearing script is RUN as in this
|
|
95
|
+
* tree. A path written to be executed starts with `./` or `/`; a pointer is
|
|
96
|
+
* written relative and bare. That is a convention, not a proof — the honest
|
|
97
|
+
* statement is that this discriminates the shapes the tree actually contains
|
|
98
|
+
* and cannot infer intent in general.
|
|
99
|
+
*
|
|
100
|
+
* KNOWN AND NOT FIXED, because the fix is worse than the gap: `Makefile`,
|
|
101
|
+
* `README` and `script.sh` are pointers this refuses, and a path containing a
|
|
102
|
+
* space is a command by the rule above. Widening the extension list buys those
|
|
103
|
+
* and costs the executable-script direction again. Both directions are pinned
|
|
104
|
+
* by test so a later change to this pattern is deliberate.
|
|
105
|
+
*/
|
|
106
|
+
const POINTER_RE = /^(?!\.{0,2}\/)[^\s`]+\.(?:ts|tsx|js|mjs|cjs|md|json|ya?ml|html|txt|lock)(?::\d+)?$/i;
|
|
107
|
+
|
|
108
|
+
/** Does this clause body name something to RUN, as opposed to something to open? */
|
|
109
|
+
export function isPointer(command: string): boolean {
|
|
110
|
+
return POINTER_RE.test(command.trim());
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
export interface BareClause {
|
|
114
|
+
/** Repo-relative path of the roadmap the clause was added to. */
|
|
115
|
+
readonly file: string;
|
|
116
|
+
/** The command half, as written. */
|
|
117
|
+
readonly command: string;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/** A git invocation that FAILED. Never collapsed into an empty-but-plausible read. */
|
|
121
|
+
export class GitReadError extends Error {
|
|
122
|
+
constructor(args: readonly string[], stderr: string) {
|
|
123
|
+
super(`git ${args.join(' ')} failed: ${stderr.trim().split('\n')[0] ?? '(no stderr)'}`);
|
|
124
|
+
this.name = 'GitReadError';
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* Run git, or throw.
|
|
130
|
+
*
|
|
131
|
+
* `{ ok: false, stdout: '' }` was the inherited shape and it is the wrong one
|
|
132
|
+
* HERE, because both readers below treat stdout as their whole corpus: a failed
|
|
133
|
+
* spawn, a missing ref or a `maxBuffer` overrun would have become "no merges"
|
|
134
|
+
* and "no clauses", and the replay would then print an authoritative-looking
|
|
135
|
+
* table of zeroes that the gate's own header cites as its evidence. A
|
|
136
|
+
* measurement that can silently measure nothing cannot justify the thing it
|
|
137
|
+
* measures. Throwing makes the failure reach an exit code.
|
|
138
|
+
*/
|
|
139
|
+
function git(args: readonly string[], cwd: string): string {
|
|
140
|
+
const res = spawnSync('git', [...args], { cwd, encoding: 'utf-8', maxBuffer: 64 * 1024 * 1024 });
|
|
141
|
+
if (res.error !== undefined || res.status !== 0) {
|
|
142
|
+
throw new GitReadError(args, res.stderr ?? res.error?.message ?? '');
|
|
143
|
+
}
|
|
144
|
+
return res.stdout ?? '';
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/** One added clause, parsed once. The gate and its report read the same list. */
|
|
148
|
+
export interface AddedClause {
|
|
149
|
+
readonly file: string;
|
|
150
|
+
readonly command: string;
|
|
151
|
+
/** The clause states an oracle — `-> 0` or `-> /regex/`. */
|
|
152
|
+
readonly hasExpectation: boolean;
|
|
153
|
+
/** The clause points at a file rather than naming something to run. */
|
|
154
|
+
readonly pointer: boolean;
|
|
155
|
+
/** States an oracle, or is exempt from stating one. The gate's predicate. */
|
|
156
|
+
readonly satisfied: boolean;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* A unified-diff line that OPENS a file section — `+++ b/<path>`.
|
|
161
|
+
*
|
|
162
|
+
* Matched as the whole header rather than by a `+++` prefix, because an added
|
|
163
|
+
* CONTENT line whose own text begins with `++` is rendered `+++…` and a prefix
|
|
164
|
+
* test discards it as metadata. Narrow in practice and wrong in principle: this
|
|
165
|
+
* reader claimed to parse a unified diff and was reading its first character.
|
|
166
|
+
* `/dev/null` is the delete side and names no file.
|
|
167
|
+
*/
|
|
168
|
+
const FILE_HEADER_RE = /^\+\+\+ (?:b\/(.+)|\/dev\/null)$/;
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* Every `verify:` clause a unified patch ADDS, each with its verdict.
|
|
172
|
+
*
|
|
173
|
+
* ONE parsed pass, deliberately. The count the gate reports and the set it
|
|
174
|
+
* convicts on used to be derived separately — a line filter for the first, a
|
|
175
|
+
* parse for the second — so a patch with ten `verify:` lines of which three
|
|
176
|
+
* were prose reported "scanned 10" while enforcing over 7. A scan count that
|
|
177
|
+
* does not describe the enforced set is the false-denominator shape this
|
|
178
|
+
* repository's gate-coverage manifest exists to prevent.
|
|
179
|
+
*
|
|
180
|
+
* Reads `+` lines only. A context line carrying a bare clause is a clause this
|
|
181
|
+
* change did not write, and convicting on it would make flipping a checkbox two
|
|
182
|
+
* lines above an unrelated verify line fail the author's change — the exact
|
|
183
|
+
* collateral that turns a diff-scoped gate back into an estate-scoped one.
|
|
184
|
+
*/
|
|
185
|
+
export function addedClausesIn(patch: string): AddedClause[] {
|
|
186
|
+
const out: AddedClause[] = [];
|
|
187
|
+
let file = '';
|
|
188
|
+
for (const raw of patch.split('\n')) {
|
|
189
|
+
const fm = FILE_HEADER_RE.exec(raw);
|
|
190
|
+
if (fm !== null) {
|
|
191
|
+
file = fm[1] ?? '';
|
|
192
|
+
continue;
|
|
193
|
+
}
|
|
194
|
+
if (!raw.startsWith('+')) continue;
|
|
195
|
+
const body = raw.slice(1);
|
|
196
|
+
if (!body.includes('verify:')) continue;
|
|
197
|
+
const clause = parseVerifyClause(body);
|
|
198
|
+
// No clause, or the prose (MANUAL) form — prose stays legal by design,
|
|
199
|
+
// and an unparseable line is not a clause this gate may convict on.
|
|
200
|
+
if (clause === null || clause.command === null) continue;
|
|
201
|
+
const hasExpectation = clause.expect !== null;
|
|
202
|
+
const pointer = isPointer(clause.command);
|
|
203
|
+
out.push({ file, command: clause.command, hasExpectation, pointer, satisfied: hasExpectation || pointer });
|
|
204
|
+
}
|
|
205
|
+
return out;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
/** The subset that fails: a command, no expectation, not a pointer. */
|
|
209
|
+
export function bareClausesIn(patch: string): BareClause[] {
|
|
210
|
+
return addedClausesIn(patch)
|
|
211
|
+
.filter((c) => !c.satisfied)
|
|
212
|
+
.map((c) => ({ file: c.file, command: c.command }));
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
export interface ReplayRow {
|
|
216
|
+
readonly merge: string;
|
|
217
|
+
readonly bare: number;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
export interface Replay {
|
|
221
|
+
readonly merges: number;
|
|
222
|
+
readonly added: number;
|
|
223
|
+
readonly withExpectation: number;
|
|
224
|
+
/** Exempted as pointers — reported separately, never folded into the above. */
|
|
225
|
+
readonly pointers: number;
|
|
226
|
+
readonly bare: readonly BareClause[];
|
|
227
|
+
readonly redMerges: readonly ReplayRow[];
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
/**
|
|
231
|
+
* Replay the proposed rule over the last `n` merges that touched the roadmaps.
|
|
232
|
+
*
|
|
233
|
+
* @throws {GitReadError} when any git read fails. Deliberate: this function's
|
|
234
|
+
* output is cited as the evidence for shipping the gate, and an evidence
|
|
235
|
+
* producer that returns zeroes when it could not read anything is worse than
|
|
236
|
+
* one that does not run.
|
|
237
|
+
*/
|
|
238
|
+
export function replay(repoRoot: string, n: number, ref = 'origin/main'): Replay {
|
|
239
|
+
const list = git(
|
|
240
|
+
['log', '--merges', '--first-parent', ref, `--max-count=${String(n)}`, '--format=%h', '--', `${ROADMAPS_REL}/*.md`],
|
|
241
|
+
repoRoot,
|
|
242
|
+
);
|
|
243
|
+
const merges = list.split('\n').filter((s) => s.trim() !== '');
|
|
244
|
+
const bare: BareClause[] = [];
|
|
245
|
+
const redMerges: ReplayRow[] = [];
|
|
246
|
+
let added = 0;
|
|
247
|
+
let withExpectation = 0;
|
|
248
|
+
let pointers = 0;
|
|
249
|
+
for (const m of merges) {
|
|
250
|
+
const patch = git(['diff', '--unified=0', `${m}^1`, m, '--', ROADMAPS_REL], repoRoot);
|
|
251
|
+
// One parsed pass feeds both halves, so the denominator describes the
|
|
252
|
+
// same set the verdict is drawn from.
|
|
253
|
+
const clauses = addedClausesIn(patch);
|
|
254
|
+
added += clauses.length;
|
|
255
|
+
withExpectation += clauses.filter((c) => c.hasExpectation).length;
|
|
256
|
+
pointers += clauses.filter((c) => c.pointer).length;
|
|
257
|
+
const hits = clauses.filter((c) => !c.satisfied).map((c) => ({ file: c.file, command: c.command }));
|
|
258
|
+
bare.push(...hits);
|
|
259
|
+
if (hits.length > 0) redMerges.push({ merge: m, bare: hits.length });
|
|
260
|
+
}
|
|
261
|
+
return { merges: merges.length, added, withExpectation, pointers, bare, redMerges };
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
function repoRootFrom(start: string): string {
|
|
265
|
+
let dir = path.resolve(start);
|
|
266
|
+
for (;;) {
|
|
267
|
+
if (fs.existsSync(path.join(dir, ROADMAPS_REL))) return dir;
|
|
268
|
+
const up = path.dirname(dir);
|
|
269
|
+
if (up === dir) return path.resolve(start);
|
|
270
|
+
dir = up;
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
function renderReplay(rep: Replay): string {
|
|
275
|
+
const out: string[] = [];
|
|
276
|
+
out.push(`${GATE} --replay: ${String(rep.merges)} merge(s) replayed`);
|
|
277
|
+
out.push(` added command-bearing clauses ${String(rep.added)}`);
|
|
278
|
+
out.push(` with an expectation ${String(rep.withExpectation)}`);
|
|
279
|
+
out.push(` exempt as a file pointer ${String(rep.pointers)}`);
|
|
280
|
+
out.push(` bare (this gate would fire) ${String(rep.bare.length)}`);
|
|
281
|
+
const share = rep.merges === 0 ? 0 : Math.round((rep.redMerges.length / rep.merges) * 100);
|
|
282
|
+
out.push(` merges that would go RED ${String(rep.redMerges.length)} of ${String(rep.merges)} (${String(share)}%)`);
|
|
283
|
+
for (const r of [...rep.redMerges].sort((a, b) => b.bare - a.bare)) {
|
|
284
|
+
out.push(` ${r.merge} ${String(r.bare).padStart(3)} bare clause(s)`);
|
|
285
|
+
}
|
|
286
|
+
return out.join('\n') + '\n';
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
/** Fixtures for `--self-test`: a throwaway repo with a base commit and a change. */
|
|
290
|
+
function fixture(opts: { base: string; added: readonly string[] }): number {
|
|
291
|
+
const dir = fs.mkdtempSync(path.join(os.tmpdir(), 'verify-delta-'));
|
|
292
|
+
try {
|
|
293
|
+
const run = (...args: string[]): void => {
|
|
294
|
+
const r = spawnSync('git', args, { cwd: dir, encoding: 'utf-8' });
|
|
295
|
+
if (r.status !== 0) throw new Error(`git ${args.join(' ')}: ${r.stderr}`);
|
|
296
|
+
};
|
|
297
|
+
const write = (rel: string, body: string): void => {
|
|
298
|
+
const abs = path.join(dir, rel);
|
|
299
|
+
fs.mkdirSync(path.dirname(abs), { recursive: true });
|
|
300
|
+
fs.writeFileSync(abs, body, 'utf-8');
|
|
301
|
+
};
|
|
302
|
+
run('init', '-q', '-b', 'main');
|
|
303
|
+
run('config', 'user.email', 'verify@test.local');
|
|
304
|
+
run('config', 'user.name', 'verify');
|
|
305
|
+
run('config', 'commit.gpgsign', 'false');
|
|
306
|
+
write(`${ROADMAPS_REL}/road-to-base.md`, `# Roadmap: base\n\n## Phase 1\n\n- [ ] **1.1** s\n verify: ${opts.base}\n`);
|
|
307
|
+
run('add', '-A');
|
|
308
|
+
run('commit', '-qm', 'base');
|
|
309
|
+
run('checkout', '-qb', 'feat/change');
|
|
310
|
+
opts.added.forEach((line, i) => {
|
|
311
|
+
write(
|
|
312
|
+
`${ROADMAPS_REL}/road-to-new-${String(i)}.md`,
|
|
313
|
+
`# Roadmap: new ${String(i)}\n\n## Phase 1\n\n- [ ] **1.1** s\n verify: ${line}\n`,
|
|
314
|
+
);
|
|
315
|
+
});
|
|
316
|
+
// An edit that touches a roadmap and adds no clause. Without it the
|
|
317
|
+
// "nothing added" case has nothing to commit and dies in git rather than
|
|
318
|
+
// in the gate — and that case is the one proving the base clause is not
|
|
319
|
+
// re-read, so it has to reach the gate to mean anything.
|
|
320
|
+
write(`${ROADMAPS_REL}/road-to-base.md`, `# Roadmap: base\n\n## Phase 1\n\n- [x] **1.1** s\n verify: ${opts.base}\n`);
|
|
321
|
+
run('add', '-A');
|
|
322
|
+
run('commit', '-qm', 'change');
|
|
323
|
+
return runGateCli(REPO_ROOT, SCRIPT_REL, ['--base', 'main'], dir);
|
|
324
|
+
} finally {
|
|
325
|
+
fs.rmSync(dir, { recursive: true, force: true });
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
function selfTest(): number {
|
|
330
|
+
const cases: SelfTestCase[] = [
|
|
331
|
+
{
|
|
332
|
+
name: 'added clause naming a command and no expectation → reject',
|
|
333
|
+
expect: 'reject',
|
|
334
|
+
run: () => fixture({ base: '`true` -> 0', added: ['`./scripts-run src/scripts/check_claims`'] }),
|
|
335
|
+
},
|
|
336
|
+
{
|
|
337
|
+
name: 'added clause naming a command AND an exit expectation → accept',
|
|
338
|
+
expect: 'accept',
|
|
339
|
+
run: () => fixture({ base: '`true` -> 0', added: ['`./scripts-run src/scripts/check_claims` -> 0'] }),
|
|
340
|
+
},
|
|
341
|
+
{
|
|
342
|
+
name: 'added clause naming a command AND a regex expectation → accept',
|
|
343
|
+
expect: 'accept',
|
|
344
|
+
run: () => fixture({ base: '`true` -> 0', added: ['`grep -c x f.md` -> /^[1-9]/'] }),
|
|
345
|
+
},
|
|
346
|
+
{
|
|
347
|
+
// Prose stays legal. Forbidding it would invalidate the large
|
|
348
|
+
// majority of clauses in the tree, which is the decision
|
|
349
|
+
// `verify_clause.ts` records and this gate does not reopen.
|
|
350
|
+
name: 'added PROSE clause → accept (the MANUAL form is legal by design)',
|
|
351
|
+
expect: 'accept',
|
|
352
|
+
run: () => fixture({ base: '`true` -> 0', added: ['a human reads the rendered page and confirms it'] }),
|
|
353
|
+
},
|
|
354
|
+
{
|
|
355
|
+
// The measured carve-out: 8 of 49 bare clauses over thirty merges.
|
|
356
|
+
name: 'added clause naming a FILE PATH → accept (a pointer is not a command)',
|
|
357
|
+
expect: 'accept',
|
|
358
|
+
run: () => fixture({ base: '`true` -> 0', added: ['`tests/scripts/dispatch_integrity.test.ts`'] }),
|
|
359
|
+
},
|
|
360
|
+
{
|
|
361
|
+
name: 'a pointer with a :line suffix → accept',
|
|
362
|
+
expect: 'accept',
|
|
363
|
+
run: () => fixture({ base: '`true` -> 0', added: ['`turn_end_gate_hook.test.ts:1427`'] }),
|
|
364
|
+
},
|
|
365
|
+
{
|
|
366
|
+
// `cat file.md` is a command whose exit decides nothing — and it is
|
|
367
|
+
// still asked for an oracle, because the carve-out is about SHAPE,
|
|
368
|
+
// not about whether the author chose a weak command.
|
|
369
|
+
name: 'a command that merely cats a file → reject (the carve-out is one token only)',
|
|
370
|
+
expect: 'reject',
|
|
371
|
+
run: () => fixture({ base: '`true` -> 0', added: ['`cat docs/CLAIMS.md`'] }),
|
|
372
|
+
},
|
|
373
|
+
{
|
|
374
|
+
name: 'two added clauses, one bare → reject',
|
|
375
|
+
expect: 'reject',
|
|
376
|
+
run: () =>
|
|
377
|
+
fixture({ base: '`true` -> 0', added: ['`./scripts-run src/scripts/check_claims` -> 0', '`npx vitest run x`'] }),
|
|
378
|
+
},
|
|
379
|
+
{
|
|
380
|
+
// The grandfathering half: an untouched bare clause at base must not
|
|
381
|
+
// convict a change that added nothing.
|
|
382
|
+
//
|
|
383
|
+
// WHAT IT DOES NOT COVER, corrected on a review finding that the
|
|
384
|
+
// earlier wording here overstated: under `--unified=0` the unchanged
|
|
385
|
+
// `verify:` line does not appear in the patch at all, so this case
|
|
386
|
+
// does not exercise context-line handling and would stay green if
|
|
387
|
+
// that handling broke. The unit test `reads ADDED lines only` is
|
|
388
|
+
// what pins it. This case pins the weaker, still real property —
|
|
389
|
+
// that a change adding no clause is not convicted of the base's.
|
|
390
|
+
name: 'a bare clause ALREADY at base, nothing added → accept',
|
|
391
|
+
expect: 'accept',
|
|
392
|
+
run: () => fixture({ base: '`cat notes.md`', added: [] }),
|
|
393
|
+
},
|
|
394
|
+
{
|
|
395
|
+
// An executable script is run, not opened, however it is spelled.
|
|
396
|
+
name: 'an added `./path/script.ts` → reject (an invocation is not a pointer)',
|
|
397
|
+
expect: 'reject',
|
|
398
|
+
run: () => fixture({ base: '`true` -> 0', added: ['`./src/scripts/check_claims.ts`'] }),
|
|
399
|
+
},
|
|
400
|
+
];
|
|
401
|
+
return runSelfTest({ gate: GATE, cases, minCases: SELF_TEST_MIN_CASES, minRejectCases: SELF_TEST_MIN_REJECT });
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
export function main(argv: string[] = process.argv.slice(2)): number {
|
|
405
|
+
if (argv.includes('--self-test')) return selfTest();
|
|
406
|
+
const repoRoot = repoRootFrom(process.cwd());
|
|
407
|
+
|
|
408
|
+
const replayIdx = argv.indexOf('--replay');
|
|
409
|
+
if (replayIdx !== -1) {
|
|
410
|
+
const raw = argv[replayIdx + 1];
|
|
411
|
+
const n = raw === undefined ? NaN : Number(raw);
|
|
412
|
+
if (!Number.isInteger(n) || n <= 0) {
|
|
413
|
+
process.stderr.write(`usage: ${GATE} [--base <ref>] [--replay <n>] [--self-test]\n`);
|
|
414
|
+
return 2;
|
|
415
|
+
}
|
|
416
|
+
try {
|
|
417
|
+
process.stdout.write(renderReplay(replay(repoRoot, n)));
|
|
418
|
+
} catch (err) {
|
|
419
|
+
if (err instanceof GitReadError) {
|
|
420
|
+
process.stderr.write(
|
|
421
|
+
`❌ ${GATE} --replay: ${err.message}\n` +
|
|
422
|
+
' No table is printed. A replay that could not read its own history would\n' +
|
|
423
|
+
' otherwise print zeroes, and those zeroes are cited as this gate\'s evidence.\n',
|
|
424
|
+
);
|
|
425
|
+
return 2;
|
|
426
|
+
}
|
|
427
|
+
throw err;
|
|
428
|
+
}
|
|
429
|
+
return 0;
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
const baseIdx = argv.indexOf('--base');
|
|
433
|
+
let baseRef: string | undefined;
|
|
434
|
+
if (baseIdx !== -1) {
|
|
435
|
+
const next = argv[baseIdx + 1];
|
|
436
|
+
if (next === undefined || next.startsWith('-')) {
|
|
437
|
+
process.stderr.write(`usage: ${GATE} [--base <ref>] [--replay <n>] [--self-test]\n`);
|
|
438
|
+
return 2;
|
|
439
|
+
}
|
|
440
|
+
baseRef = next;
|
|
441
|
+
}
|
|
442
|
+
const ref = baseRef ?? resolveBaseRef(repoRoot);
|
|
443
|
+
if (ref === null) {
|
|
444
|
+
process.stderr.write(
|
|
445
|
+
`❌ ${GATE}: no base ref resolved (no origin/main, no merge-commit parent).\n` +
|
|
446
|
+
' This gate reads the clauses a CHANGE adds, so with no base there is no change\n' +
|
|
447
|
+
' to read — and a diff-scoped gate with no diff passes every possible tree.\n' +
|
|
448
|
+
' Fetch the base (`git fetch origin main`) or name it: --base origin/main\n',
|
|
449
|
+
);
|
|
450
|
+
return 2;
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
let clauses: AddedClause[];
|
|
454
|
+
try {
|
|
455
|
+
clauses = addedClausesIn(git(['diff', '--unified=0', '--find-renames', `${ref}...HEAD`, '--', ROADMAPS_REL], repoRoot));
|
|
456
|
+
} catch (err) {
|
|
457
|
+
if (err instanceof GitReadError) {
|
|
458
|
+
process.stderr.write(`❌ ${GATE}: ${err.message}\n The change could not be read, so nothing was checked.\n`);
|
|
459
|
+
return 2;
|
|
460
|
+
}
|
|
461
|
+
throw err;
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
const bare = clauses.filter((c) => !c.satisfied);
|
|
465
|
+
// The unit is the added CLAUSE, not the file: a change adding ten clauses to
|
|
466
|
+
// one roadmap scanned ten things, and reporting "1 file" would understate
|
|
467
|
+
// what was read. It is the SAME list the verdict is drawn from, which it was
|
|
468
|
+
// not in the first version — a line filter counted prose and malformed lines
|
|
469
|
+
// the parser then dropped, so the gate reported scanning more than it judged.
|
|
470
|
+
// An empty diff is a real answer here (nothing was added), never a dead
|
|
471
|
+
// scope, so the count is allowed to be zero.
|
|
472
|
+
try {
|
|
473
|
+
reportScanned({
|
|
474
|
+
gate: GATE,
|
|
475
|
+
scanned: clauses.length,
|
|
476
|
+
units: 'added verify clause(s)',
|
|
477
|
+
roots: [ROADMAPS_REL],
|
|
478
|
+
allowEmpty: 'a change that adds no verify clause has nothing to check',
|
|
479
|
+
});
|
|
480
|
+
} catch (err) {
|
|
481
|
+
if (err instanceof DeadScopeError) {
|
|
482
|
+
process.stderr.write(`❌ ${GATE}: ${err.message}\n`);
|
|
483
|
+
return 2;
|
|
484
|
+
}
|
|
485
|
+
throw err;
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
if (bare.length === 0) {
|
|
489
|
+
process.stdout.write(`✅ ${GATE}: every added verify clause states what its command must produce.\n`);
|
|
490
|
+
return 0;
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
for (const b of bare) {
|
|
494
|
+
process.stderr.write(`❌ ${b.file}: verify clause names a command and no expectation.\n ${b.command.slice(0, 160)}\n`);
|
|
495
|
+
}
|
|
496
|
+
process.stderr.write(
|
|
497
|
+
`\n ${String(bare.length)} added verify clause(s) cannot fail. A clause that names a command and\n` +
|
|
498
|
+
' no expectation is an oracle that cannot say no: the step gets flipped on a\n' +
|
|
499
|
+
' command that was never able to fail. State what the command must produce:\n' +
|
|
500
|
+
'\n' +
|
|
501
|
+
' verify: `<cmd>` -> 0 the command must exit 0\n' +
|
|
502
|
+
' verify: `<cmd>` -> /regex/ its output must match\n' +
|
|
503
|
+
'\n' +
|
|
504
|
+
' Pick the regex form when the exit status decides nothing — `grep -c`, `wc`,\n' +
|
|
505
|
+
' `head` and `cat` all exit 0 on content nobody looked at, so `-> 0` there is an\n' +
|
|
506
|
+
' expectation that still cannot fail. Prose clauses stay legal and are not read\n' +
|
|
507
|
+
' here; so is a backticked file path, which points rather than runs. This gate\n' +
|
|
508
|
+
' reads only the clauses THIS change adds — nothing already in the tree.\n',
|
|
509
|
+
);
|
|
510
|
+
return 1;
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
function isCliEntry(): boolean {
|
|
514
|
+
const entry = process.argv[1];
|
|
515
|
+
if (entry === undefined) return false;
|
|
516
|
+
return pathToFileURL(path.resolve(entry)).href === pathToFileURL(fileURLToPath(import.meta.url)).href;
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
if (isCliEntry()) {
|
|
520
|
+
process.exit(main());
|
|
521
|
+
}
|