@event4u/agent-config 16.2.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 +89 -237
- 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 +4 -4
- 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/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/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/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/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-system-capture/references/import-procedure.md +1 -1
- package/dist/agent-src/skills/existing-ui-audit/SKILL.md +2 -2
- 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/monorepo-workspace/SKILL.md +1 -1
- 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 +2 -2
- package/dist/agent-src/templates/agents/agent-project-settings.example.yml +1 -1
- package/dist/agent-src/templates/scripts/work_engine/directives/ui/apply.ts +48 -6
- package/dist/agent-src/templates/scripts/work_engine/stack/runner.ts +774 -109
- 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-IGD6ERX6.js → chunk-JQVYKIZA.js} +10 -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-7RQP4UDH.js → chunk-KR6EM23A.js} +235 -1455
- package/dist/cli-delegate/{chunk-LTYVIY76.js → chunk-LIYTLH6O.js} +1 -1
- package/dist/cli-delegate/{chunk-YJ72UIAK.js → chunk-NQ7WT43P.js} +1186 -244
- 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-7XGBX6ZH.js → chunk-RQNNW7IF.js} +1314 -560
- package/dist/cli-delegate/{chunk-4XFP2Y3E.js → chunk-S4UMZNES.js} +1 -1
- package/dist/cli-delegate/{chunk-6KM6ORRY.js → chunk-S4YWNRKO.js} +24 -8
- package/dist/cli-delegate/{chunk-FP36SWJD.js → chunk-TRI6DQZ6.js} +2781 -340
- 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 +1167 -234
- 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 +127 -75
- 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 +5357 -6656
- package/dist/hooks/dispatch.sha256 +1 -1
- 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 +2080 -1024
- 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 +31965 -27154
- 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 +6 -0
- package/dist/shared/skillRanking.js +74 -13
- package/docs/contracts/settings-classes.md +7 -5
- package/package.json +1 -1
- 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/apply.ts +48 -6
- package/src/agent-src/templates/scripts/work_engine/stack/runner.ts +774 -109
- package/src/config/agent-settings.template.yml +62 -22
- package/src/config/continuity-surface.json +7 -0
- package/src/config/evaluator-budgets.json +4 -4
- package/src/config/gate-coverage.yml +96 -3
- package/src/config/gate-violation-baselines.json +17 -9
- package/src/config/hook-bundle-budget.json +25 -0
- package/src/config/hook-token-budget.json +6 -1
- package/src/config/host-instruction-limits.json +33 -0
- package/src/config/routing-coverage-seed.json +24 -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 +23 -71
- package/src/scripts/_cli/cmd_doctor_neighbours.ts +293 -0
- package/src/scripts/_dispatch.bash +16 -2
- package/src/scripts/_lib/agent_settings.ts +11 -0
- package/src/scripts/_lib/claude_settings_hooks.ts +10 -8
- 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/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_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/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/prompt_shape.ts +46 -0
- package/src/scripts/_lib/release_migration_gate.ts +19 -3
- package/src/scripts/_lib/reserved_name_sweep.ts +73 -0
- 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/skill_origin.ts +254 -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 +77 -2
- 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/audit_skill_overlap.ts +261 -0
- package/src/scripts/before_complete_hook.ts +243 -12
- package/src/scripts/bench_touched_file_quality.ts +238 -0
- package/src/scripts/check_enforcement_matrix.ts +377 -20
- package/src/scripts/check_estate_count.ts +130 -153
- package/src/scripts/check_finding_dispositions.ts +116 -4
- package/src/scripts/check_hook_bundle_composition.ts +370 -0
- package/src/scripts/check_kernel_edit_ratified.ts +49 -11
- package/src/scripts/check_memory.ts +7 -1
- package/src/scripts/check_release_highlights.ts +10 -0
- package/src/scripts/check_release_pr_shape.ts +38 -15
- package/src/scripts/check_standing_rule_delivery.ts +33 -13
- package/src/scripts/check_verify_expectation_delta.ts +521 -0
- 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 +33 -1
- package/src/scripts/condense.ts +14 -27
- package/src/scripts/estate_exemption_shape.ts +202 -0
- package/src/scripts/generate_host_cost_table.ts +1 -1
- package/src/scripts/hook_manifest.json +1 -1
- package/src/scripts/hook_manifest.yaml +150 -9
- package/src/scripts/hooks/block_config_weakening.ts +67 -2
- package/src/scripts/hooks/block_plumbing_writes.ts +29 -1
- package/src/scripts/hooks/code_graph_context_hook.ts +252 -23
- package/src/scripts/hooks/concern_failure_policy.ts +280 -0
- package/src/scripts/hooks/dispatch_hook.ts +52 -52
- package/src/scripts/hooks/exit_codes.ts +2 -1
- package/src/scripts/hooks/host_lowering.json +1 -1
- package/src/scripts/hooks/host_lowering.ts +19 -1
- package/src/scripts/hooks/one_question_per_ask_hook.ts +41 -25
- package/src/scripts/hooks/payload_stub.ts +10 -1
- package/src/scripts/hooks/rule_inject_hook.ts +757 -63
- package/src/scripts/hooks/table_fingerprint.ts +21 -0
- package/src/scripts/hooks/telemetry_usage_hook.ts +64 -8
- package/src/scripts/hooks/turn_end_gate_hook.ts +84 -0
- package/src/scripts/hooks_status.ts +112 -0
- package/src/scripts/injection_scan_hook.ts +7 -0
- package/src/scripts/install.ts +72 -185
- 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_hook_manifest.ts +53 -0
- package/src/scripts/lint_major_migration_sections.ts +156 -26
- package/src/scripts/lint_pack_boundaries.ts +63 -5
- package/src/scripts/lint_rule_law_section.ts +517 -0
- 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/measure_routing_signal.ts +54 -16
- package/src/scripts/measure_skill_ranker_baseline.ts +216 -8
- package/src/scripts/memory_learn_hook.ts +91 -6
- package/src/scripts/model_rule_injection.ts +52 -5
- package/src/scripts/project_thin_rules.ts +34 -327
- package/src/scripts/report_evidence_temperature.ts +657 -0
- package/src/scripts/report_installed_rule_links.ts +157 -0
- package/src/scripts/report_label_agreement.ts +233 -0
- package/src/scripts/report_obligation_mechanism.ts +230 -0
- package/src/scripts/report_single_token_triggers.ts +277 -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/rule_activation_census.ts +5 -2
- package/src/scripts/rule_trigger_eval.ts +9 -9
- package/src/scripts/schemas/review-findings.schema.json +3 -2
- package/src/scripts/schemas/rule.schema.json +5 -0
- package/src/scripts/self_review_gate.ts +62 -7
- package/src/scripts/skill_tools/score_skill_relevance.ts +290 -25
- 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 -5
- package/src/server/schemas/settings.ts +10 -0
- package/src/shared/skillRanking.ts +117 -11
- package/dist/cli-delegate/chunk-JNMVLWLR.js +0 -4457
- package/dist/cli-delegate/chunk-YDPILCOL.js +0 -152
|
@@ -0,0 +1,277 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Which one-token keyword triggers fire on prompts that belong to other rules.
|
|
4
|
+
*
|
|
5
|
+
* Step 1.3 of `road-to-rule-triggers-and-links-that-hold`. A single common word
|
|
6
|
+
* — `rename`, `delete` — is a legitimate trigger for the rule that owns the
|
|
7
|
+
* subject and a standing cost for every prompt that merely uses the word. This
|
|
8
|
+
* reports which words sit at which share of the corpus. **Report only.** A
|
|
9
|
+
* trigger change is a separate decision per rule, because a common word can be
|
|
10
|
+
* exactly right: `augment-edit-discipline` genuinely wants to fire on a rename.
|
|
11
|
+
*
|
|
12
|
+
* The corpus is `tests/eval/routing-matrix/*.yaml`, the frozen set this tree
|
|
13
|
+
* already evaluates routing against. Each `positives[].prompt` is labelled with
|
|
14
|
+
* its file's rule. For a one-token keyword `K` on rule `R`, the share is:
|
|
15
|
+
*
|
|
16
|
+
* |{ prompt : label(prompt) != R and K occurs as a word }|
|
|
17
|
+
* ---------------------------------------------------------
|
|
18
|
+
* |{ prompt : label(prompt) != R }|
|
|
19
|
+
*
|
|
20
|
+
* `near_misses` are deliberately NOT in the denominator. They carry a negative
|
|
21
|
+
* label against their own file's rule and no positive label against any other,
|
|
22
|
+
* so counting them would mix "belongs to another rule" with "belongs to no
|
|
23
|
+
* rule" — two different claims, and only the first is what a cross-firing
|
|
24
|
+
* trigger costs.
|
|
25
|
+
*
|
|
26
|
+
* The 5 % threshold is a stated default for a report, not a gate (D3). Nothing
|
|
27
|
+
* acts on the figure automatically.
|
|
28
|
+
*/
|
|
29
|
+
import * as fs from 'node:fs';
|
|
30
|
+
import * as path from 'node:path';
|
|
31
|
+
import { fileURLToPath, pathToFileURL } from 'node:url';
|
|
32
|
+
|
|
33
|
+
import { parse as parseYaml } from 'yaml';
|
|
34
|
+
|
|
35
|
+
// ledger-exempt: a REPORTER, not a gate. Its only non-zero exit says the
|
|
36
|
+
// corpus or the rule directory could not be read.
|
|
37
|
+
|
|
38
|
+
const _HERE = fileURLToPath(import.meta.url);
|
|
39
|
+
|
|
40
|
+
export const DEFAULT_THRESHOLD = 0.05;
|
|
41
|
+
|
|
42
|
+
export interface LabelledPrompt {
|
|
43
|
+
rule: string;
|
|
44
|
+
prompt: string;
|
|
45
|
+
/** `positive` — belongs to `rule`. `near_miss` — declared NOT to be `rule`. */
|
|
46
|
+
kind: 'positive' | 'near_miss';
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export interface TriggerRow {
|
|
50
|
+
rule: string;
|
|
51
|
+
keyword: string;
|
|
52
|
+
/** Foreign POSITIVE prompts the keyword occurs in. */
|
|
53
|
+
hits: number;
|
|
54
|
+
/** Prompts labelled positive against any other rule. */
|
|
55
|
+
foreign: number;
|
|
56
|
+
share: number;
|
|
57
|
+
/**
|
|
58
|
+
* Occurrences in a near-miss the rule ITSELF declares — the keyword fires
|
|
59
|
+
* on a prompt that rule's own fixture says it must not fire on. A declared
|
|
60
|
+
* false positive, and the sharpest row this report can produce.
|
|
61
|
+
*/
|
|
62
|
+
own_near_miss_hits: number;
|
|
63
|
+
own_near_misses: number;
|
|
64
|
+
/** Occurrences in another rule's near-miss list. */
|
|
65
|
+
foreign_near_miss_hits: number;
|
|
66
|
+
/** Which rules those foreign positives belong to, highest first. */
|
|
67
|
+
top_labels: { rule: string; count: number }[];
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/** Every prompt in the matrix, labelled with its file's rule and its kind. */
|
|
71
|
+
export function loadCorpus(matrixDir: string): LabelledPrompt[] {
|
|
72
|
+
const out: LabelledPrompt[] = [];
|
|
73
|
+
const files = fs
|
|
74
|
+
.readdirSync(matrixDir)
|
|
75
|
+
.filter((n) => n.endsWith('.yaml'))
|
|
76
|
+
.sort();
|
|
77
|
+
for (const file of files) {
|
|
78
|
+
const doc = parseYaml(fs.readFileSync(path.join(matrixDir, file), 'utf-8')) as {
|
|
79
|
+
rule?: unknown;
|
|
80
|
+
positives?: { prompt?: unknown }[];
|
|
81
|
+
near_misses?: { prompt?: unknown }[];
|
|
82
|
+
} | null;
|
|
83
|
+
const rule = typeof doc?.rule === 'string' ? doc.rule : '';
|
|
84
|
+
if (!rule) continue;
|
|
85
|
+
for (const [items, kind] of [
|
|
86
|
+
[doc?.positives, 'positive'],
|
|
87
|
+
[doc?.near_misses, 'near_miss'],
|
|
88
|
+
] as const) {
|
|
89
|
+
if (!Array.isArray(items)) continue;
|
|
90
|
+
for (const item of items) {
|
|
91
|
+
if (typeof item?.prompt === 'string' && item.prompt.trim()) {
|
|
92
|
+
out.push({ rule, prompt: item.prompt, kind });
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
return out;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/** One-token keyword triggers per rule, from `src/rules/*.md` frontmatter. */
|
|
101
|
+
export function singleTokenKeywords(rulesDir: string): { rule: string; keyword: string }[] {
|
|
102
|
+
const out: { rule: string; keyword: string }[] = [];
|
|
103
|
+
const files = fs
|
|
104
|
+
.readdirSync(rulesDir)
|
|
105
|
+
.filter((n) => n.endsWith('.md'))
|
|
106
|
+
.sort();
|
|
107
|
+
for (const file of files) {
|
|
108
|
+
const content = fs.readFileSync(path.join(rulesDir, file), 'utf-8');
|
|
109
|
+
if (!content.startsWith('---')) continue;
|
|
110
|
+
const end = content.indexOf('\n---', 3);
|
|
111
|
+
const block = end === -1 ? content : content.slice(0, end);
|
|
112
|
+
const rule = file.replace(/\.md$/, '');
|
|
113
|
+
for (const m of block.matchAll(/^\s*-\s*keyword:\s*["']?([^"'\n]+?)["']?\s*$/gm)) {
|
|
114
|
+
const kw = (m[1] as string).trim();
|
|
115
|
+
if (kw === '' || /\s/.test(kw)) continue;
|
|
116
|
+
out.push({ rule, keyword: kw });
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
return out;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/** Word-boundary, case-insensitive, with the keyword's own characters escaped. */
|
|
123
|
+
function occursAsWord(prompt: string, keyword: string): boolean {
|
|
124
|
+
const esc = keyword.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
125
|
+
return new RegExp(`(?:^|[^\\p{L}\\p{N}_])${esc}(?:$|[^\\p{L}\\p{N}_])`, 'iu').test(prompt);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
export function rows(
|
|
129
|
+
corpus: readonly LabelledPrompt[],
|
|
130
|
+
keywords: readonly { rule: string; keyword: string }[],
|
|
131
|
+
): TriggerRow[] {
|
|
132
|
+
const out: TriggerRow[] = [];
|
|
133
|
+
for (const { rule, keyword } of keywords) {
|
|
134
|
+
const foreign = corpus.filter((c) => c.rule !== rule && c.kind === 'positive');
|
|
135
|
+
if (foreign.length === 0) continue;
|
|
136
|
+
const hitting = foreign.filter((c) => occursAsWord(c.prompt, keyword));
|
|
137
|
+
const ownNear = corpus.filter((c) => c.rule === rule && c.kind === 'near_miss');
|
|
138
|
+
const foreignNear = corpus.filter((c) => c.rule !== rule && c.kind === 'near_miss');
|
|
139
|
+
const labels = new Map<string, number>();
|
|
140
|
+
for (const h of hitting) labels.set(h.rule, (labels.get(h.rule) ?? 0) + 1);
|
|
141
|
+
out.push({
|
|
142
|
+
rule,
|
|
143
|
+
keyword,
|
|
144
|
+
hits: hitting.length,
|
|
145
|
+
foreign: foreign.length,
|
|
146
|
+
share: hitting.length / foreign.length,
|
|
147
|
+
own_near_miss_hits: ownNear.filter((c) => occursAsWord(c.prompt, keyword)).length,
|
|
148
|
+
own_near_misses: ownNear.length,
|
|
149
|
+
foreign_near_miss_hits: foreignNear.filter((c) => occursAsWord(c.prompt, keyword)).length,
|
|
150
|
+
top_labels: [...labels.entries()]
|
|
151
|
+
.map(([r, count]) => ({ rule: r, count }))
|
|
152
|
+
.sort((a, b) => b.count - a.count || a.rule.localeCompare(b.rule))
|
|
153
|
+
.slice(0, 5),
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
out.sort(
|
|
157
|
+
(a, b) =>
|
|
158
|
+
b.share - a.share ||
|
|
159
|
+
b.own_near_miss_hits - a.own_near_miss_hits ||
|
|
160
|
+
b.foreign_near_miss_hits - a.foreign_near_miss_hits ||
|
|
161
|
+
a.rule.localeCompare(b.rule) ||
|
|
162
|
+
a.keyword.localeCompare(b.keyword),
|
|
163
|
+
);
|
|
164
|
+
return out;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
export function renderTable(data: readonly TriggerRow[]): string[] {
|
|
168
|
+
const L: string[] = [];
|
|
169
|
+
L.push(
|
|
170
|
+
'| Rule | Keyword | Foreign positives | Share | Own near-miss hits | Foreign near-miss hits | Mostly labelled against |',
|
|
171
|
+
);
|
|
172
|
+
L.push('|---|---|---:|---:|---:|---:|---|');
|
|
173
|
+
for (const r of data) {
|
|
174
|
+
const labels = r.top_labels.map((l) => `\`${l.rule}\` ${String(l.count)}`).join(', ') || '—';
|
|
175
|
+
L.push(
|
|
176
|
+
`| \`${r.rule}\` | \`${r.keyword}\` | ${String(r.hits)}/${String(r.foreign)} | ` +
|
|
177
|
+
`${(r.share * 100).toFixed(1)} % | ${String(r.own_near_miss_hits)}/${String(r.own_near_misses)} | ` +
|
|
178
|
+
`${String(r.foreign_near_miss_hits)} | ${labels} |`,
|
|
179
|
+
);
|
|
180
|
+
}
|
|
181
|
+
return L;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
const USAGE =
|
|
185
|
+
'usage: report_single_token_triggers [--root DIR] [--threshold F] [--json | --table] [--all]\n' +
|
|
186
|
+
' --threshold share above which a row is reported (default 0.05)\n' +
|
|
187
|
+
' --all report every one-token keyword, not just those over the threshold\n';
|
|
188
|
+
|
|
189
|
+
export function main(): number {
|
|
190
|
+
const argv = process.argv.slice(2);
|
|
191
|
+
if (argv.includes('--help') || argv.includes('-h')) {
|
|
192
|
+
process.stdout.write(USAGE);
|
|
193
|
+
return 0;
|
|
194
|
+
}
|
|
195
|
+
const KNOWN = ['--root', '--threshold', '--json', '--table', '--all'];
|
|
196
|
+
// A silently-ignored `--treshold` would report against a threshold the
|
|
197
|
+
// operator did not ask for, while still printing the default in the header.
|
|
198
|
+
for (const a of argv) {
|
|
199
|
+
if (a.startsWith('-') && !KNOWN.includes(a)) {
|
|
200
|
+
process.stderr.write(`unknown argument: ${a}\n${USAGE}`);
|
|
201
|
+
return 2;
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
const flagValue = (f: string): string | null => {
|
|
205
|
+
const i = argv.indexOf(f);
|
|
206
|
+
return i >= 0 && i + 1 < argv.length ? (argv[i + 1] as string) : null;
|
|
207
|
+
};
|
|
208
|
+
const root = flagValue('--root') ?? process.cwd();
|
|
209
|
+
const rawT = flagValue('--threshold');
|
|
210
|
+
const threshold = rawT === null ? DEFAULT_THRESHOLD : Number.parseFloat(rawT);
|
|
211
|
+
if (!Number.isFinite(threshold) || threshold < 0 || threshold > 1) {
|
|
212
|
+
process.stderr.write('--threshold must be a fraction between 0 and 1\n');
|
|
213
|
+
return 2;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
const matrixDir = path.join(root, 'tests', 'eval', 'routing-matrix');
|
|
217
|
+
const rulesDir = path.join(root, 'src', 'rules');
|
|
218
|
+
if (!fs.existsSync(matrixDir) || !fs.existsSync(rulesDir)) {
|
|
219
|
+
process.stderr.write(`missing ${matrixDir} or ${rulesDir}\n`);
|
|
220
|
+
return 1;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
const corpus = loadCorpus(matrixDir);
|
|
224
|
+
const keywords = singleTokenKeywords(rulesDir);
|
|
225
|
+
const all = rows(corpus, keywords);
|
|
226
|
+
// A keyword reaches the report by EITHER axis: the share the step names, or
|
|
227
|
+
// a hit on a near-miss. Filtering on the share alone would have hidden the
|
|
228
|
+
// only rows this corpus actually produces — see the report's own § on why
|
|
229
|
+
// the 5 % threshold finds nothing here.
|
|
230
|
+
const data = argv.includes('--all')
|
|
231
|
+
? all
|
|
232
|
+
: all.filter((r) => r.share > threshold || r.own_near_miss_hits > 0 || r.foreign_near_miss_hits > 0);
|
|
233
|
+
|
|
234
|
+
if (argv.includes('--json')) {
|
|
235
|
+
process.stdout.write(
|
|
236
|
+
`${JSON.stringify({ threshold, corpus: corpus.length, keywords: keywords.length, rows: data }, null, 2)}\n`,
|
|
237
|
+
);
|
|
238
|
+
return 0;
|
|
239
|
+
}
|
|
240
|
+
if (argv.includes('--table')) {
|
|
241
|
+
process.stdout.write(`${renderTable(data).join('\n')}\n`);
|
|
242
|
+
return 0;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
const positives = corpus.filter((c) => c.kind === 'positive').length;
|
|
246
|
+
process.stdout.write(
|
|
247
|
+
`corpus ${String(corpus.length)} prompt(s) — ${String(positives)} positive, ` +
|
|
248
|
+
`${String(corpus.length - positives)} near-miss · ` +
|
|
249
|
+
`${String(keywords.length)} one-token keyword(s) over ` +
|
|
250
|
+
`${String(new Set(keywords.map((k) => k.rule)).size)} rule(s)\n` +
|
|
251
|
+
`${String(all.filter((r) => r.share > threshold).length)} row(s) above ` +
|
|
252
|
+
`${(threshold * 100).toFixed(1)} % of foreign positives · ` +
|
|
253
|
+
`${String(data.length)} reportable on either axis\n\n`,
|
|
254
|
+
);
|
|
255
|
+
for (const r of data) {
|
|
256
|
+
process.stdout.write(
|
|
257
|
+
` ${(r.share * 100).toFixed(1).padStart(5)} % ${r.keyword.padEnd(18)} ${r.rule.padEnd(32)} ` +
|
|
258
|
+
`pos ${String(r.hits)}/${String(r.foreign)} own-near ${String(r.own_near_miss_hits)}/${String(r.own_near_misses)} ` +
|
|
259
|
+
`foreign-near ${String(r.foreign_near_miss_hits)}\n`,
|
|
260
|
+
);
|
|
261
|
+
}
|
|
262
|
+
return 0;
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
function _isCliEntry(): boolean {
|
|
266
|
+
if (process.argv[1] === undefined) return false;
|
|
267
|
+
if (import.meta.url === pathToFileURL(path.resolve(process.argv[1])).href) return true;
|
|
268
|
+
try {
|
|
269
|
+
return fs.realpathSync(_HERE) === fs.realpathSync(path.resolve(process.argv[1]));
|
|
270
|
+
} catch {
|
|
271
|
+
return false;
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
if (_isCliEntry()) {
|
|
276
|
+
process.exit(main());
|
|
277
|
+
}
|