@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
|
@@ -24,6 +24,7 @@ import * as path from 'node:path';
|
|
|
24
24
|
import { REPO_ROOT } from '../release_env.js';
|
|
25
25
|
import { die, run, type RunResult } from '../release_publication.js';
|
|
26
26
|
import {
|
|
27
|
+
BREAKING_INDEX_PATH,
|
|
27
28
|
MIGRATION_PATH as MAJOR_MIGRATION_PATH,
|
|
28
29
|
pendingMajorFinding,
|
|
29
30
|
} from '../lint_major_migration_sections.js';
|
|
@@ -148,8 +149,15 @@ export function assert_scheduled_deprecations_clear(
|
|
|
148
149
|
* real run will refuse and returns, because `--dry-run exits 0` is a contract
|
|
149
150
|
* this file's own tests assert.
|
|
150
151
|
*
|
|
152
|
+
* A major owes TWO records and this seam reads both: the migration section and
|
|
153
|
+
* the by-major row in `BREAKING_CHANGES.md`. Checking only the first at cut
|
|
154
|
+
* time while the lint checks both would let a cut create the exact state the
|
|
155
|
+
* lint then reds `main` over — the gate arriving one merge too late, which is
|
|
156
|
+
* the shape `pendingMajorFinding` exists to avoid in the first place.
|
|
157
|
+
*
|
|
151
158
|
* @param migrationReader Seam for the file read, so a test can drive the
|
|
152
159
|
* refusal without mutating a tracked file.
|
|
160
|
+
* @param indexReader The same seam for the breaking-changes index.
|
|
153
161
|
*/
|
|
154
162
|
export function assert_major_migration_section(
|
|
155
163
|
target: string,
|
|
@@ -157,18 +165,23 @@ export function assert_major_migration_section(
|
|
|
157
165
|
opts: { previewOnly?: boolean } = {},
|
|
158
166
|
migrationReader: () => string = () =>
|
|
159
167
|
fs.readFileSync(path.join(REPO_ROOT, MAJOR_MIGRATION_PATH), 'utf-8'),
|
|
168
|
+
indexReader: () => string = () =>
|
|
169
|
+
fs.readFileSync(path.join(REPO_ROOT, BREAKING_INDEX_PATH), 'utf-8'),
|
|
160
170
|
): void {
|
|
161
171
|
let migration: string;
|
|
172
|
+
let index: string;
|
|
162
173
|
try {
|
|
163
174
|
migration = migrationReader();
|
|
175
|
+
index = indexReader();
|
|
164
176
|
} catch (exc) {
|
|
165
177
|
die(
|
|
166
|
-
`refusing the ${target} cut: cannot read ${MAJOR_MIGRATION_PATH} ` +
|
|
178
|
+
`refusing the ${target} cut: cannot read ${MAJOR_MIGRATION_PATH} or ` +
|
|
179
|
+
`${BREAKING_INDEX_PATH} ` +
|
|
167
180
|
`(${exc instanceof Error ? exc.message : String(exc)}). That is an environment ` +
|
|
168
181
|
'failure, not a finding — fix the checkout, then re-run.',
|
|
169
182
|
);
|
|
170
183
|
}
|
|
171
|
-
const finding = pendingMajorFinding(target, changelog_entry, migration);
|
|
184
|
+
const finding = pendingMajorFinding(target, changelog_entry, migration, index);
|
|
172
185
|
if (finding === null) {
|
|
173
186
|
return;
|
|
174
187
|
}
|
|
@@ -180,5 +193,8 @@ export function assert_major_migration_section(
|
|
|
180
193
|
);
|
|
181
194
|
return;
|
|
182
195
|
}
|
|
183
|
-
die(
|
|
196
|
+
die(
|
|
197
|
+
`refusing the ${target} cut: ${MAJOR_MIGRATION_PATH} or ${BREAKING_INDEX_PATH} ` +
|
|
198
|
+
`does not name ${target}.`,
|
|
199
|
+
);
|
|
184
200
|
}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The reserved-name sweep over flat Claude Code command files.
|
|
3
|
+
*
|
|
4
|
+
* A flat command whose slug shadows a Claude Code built-in never ships on the
|
|
5
|
+
* claude-code anchor — the suite complements the host, it does not overlay its
|
|
6
|
+
* built-ins. The sweep that enforces this used to delete EVERY builtin-named
|
|
7
|
+
* `.md` in the anchor's `commands/` directory, including one another agent
|
|
8
|
+
* package or the consumer had put there. The consumer's own `/review` command
|
|
9
|
+
* disappeared at install time with no message, because the sweep's only
|
|
10
|
+
* question was the filename.
|
|
11
|
+
*
|
|
12
|
+
* The question it asks now is ownership: a file is removed when this package
|
|
13
|
+
* wrote it — the current deploy's own written set, or a path a previous
|
|
14
|
+
* install recorded in the installed-tools manifest. Anything else is FOREIGN:
|
|
15
|
+
* it stays on disk and is reported, so the consumer learns that a built-in
|
|
16
|
+
* name is shadowed by someone and can decide, rather than finding their file
|
|
17
|
+
* gone.
|
|
18
|
+
*
|
|
19
|
+
* Both halves of the sweep's original purpose survive: ours never ships under
|
|
20
|
+
* a reserved name, and the suite still never overlays a built-in with its own
|
|
21
|
+
* file. What it no longer does is enforce that on a file that is not its own.
|
|
22
|
+
*/
|
|
23
|
+
|
|
24
|
+
import * as fs from 'node:fs';
|
|
25
|
+
import * as path from 'node:path';
|
|
26
|
+
|
|
27
|
+
export interface ReservedSweepResult {
|
|
28
|
+
/** Slugs of OUR files removed because the name is a host built-in. */
|
|
29
|
+
reserved: string[];
|
|
30
|
+
/** Slugs left in place because nothing proves this package wrote them. */
|
|
31
|
+
foreign: string[];
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Remove our builtin-named flat commands from `commandsDir`; keep foreign ones.
|
|
36
|
+
*
|
|
37
|
+
* Both ownership sets are anchor-relative, exactly as the deploy inventory
|
|
38
|
+
* records them. `currentFiles` is this deploy's written set — the live half,
|
|
39
|
+
* and the only one that exists on a first install. `recordedFiles` is what a
|
|
40
|
+
* previous deploy recorded under the same anchor, so a builtin-named file of
|
|
41
|
+
* ours left behind by an older version is still reaped rather than becoming
|
|
42
|
+
* permanently unprovable. A removed entry is dropped from `currentFiles` so
|
|
43
|
+
* the inventory record stays consistent with the tree, exactly as before.
|
|
44
|
+
*/
|
|
45
|
+
export function sweepReservedNames(
|
|
46
|
+
commandsDir: string,
|
|
47
|
+
currentFiles: Set<string>,
|
|
48
|
+
isBuiltinName: (slug: string) => boolean,
|
|
49
|
+
recordedFiles: ReadonlySet<string>,
|
|
50
|
+
): ReservedSweepResult {
|
|
51
|
+
const reserved: string[] = [];
|
|
52
|
+
const foreign: string[] = [];
|
|
53
|
+
let entries: string[] = [];
|
|
54
|
+
try {
|
|
55
|
+
entries = fs.readdirSync(commandsDir).filter((f) => f.endsWith('.md'));
|
|
56
|
+
} catch {
|
|
57
|
+
return { reserved, foreign };
|
|
58
|
+
}
|
|
59
|
+
for (const fname of entries.sort()) {
|
|
60
|
+
const slug = fname.slice(0, -'.md'.length);
|
|
61
|
+
if (!isBuiltinName(slug)) continue;
|
|
62
|
+
const rel = `commands/${fname}`;
|
|
63
|
+
const ours = currentFiles.has(rel) || recordedFiles.has(rel);
|
|
64
|
+
if (!ours) {
|
|
65
|
+
foreign.push(slug);
|
|
66
|
+
continue;
|
|
67
|
+
}
|
|
68
|
+
fs.rmSync(path.join(commandsDir, fname), { force: true });
|
|
69
|
+
currentFiles.delete(rel);
|
|
70
|
+
reserved.push(slug);
|
|
71
|
+
}
|
|
72
|
+
return { reserved, foreign };
|
|
73
|
+
}
|
|
@@ -16,26 +16,58 @@
|
|
|
16
16
|
* Codepoint classes are shared with `lint_hidden_unicode` (one source of truth
|
|
17
17
|
* for what counts as a hidden-instruction vector).
|
|
18
18
|
*
|
|
19
|
-
* WHERE IT ACTUALLY RUNS —
|
|
20
|
-
* honest: an earlier version of this header named surfaces by intent, and the
|
|
21
|
-
* legacy-envelope gap below went unnoticed for exactly that reason. Every
|
|
22
|
-
* claim here is backed by a probe row in
|
|
23
|
-
* `agents/evidence/reports/sanitize-floor-wiring.md`:
|
|
19
|
+
* WHERE IT ACTUALLY RUNS — read the table, which is GENERATED:
|
|
24
20
|
*
|
|
25
|
-
*
|
|
26
|
-
* - `memory_get_v1()` — yes (same)
|
|
27
|
-
* - MCP `memory_lookup` / `memory_get` tools — inherited from the two above
|
|
28
|
-
* - `retrieve()` / `retrieve_with_meta()` — yes, since the S0.0 wiring fix;
|
|
29
|
-
* before it they emitted every vector intact, and so did the CLI default
|
|
30
|
-
* (`--envelope legacy`), which is the path the rules document
|
|
31
|
-
* - inter-agent channels (`ai_team` / `ai_council` model replies) — the
|
|
32
|
-
* inbound parse choke point only; the subagent boundary itself is a HOST
|
|
33
|
-
* primitive this package cannot reach (see the report, § S0.0b)
|
|
21
|
+
* docs/contracts/retrieval-read-surfaces.md
|
|
34
22
|
*
|
|
35
|
-
*
|
|
36
|
-
*
|
|
23
|
+
* This header used to carry that list inline, and the list was wrong in BOTH
|
|
24
|
+
* directions: a path that reaches the outside world and IS sanitized was
|
|
25
|
+
* absent from it, and two paths carrying fetched bytes toward a model-facing
|
|
26
|
+
* surface were neither listed nor covered. An earlier version had already
|
|
27
|
+
* failed the same way — it named surfaces by intent, and the legacy-envelope
|
|
28
|
+
* gap went unnoticed for exactly that reason. Twice is a property of the
|
|
29
|
+
* mechanism, not of the entries, which is why the list is now derived from the
|
|
30
|
+
* import graph by `check_read_surface_coverage` and this header points at it
|
|
31
|
+
* instead of copying it. A divergence between the two FAILS that gate; two
|
|
32
|
+
* copies is how it went stale.
|
|
33
|
+
*
|
|
34
|
+
* Anything absent from the table is uncovered, and a module the generator
|
|
35
|
+
* cannot classify appears there as an `unclassified` ROW rather than being
|
|
36
|
+
* omitted — a missing row would read as no surface at all.
|
|
37
|
+
*
|
|
38
|
+
* One boundary the table cannot move: the subagent boundary itself is a HOST
|
|
39
|
+
* primitive this package cannot reach, so the inter-agent channels are covered
|
|
40
|
+
* at the inbound parse choke point and nowhere else.
|
|
41
|
+
*
|
|
42
|
+
* loss_class: ephemeral-lossy
|
|
43
|
+
*
|
|
44
|
+
* `sanitize_text` drops hidden-instruction codepoints, control-char noise and
|
|
45
|
+
* invisible fillers, and caps the result at MAX_FIELD_CHARS. None of that is
|
|
46
|
+
* reconstructible from the output, and for the dropped vectors the
|
|
47
|
+
* unrecoverability IS the guarantee — a retrieval path that could hand back
|
|
48
|
+
* the vector it stripped would not be a floor. So the class is
|
|
49
|
+
* `ephemeral-lossy` for the module, even though `sanitize_markup` below
|
|
50
|
+
* returns structured removals for the layer it composes: a class names what a
|
|
51
|
+
* caller can recover from the output, and `sanitize_text` returns a string.
|
|
52
|
+
*
|
|
53
|
+
* THE STRUCTURAL LAYER IS A SEPARATE MODULE. Everything below is a CODEPOINT
|
|
54
|
+
* floor. Fetched markup also hides content STRUCTURALLY — an HTML comment, a
|
|
55
|
+
* `<template>` block, a `style="display:none"` span — which no codepoint
|
|
56
|
+
* predicate can see. That class is covered by `_lib/structural_hiding.ts`,
|
|
57
|
+
* composed with this floor by `sanitize_markup` below, and it is covered for
|
|
58
|
+
* fetched MARKUP only: a caller holding plain text needs nothing from it.
|
|
59
|
+
*
|
|
60
|
+
* WHAT THAT LAYER STILL DOES NOT SEE is a register in its own file —
|
|
61
|
+
* `STRUCTURAL_HIDING_GAPS` — and every surface claiming the coverage cites the
|
|
62
|
+
* register alongside the claim, because a detector cited without its gaps is
|
|
63
|
+
* how the claim becomes a false green. No recall or coverage percentage is
|
|
64
|
+
* published for it anywhere; a rate needs a frozen corpus and none exists.
|
|
65
|
+
* `aria-hidden` is deliberately NOT one of its channels
|
|
66
|
+
* (`STRUCTURAL_HIDING_NON_CHANNELS` says why).
|
|
37
67
|
*/
|
|
38
68
|
import { _classify } from '../lint_hidden_unicode.js';
|
|
69
|
+
import { strip_structural_hiding } from './structural_hiding.js';
|
|
70
|
+
import type { StructuralRemoval } from './structural_hiding.js';
|
|
39
71
|
import { TOKEN_RE, classifyToken } from './confusables.js';
|
|
40
72
|
|
|
41
73
|
/** Hard per-field length cap — bounds a runaway/adversarial body. */
|
|
@@ -85,6 +117,35 @@ export function sanitize_text(s: string): string {
|
|
|
85
117
|
return out.length > MAX_FIELD_CHARS ? out.slice(0, MAX_FIELD_CHARS) : out;
|
|
86
118
|
}
|
|
87
119
|
|
|
120
|
+
/**
|
|
121
|
+
* The fetched-markup floor: structural pre-pass, then the codepoint floor.
|
|
122
|
+
*
|
|
123
|
+
* ORDER IS LOAD-BEARING. The structural pass runs FIRST, because a codepoint
|
|
124
|
+
* floor applied first would sanitize text that is about to be discarded and,
|
|
125
|
+
* worse, would leave a hidden subtree looking clean. Running it second means
|
|
126
|
+
* every byte that survives the structural pass still clears the codepoint
|
|
127
|
+
* floor — including the text that was only reachable once markup was removed.
|
|
128
|
+
*
|
|
129
|
+
* Use this for fetched MARKUP. For plain text `sanitize_text` is the whole
|
|
130
|
+
* floor and this adds nothing but a parse.
|
|
131
|
+
*
|
|
132
|
+
* The removals are RETURNED, not logged and not swallowed: a caller debugging
|
|
133
|
+
* a corrupted result needs to know what went and where it was. See the removal
|
|
134
|
+
* policy in `structural_hiding.ts`.
|
|
135
|
+
*/
|
|
136
|
+
export function sanitize_markup(markup: string): {
|
|
137
|
+
text: string;
|
|
138
|
+
removals: readonly StructuralRemoval[];
|
|
139
|
+
truncated: boolean;
|
|
140
|
+
} {
|
|
141
|
+
const stripped = strip_structural_hiding(markup);
|
|
142
|
+
return {
|
|
143
|
+
text: sanitize_text(stripped.text),
|
|
144
|
+
removals: stripped.removals,
|
|
145
|
+
truncated: stripped.truncated,
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
|
|
88
149
|
/**
|
|
89
150
|
* Report the INVISIBLE layer without removing it.
|
|
90
151
|
*
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* How much of a release the self-review actually read, stated where the record
|
|
3
|
+
* is read.
|
|
4
|
+
*
|
|
5
|
+
* `self_review_gate` writes a `coverage` block — `{chunks, filesReviewed,
|
|
6
|
+
* filesTotal, unreviewed[]}` — into the findings artifact, `--ingest` carries it
|
|
7
|
+
* into the per-release ledger named by {@link LEDGER_DIR}, and from there NOBODY
|
|
8
|
+
* reads `filesReviewed` back. The 16.2.0 ledger records `filesReviewed: 65,
|
|
9
|
+
* filesTotal: 678`: the review saw under a tenth of the change. Every consumer
|
|
10
|
+
* of that record — the disposition gate's success line, the release-highlights
|
|
11
|
+
* gate, a human opening the file — saw output that said nothing about it.
|
|
12
|
+
*
|
|
13
|
+
* A finding count over 9.6 % of a diff and the same count over all of it are
|
|
14
|
+
* different claims, and the record spelled them identically.
|
|
15
|
+
*
|
|
16
|
+
* A LABEL, NEVER A FLOOR, and the distinction is the decision.
|
|
17
|
+
*
|
|
18
|
+
* Nothing here refuses. `coverageLabel` returns a string or `null`; no caller
|
|
19
|
+
* turns it into an exit code, and none may. Raising what a review reads costs
|
|
20
|
+
* one more paid model request per chunk per cut, which is a spend decision
|
|
21
|
+
* belonging to the owner. A gate that failed a cut on partial coverage would
|
|
22
|
+
* force that decision through the back door — the operator would either pay or
|
|
23
|
+
* be unable to release — which is exactly the move the roadmap's decision D1
|
|
24
|
+
* records as rejected.
|
|
25
|
+
*
|
|
26
|
+
* The honest cost of that choice, stated rather than left to be discovered: a
|
|
27
|
+
* release can ship with 9.6 % coverage and this module will only have said so.
|
|
28
|
+
* Saying so is the whole claim.
|
|
29
|
+
*
|
|
30
|
+
* It lives in its own module because two consumers read it — `check_finding_dispositions` on the ledger and
|
|
31
|
+
* `check_release_highlights` beside the Known-limitations field — and a label
|
|
32
|
+
* the two spell differently is a label a reader cannot compare across the two
|
|
33
|
+
* places they meet it. One definition is also the seam the unit tests use, so
|
|
34
|
+
* the arithmetic is checked without either CLI in the loop.
|
|
35
|
+
*/
|
|
36
|
+
import * as fs from 'node:fs';
|
|
37
|
+
import * as path from 'node:path';
|
|
38
|
+
|
|
39
|
+
/** Where the per-release ledgers live, relative to the repository root. */
|
|
40
|
+
export const LEDGER_DIR = path.join('agents', 'evidence', 'release-findings');
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* The coverage block as the gate writes it. Every field optional: this type
|
|
44
|
+
* describes an artifact read back off disk, which may be from an older writer
|
|
45
|
+
* or hand-edited, so the reader's job is to decide whether it can answer rather
|
|
46
|
+
* than to assume it can.
|
|
47
|
+
*/
|
|
48
|
+
export interface ReviewCoverage {
|
|
49
|
+
readonly chunks?: unknown;
|
|
50
|
+
readonly filesReviewed?: unknown;
|
|
51
|
+
readonly filesTotal?: unknown;
|
|
52
|
+
readonly unreviewed?: unknown;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function _finite(v: unknown): number | null {
|
|
56
|
+
return typeof v === 'number' && Number.isFinite(v) ? v : null;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* The one sentence both gates print, or `null` when there is nothing to say.
|
|
61
|
+
*
|
|
62
|
+
* `null` covers three cases deliberately collapsed into one, because they lead
|
|
63
|
+
* to the same output: full coverage (nothing to warn about), an absent block (an
|
|
64
|
+
* older ledger, written before the gate recorded coverage), and a malformed one
|
|
65
|
+
* (a string where a number belongs, a zero total). A reader who sees no label
|
|
66
|
+
* learns "this record makes no partial-coverage claim" — which is true of all
|
|
67
|
+
* three — and never a fabricated percentage derived from a field that was not
|
|
68
|
+
* a number.
|
|
69
|
+
*
|
|
70
|
+
* `filesTotal === 0` is `null` rather than `0 of 0 (partial)`: a change set with
|
|
71
|
+
* no files was fully read by any definition, and dividing by it says nothing.
|
|
72
|
+
*/
|
|
73
|
+
export function coverageLabel(coverage: unknown): string | null {
|
|
74
|
+
if (coverage === null || typeof coverage !== 'object') {
|
|
75
|
+
return null;
|
|
76
|
+
}
|
|
77
|
+
const c = coverage as ReviewCoverage;
|
|
78
|
+
const reviewed = _finite(c.filesReviewed);
|
|
79
|
+
const total = _finite(c.filesTotal);
|
|
80
|
+
if (reviewed === null || total === null || total <= 0 || reviewed >= total) {
|
|
81
|
+
return null;
|
|
82
|
+
}
|
|
83
|
+
return `self-review read ${String(reviewed)} of ${String(total)} changed files (partial)`;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* The `coverage` block of a committed ledger, or `undefined`.
|
|
88
|
+
*
|
|
89
|
+
* Never throws. A missing ledger is the normal state of an in-flight release and
|
|
90
|
+
* a corrupt one is already the business of the gate that parses it properly —
|
|
91
|
+
* a label is not the place to discover either, and a reader that threw here
|
|
92
|
+
* would turn an informational line into a crash on a release branch.
|
|
93
|
+
*/
|
|
94
|
+
export function readLedgerCoverage(root: string, release: string): unknown {
|
|
95
|
+
const file = path.join(root, LEDGER_DIR, `${release}.json`);
|
|
96
|
+
try {
|
|
97
|
+
const parsed: unknown = JSON.parse(fs.readFileSync(file, 'utf-8'));
|
|
98
|
+
if (parsed === null || typeof parsed !== 'object') {
|
|
99
|
+
return undefined;
|
|
100
|
+
}
|
|
101
|
+
return (parsed as Record<string, unknown>)['coverage'];
|
|
102
|
+
} catch {
|
|
103
|
+
return undefined;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/** `coverageLabel` over the committed ledger for `release`. */
|
|
108
|
+
export function ledgerCoverageLabel(root: string, release: string): string | null {
|
|
109
|
+
return coverageLabel(readLedgerCoverage(root, release));
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* The same label as a Known-limitations line, for the release-highlights gate.
|
|
114
|
+
*
|
|
115
|
+
* It carries the label plus the sentence that keeps a reader from mistaking it
|
|
116
|
+
* for a refusal, because the field it prints beside is one the gate CAN refuse
|
|
117
|
+
* on. Without that sentence the next person to read the output reasonably
|
|
118
|
+
* concludes the gate is about to start failing cuts on coverage, and the cheapest
|
|
119
|
+
* way to make the message go away becomes raising the ceiling — which is the
|
|
120
|
+
* owner's spend decision, taken by whoever happened to read the line.
|
|
121
|
+
*
|
|
122
|
+
* Returns `null` when there is nothing to say, so the caller prints nothing
|
|
123
|
+
* rather than a reassuring sentence about a number it does not have.
|
|
124
|
+
*/
|
|
125
|
+
export function coverageLimitationNote(label: string | null): string | null {
|
|
126
|
+
if (label === null) {
|
|
127
|
+
return null;
|
|
128
|
+
}
|
|
129
|
+
return (
|
|
130
|
+
`ℹ️ ${label} — a limitation of the RECORD, not a verdict on the release. ` +
|
|
131
|
+
'Stated, never enforced:\n what the review reads is a spend decision and this ' +
|
|
132
|
+
'gate does not take it.'
|
|
133
|
+
);
|
|
134
|
+
}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The high-consequence rule class — one reader for the config, the projector
|
|
3
|
+
* and the test.
|
|
4
|
+
*
|
|
5
|
+
* The criterion itself is prose and lives where an author meets it: the
|
|
6
|
+
* `consequence_class` property of `src/scripts/schemas/rule.schema.json`. This
|
|
7
|
+
* module does not restate it. It reads the list the criterion produced
|
|
8
|
+
* (`src/config/rule-consequence-class.json`), joins it to what each rule file
|
|
9
|
+
* actually declares, and answers the one question `project_thin_rules` asks:
|
|
10
|
+
* may this rule's stub carry its own law, and if not, has that been declared?
|
|
11
|
+
*
|
|
12
|
+
* WHY A DECLARED `no_stub` SUBSET RATHER THAN A SHORTER CLASS. A member whose
|
|
13
|
+
* law section is missing or over the ceiling cannot ship as stub-plus-law —
|
|
14
|
+
* there is nothing short enough to copy. Two ways to handle that: drop it from
|
|
15
|
+
* the class, or keep it in the class and record why it cannot stand. Dropping
|
|
16
|
+
* it makes the class shrinkable by NOT writing a law, which is the incentive a
|
|
17
|
+
* criterion must not create. Keeping it leaves the obligation visible and costs
|
|
18
|
+
* only a full-bodied projection, which is what those rules get today anyway.
|
|
19
|
+
*/
|
|
20
|
+
import * as fs from 'node:fs';
|
|
21
|
+
import * as path from 'node:path';
|
|
22
|
+
|
|
23
|
+
export const CLASS_CONFIG_REL = 'src/config/rule-consequence-class.json';
|
|
24
|
+
|
|
25
|
+
export const CLAUSES = ['irreversible-external', 'security-boundary', 'authority-bypass'] as const;
|
|
26
|
+
export type Clause = (typeof CLAUSES)[number];
|
|
27
|
+
|
|
28
|
+
export interface ClassMember {
|
|
29
|
+
clause: Clause;
|
|
30
|
+
/** What this rule's own law obligates, and what violating it costs. */
|
|
31
|
+
why: string;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export interface NoStubEntry extends ClassMember {
|
|
35
|
+
/** Why the law cannot stand in a stub today. */
|
|
36
|
+
reason: string;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export interface ConsequenceClassConfig {
|
|
40
|
+
criterion_ref: string;
|
|
41
|
+
members: Record<string, ClassMember>;
|
|
42
|
+
/** Subset of `members` that projects full-bodied, each with its reason. */
|
|
43
|
+
no_stub: Record<string, NoStubEntry>;
|
|
44
|
+
/** Near misses the criterion rejected, each with the reason it was rejected. */
|
|
45
|
+
excluded: Record<string, string>;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export function readConsequenceClass(repoRoot: string): ConsequenceClassConfig {
|
|
49
|
+
const raw = JSON.parse(fs.readFileSync(path.join(repoRoot, CLASS_CONFIG_REL), 'utf-8')) as Partial<
|
|
50
|
+
ConsequenceClassConfig
|
|
51
|
+
>;
|
|
52
|
+
return {
|
|
53
|
+
criterion_ref: raw.criterion_ref ?? '',
|
|
54
|
+
members: raw.members ?? {},
|
|
55
|
+
no_stub: raw.no_stub ?? {},
|
|
56
|
+
excluded: raw.excluded ?? {},
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/** Ids whose stub carries their law — members minus the declared `no_stub` set. */
|
|
61
|
+
export function stubLawIds(cfg: ConsequenceClassConfig): Set<string> {
|
|
62
|
+
return new Set(Object.keys(cfg.members).filter((id) => cfg.no_stub[id] === undefined));
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/** The `consequence_class:` value a rule file declares, or `null`. */
|
|
66
|
+
export function declaredClause(ruleText: string): Clause | null {
|
|
67
|
+
const m = /^consequence_class:\s*"?([a-z-]+)"?\s*$/m.exec(ruleText);
|
|
68
|
+
if (m === null) return null;
|
|
69
|
+
const v = m[1] as string;
|
|
70
|
+
return (CLAUSES as readonly string[]).includes(v) ? (v as Clause) : null;
|
|
71
|
+
}
|
|
@@ -72,8 +72,115 @@ export interface TierRuleMatch {
|
|
|
72
72
|
/** Kinds of trigger a prompt alone can never fire. */
|
|
73
73
|
export const PATH_TRIGGER_KINDS = ['path_prefix', 'file_pattern'] as const;
|
|
74
74
|
|
|
75
|
+
/**
|
|
76
|
+
* Set by `dispatch_hook` to its own resolved package root. Read here rather
|
|
77
|
+
* than threaded through every caller — see `ruleSourceDirs`.
|
|
78
|
+
*/
|
|
79
|
+
export const PACKAGE_ROOT_ENV = 'AGENT_CONFIG_PACKAGE_ROOT';
|
|
80
|
+
|
|
81
|
+
function statKind(p: string): 'dir' | 'file' | null {
|
|
82
|
+
try {
|
|
83
|
+
const s = fs.statSync(p);
|
|
84
|
+
return s.isDirectory() ? 'dir' : s.isFile() ? 'file' : null;
|
|
85
|
+
} catch {
|
|
86
|
+
return null;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Every tree a rule body may come from, highest precedence first.
|
|
92
|
+
*
|
|
93
|
+
* THE DEFECT THIS CLOSES, reproduced at `main` @ `9bc8cd4f2` and again on
|
|
94
|
+
* 2026-10-01. This module resolved bodies and the router under ONE root, and
|
|
95
|
+
* the carrier passed the envelope's workspace or `process.cwd()`. In this
|
|
96
|
+
* checkout those are the same directory and everything works. In a consumer
|
|
97
|
+
* project they are not: there is no `dist/` under the consumer's tree at all,
|
|
98
|
+
* so `loadRouter` threw, the carrier caught it and returned allow, and the
|
|
99
|
+
* concern delivered NOTHING while reporting no error. Every consumer runs it
|
|
100
|
+
* in someone else's project, so the shipped carrier was silent for every
|
|
101
|
+
* consumer and loud only for its author. `dispatch_hook.ts:722` has passed
|
|
102
|
+
* `AGENT_CONFIG_PACKAGE_ROOT` to every concern since the ADR-020 global-only
|
|
103
|
+
* install landed — the fix was one environment read away and nothing read it.
|
|
104
|
+
*
|
|
105
|
+
* THE ORDER IS THE CONTRACT:
|
|
106
|
+
*
|
|
107
|
+
* 1. `<root>/agents/overrides/<id>.md` — the developer's own layer.
|
|
108
|
+
* `agents_overlay.ts` already makes `overrides/` the one cascade kind
|
|
109
|
+
* that is both project- and user-global-eligible, and a consumer who has
|
|
110
|
+
* overridden a rule means it. It wins, which is what step 1.1's "with
|
|
111
|
+
* `agents/overrides/` keeping precedence" asks for.
|
|
112
|
+
* 2. `<root>/dist/agent-src/rules/<id>.md` — the maintainer checkout. Kept
|
|
113
|
+
* AHEAD of the package root and not behind it, so this repository's own
|
|
114
|
+
* behaviour is byte-identical to what it was before. A change that
|
|
115
|
+
* repairs consumers by moving the maintainer tree is one nobody can
|
|
116
|
+
* review against a known-good reading.
|
|
117
|
+
* 3. `<packageRoot>/dist/agent-src/rules/<id>.md` — the install. The only
|
|
118
|
+
* one of the three that exists in a foreign project.
|
|
119
|
+
*
|
|
120
|
+
* WHY THE ENVIRONMENT IS READ HERE rather than passed in. Nine call sites
|
|
121
|
+
* across the model, the shortlist, the arm experiment and two hooks pass a
|
|
122
|
+
* single `repoRoot`, and none of them has a second tree to offer. Threading a
|
|
123
|
+
* resolved source object through all of them would be a wide diff whose only
|
|
124
|
+
* real consumer is the carrier, and it costs runtime bytes in the composed
|
|
125
|
+
* hook bundle — which every hook event on every slot loads, under a hard
|
|
126
|
+
* ceiling (`src/config/hook-bundle-budget.json`). `roadmap_progress_hook`
|
|
127
|
+
* already reads this same variable this same way; this follows it rather than
|
|
128
|
+
* inventing a second convention. No `~` expansion: the one writer is
|
|
129
|
+
* `dispatch_hook`, which sets it from a `path.resolve` result.
|
|
130
|
+
*/
|
|
131
|
+
export interface RuleSources {
|
|
132
|
+
/** Body directories, highest precedence first. */
|
|
133
|
+
readonly dirs: readonly string[];
|
|
134
|
+
/** The resolved package root, or `null` when the variable named nothing. */
|
|
135
|
+
readonly pkg: string | null;
|
|
136
|
+
/** The `dist/router.json` to route against, or `null`. */
|
|
137
|
+
readonly router: string | null;
|
|
138
|
+
/**
|
|
139
|
+
* One line naming why nothing resolved, or `null` when something did.
|
|
140
|
+
*
|
|
141
|
+
* A caller that found nothing must be able to SAY so. An empty delivery is
|
|
142
|
+
* indistinguishable from "no rule matched", which is exactly the silence
|
|
143
|
+
* this chain exists to end; reproducing it one layer up would be the whole
|
|
144
|
+
* defect again. The three wordings are distinguishable because the
|
|
145
|
+
* operator's next action differs: the variable was never set (a host or
|
|
146
|
+
* wrapper problem), it points somewhere that is gone (a move after
|
|
147
|
+
* install), or both resolved and the package carries no built corpus.
|
|
148
|
+
*/
|
|
149
|
+
readonly gap: string | null;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/** Resolve the body dirs, the router and the gap wording in ONE filesystem pass. */
|
|
153
|
+
export function ruleSources(repoRoot: string): RuleSources {
|
|
154
|
+
const env = (process.env[PACKAGE_ROOT_ENV] ?? '').trim();
|
|
155
|
+
const pkg = env ? path.resolve(env) : null;
|
|
156
|
+
const dirs: string[] = [];
|
|
157
|
+
const add = (d: string): void => {
|
|
158
|
+
if (statKind(d) === 'dir' && !dirs.includes(d)) dirs.push(d);
|
|
159
|
+
};
|
|
160
|
+
add(path.join(repoRoot, 'agents', 'overrides'));
|
|
161
|
+
add(path.join(repoRoot, 'dist', 'agent-src', 'rules'));
|
|
162
|
+
if (pkg !== null) add(path.join(pkg, 'dist', 'agent-src', 'rules'));
|
|
163
|
+
|
|
164
|
+
const local = path.join(repoRoot, 'dist', 'router.json');
|
|
165
|
+
let router: string | null = statKind(local) === 'file' ? local : null;
|
|
166
|
+
if (router === null && pkg !== null) {
|
|
167
|
+
const shipped = path.join(pkg, 'dist', 'router.json');
|
|
168
|
+
if (statKind(shipped) === 'file') router = shipped;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
let gap: string | null = null;
|
|
172
|
+
if (router === null || dirs.length === 0) {
|
|
173
|
+
const miss =
|
|
174
|
+
pkg === null
|
|
175
|
+
? `${PACKAGE_ROOT_ENV} unset`
|
|
176
|
+
: `no ${router === null ? 'dist/router.json' : 'dist/agent-src/rules'} under ${repoRoot} or ${pkg}`;
|
|
177
|
+
gap = `rule-inject: no rule source — ${miss}`;
|
|
178
|
+
}
|
|
179
|
+
return { dirs, pkg, router, gap };
|
|
180
|
+
}
|
|
181
|
+
|
|
75
182
|
export function loadRouter(repoRoot: string): Router {
|
|
76
|
-
const p = path.join(repoRoot, 'dist', 'router.json');
|
|
183
|
+
const p = ruleSources(repoRoot).router ?? path.join(repoRoot, 'dist', 'router.json');
|
|
77
184
|
return JSON.parse(fs.readFileSync(p, 'utf8')) as Router;
|
|
78
185
|
}
|
|
79
186
|
|
|
@@ -163,16 +270,29 @@ export function matchTierRules(
|
|
|
163
270
|
return out;
|
|
164
271
|
}
|
|
165
272
|
|
|
166
|
-
/**
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
273
|
+
/**
|
|
274
|
+
* The projected body from the highest-precedence tree carrying it, or `null`.
|
|
275
|
+
*
|
|
276
|
+
* `ruleBodyPath` used to sit in front of this and is gone: it returned the
|
|
277
|
+
* single-root path unconditionally, this diff changed its contract to "the
|
|
278
|
+
* first tree that has the file", and nothing outside this module ever called
|
|
279
|
+
* it. An exported helper whose last caller disappeared in the same diff is an
|
|
280
|
+
* own-orphan, and the composed hook bundle charges for it on every dispatch
|
|
281
|
+
* (`src/config/hook-bundle-budget.json`), so it is removed rather than left as
|
|
282
|
+
* a wrapper nobody uses.
|
|
283
|
+
*/
|
|
172
284
|
export function loadRuleBody(repoRoot: string, id: string): string | null {
|
|
173
|
-
const
|
|
174
|
-
|
|
175
|
-
|
|
285
|
+
for (const dir of ruleSources(repoRoot).dirs) {
|
|
286
|
+
const p = path.join(dir, `${id}.md`);
|
|
287
|
+
if (statKind(p) === 'file') {
|
|
288
|
+
try {
|
|
289
|
+
return fs.readFileSync(p, 'utf8');
|
|
290
|
+
} catch {
|
|
291
|
+
return null;
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
return null;
|
|
176
296
|
}
|
|
177
297
|
|
|
178
298
|
/**
|