@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
package/src/scripts/ci_settle.ts
CHANGED
|
@@ -237,9 +237,30 @@ export function classifyPoll(stdout: string, stderr: string, status: number | nu
|
|
|
237
237
|
return { kind: 'pending', total: rows.length, done };
|
|
238
238
|
}
|
|
239
239
|
const bad = new Set(['FAILURE', 'TIMED_OUT', 'CANCELLED', 'ACTION_REQUIRED', 'STARTUP_FAILURE']);
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
240
|
+
// A concurrency group that supersedes its own earlier run leaves TWO rows
|
|
241
|
+
// under one name: the superseded one CANCELLED, the one that counts
|
|
242
|
+
// SUCCESS. The forge reports that check green; this classifier reported the
|
|
243
|
+
// whole PR red, because CANCELLED sat in `bad` and nothing looked at the
|
|
244
|
+
// twin. Measured 2026-10-01 on PR #2135 (`lint commit subjects`), where the
|
|
245
|
+
// false red cost a run a diagnosis it did not owe.
|
|
246
|
+
//
|
|
247
|
+
// The reprieve is deliberately the narrowest one that fixes it: CANCELLED
|
|
248
|
+
// only, and only when a row of the SAME NAME concluded SUCCESS. A genuine
|
|
249
|
+
// cancellation — a human stopping a run, a timeout killing one — has no
|
|
250
|
+
// successful twin and stays failing. Widening this to every bad conclusion,
|
|
251
|
+
// or to CANCELLED unconditionally, would trade a false red for a false
|
|
252
|
+
// green, which is the worse error in a tool whose output is acted on.
|
|
253
|
+
const nameOf = (r: (typeof rows)[number]): string => String(r.name ?? '?');
|
|
254
|
+
const concl = (r: (typeof rows)[number]): string => String(r.conclusion).toUpperCase();
|
|
255
|
+
const succeeded = new Set(rows.filter((r) => concl(r) === 'SUCCESS').map(nameOf));
|
|
256
|
+
const failing = [
|
|
257
|
+
...new Set(
|
|
258
|
+
rows
|
|
259
|
+
.filter((r) => bad.has(concl(r)))
|
|
260
|
+
.filter((r) => !(concl(r) === 'CANCELLED' && succeeded.has(nameOf(r))))
|
|
261
|
+
.map(nameOf),
|
|
262
|
+
),
|
|
263
|
+
];
|
|
243
264
|
return { kind: 'settled', failing, total: rows.length };
|
|
244
265
|
}
|
|
245
266
|
|
|
@@ -293,25 +314,131 @@ function sleepSync(seconds: number): void {
|
|
|
293
314
|
});
|
|
294
315
|
}
|
|
295
316
|
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
317
|
+
/** The only flags this waiter honours. Anything else is a caller mistake. */
|
|
318
|
+
const KNOWN_FLAGS = ['--timeout-min', '--interval-sec'] as const;
|
|
319
|
+
|
|
320
|
+
const USAGE =
|
|
321
|
+
'usage: ci_settle <pr> [--timeout-min N] [--interval-sec N]\n' +
|
|
322
|
+
` default --timeout-min is ${String(FOREGROUND_CEILING_MIN)}, which fits inside one foreground Bash call (600 s cap).\n` +
|
|
323
|
+
' a longer wait is a BACKGROUND job, not a bigger number — a foreground call past the cap is killed and reports nothing.\n';
|
|
324
|
+
|
|
325
|
+
export type ParsedArgs =
|
|
326
|
+
| { kind: 'ok'; pr: string; timeoutMin: number; intervalSec: number }
|
|
327
|
+
| { kind: 'usage'; message: string };
|
|
328
|
+
|
|
329
|
+
/**
|
|
330
|
+
* Parse argv, REFUSING anything this waiter would not honour.
|
|
331
|
+
*
|
|
332
|
+
* Refusal rather than a default is the whole point. The previous parser read
|
|
333
|
+
* its two knobs with `argv.indexOf(flag)` and filtered positionals on a leading
|
|
334
|
+
* `--`, so a caller who wrote the near-universal `--timeout 1700` got two
|
|
335
|
+
* silent substitutions at once: the unknown flag was ignored, and its value —
|
|
336
|
+
* carrying no dashes — survived as a second positional and was dropped. The
|
|
337
|
+
* wait then ran for the 9-minute default while the caller believed they had
|
|
338
|
+
* asked for 28, and the resulting `DID NOT SETTLE` read as a slow CI rather
|
|
339
|
+
* than as their own typo.
|
|
340
|
+
*
|
|
341
|
+
* That is the one failure a waiter must not have. Its entire product is a
|
|
342
|
+
* verdict somebody will act on, and a verdict produced under arguments the
|
|
343
|
+
* caller did not actually give is worse than no verdict, because it looks like
|
|
344
|
+
* one. So every unrecognised flag, every unusable value and every extra
|
|
345
|
+
* positional is a usage refusal, exit 2 — the code this tool already reserves
|
|
346
|
+
* for "no verdict is claimed".
|
|
347
|
+
*
|
|
348
|
+
* `--flag=value` is accepted beside `--flag value` because it is the other
|
|
349
|
+
* spelling a caller reaches for, and refusing it would trade one silent
|
|
350
|
+
* surprise for a noisy one with no safety gained.
|
|
351
|
+
*/
|
|
352
|
+
export function parseArgs(argv: readonly string[]): ParsedArgs {
|
|
353
|
+
const refuse = (why: string): ParsedArgs => ({ kind: 'usage', message: `ci_settle: ${why}\n${USAGE}` });
|
|
354
|
+
|
|
355
|
+
const positional: string[] = [];
|
|
356
|
+
const given = new Map<string, string>();
|
|
357
|
+
|
|
358
|
+
for (let i = 0; i < argv.length; i++) {
|
|
359
|
+
const a = argv[i] as string;
|
|
360
|
+
if (!a.startsWith('--')) {
|
|
361
|
+
positional.push(a);
|
|
362
|
+
continue;
|
|
363
|
+
}
|
|
364
|
+
const eq = a.indexOf('=');
|
|
365
|
+
const name = eq === -1 ? a : a.slice(0, eq);
|
|
366
|
+
if (!(KNOWN_FLAGS as readonly string[]).includes(name)) {
|
|
367
|
+
return refuse(
|
|
368
|
+
`unknown flag ${name}. This waiter spells its deadline --timeout-min (in MINUTES), not --timeout`,
|
|
369
|
+
);
|
|
370
|
+
}
|
|
371
|
+
if (given.has(name)) return refuse(`${name} given twice`);
|
|
372
|
+
if (eq !== -1) {
|
|
373
|
+
given.set(name, a.slice(eq + 1));
|
|
374
|
+
continue;
|
|
375
|
+
}
|
|
376
|
+
const v = argv[i + 1];
|
|
377
|
+
if (v === undefined || v.startsWith('--')) return refuse(`${name} needs a value`);
|
|
378
|
+
given.set(name, v);
|
|
379
|
+
i++;
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
const raw = positional[0];
|
|
383
|
+
if (raw === undefined) return refuse('no PR number given');
|
|
384
|
+
if (positional.length > 1) {
|
|
385
|
+
return refuse(
|
|
386
|
+
`unexpected argument ${JSON.stringify(positional[1])} — this tool takes exactly one positional, the PR number; ` +
|
|
387
|
+
'a flag value must follow its own flag',
|
|
304
388
|
);
|
|
305
|
-
return 2;
|
|
306
389
|
}
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
390
|
+
|
|
391
|
+
// Finding 1 of the 2026-10-01 R2 review: the first version of this guard
|
|
392
|
+
// validated every OPTIONAL argument and waved the mandatory one through, so
|
|
393
|
+
// the failure it exists to remove stayed reachable through the front door.
|
|
394
|
+
// `ci_settle PR-2130` parsed as ok; `gh pr view PR-2130` then exits non-zero
|
|
395
|
+
// on every poll, each one classifies as unreadable, no streak caps the loop,
|
|
396
|
+
// and the run spends its entire budget to arrive at `DID NOT SETTLE` — which
|
|
397
|
+
// is read as a slow CI rather than as the typo it is. A guard that refuses
|
|
398
|
+
// the arguments a caller may omit and accepts the one they cannot is not a
|
|
399
|
+
// guard. `#123` and a PR URL are admitted because both are what a caller
|
|
400
|
+
// copies out of the forge; a branch name is NOT, because this tool's whole
|
|
401
|
+
// verdict is bound to one head and a branch makes that binding ambiguous.
|
|
402
|
+
const pr = /^#?[0-9]+$/.test(raw)
|
|
403
|
+
? raw.replace(/^#/, '')
|
|
404
|
+
: (/^https?:\/\/[^\s]*\/pull\/([0-9]+)(?:[/?#].*)?$/.exec(raw)?.[1] ?? null);
|
|
405
|
+
if (pr === null || pr === '0' || /^0+$/.test(pr)) {
|
|
406
|
+
return refuse(
|
|
407
|
+
`${JSON.stringify(raw)} is not a PR number — give the number itself (2130), #2130, or the pull-request URL`,
|
|
408
|
+
);
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
const num = (flag: string, dflt: number): number | string => {
|
|
412
|
+
const v = given.get(flag);
|
|
413
|
+
if (v === undefined) return dflt;
|
|
414
|
+
const unit = flag === '--timeout-min' ? 'minutes' : 'seconds';
|
|
415
|
+
if (!/^[0-9]+$/.test(v)) return `${flag} wants a whole number of ${unit}, got ${JSON.stringify(v)}`;
|
|
416
|
+
const n = parseInt(v, 10);
|
|
417
|
+
// Finding 2: the parser this replaced guarded with `Number.isFinite`, and
|
|
418
|
+
// the digits-only test that replaced it does not. A long enough run of
|
|
419
|
+
// digits parses to Infinity, clears `n > 0`, and makes `deadline`
|
|
420
|
+
// unreachable — an unbounded wait in a tool whose contract is that it
|
|
421
|
+
// always returns a stated verdict or a stated non-verdict.
|
|
422
|
+
if (!Number.isFinite(n)) return `${flag} is too large to be a number of ${unit}`;
|
|
423
|
+
if (n <= 0) return `${flag} wants a positive number, got ${v}`;
|
|
424
|
+
return n;
|
|
313
425
|
};
|
|
426
|
+
|
|
314
427
|
const timeoutMin = num('--timeout-min', FOREGROUND_CEILING_MIN);
|
|
428
|
+
if (typeof timeoutMin === 'string') return refuse(timeoutMin);
|
|
429
|
+
const intervalSec = num('--interval-sec', 60);
|
|
430
|
+
if (typeof intervalSec === 'string') return refuse(intervalSec);
|
|
431
|
+
|
|
432
|
+
return { kind: 'ok', pr, timeoutMin, intervalSec };
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
export function main(argv: readonly string[]): number {
|
|
436
|
+
const parsed = parseArgs(argv);
|
|
437
|
+
if (parsed.kind === 'usage') {
|
|
438
|
+
process.stderr.write(parsed.message);
|
|
439
|
+
return 2;
|
|
440
|
+
}
|
|
441
|
+
const { pr, timeoutMin, intervalSec } = parsed;
|
|
315
442
|
if (timeoutMin > FOREGROUND_CEILING_MIN) {
|
|
316
443
|
// Said once, up front, rather than discovered when the call is killed:
|
|
317
444
|
// a truncated wait produces no line at all, so the warning has to come
|
|
@@ -322,7 +449,6 @@ export function main(argv: readonly string[]): number {
|
|
|
322
449
|
'the deadline and will report nothing — run it as a background job for a wait this long.\n',
|
|
323
450
|
);
|
|
324
451
|
}
|
|
325
|
-
const intervalSec = num('--interval-sec', 60);
|
|
326
452
|
|
|
327
453
|
// Up front, because waiting nine minutes to learn the PR was merged before
|
|
328
454
|
// the wait began is the expensive way to find out.
|
|
@@ -19,6 +19,8 @@
|
|
|
19
19
|
* `unpicked-alternative` "either X or Y", "option A … option B"
|
|
20
20
|
* `unchecked-assumption` "assuming", "presumably", "probably fine"
|
|
21
21
|
* `missing-verify` an open step with no `verify:` line
|
|
22
|
+
* `unfalsifiable-verify` a step WITH a `verify:` line whose oracle
|
|
23
|
+
* cannot say no
|
|
22
24
|
* `ambiguous-acceptance` a vague acceptance criterion (improve / clean up
|
|
23
25
|
* / best practices / handle errors properly)
|
|
24
26
|
* `contradictory` "contradicts", "conflicts with", "but also"
|
|
@@ -35,6 +37,24 @@
|
|
|
35
37
|
* Exit codes: 0 no open decisions · 1 open decisions found · 2 bad argv.
|
|
36
38
|
* Finding open decisions is the POINT, so `--strict` is what makes exit 1 a
|
|
37
39
|
* failure for a caller that wants one; the default is a report.
|
|
40
|
+
*
|
|
41
|
+
* ONE FAMILY IS A LISTING AND NEVER A GATE. `unfalsifiable-verify` exits 0
|
|
42
|
+
* unconditionally — under `--strict` too — and that is a property of the
|
|
43
|
+
* family, not a flag a caller can flip. The reason is the one this script's
|
|
44
|
+
* own header already records about a detector that fires on ordinary prose,
|
|
45
|
+
* sharpened by a measurement: on 2026-09-29 the active roadmap tree carried
|
|
46
|
+
* 230 clauses and 6 machine-decidable expectations — 97.4% of them state no
|
|
47
|
+
* oracle — so a family promoted to a gate would red all but a handful of
|
|
48
|
+
* roadmaps at once, and the cheapest repair for a gate that reds on
|
|
49
|
+
* everything is to weaken it until it finds nothing. The exemption is
|
|
50
|
+
* narrow: a `tbd` in the same corpus still goes red under `--strict`.
|
|
51
|
+
*
|
|
52
|
+
* The figure is the MEASURED one, not the commissioning roadmap's. That
|
|
53
|
+
* roadmap asserted zero expectations tree-wide; a reading refuted it — six
|
|
54
|
+
* exist, all six written before the grammar was legal, and three of them are
|
|
55
|
+
* that roadmap's own verify lines. The producing
|
|
56
|
+
* command is `./scripts-run src/scripts/roadmap_verify_share`, so the number
|
|
57
|
+
* above is re-derivable rather than remembered.
|
|
38
58
|
*/
|
|
39
59
|
|
|
40
60
|
import * as fs from 'node:fs';
|
|
@@ -42,6 +62,8 @@ import * as path from 'node:path';
|
|
|
42
62
|
import process from 'node:process';
|
|
43
63
|
import { fileURLToPath } from 'node:url';
|
|
44
64
|
|
|
65
|
+
import { parseVerifyClause, type VerifyClause } from './_lib/verify_clause.js';
|
|
66
|
+
|
|
45
67
|
const _HERE = fileURLToPath(import.meta.url);
|
|
46
68
|
const _PROG = 'closure_scan';
|
|
47
69
|
|
|
@@ -50,6 +72,7 @@ export type Kind =
|
|
|
50
72
|
| 'unpicked-alternative'
|
|
51
73
|
| 'unchecked-assumption'
|
|
52
74
|
| 'missing-verify'
|
|
75
|
+
| 'unfalsifiable-verify'
|
|
53
76
|
| 'ambiguous-acceptance'
|
|
54
77
|
| 'contradictory'
|
|
55
78
|
| 'product-semantics'
|
|
@@ -74,6 +97,7 @@ export const OWNERSHIP_BY_KIND: Readonly<Record<Kind, string>> = {
|
|
|
74
97
|
'unpicked-alternative': 'contested-technical',
|
|
75
98
|
'unchecked-assumption': 'reversible-technical',
|
|
76
99
|
'missing-verify': 'deterministic',
|
|
100
|
+
'unfalsifiable-verify': 'deterministic',
|
|
77
101
|
'ambiguous-acceptance': 'reversible-technical',
|
|
78
102
|
contradictory: 'contested-technical',
|
|
79
103
|
'product-semantics': 'product-owned',
|
|
@@ -88,6 +112,73 @@ export const OWNER_ROUTED: ReadonlySet<string> = new Set([
|
|
|
88
112
|
'destructive-owned',
|
|
89
113
|
]);
|
|
90
114
|
|
|
115
|
+
/**
|
|
116
|
+
* Families that report and never gate — `--strict` cannot make these exit 1.
|
|
117
|
+
*
|
|
118
|
+
* A set rather than a flag, so the exemption is a property of the family that a
|
|
119
|
+
* caller cannot accidentally promote. See the header for the measurement that
|
|
120
|
+
* makes promotion a bad trade today.
|
|
121
|
+
*/
|
|
122
|
+
export const NON_BLOCKING_KINDS: ReadonlySet<Kind> = new Set<Kind>(['unfalsifiable-verify']);
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Command heads whose exit status is decided by something other than the
|
|
126
|
+
* property a step is claiming.
|
|
127
|
+
*
|
|
128
|
+
* Deliberately short. `echo`, `true` and `printf` cannot fail at all; `cat`,
|
|
129
|
+
* `ls`, `pwd` and `date` fail only on a missing path or a broken clock, never
|
|
130
|
+
* on the CONTENT a step asserts. Anything whose exit code already tracks the
|
|
131
|
+
* claim — `grep` (1 on no match), a linter, a test runner — is absent on
|
|
132
|
+
* purpose: including it would turn this listing into a census of every verify
|
|
133
|
+
* line in the tree, which is step 2.2's instrument, not this one.
|
|
134
|
+
*/
|
|
135
|
+
const FIXED_OUTPUT_HEADS: ReadonlySet<string> = new Set(['echo', 'true', 'printf', 'cat', 'ls', 'pwd', 'date']);
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* Why this clause's oracle cannot say no — or `null` when it can.
|
|
139
|
+
*
|
|
140
|
+
* Three shapes, each one a way of carrying a `verify:` line that reads as
|
|
141
|
+
* verification and decides nothing.
|
|
142
|
+
*
|
|
143
|
+
* THE COUNT IS A LOWER BOUND, and saying so is the point. `scan()` assigns at
|
|
144
|
+
* most one kind per unit and the line patterns run first, so a step that also
|
|
145
|
+
* says "assuming", "merge" or "deploy" is claimed by the broader family and
|
|
146
|
+
* never reaches this one. Measured on 2026-09-29: 12 of 50 candidates were
|
|
147
|
+
* shadowed that way, so the published listing under-reports by roughly a
|
|
148
|
+
* quarter. A reader told a number and not told it is a floor would read the
|
|
149
|
+
* remainder as clean, which is the same mistake as reporting a share off a
|
|
150
|
+
* corpus nobody scanned.
|
|
151
|
+
*/
|
|
152
|
+
export function unfalsifiableReason(clause: VerifyClause): string | null {
|
|
153
|
+
if (clause.command === null) {
|
|
154
|
+
// A MANUAL clause asserting a QUANTITY nothing produced. Narrowed to a
|
|
155
|
+
// multi-digit number or an explicit `N of`/`N%` shape: a lone digit is
|
|
156
|
+
// usually a step id or an exit code being discussed, and firing on
|
|
157
|
+
// those would bury the real ones.
|
|
158
|
+
const quantity = /\b\d{2,}\b/.test(clause.raw) || /\b\d+\s*(?:%|of\b)/.test(clause.raw);
|
|
159
|
+
return quantity ? 'a manual clause asserts a quantity nothing here produces' : null;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
const head = (clause.command.trim().split(/\s+/)[0] ?? '').split('/').pop() ?? '';
|
|
163
|
+
if (FIXED_OUTPUT_HEADS.has(head) && clause.expect?.kind !== 'regex') {
|
|
164
|
+
// A regex expectation rescues a fixed-output head: `cat f -> /x/` does
|
|
165
|
+
// decide something. An exit expectation does not — naming exit 0 on a
|
|
166
|
+
// command that cannot exit anything else adds a symbol, not an oracle.
|
|
167
|
+
return `the command head \`${head}\` produces a fixed result, so the clause cannot fail`;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
if (clause.expect?.kind === 'regex') {
|
|
171
|
+
try {
|
|
172
|
+
if (new RegExp(clause.expect.source).test(clause.command)) {
|
|
173
|
+
return 'the expectation matches the command text, so an echo of the command satisfies it';
|
|
174
|
+
}
|
|
175
|
+
} catch {
|
|
176
|
+
// An expectation that cannot compile never became one upstream.
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
return null;
|
|
180
|
+
}
|
|
181
|
+
|
|
91
182
|
interface Pattern {
|
|
92
183
|
readonly kind: Kind;
|
|
93
184
|
readonly re: RegExp;
|
|
@@ -145,6 +236,17 @@ export interface Unit {
|
|
|
145
236
|
/** 1-based line of the unit's first line. */
|
|
146
237
|
readonly line: number;
|
|
147
238
|
readonly text: string;
|
|
239
|
+
/**
|
|
240
|
+
* The same block with its NEWLINES intact.
|
|
241
|
+
*
|
|
242
|
+
* `text` is joined with spaces so a wrapped pattern still matches across
|
|
243
|
+
* the wrap, and that is right for the line patterns. It is wrong for the
|
|
244
|
+
* `verify:` clause: with no newline left, "to end of line" means "to end of
|
|
245
|
+
* the step", so a manual clause inherited every digit in the evidence block
|
|
246
|
+
* written under it. Measured before this field existed: 46 of 50
|
|
247
|
+
* `unfalsifiable-verify` hits fired on a quantity the clause never wrote.
|
|
248
|
+
*/
|
|
249
|
+
readonly blockText: string;
|
|
148
250
|
readonly inAcceptance: boolean;
|
|
149
251
|
readonly isOpenStep: boolean;
|
|
150
252
|
readonly hasVerify: boolean;
|
|
@@ -188,6 +290,7 @@ export function units(lines: readonly string[]): Unit[] {
|
|
|
188
290
|
// written with single spaces stops matching across the wrap —
|
|
189
291
|
// which is the case this unit exists to catch.
|
|
190
292
|
text: block.join(' ').replace(/\s+/g, ' '),
|
|
293
|
+
blockText: block.join('\n'),
|
|
191
294
|
inAcceptance,
|
|
192
295
|
isOpenStep: OPEN_STEP_RE.test(line),
|
|
193
296
|
hasVerify: /(?:^|\s)verify:/m.test(block.join('\n')),
|
|
@@ -198,6 +301,7 @@ export function units(lines: readonly string[]): Unit[] {
|
|
|
198
301
|
out.push({
|
|
199
302
|
line: i + 1,
|
|
200
303
|
text: line,
|
|
304
|
+
blockText: line,
|
|
201
305
|
inAcceptance,
|
|
202
306
|
isOpenStep: false,
|
|
203
307
|
hasVerify: false,
|
|
@@ -227,6 +331,14 @@ export function scan(text: string): Finding[] {
|
|
|
227
331
|
if (matched === null && u.isOpenStep && !u.hasVerify && !u.inAcceptance) {
|
|
228
332
|
matched = 'missing-verify';
|
|
229
333
|
}
|
|
334
|
+
// A step that HAS a verify line, whose oracle still cannot say no.
|
|
335
|
+
// Checked on closed steps too — a `[x]` flipped on a command that
|
|
336
|
+
// could not fail is the defect in its completed form, and restricting
|
|
337
|
+
// this to open steps would hide every instance that already landed.
|
|
338
|
+
if (matched === null && u.hasVerify && !u.inAcceptance) {
|
|
339
|
+
const clause = parseVerifyClause(u.blockText);
|
|
340
|
+
if (clause !== null && unfalsifiableReason(clause) !== null) matched = 'unfalsifiable-verify';
|
|
341
|
+
}
|
|
230
342
|
if (matched === null) continue;
|
|
231
343
|
findings.push({
|
|
232
344
|
id: '',
|
|
@@ -316,7 +428,9 @@ export function main(argv?: readonly string[]): number {
|
|
|
316
428
|
}
|
|
317
429
|
}
|
|
318
430
|
if (!findings.length) return 0;
|
|
319
|
-
|
|
431
|
+
// `--strict` goes red on the families that gate, never on the listing.
|
|
432
|
+
const blocking = findings.filter((f) => !NON_BLOCKING_KINDS.has(f.kind));
|
|
433
|
+
return strict && blocking.length > 0 ? 1 : 0;
|
|
320
434
|
}
|
|
321
435
|
|
|
322
436
|
function _isCliEntry(): boolean {
|
|
@@ -17,7 +17,9 @@ import { execFileSync } from 'node:child_process';
|
|
|
17
17
|
import * as fs from 'node:fs';
|
|
18
18
|
import * as path from 'node:path';
|
|
19
19
|
|
|
20
|
+
import { load_agent_settings } from '../_lib/agent_settings.js';
|
|
20
21
|
import { hardenedSpawnEnv } from '../_lib/spawn_env.js';
|
|
22
|
+
import { EXT_LANG } from './types.js';
|
|
21
23
|
import { validateGraph } from './validate.js';
|
|
22
24
|
|
|
23
25
|
export type SourceKind = 'consumer' | 'scip' | 'native';
|
|
@@ -33,6 +35,44 @@ export interface SourceVerdict {
|
|
|
33
35
|
|
|
34
36
|
const CONSUMER_CANDIDATES = ['graph.json', 'code-graph.json', '.code-graph/graph.json'];
|
|
35
37
|
|
|
38
|
+
/**
|
|
39
|
+
* Extra graph paths the CONSUMER declares, from `code_graph.consumer_index_paths`.
|
|
40
|
+
*
|
|
41
|
+
* The default list above stays generic on purpose — three filenames, none of
|
|
42
|
+
* them any particular tool's. A tool that writes its index somewhere else is
|
|
43
|
+
* reachable by the consumer naming the path, never by this package shipping a
|
|
44
|
+
* table of vendor locations: such a table is wrong the day a tool moves its
|
|
45
|
+
* file and wrong forever about one nobody thought of, and
|
|
46
|
+
* `check_no_external_sources` would fail the build for carrying it.
|
|
47
|
+
*
|
|
48
|
+
* Absolute paths and anything escaping the project root are dropped. A setting
|
|
49
|
+
* that could point the walk at `/etc` would be a path-traversal surface in a
|
|
50
|
+
* read a consumer did not ask for.
|
|
51
|
+
*/
|
|
52
|
+
export function consumerCandidates(root: string): string[] {
|
|
53
|
+
let declared: unknown;
|
|
54
|
+
try {
|
|
55
|
+
const settings = load_agent_settings({ cwd: root }) ?? {};
|
|
56
|
+
const section = (settings as Record<string, unknown>)['code_graph'];
|
|
57
|
+
declared =
|
|
58
|
+
section !== null && typeof section === 'object' && !Array.isArray(section)
|
|
59
|
+
? (section as Record<string, unknown>)['consumer_index_paths']
|
|
60
|
+
: undefined;
|
|
61
|
+
} catch {
|
|
62
|
+
declared = undefined;
|
|
63
|
+
}
|
|
64
|
+
const extra = Array.isArray(declared)
|
|
65
|
+
? declared.filter(
|
|
66
|
+
(p): p is string =>
|
|
67
|
+
typeof p === 'string' &&
|
|
68
|
+
p !== '' &&
|
|
69
|
+
!path.isAbsolute(p) &&
|
|
70
|
+
!path.normalize(p).startsWith('..'),
|
|
71
|
+
)
|
|
72
|
+
: [];
|
|
73
|
+
return [...CONSUMER_CANDIDATES, ...extra.filter((p) => !CONSUMER_CANDIDATES.includes(p))];
|
|
74
|
+
}
|
|
75
|
+
|
|
36
76
|
function gitLastCommitEpoch(root: string): number | null {
|
|
37
77
|
try {
|
|
38
78
|
const out = execFileSync('git', ['-C', root, 'log', '-1', '--format=%ct'], {
|
|
@@ -100,7 +140,7 @@ export function detectSources(root: string, nativeCache: string): SourceVerdict[
|
|
|
100
140
|
const abs = path.resolve(root);
|
|
101
141
|
const out: SourceVerdict[] = [];
|
|
102
142
|
|
|
103
|
-
for (const rel of
|
|
143
|
+
for (const rel of consumerCandidates(abs)) {
|
|
104
144
|
const p = path.join(abs, rel);
|
|
105
145
|
if (fs.existsSync(p)) {
|
|
106
146
|
const { ok, sha } = looksLikeGraph(p);
|
|
@@ -189,7 +229,12 @@ export function computeVerdict(root: string, nativeCache: string): VerdictJSON {
|
|
|
189
229
|
export const NATIVE_CACHE_REL = path.join('agents', 'runtime', 'state', 'code-graph-v1.json');
|
|
190
230
|
|
|
191
231
|
/**
|
|
192
|
-
* The
|
|
232
|
+
* The four-state staleness token every consumer of the graph reports.
|
|
233
|
+
*
|
|
234
|
+
* `edited` is the fourth and newest (`road-to-a-graph-that-feeds-the-gate` 2.3).
|
|
235
|
+
* Without it an uncommitted change to an indexed file read as `fresh` — the one
|
|
236
|
+
* state that says "nothing stands between this answer and the tree" — which is
|
|
237
|
+
* the reading most likely to be wrong while someone is editing.
|
|
193
238
|
*
|
|
194
239
|
* Lives HERE rather than in the PreToolUse hook that first needed it
|
|
195
240
|
* (`hooks/code_graph_context_hook.ts`, step 1.2). Phase 3's verbs must each
|
|
@@ -198,7 +243,73 @@ export const NATIVE_CACHE_REL = path.join('agents', 'runtime', 'state', 'code-gr
|
|
|
198
243
|
* the engine, never the other way round. The hook re-exports this so its own
|
|
199
244
|
* consumers are unaffected.
|
|
200
245
|
*/
|
|
201
|
-
export type GraphState = 'absent' | 'fresh' | `behind:${number}`;
|
|
246
|
+
export type GraphState = 'absent' | 'fresh' | 'edited' | `behind:${number}`;
|
|
247
|
+
|
|
248
|
+
/**
|
|
249
|
+
* The working tree carries an uncommitted change to a file the extractor would
|
|
250
|
+
* index.
|
|
251
|
+
*
|
|
252
|
+
* WHY POINT-IN-TIME PORCELAIN AND NOT THE ARTIFACT'S MTIME. An mtime comparison
|
|
253
|
+
* looks cheaper and is wrong in the one direction that matters: restoring a
|
|
254
|
+
* stashed or checked-out file rewrites its mtime, so a tree put back exactly as
|
|
255
|
+
* the graph saw it would read stale forever and never return to `fresh`. The
|
|
256
|
+
* porcelain result describes a CONTENT difference, so a revert is visible as a
|
|
257
|
+
* revert.
|
|
258
|
+
*
|
|
259
|
+
* "Indexed paths" is read as *paths of the kind the extractor indexes* —
|
|
260
|
+
* `EXT_LANG`'s extensions — not as the node set of a loaded graph. Loading the
|
|
261
|
+
* graph to answer a freshness question would mean opening the index on every
|
|
262
|
+
* PreToolUse call this now runs on, which is the latency the Risk Register
|
|
263
|
+
* names; the extension filter answers the same question with no read. It can
|
|
264
|
+
* over-report (a `.ts` file the build excluded) and cannot under-report, and
|
|
265
|
+
* over-reporting `edited` only ever makes an answer look worth less than it is.
|
|
266
|
+
*
|
|
267
|
+
* Untracked files count. A source file that exists only in the working tree is
|
|
268
|
+
* precisely something the index cannot know about.
|
|
269
|
+
*
|
|
270
|
+
* `--untracked-files=all` IS LOAD-BEARING, and the default was wrong. Plain
|
|
271
|
+
* porcelain COLLAPSES an untracked directory to one entry — `?? src/` — which
|
|
272
|
+
* carries no extension, so the filter below skipped it and an entire new source
|
|
273
|
+
* tree read as `fresh`. A completion review reproduced exactly that, and it is
|
|
274
|
+
* the one direction the paragraph above promises cannot happen. The cost is
|
|
275
|
+
* enumerating untracked files rather than untracked directories; `.gitignore`
|
|
276
|
+
* still applies, so a vendored tree stays out of it.
|
|
277
|
+
*/
|
|
278
|
+
function hasUncommittedIndexedEdit(root: string): boolean {
|
|
279
|
+
let out: string;
|
|
280
|
+
try {
|
|
281
|
+
out = execFileSync('git', ['-C', root, 'status', '--porcelain', '--untracked-files=all'], {
|
|
282
|
+
env: hardenedSpawnEnv(),
|
|
283
|
+
encoding: 'utf-8',
|
|
284
|
+
stdio: ['ignore', 'pipe', 'ignore'],
|
|
285
|
+
// Both bounds are the review's: Node's 1 MB default would throw
|
|
286
|
+
// ENOBUFS on a large working tree, the catch below would return
|
|
287
|
+
// false, and the state would read `fresh` — a second silent
|
|
288
|
+
// under-report on a probe that runs at PreToolUse and at every stop.
|
|
289
|
+
// The timeout bounds the other failure: this probe sits in front of
|
|
290
|
+
// a tool call, so a hung git must not hold one up.
|
|
291
|
+
maxBuffer: 32 * 1024 * 1024,
|
|
292
|
+
timeout: 5_000,
|
|
293
|
+
});
|
|
294
|
+
} catch {
|
|
295
|
+
// Not a repository, or the probe failed: nothing is known, and an
|
|
296
|
+
// unknown is reported as the state the caller already had.
|
|
297
|
+
return false;
|
|
298
|
+
}
|
|
299
|
+
for (const raw of out.split('\n')) {
|
|
300
|
+
if (raw.length < 4) continue;
|
|
301
|
+
// `XY <path>`; a rename or copy is `XY <old> -> <new>`, and the NEW path
|
|
302
|
+
// is the one on disk. Quotes appear under core.quotepath for non-ASCII.
|
|
303
|
+
let p = raw.slice(3);
|
|
304
|
+
const arrow = p.indexOf(' -> ');
|
|
305
|
+
if (arrow !== -1) p = p.slice(arrow + 4);
|
|
306
|
+
p = p.trim().replace(/^"|"$/g, '');
|
|
307
|
+
const dot = p.lastIndexOf('.');
|
|
308
|
+
if (dot === -1) continue;
|
|
309
|
+
if (p.slice(dot).toLowerCase() in EXT_LANG) return true;
|
|
310
|
+
}
|
|
311
|
+
return false;
|
|
312
|
+
}
|
|
202
313
|
|
|
203
314
|
/**
|
|
204
315
|
* Resolve the graph's state for `root`.
|
|
@@ -206,7 +317,10 @@ export type GraphState = 'absent' | 'fresh' | `behind:${number}`;
|
|
|
206
317
|
* `absent` means no source at all — the silent case. A picked source whose
|
|
207
318
|
* staleness is UNKNOWN reads as `fresh`, mirroring {@link computeVerdict}'s own
|
|
208
319
|
* `picked.stale ? STALE : FRESH`: unknown is not treated as stale, because
|
|
209
|
-
* inventing a commit count would be worse than reporting none.
|
|
320
|
+
* inventing a commit count would be worse than reporting none. A source level
|
|
321
|
+
* with HEAD then reads `edited` instead of `fresh` while the working tree
|
|
322
|
+
* carries an uncommitted change to an indexable file — see
|
|
323
|
+
* {@link hasUncommittedIndexedEdit} for why that probe is porcelain, not mtime.
|
|
210
324
|
*
|
|
211
325
|
* `nativeCache` overrides where the native graph is looked for. It exists
|
|
212
326
|
* because a verb invoked with an explicit `--graph <path>` would otherwise
|
|
@@ -218,7 +332,13 @@ export type GraphState = 'absent' | 'fresh' | `behind:${number}`;
|
|
|
218
332
|
export function graphState(root: string, nativeCache?: string): GraphState {
|
|
219
333
|
const picked = pickSource(detectSources(root, nativeCache ?? path.join(root, NATIVE_CACHE_REL)));
|
|
220
334
|
if (!picked) return 'absent';
|
|
221
|
-
if (picked.stale
|
|
222
|
-
|
|
223
|
-
|
|
335
|
+
if (picked.stale === true) {
|
|
336
|
+
const behind = picked.commits_behind;
|
|
337
|
+
return `behind:${typeof behind === 'number' ? behind : 0}`;
|
|
338
|
+
}
|
|
339
|
+
// The commit count comes FIRST and wins: `behind:N` already says the index
|
|
340
|
+
// predates committed work, and reporting `edited` instead would hide the
|
|
341
|
+
// larger gap behind the smaller one. Only a graph level with HEAD has an
|
|
342
|
+
// uncommitted edit as its whole remaining distance.
|
|
343
|
+
return hasUncommittedIndexedEdit(root) ? 'edited' : 'fresh';
|
|
224
344
|
}
|