@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,294 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* The kill-switch table says what it counts — this checks that it still does.
|
|
4
|
+
*
|
|
5
|
+
* `docs/contracts/hook-architecture-v1.md` § Kill switches enumerates every
|
|
6
|
+
* `AGENT_CONFIG_*` identifier a file under `src/scripts/hooks/` or
|
|
7
|
+
* `src/scripts/_lib/` carries, and publishes the command that reproduces the
|
|
8
|
+
* count. An equality between a hand-written table and a grep over a growing
|
|
9
|
+
* tree is exactly the claim that decays without anybody touching the document:
|
|
10
|
+
* the table shipped at 28 == 28 and was stale within a day, because a merge
|
|
11
|
+
* brought in one hook carrying one new switch. Found by an independent review,
|
|
12
|
+
* which is a worse way to find it than a gate.
|
|
13
|
+
*
|
|
14
|
+
* WHAT IS CHECKED, and it is the equality itself rather than a proxy for it:
|
|
15
|
+
* the gate runs the published enumeration and compares the SET against the
|
|
16
|
+
* table's rows. A set comparison rather than a count, because two errors that
|
|
17
|
+
* cancel — one switch added, one row for a deleted switch left behind — is the
|
|
18
|
+
* failure a count cannot see, and it is the one that leaves a reader chasing a
|
|
19
|
+
* variable nothing reads.
|
|
20
|
+
*
|
|
21
|
+
* WHAT IS DELIBERATELY NOT CHECKED: the owner class, and the prose of each row.
|
|
22
|
+
* Whether a switch is `maintainer` or `harness` is a judgement about who is
|
|
23
|
+
* expected to set it, and a gate that guessed at it would either be wrong or
|
|
24
|
+
* would have to encode the judgement somewhere else — which is the table.
|
|
25
|
+
*
|
|
26
|
+
* THE TWO EXCLUSIONS ARE PART OF THE CONTRACT, not a convenience.
|
|
27
|
+
* `__AGENT_CONFIG_BUNDLE__` and `__AGENT_CONFIG_CLI_DELEGATE__` are esbuild
|
|
28
|
+
* `--define` identifiers (see `package.json`'s `build:*` scripts): nothing can
|
|
29
|
+
* set one at runtime, so neither is a switch. They are excluded on the emitted
|
|
30
|
+
* token, because `grep -o` strips the leading underscores and the naive
|
|
31
|
+
* `grep -v __AGENT_CONFIG_BUNDLE__` therefore matches nothing.
|
|
32
|
+
*/
|
|
33
|
+
import * as fs from 'node:fs';
|
|
34
|
+
import * as path from 'node:path';
|
|
35
|
+
import process from 'node:process';
|
|
36
|
+
import { fileURLToPath, pathToFileURL } from 'node:url';
|
|
37
|
+
|
|
38
|
+
import { GateLedger } from './_lib/gate_ledger.js';
|
|
39
|
+
import { runGateCli, runSelfTest, type SelfTestCase } from './_lib/gate_self_test.js';
|
|
40
|
+
import { assertScanned, reportScanned } from './_lib/scan_scope.js';
|
|
41
|
+
|
|
42
|
+
const GATE = 'check_kill_switch_table';
|
|
43
|
+
const CONTRACT = path.join('docs', 'contracts', 'hook-architecture-v1.md');
|
|
44
|
+
const SECTION = '## Kill switches';
|
|
45
|
+
const ROOTS = [path.join('src', 'scripts', 'hooks'), path.join('src', 'scripts', '_lib')];
|
|
46
|
+
|
|
47
|
+
/** The esbuild defines. Not environment variables, so not switches. */
|
|
48
|
+
const BUILD_DEFINES: ReadonlySet<string> = new Set([
|
|
49
|
+
'AGENT_CONFIG_BUNDLE__',
|
|
50
|
+
'AGENT_CONFIG_CLI_DELEGATE__',
|
|
51
|
+
]);
|
|
52
|
+
|
|
53
|
+
const TOKEN = /AGENT_CONFIG_[A-Z_]+/g;
|
|
54
|
+
/** A table row: `| \`AGENT_CONFIG_X\` | owner | … |`. */
|
|
55
|
+
const ROW = /^\|\s*`(AGENT_CONFIG_[A-Z_]+)`\s*\|/gm;
|
|
56
|
+
|
|
57
|
+
function walk(dir: string, out: string[]): void {
|
|
58
|
+
let entries: fs.Dirent[];
|
|
59
|
+
try {
|
|
60
|
+
entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
61
|
+
} catch {
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
for (const e of entries) {
|
|
65
|
+
const full = path.join(dir, e.name);
|
|
66
|
+
if (e.isDirectory()) {
|
|
67
|
+
walk(full, out);
|
|
68
|
+
} else if (e.isFile()) {
|
|
69
|
+
out.push(full);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/** Every switch name the declared roots carry, minus the build defines. */
|
|
75
|
+
export function switchesInTree(root: string): { names: Set<string>; files: number } {
|
|
76
|
+
const files: string[] = [];
|
|
77
|
+
for (const rel of ROOTS) {
|
|
78
|
+
walk(path.join(root, rel), files);
|
|
79
|
+
}
|
|
80
|
+
const names = new Set<string>();
|
|
81
|
+
for (const f of files) {
|
|
82
|
+
let text: string;
|
|
83
|
+
try {
|
|
84
|
+
text = fs.readFileSync(f, 'utf-8');
|
|
85
|
+
} catch {
|
|
86
|
+
continue;
|
|
87
|
+
}
|
|
88
|
+
for (const m of text.matchAll(TOKEN)) {
|
|
89
|
+
const name = m[0];
|
|
90
|
+
if (!BUILD_DEFINES.has(name)) names.add(name);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
return { names, files: files.length };
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/** Every switch the contract's table has a row for. */
|
|
97
|
+
export function switchesInTable(root: string): { names: Set<string>; present: boolean } {
|
|
98
|
+
let text: string;
|
|
99
|
+
try {
|
|
100
|
+
text = fs.readFileSync(path.join(root, CONTRACT), 'utf-8');
|
|
101
|
+
} catch {
|
|
102
|
+
return { names: new Set(), present: false };
|
|
103
|
+
}
|
|
104
|
+
const at = text.indexOf(SECTION);
|
|
105
|
+
if (at === -1) return { names: new Set(), present: false };
|
|
106
|
+
const rest = text.slice(at + SECTION.length);
|
|
107
|
+
const end = rest.indexOf('\n## ');
|
|
108
|
+
const section = end === -1 ? rest : rest.slice(0, end);
|
|
109
|
+
const names = new Set<string>();
|
|
110
|
+
for (const m of section.matchAll(ROW)) {
|
|
111
|
+
const n = m[1];
|
|
112
|
+
if (n !== undefined) names.add(n);
|
|
113
|
+
}
|
|
114
|
+
return { names, present: true };
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
export function main(argv: readonly string[] = process.argv.slice(2)): number {
|
|
118
|
+
if (argv.includes('--self-test')) return selfTest();
|
|
119
|
+
|
|
120
|
+
const root = process.cwd();
|
|
121
|
+
const ledger = new GateLedger(GATE);
|
|
122
|
+
ledger.plan(['tree-enumeration', 'table-rows', 'set-equality']);
|
|
123
|
+
|
|
124
|
+
const tree = switchesInTree(root);
|
|
125
|
+
const scope = {
|
|
126
|
+
gate: GATE,
|
|
127
|
+
scanned: tree.files,
|
|
128
|
+
units: 'source file(s)',
|
|
129
|
+
roots: ROOTS,
|
|
130
|
+
};
|
|
131
|
+
// BEFORE the verdict, per the empty-corpus contract: a run that read no
|
|
132
|
+
// source file must refuse rather than report an empty tree as agreement
|
|
133
|
+
// with an empty table.
|
|
134
|
+
assertScanned(scope);
|
|
135
|
+
reportScanned(scope);
|
|
136
|
+
ledger.complete('tree-enumeration');
|
|
137
|
+
|
|
138
|
+
const table = switchesInTable(root);
|
|
139
|
+
if (!table.present) {
|
|
140
|
+
ledger.fail('table-rows', `no "${SECTION}" section in ${CONTRACT}`);
|
|
141
|
+
ledger.fail('set-equality', 'nothing to compare against');
|
|
142
|
+
ledger.report();
|
|
143
|
+
process.stderr.write(
|
|
144
|
+
`❌ ${GATE}: ${CONTRACT} carries no "${SECTION}" section. The section is the\n` +
|
|
145
|
+
' contract; a tree enumeration with nothing to compare it against is not a pass.\n',
|
|
146
|
+
);
|
|
147
|
+
return 1;
|
|
148
|
+
}
|
|
149
|
+
ledger.complete('table-rows');
|
|
150
|
+
|
|
151
|
+
const missing = [...tree.names].filter((n) => !table.names.has(n)).sort();
|
|
152
|
+
const extra = [...table.names].filter((n) => !tree.names.has(n)).sort();
|
|
153
|
+
|
|
154
|
+
if (missing.length === 0 && extra.length === 0) {
|
|
155
|
+
ledger.complete('set-equality');
|
|
156
|
+
ledger.report();
|
|
157
|
+
process.stdout.write(
|
|
158
|
+
`✅ ${GATE}: ${String(tree.names.size)} switch(es) in ` +
|
|
159
|
+
`${String(tree.files)} file(s), ${String(table.names.size)} table row(s), sets equal\n`,
|
|
160
|
+
);
|
|
161
|
+
return 0;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
ledger.fail('set-equality', `${String(missing.length + extra.length)} mismatch(es)`);
|
|
165
|
+
ledger.report();
|
|
166
|
+
process.stderr.write(`❌ ${GATE}: the table and the tree disagree.\n\n`);
|
|
167
|
+
for (const n of missing) {
|
|
168
|
+
process.stderr.write(` MISSING ROW ${n} — read by the tree, absent from the table\n`);
|
|
169
|
+
}
|
|
170
|
+
for (const n of extra) {
|
|
171
|
+
process.stderr.write(
|
|
172
|
+
` STALE ROW ${n} — a table row for a name the tree no longer carries\n`,
|
|
173
|
+
);
|
|
174
|
+
}
|
|
175
|
+
process.stderr.write(
|
|
176
|
+
`\nAdd or remove the row in ${CONTRACT} § Kill switches. A switch with no row is\n` +
|
|
177
|
+
'one an operator cannot find; a row with no switch is one they will set expecting\n' +
|
|
178
|
+
'an effect. If a name is genuinely read outside the two declared roots, the row\n' +
|
|
179
|
+
'stays and says so — the row still has to exist.\n',
|
|
180
|
+
);
|
|
181
|
+
return 1;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
// ---------------------------------------------------------------------------
|
|
185
|
+
// Self-test — the gate proving its own rejections still fire
|
|
186
|
+
// ---------------------------------------------------------------------------
|
|
187
|
+
|
|
188
|
+
function fixture(body: { tree: string; table: string }): string {
|
|
189
|
+
const dir = fs.mkdtempSync(path.join(process.cwd(), '.kst-'));
|
|
190
|
+
fs.mkdirSync(path.join(dir, 'src', 'scripts', 'hooks'), { recursive: true });
|
|
191
|
+
fs.mkdirSync(path.join(dir, 'src', 'scripts', '_lib'), { recursive: true });
|
|
192
|
+
fs.mkdirSync(path.join(dir, 'docs', 'contracts'), { recursive: true });
|
|
193
|
+
fs.writeFileSync(path.join(dir, 'src', 'scripts', 'hooks', 'a.ts'), body.tree, 'utf-8');
|
|
194
|
+
fs.writeFileSync(path.join(dir, CONTRACT), body.table, 'utf-8');
|
|
195
|
+
return dir;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
function table(...names: string[]): string {
|
|
199
|
+
const rows = names.map((n) => `| \`${n}\` | maintainer | does a thing | a.ts:1 |`).join('\n');
|
|
200
|
+
return `# Contract\n\n${SECTION}\n\n| Switch | Owner | What | Read at |\n|---|---|---|---|\n${rows}\n\n## Stability\n\nBeta.\n`;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
function selfTest(): number {
|
|
204
|
+
const repoRoot = process.cwd();
|
|
205
|
+
const script = path.join('src', 'scripts', 'check_kill_switch_table.ts');
|
|
206
|
+
const dirs: string[] = [];
|
|
207
|
+
const run = (body: { tree: string; table: string }): number => {
|
|
208
|
+
const dir = fixture(body);
|
|
209
|
+
dirs.push(dir);
|
|
210
|
+
return runGateCli(repoRoot, script, [], dir);
|
|
211
|
+
};
|
|
212
|
+
|
|
213
|
+
const cases: SelfTestCase[] = [
|
|
214
|
+
{
|
|
215
|
+
name: 'equal sets pass',
|
|
216
|
+
expect: 'accept',
|
|
217
|
+
run: () =>
|
|
218
|
+
run({
|
|
219
|
+
tree: "const A = process.env['AGENT_CONFIG_ALPHA'];\n",
|
|
220
|
+
table: table('AGENT_CONFIG_ALPHA'),
|
|
221
|
+
}),
|
|
222
|
+
},
|
|
223
|
+
{
|
|
224
|
+
name: 'a switch with no row is rejected',
|
|
225
|
+
expect: 'reject',
|
|
226
|
+
run: () =>
|
|
227
|
+
run({
|
|
228
|
+
tree: "const A = process.env['AGENT_CONFIG_ALPHA'];\nconst B = process.env['AGENT_CONFIG_BETA'];\n",
|
|
229
|
+
table: table('AGENT_CONFIG_ALPHA'),
|
|
230
|
+
}),
|
|
231
|
+
},
|
|
232
|
+
{
|
|
233
|
+
name: 'a row with no switch is rejected',
|
|
234
|
+
expect: 'reject',
|
|
235
|
+
run: () =>
|
|
236
|
+
run({
|
|
237
|
+
tree: "const A = process.env['AGENT_CONFIG_ALPHA'];\n",
|
|
238
|
+
table: table('AGENT_CONFIG_ALPHA', 'AGENT_CONFIG_GONE'),
|
|
239
|
+
}),
|
|
240
|
+
},
|
|
241
|
+
{
|
|
242
|
+
name: 'one added and one stale do NOT cancel — the count would hide it',
|
|
243
|
+
expect: 'reject',
|
|
244
|
+
run: () =>
|
|
245
|
+
run({
|
|
246
|
+
tree: "const B = process.env['AGENT_CONFIG_BETA'];\n",
|
|
247
|
+
table: table('AGENT_CONFIG_ALPHA'),
|
|
248
|
+
}),
|
|
249
|
+
},
|
|
250
|
+
{
|
|
251
|
+
name: 'the esbuild defines are excluded, not counted',
|
|
252
|
+
expect: 'accept',
|
|
253
|
+
run: () =>
|
|
254
|
+
run({
|
|
255
|
+
tree:
|
|
256
|
+
'declare const __AGENT_CONFIG_BUNDLE__: boolean;\n'
|
|
257
|
+
+ 'declare const __AGENT_CONFIG_CLI_DELEGATE__: boolean;\n'
|
|
258
|
+
+ "const A = process.env['AGENT_CONFIG_ALPHA'];\n",
|
|
259
|
+
table: table('AGENT_CONFIG_ALPHA'),
|
|
260
|
+
}),
|
|
261
|
+
},
|
|
262
|
+
{
|
|
263
|
+
name: 'a missing section is rejected, never read as an empty table',
|
|
264
|
+
expect: 'reject',
|
|
265
|
+
run: () =>
|
|
266
|
+
run({
|
|
267
|
+
tree: "const A = process.env['AGENT_CONFIG_ALPHA'];\n",
|
|
268
|
+
table: '# Contract\n\n## Stability\n\nBeta.\n',
|
|
269
|
+
}),
|
|
270
|
+
},
|
|
271
|
+
];
|
|
272
|
+
|
|
273
|
+
try {
|
|
274
|
+
return runSelfTest({ gate: GATE, cases, minCases: 6, minRejectCases: 4 });
|
|
275
|
+
} finally {
|
|
276
|
+
for (const d of dirs) fs.rmSync(d, { recursive: true, force: true });
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
function isCliEntry(): boolean {
|
|
281
|
+
const argv1 = process.argv[1];
|
|
282
|
+
if (argv1 === undefined) return false;
|
|
283
|
+
try {
|
|
284
|
+
return (
|
|
285
|
+
fs.realpathSync(fileURLToPath(import.meta.url)) === fs.realpathSync(path.resolve(argv1))
|
|
286
|
+
);
|
|
287
|
+
} catch {
|
|
288
|
+
return pathToFileURL(argv1).href === import.meta.url;
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
if (isCliEntry()) {
|
|
293
|
+
process.exit(main());
|
|
294
|
+
}
|
|
@@ -607,7 +607,13 @@ function _checkAppendOnly(base: string | null, findings: Finding[]): void {
|
|
|
607
607
|
'--no-color',
|
|
608
608
|
ref,
|
|
609
609
|
'--',
|
|
610
|
-
'
|
|
610
|
+
// The JSONL drops, not the directory. `INTAKE_GLOB`, this module's
|
|
611
|
+
// docstring and every fixture in the suite all scope this check to
|
|
612
|
+
// `*.jsonl`; asking git for the directory made it govern the tracked
|
|
613
|
+
// skeleton too, so editing the README that documents the append-only
|
|
614
|
+
// rule was reported as a violation of it. `:(glob)` is explicit rather
|
|
615
|
+
// than relying on the default pathspec magic.
|
|
616
|
+
':(glob)agents/memory/intake/*.jsonl',
|
|
611
617
|
]);
|
|
612
618
|
if (rc !== 0) {
|
|
613
619
|
findings.push(new Finding(INTAKE_GLOB, 0, 'warning', `append-only: git diff failed vs ${ref}`));
|
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
#!/usr/bin/env tsx
|
|
2
|
+
/**
|
|
3
|
+
* The placeholder-drift ratchet — foreign placeholder syntaxes in prose may
|
|
4
|
+
* shrink, never grow.
|
|
5
|
+
*
|
|
6
|
+
* road-to-an-invocation-contract-that-reaches-the-wire 1.2.
|
|
7
|
+
*
|
|
8
|
+
* WHAT IT GATES, AND WHAT IT DELIBERATELY DOES NOT
|
|
9
|
+
*
|
|
10
|
+
* It fails on GROWTH of the foreign forms only. It never fails on the absolute
|
|
11
|
+
* number, and it never fails on the plurality form — so holding at the seeded
|
|
12
|
+
* counts is permanently green, and nothing here asks for a rewrite of a working
|
|
13
|
+
* body. That is the whole of Risk 2's mitigation: a committed number naming two
|
|
14
|
+
* syntaxes as foreign reads like a canon ruling whose obvious next move is
|
|
15
|
+
* rewriting those bodies, and a gate that is green at the seed removes the
|
|
16
|
+
* pressure to do it.
|
|
17
|
+
*
|
|
18
|
+
* THE SEED IS MEASURED, NOT COPIED
|
|
19
|
+
*
|
|
20
|
+
* The roadmap's step text says "seeded at the measured 4 and 2". The operative
|
|
21
|
+
* word is MEASURED: under the census's published unit — a token in PROSE,
|
|
22
|
+
* outside fenced blocks, indented blocks and inline code spans — the corpus
|
|
23
|
+
* carries different numbers, because the source figures counted tokens inside
|
|
24
|
+
* demonstrated code (JS template literals in `playwright-testing`, HCL in
|
|
25
|
+
* `terragrunt`, a table-cell marker the prose is talking ABOUT in
|
|
26
|
+
* `livewire-architect`). The seed below is this tree's own reading. The
|
|
27
|
+
* reasoning lives in `report_invocation_surface.ts`'s module header, and the
|
|
28
|
+
* per-file breakdown is in the census artifact, so the definition is arguable
|
|
29
|
+
* rather than merely asserted.
|
|
30
|
+
*
|
|
31
|
+
* A NOTE ON WHAT A ZERO SEED MEANS. `{{…}}` seeds at zero. That is not "the
|
|
32
|
+
* check has nothing to do" — a zero-seeded ratchet is the strictest form of
|
|
33
|
+
* this gate, because the first occurrence is growth. It is also the cheapest
|
|
34
|
+
* possible moment to hold a line: no existing body has to change for it.
|
|
35
|
+
*
|
|
36
|
+
* Exit codes: 0 within the ratchet · 1 growth · 2 the corpus could not be read.
|
|
37
|
+
*/
|
|
38
|
+
|
|
39
|
+
import fs from 'node:fs';
|
|
40
|
+
import os from 'node:os';
|
|
41
|
+
import path from 'node:path';
|
|
42
|
+
import { fileURLToPath, pathToFileURL } from 'node:url';
|
|
43
|
+
|
|
44
|
+
import { GateLedger } from './_lib/gate_ledger.js';
|
|
45
|
+
import { runGateCli, runSelfTest } from './_lib/gate_self_test.js';
|
|
46
|
+
import { assertScanned, reportScanned } from './_lib/scan_scope.js';
|
|
47
|
+
import { SYNTAXES, type SyntaxId, census } from './report_invocation_surface.js';
|
|
48
|
+
|
|
49
|
+
const _HERE = fileURLToPath(import.meta.url);
|
|
50
|
+
const ROOT = path.resolve(path.dirname(_HERE), '..', '..');
|
|
51
|
+
|
|
52
|
+
export const GATE = 'check_placeholder_drift';
|
|
53
|
+
|
|
54
|
+
/** Where the seed lives, so a deliberate change is a reviewable diff. */
|
|
55
|
+
export const BUDGET_REL = path.join('src', 'config', 'placeholder-drift-budget.json');
|
|
56
|
+
|
|
57
|
+
export interface Budget {
|
|
58
|
+
readonly seeded_at: string;
|
|
59
|
+
readonly note: string;
|
|
60
|
+
readonly ceilings: Readonly<Partial<Record<SyntaxId, number>>>;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export function readBudget(root: string): Budget | null {
|
|
64
|
+
const p = path.join(root, BUDGET_REL);
|
|
65
|
+
if (!fs.existsSync(p)) return null;
|
|
66
|
+
try {
|
|
67
|
+
return JSON.parse(fs.readFileSync(p, 'utf8')) as Budget;
|
|
68
|
+
} catch {
|
|
69
|
+
return null;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export interface Finding {
|
|
74
|
+
readonly syntax: SyntaxId;
|
|
75
|
+
readonly ceiling: number;
|
|
76
|
+
readonly measured: number;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/** Which foreign syntaxes exceed their ceiling. Plurality forms are skipped. */
|
|
80
|
+
export function findings(
|
|
81
|
+
occurrences: Readonly<Record<SyntaxId, number>>,
|
|
82
|
+
budget: Budget,
|
|
83
|
+
): Finding[] {
|
|
84
|
+
const out: Finding[] = [];
|
|
85
|
+
for (const s of SYNTAXES) {
|
|
86
|
+
if (s.canonical) continue;
|
|
87
|
+
const ceiling = budget.ceilings[s.id];
|
|
88
|
+
if (ceiling === undefined) continue;
|
|
89
|
+
const measured = occurrences[s.id] ?? 0;
|
|
90
|
+
if (measured > ceiling) out.push({ syntax: s.id, ceiling, measured });
|
|
91
|
+
}
|
|
92
|
+
return out;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
export function main(argv: readonly string[]): number {
|
|
96
|
+
if (argv.includes('--self-test')) return selfTest();
|
|
97
|
+
const rootIdx = argv.indexOf('--root');
|
|
98
|
+
const root = rootIdx === -1 ? ROOT : (argv[rootIdx + 1] ?? ROOT);
|
|
99
|
+
|
|
100
|
+
const budget = readBudget(root);
|
|
101
|
+
if (budget === null) {
|
|
102
|
+
process.stderr.write(
|
|
103
|
+
`❌ ${GATE}: ${BUDGET_REL} is missing or unreadable. A ratchet that cannot read ` +
|
|
104
|
+
'its own seed must not pass — it would be a green nobody earned.\n',
|
|
105
|
+
);
|
|
106
|
+
return 2;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
const c = census(root);
|
|
110
|
+
const foreign = SYNTAXES.filter((s) => !s.canonical);
|
|
111
|
+
const ledger = new GateLedger(GATE);
|
|
112
|
+
ledger.plan(foreign.map((s) => s.id));
|
|
113
|
+
|
|
114
|
+
const found = findings(c.occurrences, budget);
|
|
115
|
+
for (const s of foreign) {
|
|
116
|
+
const f = found.find((x) => x.syntax === s.id);
|
|
117
|
+
if (f === undefined) ledger.complete(s.id);
|
|
118
|
+
else ledger.fail(s.id, `${String(f.measured)} occurrence(s) against a ceiling of ${String(f.ceiling)}`);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
// A gate that read nothing has not passed. This fires BEFORE the verdict,
|
|
122
|
+
// because certifying against an empty corpus is the false green the coverage
|
|
123
|
+
// manifest exists to refuse — named by the provider-diverse ratification
|
|
124
|
+
// review as one condition that would have flipped its verdict.
|
|
125
|
+
assertScanned({ gate: GATE, scanned: c.rows.length, units: 'artifact(s)', roots: [BUDGET_REL, 'dist/agent-src/commands', 'src/skills'] });
|
|
126
|
+
|
|
127
|
+
reportScanned({
|
|
128
|
+
gate: GATE,
|
|
129
|
+
scanned: c.rows.length,
|
|
130
|
+
units: 'artifact(s)',
|
|
131
|
+
roots: [BUDGET_REL],
|
|
132
|
+
});
|
|
133
|
+
ledger.report();
|
|
134
|
+
|
|
135
|
+
if (found.length > 0) {
|
|
136
|
+
for (const f of found) {
|
|
137
|
+
const label = SYNTAXES.find((s) => s.id === f.syntax)?.label ?? f.syntax;
|
|
138
|
+
process.stdout.write(
|
|
139
|
+
`❌ ${GATE}: \`${label}\` grew to ${String(f.measured)} prose occurrence(s), ceiling ${String(f.ceiling)}.\n`,
|
|
140
|
+
);
|
|
141
|
+
}
|
|
142
|
+
process.stdout.write(
|
|
143
|
+
'\nThe ratchet walks DOWN only. Use the plurality form instead, or — if the new ' +
|
|
144
|
+
`occurrence is genuinely right — lower nothing and raise the ceiling in ` +
|
|
145
|
+
`\`${BUDGET_REL}\` in the same change, with the reason in the diff.\n` +
|
|
146
|
+
'Counting unit and the per-file breakdown: ' +
|
|
147
|
+
'`./scripts-run src/scripts/report_invocation_surface --write`.\n',
|
|
148
|
+
);
|
|
149
|
+
return 1;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
process.stdout.write(
|
|
153
|
+
`✅ ${GATE}: foreign placeholder syntaxes within their ratchet ` +
|
|
154
|
+
`(${foreign.map((s) => `${s.label} ${String(c.occurrences[s.id])}/${String(budget.ceilings[s.id] ?? 0)}`).join(' · ')}).\n`,
|
|
155
|
+
);
|
|
156
|
+
return 0;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* A ratchet that cannot be shown to move is a number, not a gate. Each rejecting
|
|
161
|
+
* case is one occurrence over a ceiling; the accepting cases are the seed itself
|
|
162
|
+
* and a shrink, because a suite that only proves failures proves a gate that is
|
|
163
|
+
* merely loud.
|
|
164
|
+
*/
|
|
165
|
+
function selfTest(): number {
|
|
166
|
+
const plant = (name: string, bodies: readonly string[], ceilings: Record<string, number>): string => {
|
|
167
|
+
const dir = fs.mkdtempSync(path.join(os.tmpdir(), `drift-${name}-`));
|
|
168
|
+
fs.mkdirSync(path.join(dir, 'src', 'config'), { recursive: true });
|
|
169
|
+
fs.writeFileSync(
|
|
170
|
+
path.join(dir, 'src', 'config', 'placeholder-drift-budget.json'),
|
|
171
|
+
JSON.stringify({ seeded_at: '2026-09-29', note: 'fixture', ceilings }, null, 2),
|
|
172
|
+
'utf-8',
|
|
173
|
+
);
|
|
174
|
+
bodies.forEach((body, i) => {
|
|
175
|
+
const d = path.join(dir, 'src', 'skills', `probe-${String(i)}`);
|
|
176
|
+
fs.mkdirSync(d, { recursive: true });
|
|
177
|
+
fs.writeFileSync(path.join(d, 'SKILL.md'), `---\nname: probe-${String(i)}\n---\n\n${body}\n`, 'utf-8');
|
|
178
|
+
});
|
|
179
|
+
return dir;
|
|
180
|
+
};
|
|
181
|
+
const run = (root: string): number =>
|
|
182
|
+
runGateCli(ROOT, path.join('src', 'scripts', 'check_placeholder_drift.ts'), ['--root', root], ROOT);
|
|
183
|
+
|
|
184
|
+
return runSelfTest({
|
|
185
|
+
gate: GATE,
|
|
186
|
+
minCases: 5,
|
|
187
|
+
minRejectCases: 3,
|
|
188
|
+
cases: [
|
|
189
|
+
{
|
|
190
|
+
name: 'at the seed it is green',
|
|
191
|
+
expect: 'accept',
|
|
192
|
+
run: () => run(plant('seed', ['Uses {{a}} once.'], { 'double-brace': 1, 'angle-upper': 0 })),
|
|
193
|
+
},
|
|
194
|
+
{
|
|
195
|
+
name: 'below the seed it stays green — it never fails on the absolute number',
|
|
196
|
+
expect: 'accept',
|
|
197
|
+
run: () => run(plant('shrink', ['no placeholders'], { 'double-brace': 1, 'angle-upper': 0 })),
|
|
198
|
+
},
|
|
199
|
+
{
|
|
200
|
+
name: 'one occurrence over the ceiling fails',
|
|
201
|
+
expect: 'reject',
|
|
202
|
+
run: () => run(plant('grow', ['Uses {{a}} and {{b}}.'], { 'double-brace': 1, 'angle-upper': 0 })),
|
|
203
|
+
},
|
|
204
|
+
{
|
|
205
|
+
name: 'a zero ceiling makes the first occurrence growth',
|
|
206
|
+
expect: 'reject',
|
|
207
|
+
run: () => run(plant('zero', ['Uses <NAME> here.'], { 'double-brace': 0, 'angle-upper': 0 })),
|
|
208
|
+
},
|
|
209
|
+
{
|
|
210
|
+
name: 'an unreadable budget refuses rather than certifying a green',
|
|
211
|
+
expect: 'reject',
|
|
212
|
+
run: () => runGateCli(ROOT, path.join('src', 'scripts', 'check_placeholder_drift.ts'),
|
|
213
|
+
['--root', fs.mkdtempSync(path.join(os.tmpdir(), 'drift-nobudget-'))], ROOT),
|
|
214
|
+
},
|
|
215
|
+
],
|
|
216
|
+
});
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
if (process.argv[1] && import.meta.url === pathToFileURL(path.resolve(process.argv[1])).href) {
|
|
220
|
+
process.exit(main(process.argv.slice(2)));
|
|
221
|
+
}
|