@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
|
@@ -238,7 +238,11 @@ Tier 2 — maintenance / internal (hooks, MCP, memory, telemetry):
|
|
|
238
238
|
roadmap:set-step Flip ONE checkbox glyph safely (lock + line anchor +
|
|
239
239
|
live invariant + survival check)
|
|
240
240
|
roadmap:archive Archive completed roadmaps (branch-touched by default;
|
|
241
|
-
--all for every complete one; --dry-run to preview
|
|
241
|
+
--all for every complete one; --dry-run to preview;
|
|
242
|
+
bare [~] steps are carried to a follow-up first,
|
|
243
|
+
--no-carry to leave them blocking; owner-blocked
|
|
244
|
+
steps ask first; --owner-decision later --only <x>
|
|
245
|
+
parks that one roadmap)
|
|
242
246
|
stubs:due Read-only: roadmap stubs past their `review_by:`
|
|
243
247
|
date, plus the decisions routed to the owner.
|
|
244
248
|
Writes nothing. Flags: --json, --counts,
|
|
@@ -342,7 +346,9 @@ Tier 2 — maintenance / internal (hooks, MCP, memory, telemetry):
|
|
|
342
346
|
memory:check-proposal Run the admission gate on a memory proposal
|
|
343
347
|
memory:learn Aggregate memory intake signals into the local learning
|
|
344
348
|
sidecar (read-only; --write to emit). Usage: memory:learn [--intake-dir DIR]
|
|
345
|
-
[--out-dir DIR] [--now ISO] [--write] [--format text|json]
|
|
349
|
+
[--out-dir DIR] [--now ISO] [--write] [--format text|json|status]
|
|
350
|
+
--format status prints the one-screen human view (verdict counts,
|
|
351
|
+
top preferred lessons, the hand-off); it refuses --write.
|
|
346
352
|
analytics Local-only workspace analytics (emit|show|prune|migrate).
|
|
347
353
|
Usage: analytics show [--window 30d|7d|24h] · analytics prune
|
|
348
354
|
knowledge Global knowledge-card store (list|show|trace|forget|promote|
|
|
@@ -1456,7 +1462,15 @@ cmd_prune() {
|
|
|
1456
1462
|
# `agent-config doctor` — read-only drift report against the manifest.
|
|
1457
1463
|
# Surfaces missing / modified / foreign files. Exit 0 clean, 1 drift,
|
|
1458
1464
|
# 2 manifest-absent. See scripts/_cli/cmd_doctor.ts.
|
|
1465
|
+
# `doctor neighbours` routes to its own entry point rather than a branch inside
|
|
1466
|
+
# cmd_doctor.ts, which is 2,000 lines over the source-size ceiling and cannot
|
|
1467
|
+
# grow. Routed here because the dispatcher is where verbs are already resolved.
|
|
1459
1468
|
cmd_doctor() {
|
|
1469
|
+
if [[ "${1:-}" == "neighbours" ]]; then
|
|
1470
|
+
shift
|
|
1471
|
+
exec_ts "$PACKAGE_ROOT/src/scripts/_cli/cmd_doctor_neighbours.ts" "$@"
|
|
1472
|
+
return
|
|
1473
|
+
fi
|
|
1460
1474
|
exec_ts "$PACKAGE_ROOT/src/scripts/_cli/cmd_doctor.ts" "$@"
|
|
1461
1475
|
}
|
|
1462
1476
|
|
|
@@ -305,6 +305,17 @@ export const MERGEABLE_KEYS: readonly string[] = [
|
|
|
305
305
|
// GUI; whitelisting decides only whether the value SURVIVES the merge
|
|
306
306
|
// (ADR-271, road-to-design-intent-conformance 2.3).
|
|
307
307
|
'design.fidelity_mode',
|
|
308
|
+
// `lean_projection.*` is a per-MACHINE setting and the install it governs is
|
|
309
|
+
// a user-scope one: the layer being thinned is `~/.claude/rules`, which
|
|
310
|
+
// belongs to the machine and not to any checkout. Without these two rows a
|
|
311
|
+
// consumer who wrote the opt-in into the user-global file got no error, no
|
|
312
|
+
// warning and no effect — the same silent-filter defect the two entries
|
|
313
|
+
// above repair, reaching a third key, and unsatisfiable-by-construction on
|
|
314
|
+
// an ADR-020 global-only install, where no project layer exists to carry it.
|
|
315
|
+
// Whitelisting decides only whether a value SURVIVES the merge: it sets
|
|
316
|
+
// nothing, and `installerThinsHost` still refuses a template-only value.
|
|
317
|
+
'lean_projection.mode',
|
|
318
|
+
'lean_projection.hosts',
|
|
308
319
|
];
|
|
309
320
|
|
|
310
321
|
/** The shipped template, relative to the package root. */
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `body-portable` — does a skill's declared frontmatter survive the MCP-lite
|
|
3
|
+
* carrier whole?
|
|
4
|
+
*
|
|
5
|
+
* road-to-semantic-parity-before-off-menu, Phase 2.1.
|
|
6
|
+
*
|
|
7
|
+
* WHAT THIS DECIDES, AND WHAT IT DOES NOT
|
|
8
|
+
*
|
|
9
|
+
* It decides ELIGIBILITY only. It marks nothing, excludes nothing, and is not a
|
|
10
|
+
* verdict about which skills matter. A committed list of skills this returns
|
|
11
|
+
* false for is one step from a menu-exclusion discharged by citing it, which is
|
|
12
|
+
* precisely the laundering the parked menu-economy roadmap's Risk 1 names — a
|
|
13
|
+
* measurement of carrier coverage reused as a judgement about worth. Nothing in
|
|
14
|
+
* the tree consumes this as an exclusion trigger, and building the half that
|
|
15
|
+
* could is a separate decision that has not been taken.
|
|
16
|
+
*
|
|
17
|
+
* THE RULE
|
|
18
|
+
*
|
|
19
|
+
* A skill is body-portable when every key it declares is one the carrier
|
|
20
|
+
* transports whole. Three ways to fail, and they are deliberately not
|
|
21
|
+
* distinguished in the boolean:
|
|
22
|
+
*
|
|
23
|
+
* - a DROPPED key — the carrier never reads it, so the semantic stays on disk.
|
|
24
|
+
* - a PARTIAL key — the carrier reads it and transports part of the value.
|
|
25
|
+
* `triggers` is the only one: `keyword` and `phrase` travel, while
|
|
26
|
+
* `file_pattern`, `path_prefix`, `command` and `reason` do not. Counting it
|
|
27
|
+
* as portable would make a path-triggered skill look complete when the very
|
|
28
|
+
* routing that selects it never leaves the disk.
|
|
29
|
+
* - an UNKNOWN key — one the schema does not declare at all. It fails CLOSED.
|
|
30
|
+
* The alternative is to ignore what you cannot classify, and an unknown key
|
|
31
|
+
* is exactly the case where the carrier's behaviour is unestablished, so
|
|
32
|
+
* returning true there would assert portability from ignorance.
|
|
33
|
+
*
|
|
34
|
+
* SCOPE: one carrier, `ContentEntry` in `src/cli/mcp/content.ts`. A second
|
|
35
|
+
* delivery path drops a different set and needs its own predicate rather than a
|
|
36
|
+
* widened reading of this one.
|
|
37
|
+
*/
|
|
38
|
+
|
|
39
|
+
import { INDEXED_TRIGGER_KEYS } from '../../shared/skillRanking.js';
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Frontmatter keys `buildEntry` reads and transports whole
|
|
43
|
+
* (`src/cli/mcp/content.ts` — `fm.name`, `fm.description`, `fm.source`,
|
|
44
|
+
* `fm.personas`).
|
|
45
|
+
*
|
|
46
|
+
* Derived from the carrier source, never from the schema: a schema property the
|
|
47
|
+
* carrier does not read is dropped no matter what the schema says about it.
|
|
48
|
+
*/
|
|
49
|
+
export const CARRIED_KEYS: readonly string[] = ['name', 'description', 'source', 'personas'];
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Keys the carrier reads but truncates, with the sub-keys that actually travel.
|
|
53
|
+
*
|
|
54
|
+
* The sub-key list is IMPORTED from `INDEXED_TRIGGER_KEYS` rather than restated.
|
|
55
|
+
* Restating it was the first version of this file and it is a silent-lie shape:
|
|
56
|
+
* add a third indexed key and a hand-copied literal keeps reporting the old two
|
|
57
|
+
* while the carrier transports three, so the census `travels` column would be
|
|
58
|
+
* wrong with every test still green.
|
|
59
|
+
*/
|
|
60
|
+
export const PARTIAL_KEYS: Readonly<Record<string, readonly string[]>> = {
|
|
61
|
+
triggers: INDEXED_TRIGGER_KEYS,
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
/** Why a skill is not body-portable. Empty when it is. */
|
|
65
|
+
export interface PortabilityReasons {
|
|
66
|
+
/** Declared keys the carrier transports only in part. */
|
|
67
|
+
readonly partial: readonly string[];
|
|
68
|
+
/** Declared keys the carrier does not read, including keys the schema does not declare. */
|
|
69
|
+
readonly dropped: readonly string[];
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export interface PortabilityVerdict extends PortabilityReasons {
|
|
73
|
+
readonly portable: boolean;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Classify one skill's declared frontmatter keys.
|
|
78
|
+
*
|
|
79
|
+
* Pure: it reads nothing and depends only on its argument and the two constants
|
|
80
|
+
* above.
|
|
81
|
+
*/
|
|
82
|
+
export function classifyPortability(frontmatter: Readonly<Record<string, unknown>>): PortabilityVerdict {
|
|
83
|
+
const partial: string[] = [];
|
|
84
|
+
const dropped: string[] = [];
|
|
85
|
+
|
|
86
|
+
for (const key of Object.keys(frontmatter).sort()) {
|
|
87
|
+
if (CARRIED_KEYS.includes(key)) continue;
|
|
88
|
+
if (Object.hasOwn(PARTIAL_KEYS, key)) {
|
|
89
|
+
partial.push(key);
|
|
90
|
+
continue;
|
|
91
|
+
}
|
|
92
|
+
// Dropped, and an unknown key lands here too — failing closed.
|
|
93
|
+
dropped.push(key);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
return { portable: partial.length === 0 && dropped.length === 0, partial, dropped };
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/** The predicate itself. `true` only when nothing the skill declares is lost. */
|
|
100
|
+
export function isBodyPortable(frontmatter: Readonly<Record<string, unknown>>): boolean {
|
|
101
|
+
return classifyPortability(frontmatter).portable;
|
|
102
|
+
}
|
|
@@ -82,6 +82,16 @@ export interface TranscriptRecord {
|
|
|
82
82
|
/** Raw `timestamp` field from the record, or null when absent. */
|
|
83
83
|
timestamp: string | null;
|
|
84
84
|
usage: TokenCounts;
|
|
85
|
+
/**
|
|
86
|
+
* UTF-8 byte length of this record's own `message.content`, or `null` when
|
|
87
|
+
* the scan did not ask for it ({@link ScanOptions.measureBytes}) or the
|
|
88
|
+
* record carries no serialisable content.
|
|
89
|
+
*
|
|
90
|
+
* `null` is NOT zero. A record whose content was never measured and a
|
|
91
|
+
* record whose content is empty are different facts, and a ratio built
|
|
92
|
+
* over the first would divide by a denominator it never observed.
|
|
93
|
+
*/
|
|
94
|
+
content_bytes: number | null;
|
|
85
95
|
}
|
|
86
96
|
|
|
87
97
|
export interface ScanOptions {
|
|
@@ -98,6 +108,17 @@ export interface ScanOptions {
|
|
|
98
108
|
maxAgeDays?: number;
|
|
99
109
|
/** Clock used to evaluate `maxAgeDays` — injectable for tests. */
|
|
100
110
|
now?: Date;
|
|
111
|
+
/**
|
|
112
|
+
* Also measure each record's `message.content` byte length
|
|
113
|
+
* ({@link TranscriptRecord.content_bytes}).
|
|
114
|
+
*
|
|
115
|
+
* OPT-IN, because it costs a second serialisation of content the scan
|
|
116
|
+
* otherwise never touches, and the existing callers — `cost_summary`,
|
|
117
|
+
* `preamble_byte_census`, the bench harness — want token sums only. A
|
|
118
|
+
* caller that does not ask gets `content_bytes: null` on every record and
|
|
119
|
+
* pays nothing.
|
|
120
|
+
*/
|
|
121
|
+
measureBytes?: boolean;
|
|
101
122
|
}
|
|
102
123
|
|
|
103
124
|
export interface ScanResult {
|
|
@@ -161,7 +182,7 @@ interface RawUsage {
|
|
|
161
182
|
|
|
162
183
|
interface RawAssistantRecord {
|
|
163
184
|
type?: unknown;
|
|
164
|
-
message?: { id?: unknown; model?: unknown; usage?: RawUsage };
|
|
185
|
+
message?: { id?: unknown; model?: unknown; usage?: RawUsage; content?: unknown };
|
|
165
186
|
requestId?: unknown;
|
|
166
187
|
agentId?: unknown;
|
|
167
188
|
isSidechain?: unknown;
|
|
@@ -180,6 +201,29 @@ function toTokenCounts(raw: RawUsage | undefined): TokenCounts {
|
|
|
180
201
|
};
|
|
181
202
|
}
|
|
182
203
|
|
|
204
|
+
/**
|
|
205
|
+
* UTF-8 byte length of one record's `message.content`, or `null` when there is
|
|
206
|
+
* nothing serialisable to measure.
|
|
207
|
+
*
|
|
208
|
+
* Bytes, never characters: a multibyte block costs what it costs, and
|
|
209
|
+
* `String.length` would under-report it. Content is what this reader can
|
|
210
|
+
* actually SEE — the request's system prompt, tool definitions and prior turns
|
|
211
|
+
* are not in the transcript at all (`preamble_byte_census` records the same
|
|
212
|
+
* limitation), so a ratio built from this is a ratio over assistant output and
|
|
213
|
+
* is labelled as such wherever it surfaces.
|
|
214
|
+
*/
|
|
215
|
+
export function measureContentBytes(raw: RawAssistantRecord): number | null {
|
|
216
|
+
const content = raw.message?.content;
|
|
217
|
+
if (content === undefined || content === null) return null;
|
|
218
|
+
if (typeof content === 'string') return Buffer.byteLength(content, 'utf8');
|
|
219
|
+
try {
|
|
220
|
+
return Buffer.byteLength(JSON.stringify(content), 'utf8');
|
|
221
|
+
} catch {
|
|
222
|
+
// Circular or otherwise unserialisable — unmeasurable, not zero.
|
|
223
|
+
return null;
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
|
|
183
227
|
/** Subagent iff a non-empty top-level `agentId` OR `isSidechain === true` — see module doc comment. */
|
|
184
228
|
function classifyBucket(raw: RawAssistantRecord): TranscriptBucket {
|
|
185
229
|
const hasAgentId = typeof raw.agentId === 'string' && raw.agentId.length > 0;
|
|
@@ -285,6 +329,7 @@ export function scanTranscripts(opts: ScanOptions = {}): ScanResult {
|
|
|
285
329
|
model: typeof raw.message.model === 'string' ? raw.message.model : 'unknown',
|
|
286
330
|
timestamp: typeof raw.timestamp === 'string' ? raw.timestamp : null,
|
|
287
331
|
usage: toTokenCounts(raw.message.usage),
|
|
332
|
+
content_bytes: opts.measureBytes === true ? measureContentBytes(raw) : null,
|
|
288
333
|
});
|
|
289
334
|
}
|
|
290
335
|
}
|
|
@@ -298,6 +343,92 @@ export function scanTranscripts(opts: ScanOptions = {}): ScanResult {
|
|
|
298
343
|
};
|
|
299
344
|
}
|
|
300
345
|
|
|
346
|
+
/* -------------------------------------------------------------------------- */
|
|
347
|
+
/* Bytes — measured on the corpus, never assumed */
|
|
348
|
+
/* -------------------------------------------------------------------------- */
|
|
349
|
+
|
|
350
|
+
/**
|
|
351
|
+
* A bytes-per-token ratio, together with the two sums it was divided from and
|
|
352
|
+
* the population it was measured over.
|
|
353
|
+
*
|
|
354
|
+
* The sums travel WITH the ratio on purpose. A bare ratio is the shape that
|
|
355
|
+
* becomes a constant: somebody copies the number, it outlives the corpus that
|
|
356
|
+
* produced it, and the next reader cannot tell what it measured. Carrying
|
|
357
|
+
* `content_bytes` and `output_tokens` means the division is re-derivable from
|
|
358
|
+
* the record itself.
|
|
359
|
+
*/
|
|
360
|
+
export interface BytesPerToken {
|
|
361
|
+
/** Always `'measured'` — this value is a division of two counted sums. */
|
|
362
|
+
basis: 'measured';
|
|
363
|
+
/** Summed `content_bytes` over the records that carried one. */
|
|
364
|
+
content_bytes: number;
|
|
365
|
+
/** Summed `output_tokens` over those same records. */
|
|
366
|
+
output_tokens: number;
|
|
367
|
+
/** `content_bytes / output_tokens`. */
|
|
368
|
+
bytes_per_token: number;
|
|
369
|
+
/** Records that contributed — `content_bytes !== null` and `output_tokens > 0`. */
|
|
370
|
+
records: number;
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
/**
|
|
374
|
+
* Measure a bytes-per-token ratio ON THE GIVEN RECORDS. Returns `null` when
|
|
375
|
+
* nothing in the corpus can supply one.
|
|
376
|
+
*
|
|
377
|
+
* `null` is the honest outcome and callers must render it as such rather than
|
|
378
|
+
* substituting a default: a ratio invented where none was measured is exactly
|
|
379
|
+
* the constant this function exists to make unnecessary. There is deliberately
|
|
380
|
+
* no fallback value anywhere in this module — the factor is a property of the
|
|
381
|
+
* corpus, and a corpus that cannot supply one has not supplied one.
|
|
382
|
+
*/
|
|
383
|
+
export function measureBytesPerToken(records: readonly TranscriptRecord[]): BytesPerToken | null {
|
|
384
|
+
let bytes = 0;
|
|
385
|
+
let tokens = 0;
|
|
386
|
+
let n = 0;
|
|
387
|
+
for (const rec of records) {
|
|
388
|
+
if (rec.content_bytes === null || rec.usage.output_tokens <= 0) continue;
|
|
389
|
+
bytes += rec.content_bytes;
|
|
390
|
+
tokens += rec.usage.output_tokens;
|
|
391
|
+
n += 1;
|
|
392
|
+
}
|
|
393
|
+
if (n === 0 || tokens <= 0) return null;
|
|
394
|
+
return {
|
|
395
|
+
basis: 'measured',
|
|
396
|
+
content_bytes: bytes,
|
|
397
|
+
output_tokens: tokens,
|
|
398
|
+
bytes_per_token: bytes / tokens,
|
|
399
|
+
records: n,
|
|
400
|
+
};
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
/** A byte figure obtained by multiplying a token count by a measured ratio. */
|
|
404
|
+
export interface DerivedBytes {
|
|
405
|
+
/** Always `'derived'`. Never `'measured'` — nothing counted these bytes. */
|
|
406
|
+
basis: 'derived';
|
|
407
|
+
/** The token count that was multiplied. */
|
|
408
|
+
tokens: number;
|
|
409
|
+
/** The ratio used, carried so the arithmetic sits beside its result. */
|
|
410
|
+
factor: BytesPerToken;
|
|
411
|
+
/** `tokens * factor.bytes_per_token`, rounded to a whole byte. */
|
|
412
|
+
bytes: number;
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
/**
|
|
416
|
+
* Multiply a token count by a ratio measured on the same corpus.
|
|
417
|
+
*
|
|
418
|
+
* The result carries `basis: 'derived'` and the factor that produced it, so a
|
|
419
|
+
* derived figure and a counted one can never be read as the same number — the
|
|
420
|
+
* failure this whole path is shaped to prevent. `null` factor in, `null` out.
|
|
421
|
+
*/
|
|
422
|
+
export function derivedBytes(tokens: number, factor: BytesPerToken | null): DerivedBytes | null {
|
|
423
|
+
if (factor === null) return null;
|
|
424
|
+
return {
|
|
425
|
+
basis: 'derived',
|
|
426
|
+
tokens,
|
|
427
|
+
factor,
|
|
428
|
+
bytes: Math.round(tokens * factor.bytes_per_token),
|
|
429
|
+
};
|
|
430
|
+
}
|
|
431
|
+
|
|
301
432
|
function emptyAggregate(bucket: TranscriptBucket): BucketAggregate {
|
|
302
433
|
return {
|
|
303
434
|
bucket,
|
|
@@ -98,16 +98,18 @@ export function build_claude_hook_matrix(manifest_path: string): ClaudeHookMatri
|
|
|
98
98
|
const aliasesAll = (manifest['native_event_aliases'] ?? {}) as Record<string, unknown>;
|
|
99
99
|
const aliases = ((aliasesAll['claude'] ?? {}) as Record<string, unknown>) || {};
|
|
100
100
|
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
101
|
+
// Iterating the ALIAS map, not the event map, because the relation is
|
|
102
|
+
// many-natives-to-one-event and the inversion this replaced silently lost
|
|
103
|
+
// every native but the last. `PostToolUse` and `PostToolUseFailure` both
|
|
104
|
+
// lower to `post_tool_use`; building `ac_to_native` would have kept one of
|
|
105
|
+
// them and UNBOUND the other, turning a routing fix into a routing
|
|
106
|
+
// regression that no existing test could see. Pinned by
|
|
107
|
+
// `before_complete_failure_envelope.test.ts` ("both natives stay bound").
|
|
106
108
|
const matrix: ClaudeHookMatrix = {};
|
|
107
|
-
for (const [
|
|
109
|
+
for (const [native, ac_raw] of Object.entries(aliases)) {
|
|
110
|
+
const ac_event = String(ac_raw);
|
|
111
|
+
const concerns = claude_events[ac_event];
|
|
108
112
|
if (!concerns || (Array.isArray(concerns) && concerns.length === 0)) continue;
|
|
109
|
-
const native = ac_to_native[ac_event];
|
|
110
|
-
if (native === undefined) continue;
|
|
111
113
|
// Bundle fast path (road-to-hook-latency-repair Phase 2): invoke the
|
|
112
114
|
// precompiled dispatcher bundle directly — no bash shim, no CLI boot
|
|
113
115
|
// (measured ~450-500 ms CLI vs ~110 ms bundle per event on a 1-vCPU
|
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Per-concern SLA measurement and the warn-only window's reporting.
|
|
3
|
+
*
|
|
4
|
+
* Extracted from `bench_hook_latency.ts` on 2026-10-01, not for tidiness: the
|
|
5
|
+
* additions that made `one-question-per-ask` measurable and gave the warn-only
|
|
6
|
+
* window a reader pushed that file from 1,361 lines to 1,583, i.e. 83 lines
|
|
7
|
+
* past the 1,500-line source ceiling, and `check_source_size_budget`'s ratchet
|
|
8
|
+
* asked for exactly this by name. Raising the baseline was the other option
|
|
9
|
+
* and is the one the ratchet exists to make visible rather than easy — a MOVE
|
|
10
|
+
* gives the budget back instead of spending it, which is the doctrine every
|
|
11
|
+
* entry in `gate-violation-baselines.json` records.
|
|
12
|
+
*
|
|
13
|
+
* It is also the better boundary on its own terms. Everything here answers one
|
|
14
|
+
* question — which blocking concern is bounded, by how much, and did this run
|
|
15
|
+
* cross it — and none of it is about measuring a hook SLOT, which is what the
|
|
16
|
+
* bench itself does.
|
|
17
|
+
*
|
|
18
|
+
* NOTHING HERE GATES. The bound these functions read is not armed anywhere:
|
|
19
|
+
* step 3.3 of `road-to-a-kernel-that-guards-its-plumbing` is its only consumer
|
|
20
|
+
* and is blocked on the window these functions report. A measurement that can
|
|
21
|
+
* red a build before its bar is validated is Risk 1 of that roadmap.
|
|
22
|
+
*/
|
|
23
|
+
import * as fs from 'node:fs';
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* The subset of a per-concern row the window needs: a measurement and a bound.
|
|
27
|
+
*
|
|
28
|
+
* Declared here rather than imported so the dependency runs one way only —
|
|
29
|
+
* `bench_hook_latency.ts` imports this module and this module imports nothing
|
|
30
|
+
* back. `ConcernLatencyRow` satisfies it structurally, so the caller passes its
|
|
31
|
+
* own rows unchanged and no adapter exists to drift.
|
|
32
|
+
*/
|
|
33
|
+
export interface BoundedConcern {
|
|
34
|
+
readonly concern: string;
|
|
35
|
+
/** p95 of the concern's own durations in microseconds, or null when untimed. */
|
|
36
|
+
readonly p95_us: number | null;
|
|
37
|
+
/** The registered SLA in milliseconds, or null when none is registered. */
|
|
38
|
+
readonly sla_ms: number | null;
|
|
39
|
+
/** The budget carried a value for this concern that is not a number. */
|
|
40
|
+
readonly sla_malformed: boolean;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* An alternate tool shape for the synthetic payload.
|
|
45
|
+
*
|
|
46
|
+
* The default payload names `Read`, which is the right default for every gated
|
|
47
|
+
* number: it is the common non-matching case consumers pay on every tool call.
|
|
48
|
+
* But a concern filtered by the manifest's per-concern `tools:` key is SKIPPED
|
|
49
|
+
* in-process on a payload naming a tool it does not claim, so it never produces
|
|
50
|
+
* a sample and the per-concern report prints `not_measured` for it — correctly,
|
|
51
|
+
* and uselessly for a step that needs a bound.
|
|
52
|
+
*
|
|
53
|
+
* `one-question-per-ask` is the live instance: `severity: blocking`, filtered to
|
|
54
|
+
* `AskUserQuestion` and five aliases. It is the only blocking concern the
|
|
55
|
+
* default payload cannot reach, and the owning roadmap's Phase-3 blocker names
|
|
56
|
+
* the choice explicitly — "either a payload shaped to trigger it or an explicit
|
|
57
|
+
* decision that an unmeasured blocking concern keeps the current 30 s timeout".
|
|
58
|
+
* This is the first branch: measure it, so the decision is not forced by the
|
|
59
|
+
* harness.
|
|
60
|
+
*
|
|
61
|
+
* Measurement-only, like `--bundle` and `--payload-bytes`. It is reachable only
|
|
62
|
+
* from `concernSlaPass`, which gates nothing and writes no budget row — a probe
|
|
63
|
+
* payload must never produce a gated slot number, because the slot caps were
|
|
64
|
+
* derived against the `Read` shape and a different shape runs a different
|
|
65
|
+
* concern chain.
|
|
66
|
+
*/
|
|
67
|
+
export interface ToolShape {
|
|
68
|
+
readonly tool_name: string;
|
|
69
|
+
readonly tool_input: Record<string, unknown>;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* The probe that reaches `one-question-per-ask`.
|
|
74
|
+
*
|
|
75
|
+
* ONE question, not two: a single question is the ALLOW path, and the allow
|
|
76
|
+
* path is what an ordinary call costs. Two questions would measure the deny
|
|
77
|
+
* path — the rarer branch, and the one that builds a message — so a bound taken
|
|
78
|
+
* from it would describe the exception rather than the rule. Both run
|
|
79
|
+
* `countStructuredAskQuestions`, which is the concern's actual work.
|
|
80
|
+
*/
|
|
81
|
+
export const ASK_PROBE: ToolShape = {
|
|
82
|
+
tool_name: 'AskUserQuestion',
|
|
83
|
+
tool_input: { questions: [{ question: 'bench probe' }] },
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* The one concern the ask probe exists to measure.
|
|
88
|
+
*
|
|
89
|
+
* Named rather than inferred from the `tools:` filter: a future concern added
|
|
90
|
+
* with an overlapping filter would be measured under a payload chosen for THIS
|
|
91
|
+
* one, and silently adopting it is the contamination above wearing a different
|
|
92
|
+
* shape.
|
|
93
|
+
*/
|
|
94
|
+
export const PROBE_TARGET = 'one-question-per-ask';
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Append only `target`'s samples from the probe sink onto the main sink.
|
|
98
|
+
*
|
|
99
|
+
* The probe sink is read and then left in place; it is a temp-dir file the
|
|
100
|
+
* caller owns. A read failure is not fatal — the probe is an observation, and
|
|
101
|
+
* a bench that dies because one auxiliary sink was unreadable converts a
|
|
102
|
+
* measurement into an outage, which is the posture `readConcernTimings`
|
|
103
|
+
* already takes one level down.
|
|
104
|
+
*/
|
|
105
|
+
export function mergeProbeSamples(probeSink: string, sinkPath: string, target: string): void {
|
|
106
|
+
let text: string;
|
|
107
|
+
try {
|
|
108
|
+
text = fs.readFileSync(probeSink, 'utf-8');
|
|
109
|
+
} catch {
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
112
|
+
const keep: string[] = [];
|
|
113
|
+
for (const line of text.split('\n')) {
|
|
114
|
+
const trimmed = line.trim();
|
|
115
|
+
if (trimmed === '') continue;
|
|
116
|
+
let row: { concern?: unknown };
|
|
117
|
+
try {
|
|
118
|
+
row = JSON.parse(trimmed) as typeof row;
|
|
119
|
+
} catch {
|
|
120
|
+
continue;
|
|
121
|
+
}
|
|
122
|
+
if (row.concern === target) keep.push(trimmed);
|
|
123
|
+
}
|
|
124
|
+
if (keep.length === 0) return;
|
|
125
|
+
try {
|
|
126
|
+
fs.appendFileSync(sinkPath, `${keep.join('\n')}\n`, 'utf-8');
|
|
127
|
+
} catch {
|
|
128
|
+
/* the sink is an observation aid; losing it must not fail the bench */
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* The warn-only window, made legible — observe-only, gating nothing.
|
|
134
|
+
*
|
|
135
|
+
* Step 3.3 derives a per-concern timeout of `sla_ms x 3` and its own text says
|
|
136
|
+
* "warn-only for the first measured window, then deny". A window nothing
|
|
137
|
+
* observes is not a window: with `sla_ms` registered and no reader, the flip
|
|
138
|
+
* would be taken on the absence of a complaint rather than on a reading.
|
|
139
|
+
*
|
|
140
|
+
* So this is the instrument. Every bench run — local or CI, gated or not —
|
|
141
|
+
* prints each blocking concern's measured p95 beside its registered bound and
|
|
142
|
+
* names any concern that crossed it. The window is then a span of runs a human
|
|
143
|
+
* can read, and the flip has an evidence base that exists before it is taken.
|
|
144
|
+
*
|
|
145
|
+
* It lives in the measurement harness and NOT in the dispatcher deliberately.
|
|
146
|
+
* A runtime warn would be a dispatcher change shipped as part of a step that is
|
|
147
|
+
* blocked on the very readings it would produce, and Risk 1 of the owning
|
|
148
|
+
* roadmap is precisely about acting on a bound before it is validated.
|
|
149
|
+
*
|
|
150
|
+
* A concern with no registered SLA, or no measurement, is NOT an overrun — it
|
|
151
|
+
* is an unknown, and the two must not collapse. Returning it as "fine" would
|
|
152
|
+
* let an unregistered concern read as a clean window.
|
|
153
|
+
*/
|
|
154
|
+
export interface SlaOverrun {
|
|
155
|
+
concern: string;
|
|
156
|
+
p95_us: number;
|
|
157
|
+
/** `sla_ms x 3`, in microseconds — the bound step 3.3 would apply. */
|
|
158
|
+
bound_us: number;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* What a run can actually say about the window — three counts, never one.
|
|
163
|
+
*
|
|
164
|
+
* `registered` is how many concerns carry a bound. `usable` is how many of
|
|
165
|
+
* those this run could compare against it. The gap is what an earlier version
|
|
166
|
+
* of the summary line silently dropped: it printed "none over" off `registered`,
|
|
167
|
+
* so a run that measured none of its bounded concerns read exactly like a run
|
|
168
|
+
* that measured all of them and found nothing. That is the same
|
|
169
|
+
* unknown-collapsed-into-fine failure `slaOverruns` refuses per row, one level
|
|
170
|
+
* up at the summary.
|
|
171
|
+
*/
|
|
172
|
+
export interface WindowState {
|
|
173
|
+
registered: number;
|
|
174
|
+
usable: number;
|
|
175
|
+
/** Registered but not comparable this run — unmeasured or malformed. */
|
|
176
|
+
unusable: number;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
export function windowState(rows: readonly BoundedConcern[]): WindowState {
|
|
180
|
+
let registered = 0;
|
|
181
|
+
let usable = 0;
|
|
182
|
+
for (const row of rows) {
|
|
183
|
+
if (row.sla_ms === null && !row.sla_malformed) continue;
|
|
184
|
+
registered += 1;
|
|
185
|
+
if (!row.sla_malformed && row.sla_ms !== null && row.p95_us !== null) usable += 1;
|
|
186
|
+
}
|
|
187
|
+
return { registered, usable, unusable: registered - usable };
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
export function slaOverruns(rows: readonly BoundedConcern[]): SlaOverrun[] {
|
|
191
|
+
const out: SlaOverrun[] = [];
|
|
192
|
+
for (const row of rows) {
|
|
193
|
+
if (row.sla_ms === null || row.sla_malformed || row.p95_us === null) continue;
|
|
194
|
+
const bound_us = row.sla_ms * 3 * 1000;
|
|
195
|
+
if (row.p95_us > bound_us) {
|
|
196
|
+
out.push({ concern: row.concern, p95_us: row.p95_us, bound_us });
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
return out;
|
|
200
|
+
}
|