@event4u/agent-config 16.1.0 → 16.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.augment-plugin/marketplace.json +3 -3
- package/.augment-plugin/plugin.json +1 -1
- package/.claude-plugin/marketplace.json +1 -1
- package/CHANGELOG.md +98 -257
- package/README.md +14 -12
- package/dist/agent-src/commands/analyze/inbox.md +1 -1
- package/dist/agent-src/commands/analyze/roadmap-repos.md +1 -1
- package/dist/agent-src/commands/bug/fix.md +17 -2
- package/dist/agent-src/commands/feature/plan.md +1 -1
- package/dist/agent-src/commands/feature/roadmap.md +1 -1
- package/dist/agent-src/commands/fix/ci.md +1 -1
- package/dist/agent-src/commands/implement-ticket.md +1 -1
- package/dist/agent-src/commands/jira-ticket.md +1 -1
- package/dist/agent-src/commands/roadmap/create.md +1 -1
- package/dist/agent-src/commands/roadmap/materialize.md +1 -1
- package/dist/agent-src/commands/roadmap/process-full.md +5 -5
- package/dist/agent-src/commands/roadmap/resolve-blockers.md +361 -0
- package/dist/agent-src/commands/roadmap/triage-parked.md +325 -0
- package/dist/agent-src/commands/roadmap.md +18 -4
- package/dist/agent-src/commands/tests/create.md +17 -3
- package/dist/agent-src/commands/tests/execute.md +22 -5
- package/dist/agent-src/commands/work.md +4 -0
- package/dist/agent-src/contexts/authority/decision-revisit-gate-enforcement.md +43 -0
- package/dist/agent-src/contexts/communication/rules-auto/design-fidelity-enforcement.md +24 -0
- package/dist/agent-src/contexts/execution/auto-dispatch-classification.md +6 -6
- package/dist/agent-src/contexts/execution/autonomy-mechanics.md +4 -8
- package/dist/agent-src/contexts/execution/roadmap-process-loop.md +32 -2
- package/dist/agent-src/contexts/execution/session-canary-enforcement-history.md +67 -0
- package/dist/agent-src/contexts/execution/toolchain-resolver.md +101 -7
- package/dist/agent-src/rules/active-remediation.md +1 -1
- package/dist/agent-src/rules/autonomous-execution.md +1 -0
- package/dist/agent-src/rules/broken-access-control.md +1 -0
- package/dist/agent-src/rules/command-suggestion-policy.md +1 -0
- package/dist/agent-src/rules/context-hygiene.md +1 -1
- package/dist/agent-src/rules/decision-revisit-gate.md +16 -33
- package/dist/agent-src/rules/design-fidelity.md +13 -16
- package/dist/agent-src/rules/doc-screenshot-hygiene.md +1 -0
- package/dist/agent-src/rules/domain-safety-disclaimer.md +1 -0
- package/dist/agent-src/rules/domain-safety-pii.md +1 -0
- package/dist/agent-src/rules/domain-safety-retention.md +1 -0
- package/dist/agent-src/rules/engineering-safety-floor.md +1 -0
- package/dist/agent-src/rules/evaluator-independence.md +3 -2
- package/dist/agent-src/rules/fast-path-marker-visibility.md +1 -0
- package/dist/agent-src/rules/finance-safety-floor.md +1 -0
- package/dist/agent-src/rules/git-history-discipline.md +1 -0
- package/dist/agent-src/rules/image-likeness-and-rights.md +1 -0
- package/dist/agent-src/rules/legal-safety-floor.md +3 -2
- package/dist/agent-src/rules/lethal-trifecta-guard.md +1 -0
- package/dist/agent-src/rules/low-impact-corpus-privacy-floor.md +1 -0
- package/dist/agent-src/rules/media-governance-routing.md +14 -17
- package/dist/agent-src/rules/persona-governance.md +2 -2
- package/dist/agent-src/rules/provider-lifecycle-discipline.md +1 -1
- package/dist/agent-src/rules/question-not-instruction.md +1 -0
- package/dist/agent-src/rules/roadmap-progress-sync.md +1 -1
- package/dist/agent-src/rules/runtime-safety.md +1 -0
- package/dist/agent-src/rules/secret-vcs-guard.md +1 -0
- package/dist/agent-src/rules/security-sensitive-stop.md +3 -2
- package/dist/agent-src/rules/session-canary.md +8 -62
- package/dist/agent-src/rules/settings-ask-protocol.md +1 -0
- package/dist/agent-src/rules/source-confidentiality.md +1 -0
- package/dist/agent-src/rules/strategy-safety-floor.md +1 -0
- package/dist/agent-src/rules/tool-safety.md +1 -0
- package/dist/agent-src/rules/ui-audit-gate.md +1 -2
- package/dist/agent-src/rules/untrusted-input-defense.md +1 -0
- package/dist/agent-src/rules/user-interrupt-priority.md +1 -0
- package/dist/agent-src/scripts/archive_completed_roadmaps.ts +115 -20
- package/dist/agent-src/scripts/deferral_carry.ts +339 -0
- package/dist/agent-src/scripts/update_roadmap_progress.ts +4 -1
- package/dist/agent-src/skills/accessibility-auditor/data/aria-patterns.csv +1 -1
- package/dist/agent-src/skills/accessibility-auditor/data/manifest.json +2 -2
- package/dist/agent-src/skills/api-design/data/manifest.json +2 -2
- package/dist/agent-src/skills/api-testing/SKILL.md +17 -0
- package/dist/agent-src/skills/code-intelligence/SKILL.md +14 -2
- package/dist/agent-src/skills/design-review/SKILL.md +30 -4
- package/dist/agent-src/skills/design-review/references/verification-automation.md +32 -0
- package/dist/agent-src/skills/design-system-capture/references/import-procedure.md +1 -1
- package/dist/agent-src/skills/existing-ui-audit/SKILL.md +18 -3
- package/dist/agent-src/skills/existing-ui-audit/references/component-taxonomy-detection.md +56 -0
- package/dist/agent-src/skills/fe-design/SKILL.md +1 -1
- package/dist/agent-src/skills/iconography/SKILL.md +1 -1
- package/dist/agent-src/skills/js-library-packaging/SKILL.md +2 -2
- package/dist/agent-src/skills/markitdown/SKILL.md +4 -0
- package/dist/agent-src/skills/monorepo-workspace/SKILL.md +1 -1
- package/dist/agent-src/skills/playwright-testing/SKILL.md +30 -6
- package/dist/agent-src/skills/quality-tools/SKILL.md +11 -1
- package/dist/agent-src/skills/quality-tools/references/go-tools.md +76 -0
- package/dist/agent-src/skills/quality-tools/references/python-tools.md +104 -0
- package/dist/agent-src/skills/review-routing/SKILL.md +2 -2
- package/dist/agent-src/skills/skill-improvement-pipeline/SKILL.md +1 -1
- package/dist/agent-src/skills/storybook-workshop/SKILL.md +3 -3
- package/dist/agent-src/skills/tailwind-engineer/SKILL.md +1 -1
- package/dist/agent-src/skills/test-case-discovery/SKILL.md +7 -0
- package/dist/agent-src/skills/test-driven-development/SKILL.md +17 -0
- package/dist/agent-src/skills/test-performance/SKILL.md +19 -1
- package/dist/agent-src/skills/ui-component-architect/SKILL.md +25 -2
- package/dist/agent-src/templates/agents/agent-project-settings.example.yml +1 -1
- package/dist/agent-src/templates/roadmaps.md +30 -0
- package/dist/agent-src/templates/scripts/work_engine/directives/ui/app_spec.ts +10 -4
- package/dist/agent-src/templates/scripts/work_engine/directives/ui/apply.ts +302 -21
- package/dist/agent-src/templates/scripts/work_engine/directives/ui/audit.ts +22 -3
- package/dist/agent-src/templates/scripts/work_engine/directives/ui/scaffold.ts +6 -1
- package/dist/agent-src/templates/scripts/work_engine/stack/runner.ts +774 -109
- package/dist/agent-src/templates/scripts/work_engine/state.ts +57 -7
- package/dist/agent-src/templates/scripts/work_engine/taxonomy/detect.ts +500 -0
- package/dist/agent-src/templates/scripts/work_engine/taxonomy/place.ts +183 -0
- package/dist/cli/python/knowledge_ingest.js +1 -1
- package/dist/cli/python/workspace_drive.js +1 -1
- package/dist/cli/registry.js +1 -1
- package/dist/cli-delegate/archive_completed_roadmaps.js +92 -12
- package/dist/cli-delegate/check_update_banner.js +12 -1
- package/dist/cli-delegate/chunk-523HCFYO.js +90 -0
- package/dist/cli-delegate/{chunk-M2DPGFZ4.js → chunk-6V6TA25H.js} +22 -152
- package/dist/cli-delegate/chunk-7IQE3D5S.js +191 -0
- package/dist/cli-delegate/{chunk-6KFEC3G7.js → chunk-CQWX336L.js} +1 -1
- package/dist/cli-delegate/chunk-DEIV7XP7.js +108 -0
- package/dist/cli-delegate/chunk-EEHDXSYD.js +2040 -0
- package/dist/cli-delegate/{chunk-P6ZHP5W2.js → chunk-GKE7ZVFA.js} +4 -4
- package/dist/cli-delegate/chunk-JQOM7TTM.js +1201 -0
- package/dist/cli-delegate/{chunk-UNCRJBT3.js → chunk-JQVYKIZA.js} +41 -0
- package/dist/cli-delegate/{chunk-FC75PGJE.js → chunk-JY2I2DXV.js} +12 -1
- package/dist/cli-delegate/chunk-KB5FZ655.js +208 -0
- package/dist/cli-delegate/{chunk-YUM5KURG.js → chunk-KR6EM23A.js} +235 -1455
- package/dist/cli-delegate/{chunk-LTYVIY76.js → chunk-LIYTLH6O.js} +1 -1
- package/dist/cli-delegate/chunk-NQ7WT43P.js +2729 -0
- package/dist/cli-delegate/chunk-NXEILF2K.js +2160 -0
- package/dist/cli-delegate/{chunk-5R7HOLAF.js → chunk-NYX3L2PZ.js} +1 -1
- package/dist/cli-delegate/{chunk-4E2W63DA.js → chunk-OKJUIAPS.js} +62 -1
- package/dist/cli-delegate/{chunk-QAJS5YWY.js → chunk-PHD7OOLE.js} +2 -1
- package/dist/cli-delegate/{chunk-RGNIWTEA.js → chunk-QLDHIPWR.js} +1 -1
- package/dist/cli-delegate/{chunk-HDVVGPQW.js → chunk-RQNNW7IF.js} +1405 -567
- package/dist/cli-delegate/{chunk-S3VFXMTM.js → chunk-S4UMZNES.js} +1 -1
- package/dist/cli-delegate/{chunk-6KM6ORRY.js → chunk-S4YWNRKO.js} +24 -8
- package/dist/cli-delegate/{chunk-GJCBB2UG.js → chunk-TRI6DQZ6.js} +3054 -325
- package/dist/cli-delegate/chunk-ULQRUR23.js +208 -0
- package/dist/cli-delegate/{chunk-NUHLI2RX.js → chunk-YCU3TIXH.js} +2 -0
- package/dist/cli-delegate/chunk-ZBZV2G5R.js +210 -0
- package/dist/cli-delegate/{chunk-WGXTVKCQ.js → chunk-ZUZKZYCN.js} +5 -3
- package/dist/cli-delegate/cmd_analyze_session.js +1 -1
- package/dist/cli-delegate/cmd_brand_status.js +1 -1
- package/dist/cli-delegate/cmd_conformance.js +1862 -809
- package/dist/cli-delegate/cmd_doctor.js +13 -6
- package/dist/cli-delegate/cmd_doctor_neighbours.js +23 -0
- package/dist/cli-delegate/cmd_explain.js +5 -5
- package/dist/cli-delegate/cmd_export.js +11 -8
- package/dist/cli-delegate/cmd_fleet.js +3 -3
- package/dist/cli-delegate/cmd_handoff.js +10 -7
- package/dist/cli-delegate/cmd_mcp_available.js +1 -1
- package/dist/cli-delegate/cmd_memory_get.js +3 -1
- package/dist/cli-delegate/cmd_migrate.js +2 -2
- package/dist/cli-delegate/cmd_packs_active.js +3 -3
- package/dist/cli-delegate/cmd_preflight.js +6 -6
- package/dist/cli-delegate/cmd_prune.js +11 -8
- package/dist/cli-delegate/cmd_refresh.js +2 -1
- package/dist/cli-delegate/cmd_route_audit.js +8 -6
- package/dist/cli-delegate/cmd_route_explain.js +4 -4
- package/dist/cli-delegate/cmd_session_recycle.js +4 -3
- package/dist/cli-delegate/cmd_settings_get.js +1 -1
- package/dist/cli-delegate/cmd_settings_migrate.js +11 -8
- package/dist/cli-delegate/cmd_settings_set.js +4 -4
- package/dist/cli-delegate/cmd_sync.js +11 -8
- package/dist/cli-delegate/cmd_uninstall.js +11 -8
- package/dist/cli-delegate/cmd_update.js +1 -1
- package/dist/cli-delegate/cmd_upgrade.js +3 -2
- package/dist/cli-delegate/cmd_validate.js +11 -8
- package/dist/cli-delegate/cmd_versions.js +1 -1
- package/dist/cli-delegate/deferral_carry.js +16 -0
- package/dist/cli-delegate/gate_execute.js +2 -2
- package/dist/cli-delegate/roadmap_gates.js +5 -5
- package/dist/cli-delegate/update_roadmap_progress.js +1 -1
- package/dist/discovery/deprecation-report.md +1 -1
- package/dist/discovery/discovery-manifest.json +132 -80
- package/dist/discovery/discovery-manifest.json.sha256 +1 -1
- package/dist/discovery/discovery-manifest.summary.md +3 -3
- package/dist/discovery/dormancy-report.md +1 -1
- package/dist/discovery/orphan-report.md +1 -1
- package/dist/discovery/packs.json +7 -5
- package/dist/discovery/trust-report.md +2 -2
- package/dist/discovery/workspaces.json +6 -4
- package/dist/hooks/dispatch.js +7972 -5186
- package/dist/hooks/dispatch.sha256 +1 -0
- package/dist/install/claudePathsPlan.js +47 -6
- package/dist/install/claudeRuleRewrite.js +7 -0
- package/dist/install/emit_host_rules_cli.js +39 -36
- package/dist/install/globalRuleScope.js +87 -0
- package/dist/install/host_rule_ownership.js +160 -0
- package/dist/install/install.mjs +2226 -1055
- package/dist/install/installThinLayer.js +261 -0
- package/dist/install/installedRuleLinks.js +176 -0
- package/dist/install/wizard-plan.js +24 -0
- package/dist/mcp/registry-manifest.json +3 -3
- package/dist/mcp/server.json +2 -2
- package/dist/mcp/server.mjs +40913 -34865
- package/dist/scripts/_lib/agent_settings.js +11 -0
- package/dist/scripts/_lib/claude_settings_hooks.js +10 -8
- package/dist/scripts/_lib/installed_layer.js +378 -0
- package/dist/scripts/_lib/lean_projection_mode.js +218 -15
- package/dist/scripts/_lib/rule_consequence_class.js +45 -0
- package/dist/scripts/_lib/rule_injection.js +67 -10
- package/dist/scripts/_lib/rule_law_section.js +122 -0
- package/dist/scripts/_lib/thin_rules.js +458 -0
- package/dist/scripts/_lib/windsurf_render.js +60 -0
- package/dist/scripts/condense.js +14 -26
- package/dist/scripts/project_thin_rules.js +14 -294
- package/dist/server/schemas/settings.js +29 -0
- package/dist/shared/skillRanking.js +74 -13
- package/dist/ui/assets/index-Cwq4d0hX.js +23 -0
- package/dist/ui/assets/index-Cyjy8bWO.css +1 -0
- package/dist/ui/index.html +2 -2
- package/docs/contracts/settings-classes.md +10 -6
- package/package.json +4 -4
- package/src/agent-src/scripts/archive_completed_roadmaps.ts +115 -20
- package/src/agent-src/scripts/deferral_carry.ts +339 -0
- package/src/agent-src/scripts/update_roadmap_progress.ts +4 -1
- package/src/agent-src/templates/scripts/work_engine/directives/ui/app_spec.ts +10 -4
- package/src/agent-src/templates/scripts/work_engine/directives/ui/apply.ts +302 -21
- package/src/agent-src/templates/scripts/work_engine/directives/ui/audit.ts +22 -3
- package/src/agent-src/templates/scripts/work_engine/directives/ui/scaffold.ts +6 -1
- package/src/agent-src/templates/scripts/work_engine/stack/runner.ts +774 -109
- package/src/agent-src/templates/scripts/work_engine/state.ts +57 -7
- package/src/agent-src/templates/scripts/work_engine/taxonomy/detect.ts +500 -0
- package/src/agent-src/templates/scripts/work_engine/taxonomy/place.ts +183 -0
- package/src/config/agent-settings.template.yml +91 -22
- package/src/config/ci-local-parity.yml +18 -0
- package/src/config/continuity-surface.json +9 -2
- package/src/config/evaluator-budgets.json +4 -4
- package/src/config/gate-coverage.yml +327 -3
- package/src/config/gate-violation-baselines.json +21 -9
- package/src/config/hook-bundle-budget.json +25 -0
- package/src/config/hook-latency-budget.json +21 -0
- package/src/config/hook-token-budget.json +8 -3
- package/src/config/host-instruction-limits.json +33 -0
- package/src/config/metric-registry.yml +114 -0
- package/src/config/placeholder-drift-budget.json +10 -0
- package/src/config/routing-coverage-seed.json +38 -3
- package/src/config/rule-activation-census.json +7 -3
- package/src/config/rule-consequence-class.json +161 -0
- package/src/config/rule-law-ceilings.json +99 -0
- package/src/install/claudePathsPlan.ts +46 -4
- package/src/install/claudeRuleRewrite.ts +10 -1
- package/src/install/emit_host_rules_cli.ts +43 -34
- package/src/install/globalRuleScope.ts +109 -0
- package/src/install/host_rule_ownership.ts +170 -0
- package/src/install/installThinLayer.ts +312 -0
- package/src/install/installedRuleLinks.ts +220 -0
- package/src/install/wizard-plan.ts +24 -0
- package/src/scripts/_cli/cmd_doctor.ts +28 -90
- package/src/scripts/_cli/cmd_doctor_neighbours.ts +293 -0
- package/src/scripts/_cli/doctor_execution.ts +100 -17
- package/src/scripts/_cli/doctor_network_posture.ts +226 -0
- package/src/scripts/_dispatch.bash +16 -2
- package/src/scripts/_lib/agent_settings.ts +11 -0
- package/src/scripts/_lib/body_portable.ts +102 -0
- package/src/scripts/_lib/cc_transcript.ts +132 -1
- package/src/scripts/_lib/claude_settings_hooks.ts +10 -8
- package/src/scripts/_lib/concern_sla_window.ts +200 -0
- package/src/scripts/_lib/estate_offsets.ts +241 -0
- package/src/scripts/_lib/exemption_shape.ts +143 -0
- package/src/scripts/_lib/fnv.ts +23 -0
- package/src/scripts/_lib/foreign_scan.ts +106 -0
- package/src/scripts/_lib/forge_protection.ts +114 -0
- package/src/scripts/_lib/forge_reader.ts +558 -0
- package/src/scripts/_lib/gitignore_block.ts +314 -0
- package/src/scripts/_lib/global_deploy_inventory.ts +32 -0
- package/src/scripts/_lib/graph_feeder_record.ts +214 -0
- package/src/scripts/_lib/hook_settings.ts +73 -0
- package/src/scripts/_lib/host_capability.ts +40 -19
- package/src/scripts/_lib/host_env_write.ts +111 -0
- package/src/scripts/_lib/host_hook_merge.ts +165 -0
- package/src/scripts/_lib/installed_layer.ts +538 -0
- package/src/scripts/_lib/json_merge.ts +82 -0
- package/src/scripts/_lib/json_pointers.ts +93 -11
- package/src/scripts/_lib/lean_projection_mode.ts +275 -15
- package/src/scripts/_lib/llm_proposer_transport.ts +14 -4
- package/src/scripts/_lib/machine_wake.ts +16 -3
- package/src/scripts/_lib/neighbour_census.ts +760 -0
- package/src/scripts/_lib/neighbour_scan.ts +122 -0
- package/src/scripts/_lib/neighbour_tool_use.ts +189 -0
- package/src/scripts/_lib/obligations.ts +119 -8
- package/src/scripts/_lib/probe_inputs.ts +271 -0
- package/src/scripts/_lib/prompt_shape.ts +46 -0
- package/src/scripts/_lib/read_surface_scan.ts +322 -0
- package/src/scripts/_lib/release_highlights.ts +2 -1
- package/src/scripts/_lib/release_migration_gate.ts +19 -3
- package/src/scripts/_lib/reserved_name_sweep.ts +73 -0
- package/src/scripts/_lib/retrieval_sanitize.ts +77 -16
- package/src/scripts/_lib/review_coverage.ts +134 -0
- package/src/scripts/_lib/rule_consequence_class.ts +71 -0
- package/src/scripts/_lib/rule_injection.ts +130 -10
- package/src/scripts/_lib/rule_law_section.ts +147 -0
- package/src/scripts/_lib/rule_layer_overlap.ts +58 -0
- package/src/scripts/_lib/shell_write_shapes.ts +108 -0
- package/src/scripts/_lib/skill_origin.ts +254 -0
- package/src/scripts/_lib/structural_hiding.ts +622 -0
- package/src/scripts/_lib/structured_ask.ts +64 -21
- package/src/scripts/_lib/thin_rules.ts +540 -0
- package/src/scripts/_lib/touched_file_quality.ts +434 -0
- package/src/scripts/_lib/turn_end_refusals.ts +600 -4
- package/src/scripts/_lib/turn_end_transcript.ts +216 -0
- package/src/scripts/_lib/verification_command.ts +324 -0
- package/src/scripts/_lib/verification_evidence.ts +647 -0
- package/src/scripts/_lib/verify_clause.ts +280 -0
- package/src/scripts/_lib/windsurf_render.ts +63 -0
- package/src/scripts/ai_council/cli_call_budget.ts +13 -5
- package/src/scripts/ai_council/clients.ts +26 -57
- package/src/scripts/ai_council/config.ts +1 -1
- package/src/scripts/ai_council/vendor_defaults.ts +45 -0
- package/src/scripts/ai_team/team_dispatch.ts +4 -0
- package/src/scripts/audit_skill_overlap.ts +261 -0
- package/src/scripts/before_complete_hook.ts +573 -25
- package/src/scripts/bench_hook_latency.ts +412 -5
- package/src/scripts/bench_touched_file_quality.ts +238 -0
- package/src/scripts/cache_realization_report.ts +61 -1
- package/src/scripts/check_argument_hint.ts +287 -0
- package/src/scripts/check_claims.ts +125 -1
- package/src/scripts/check_enforcement_coverage.ts +38 -9
- package/src/scripts/check_enforcement_matrix.ts +621 -22
- package/src/scripts/check_estate_count.ts +130 -153
- package/src/scripts/check_finding_dispositions.ts +138 -7
- package/src/scripts/check_generator_sync.ts +71 -0
- package/src/scripts/check_hook_bundle_composition.ts +370 -0
- package/src/scripts/check_host_docs_digest.ts +786 -0
- package/src/scripts/check_host_format_column.ts +559 -0
- package/src/scripts/check_input_references.ts +228 -0
- package/src/scripts/check_inputs_parity.ts +235 -0
- package/src/scripts/check_kernel_edit_ratified.ts +89 -9
- package/src/scripts/check_kill_switch_table.ts +294 -0
- package/src/scripts/check_memory.ts +7 -1
- package/src/scripts/check_placeholder_drift.ts +221 -0
- package/src/scripts/check_read_surface_coverage.ts +515 -0
- package/src/scripts/check_release_highlights.ts +10 -0
- package/src/scripts/check_release_holds.ts +2 -1
- package/src/scripts/check_release_pr_shape.ts +38 -15
- package/src/scripts/check_routing_coverage.ts +378 -11
- package/src/scripts/check_standing_rule_delivery.ts +33 -13
- package/src/scripts/check_static_parity.ts +17 -0
- package/src/scripts/check_verify_expectation_delta.ts +521 -0
- package/src/scripts/ci_settle.ts +145 -19
- package/src/scripts/closure_scan.ts +115 -1
- package/src/scripts/code_graph/detect.ts +127 -7
- package/src/scripts/code_graph/foreign.ts +194 -0
- package/src/scripts/code_graph/query.ts +217 -4
- package/src/scripts/code_graph/types.ts +26 -2
- package/src/scripts/code_graph/validate.ts +3 -1
- package/src/scripts/code_graph/verbs.ts +103 -0
- package/src/scripts/compile_hook_manifest.ts +90 -14
- package/src/scripts/condense.ts +14 -27
- package/src/scripts/estate_exemption_shape.ts +202 -0
- package/src/scripts/external_sources_denylist.json +29 -4
- package/src/scripts/generate_host_cost_table.ts +1 -1
- package/src/scripts/hook_manifest.json +1 -1
- package/src/scripts/hook_manifest.yaml +192 -14
- package/src/scripts/hooks/block_config_weakening.ts +294 -4
- package/src/scripts/hooks/block_kernel_rule_writes.ts +9 -78
- package/src/scripts/hooks/block_plumbing_writes.ts +342 -0
- package/src/scripts/hooks/bundle_integrity.ts +291 -0
- package/src/scripts/hooks/chain_nudge_hook.ts +1 -2
- package/src/scripts/hooks/code_graph_context_hook.ts +253 -25
- package/src/scripts/hooks/comment_discipline_hook.ts +1 -3
- package/src/scripts/hooks/concern_failure_policy.ts +280 -0
- package/src/scripts/hooks/concern_registry.ts +2 -0
- package/src/scripts/hooks/concern_timings.ts +94 -0
- package/src/scripts/hooks/delegation_nudge_hook.ts +1 -2
- package/src/scripts/hooks/design_pass_hook.ts +100 -9
- package/src/scripts/hooks/design_slop_hook.ts +1 -2
- package/src/scripts/hooks/dispatch_hook.ts +77 -71
- package/src/scripts/hooks/edit_shape_hook.ts +1 -2
- package/src/scripts/hooks/end_review_nudge_hook.ts +1 -1
- package/src/scripts/hooks/evidence_independence.ts +1 -2
- package/src/scripts/hooks/exit_codes.ts +129 -0
- package/src/scripts/hooks/host_lowering.json +1 -0
- package/src/scripts/hooks/host_lowering.ts +146 -3
- package/src/scripts/hooks/host_lowering.yaml +262 -46
- package/src/scripts/hooks/host_semantics.ts +30 -2
- package/src/scripts/hooks/injection_budget.ts +9 -2
- package/src/scripts/hooks/interruption_ledger_hook.ts +1 -2
- package/src/scripts/hooks/journal_record_hook.ts +1 -2
- package/src/scripts/hooks/memory_recall_hook.ts +1 -2
- package/src/scripts/hooks/obligation_settle_hook.ts +151 -5
- package/src/scripts/hooks/one_question_per_ask_hook.ts +43 -6
- package/src/scripts/hooks/orchestration_record_hook.ts +1 -2
- package/src/scripts/hooks/payload_stub.ts +10 -1
- package/src/scripts/hooks/permission_gate.ts +1 -2
- package/src/scripts/hooks/push_settle_hook.ts +1 -3
- package/src/scripts/hooks/replay_hook.ts +2 -1
- package/src/scripts/hooks/reread_guard_hook.ts +1 -2
- package/src/scripts/hooks/review_baseline_hook.ts +1 -2
- package/src/scripts/hooks/rtk_wrap_hook.ts +1 -2
- package/src/scripts/hooks/rule_inject_hook.ts +765 -68
- package/src/scripts/hooks/run_continuation_hook.ts +13 -15
- package/src/scripts/hooks/skill_route_hook.ts +1 -2
- package/src/scripts/hooks/source_first_gate_hook.ts +1 -2
- package/src/scripts/hooks/spawn_guard_shadow_hook.ts +1 -2
- package/src/scripts/hooks/subagent_ledger_hook.ts +1 -2
- package/src/scripts/hooks/suggestion_capture_hook.ts +1 -1
- package/src/scripts/hooks/table_fingerprint.ts +70 -0
- package/src/scripts/hooks/telemetry_flush_hook.ts +1 -2
- package/src/scripts/hooks/telemetry_usage_hook.ts +65 -10
- package/src/scripts/hooks/tool_result_bytes_hook.ts +93 -9
- package/src/scripts/hooks/turn_end_gate_hook.ts +421 -324
- package/src/scripts/hooks/ui_route_nudge_hook.ts +1 -2
- package/src/scripts/hooks_status.ts +112 -0
- package/src/scripts/injection_scan_hook.ts +7 -0
- package/src/scripts/install.ts +75 -189
- package/src/scripts/installed_layer_report.ts +103 -0
- package/src/scripts/language_mirror_hook.ts +15 -6
- package/src/scripts/learning_sidecar.ts +119 -8
- package/src/scripts/lint_deny_text.ts +419 -0
- package/src/scripts/lint_exit_codes.ts +262 -0
- package/src/scripts/lint_hook_manifest.ts +108 -0
- package/src/scripts/lint_major_migration_sections.ts +156 -26
- package/src/scripts/lint_pack_boundaries.ts +63 -5
- package/src/scripts/lint_roadmap_blockers.ts +78 -12
- package/src/scripts/lint_rule_law_section.ts +517 -0
- package/src/scripts/lint_skill_descriptions.ts +1 -1
- package/src/scripts/lint_skill_scripts_readonly.ts +1 -1
- package/src/scripts/lint_workflow_security.ts +161 -5
- package/src/scripts/mcp_server/consumer_tool_catalog.json +53 -0
- package/src/scripts/mcp_server/graph_tools.ts +72 -3
- package/src/scripts/mcp_server/prompts.ts +142 -1
- package/src/scripts/measure_routing_signal.ts +54 -16
- package/src/scripts/measure_skill_ranker_baseline.ts +515 -53
- package/src/scripts/measure_turn_end_gate.ts +193 -0
- package/src/scripts/memory_learn_hook.ts +91 -6
- package/src/scripts/memory_lookup.ts +1 -1
- package/src/scripts/model_rule_injection.ts +52 -5
- package/src/scripts/prepack-check.mjs +53 -0
- package/src/scripts/project_thin_rules.ts +34 -327
- package/src/scripts/release_publication.ts +13 -1
- package/src/scripts/report_evidence_temperature.ts +657 -0
- package/src/scripts/report_installed_rule_links.ts +157 -0
- package/src/scripts/report_invocation_surface.ts +383 -0
- package/src/scripts/report_label_agreement.ts +233 -0
- package/src/scripts/report_obligation_carriers.ts +699 -0
- package/src/scripts/report_obligation_mechanism.ts +230 -0
- package/src/scripts/report_obligation_writer_split.ts +236 -0
- package/src/scripts/report_single_token_triggers.ts +277 -0
- package/src/scripts/report_skill_menu_census.ts +208 -0
- package/src/scripts/report_skill_ranker_confusion.ts +442 -0
- package/src/scripts/report_standing_payload_by_host.ts +188 -15
- package/src/scripts/report_verification_record_coverage.ts +306 -0
- package/src/scripts/roadmap_verify_share.ts +213 -0
- package/src/scripts/rule_activation_census.ts +5 -2
- package/src/scripts/rule_trigger_eval.ts +9 -9
- package/src/scripts/schemas/command.schema.json +44 -0
- package/src/scripts/schemas/review-findings.schema.json +7 -2
- package/src/scripts/schemas/rule.schema.json +5 -0
- package/src/scripts/schemas/skill.schema.json +44 -0
- package/src/scripts/self_review_gate.ts +421 -17
- package/src/scripts/semantic_parity_census.ts +314 -0
- package/src/scripts/session_eol_report.ts +54 -1
- package/src/scripts/skill_tools/score_skill_relevance.ts +290 -25
- package/src/scripts/sweep_dead_scan_roots.ts +1 -1
- package/src/scripts/sweep_skill_ranker_signals.ts +129 -0
- package/src/scripts/sync_gitignore.ts +29 -235
- package/src/scripts/trigger_eval_grandfather.json +0 -7
- package/src/scripts/trigger_eval_rotation.ts +122 -27
- package/src/scripts/ui_conformance_probe.ts +156 -4
- package/src/scripts/update_prices.ts +85 -3
- package/src/scripts/write_bundle_digest.mjs +74 -0
- package/src/server/schemas/settings.ts +41 -0
- package/src/shared/skillRanking.ts +117 -11
- package/src/templates/consumer-settings/ONBOARDING.md +1 -0
- package/dist/cli-delegate/chunk-FXYUYU4N.js +0 -4416
- package/dist/cli-delegate/chunk-QJWAUMJW.js +0 -1072
- package/dist/cli-delegate/chunk-YDPILCOL.js +0 -152
- package/dist/ui/assets/index-DH1xc62v.js +0 -29
- package/dist/ui/assets/index-jSfMW8_t.css +0 -1
|
@@ -0,0 +1,238 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* bench_touched_file_quality — what the shadow quality pass costs at stop.
|
|
4
|
+
*
|
|
5
|
+
* `road-to-touched-files-that-pass-their-own-tools` 1.4: record the `shadow`
|
|
6
|
+
* variant's p95 over a five-file TypeScript fixture BEFORE any default moves.
|
|
7
|
+
* Risk 1 of that roadmap is that a quality pass makes stop the slowest hook in
|
|
8
|
+
* the chain, and 2.3 defers the `shadow → warn` flip to the owner. Neither
|
|
9
|
+
* decision should be taken on an estimate.
|
|
10
|
+
*
|
|
11
|
+
* CORRECTED FROM REPRODUCTION — the step's premise was wrong, and the
|
|
12
|
+
* correction is why this is a file rather than a patch.
|
|
13
|
+
*
|
|
14
|
+
* The step reads "the per-concern bench already measures `verify-before-complete`
|
|
15
|
+
* at default". It does not. `bench_hook_latency.perConcernRows` is fed by
|
|
16
|
+
* `blockingConcerns()`, which filters `hook_manifest.yaml` to
|
|
17
|
+
* `severity: blocking`; `verify-before-complete` is declared `severity: advisory`
|
|
18
|
+
* (manifest line ~122), so it has never had a per-concern row and there was no
|
|
19
|
+
* `default` reading to add a `shadow` variant beside. Adding the concern to that
|
|
20
|
+
* filter would have changed what "blocking" means in a report whose consumer
|
|
21
|
+
* (step 3.3 of the kernel-plumbing roadmap) derives per-concern TIMEOUTS from it
|
|
22
|
+
* — a timeout for an advisory concern is a different decision, and smuggling it
|
|
23
|
+
* in through a measurement would have been the wrong place to take it.
|
|
24
|
+
*
|
|
25
|
+
* So this measures the pass directly, which is also the number the two open
|
|
26
|
+
* decisions actually need: the slot p95 in `docs/hook-latency.json` is dominated
|
|
27
|
+
* by spawn + bundle load, and what 1.4 asks about is the DELTA the pass adds.
|
|
28
|
+
*
|
|
29
|
+
* METHOD, pinned so the number reproduces:
|
|
30
|
+
* - A throwaway consumer-shaped project: `package.json` declaring `typescript`
|
|
31
|
+
* and `eslint`, five TypeScript files, a flat ESLint config, `git init`, and
|
|
32
|
+
* a `minimal-safe-diff.json` naming all five as this turn's touched files.
|
|
33
|
+
* - `node_modules` is SYMLINKED to this repository's, so `npx eslint` resolves
|
|
34
|
+
* a real, installed linter and runs offline. The measurement is therefore of
|
|
35
|
+
* a real tool over real files, not of a stub.
|
|
36
|
+
* - N iterations (default 20, `--runs N`) of `collectTouchedFileQuality` — the
|
|
37
|
+
* exact function the stop path calls — measured with `performance.now()`.
|
|
38
|
+
* That covers the recorder read, `git status`, `resolve_toolchain`, and every
|
|
39
|
+
* spawn the plan produced.
|
|
40
|
+
* - The `off` baseline is measured too, by the same loop with the pass skipped,
|
|
41
|
+
* so the row reports a DELTA rather than an absolute whose floor is unknown.
|
|
42
|
+
*
|
|
43
|
+
* WHAT THE NUMBER IS NOT. It is one machine's reading, and the dominant term is
|
|
44
|
+
* whichever tools the fixture's resolver happens to emit — a consumer whose
|
|
45
|
+
* toolchain resolves `phpstan` over a large tree will measure something else
|
|
46
|
+
* entirely. It bounds the decision for THIS shape; it is not a budget.
|
|
47
|
+
*
|
|
48
|
+
* Exit codes: 0 measured · 2 the fixture could not be built.
|
|
49
|
+
*/
|
|
50
|
+
import { spawnSync } from 'node:child_process';
|
|
51
|
+
import * as fs from 'node:fs';
|
|
52
|
+
import * as os from 'node:os';
|
|
53
|
+
import * as path from 'node:path';
|
|
54
|
+
import { fileURLToPath } from 'node:url';
|
|
55
|
+
|
|
56
|
+
import { collectTouchedFileQuality } from './before_complete_hook.js';
|
|
57
|
+
|
|
58
|
+
const REPO_ROOT = path.resolve(path.dirname(path.resolve(fileURLToPath(import.meta.url))), '..', '..');
|
|
59
|
+
|
|
60
|
+
/** Files in the fixture. Five, per the step. */
|
|
61
|
+
export const FIXTURE_FILE_COUNT = 5;
|
|
62
|
+
|
|
63
|
+
const SESSION = 'bench-touched-file-quality';
|
|
64
|
+
|
|
65
|
+
export function percentile(samples: readonly number[], p: number): number {
|
|
66
|
+
if (samples.length === 0) return 0;
|
|
67
|
+
const sorted = [...samples].sort((a, b) => a - b);
|
|
68
|
+
const idx = Math.min(sorted.length - 1, Math.ceil((p / 100) * sorted.length) - 1);
|
|
69
|
+
return sorted[Math.max(0, idx)] as number;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Build the throwaway consumer project and return its root.
|
|
74
|
+
*
|
|
75
|
+
* Deliberately NOT inside the repository: a fixture under `src/` or `agents/`
|
|
76
|
+
* would be picked up by the tree's own gates, and one that `git init`s inside an
|
|
77
|
+
* existing worktree would report the repository's status rather than its own.
|
|
78
|
+
*/
|
|
79
|
+
export function buildFixture(): string {
|
|
80
|
+
const root = fs.mkdtempSync(path.join(os.tmpdir(), 'tfq-bench-'));
|
|
81
|
+
|
|
82
|
+
fs.writeFileSync(
|
|
83
|
+
path.join(root, 'package.json'),
|
|
84
|
+
JSON.stringify(
|
|
85
|
+
{ name: 'tfq-bench-fixture', private: true, devDependencies: { typescript: '*', eslint: '*' } },
|
|
86
|
+
null,
|
|
87
|
+
2,
|
|
88
|
+
),
|
|
89
|
+
'utf-8',
|
|
90
|
+
);
|
|
91
|
+
// A flat config with no rules: eslint still parses every file, which is the
|
|
92
|
+
// cost being measured, without a rule set that would make the number a
|
|
93
|
+
// statement about this repository's lint configuration.
|
|
94
|
+
fs.writeFileSync(path.join(root, 'eslint.config.mjs'), 'export default [];\n', 'utf-8');
|
|
95
|
+
|
|
96
|
+
for (let i = 0; i < FIXTURE_FILE_COUNT; i += 1) {
|
|
97
|
+
fs.writeFileSync(
|
|
98
|
+
path.join(root, `mod${String(i)}.ts`),
|
|
99
|
+
`export interface Row${String(i)} { id: number; name: string }\n` +
|
|
100
|
+
`export function build${String(i)}(n: number): Row${String(i)}[] {\n` +
|
|
101
|
+
` return Array.from({ length: n }, (_, j) => ({ id: j, name: 'r' + String(j) }));\n` +
|
|
102
|
+
`}\n`,
|
|
103
|
+
'utf-8',
|
|
104
|
+
);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
try {
|
|
108
|
+
fs.symlinkSync(path.join(REPO_ROOT, 'node_modules'), path.join(root, 'node_modules'), 'dir');
|
|
109
|
+
} catch {
|
|
110
|
+
// Left absent on a platform that refuses the link: `npx eslint` then
|
|
111
|
+
// resolves to nothing and the pass records `skipped: absent`, which the
|
|
112
|
+
// report states rather than hides.
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
spawnSync('git', ['init', '-q'], { cwd: root });
|
|
116
|
+
|
|
117
|
+
fs.mkdirSync(path.join(root, 'agents', 'state'), { recursive: true });
|
|
118
|
+
fs.writeFileSync(
|
|
119
|
+
path.join(root, 'agents', 'state', 'minimal-safe-diff.json'),
|
|
120
|
+
JSON.stringify({
|
|
121
|
+
session_id: SESSION,
|
|
122
|
+
files_touched_this_turn: Array.from(
|
|
123
|
+
{ length: FIXTURE_FILE_COUNT },
|
|
124
|
+
(_, i) => `mod${String(i)}.ts`,
|
|
125
|
+
),
|
|
126
|
+
}),
|
|
127
|
+
'utf-8',
|
|
128
|
+
);
|
|
129
|
+
|
|
130
|
+
return root;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
export interface BenchRow {
|
|
134
|
+
readonly concern: string;
|
|
135
|
+
readonly mode: 'off' | 'shadow';
|
|
136
|
+
readonly runs: number;
|
|
137
|
+
readonly p50_ms: number;
|
|
138
|
+
readonly p95_ms: number;
|
|
139
|
+
readonly max_ms: number;
|
|
140
|
+
/** What the pass actually did, so a row of zeros is never mistaken for speed. */
|
|
141
|
+
readonly commands: readonly string[];
|
|
142
|
+
readonly skipped: readonly string[];
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
export function measure(root: string, iterations: number): { off: BenchRow; shadow: BenchRow } {
|
|
146
|
+
const offSamples: number[] = [];
|
|
147
|
+
const shadowSamples: number[] = [];
|
|
148
|
+
let commands: string[] = [];
|
|
149
|
+
let skipped: string[] = [];
|
|
150
|
+
|
|
151
|
+
// One warm-up outside the samples: the first `npx` resolution pays a cost no
|
|
152
|
+
// subsequent stop pays, and reporting it inside the p95 would describe a
|
|
153
|
+
// session's first stop as if it were every stop.
|
|
154
|
+
collectTouchedFileQuality(root, SESSION);
|
|
155
|
+
|
|
156
|
+
for (let i = 0; i < iterations; i += 1) {
|
|
157
|
+
const t0 = performance.now();
|
|
158
|
+
const result = collectTouchedFileQuality(root, SESSION);
|
|
159
|
+
shadowSamples.push(performance.now() - t0);
|
|
160
|
+
if (i === 0 && result !== null) {
|
|
161
|
+
commands = result.runs.filter((r) => r.skipped === null).map((r) => r.command);
|
|
162
|
+
skipped = result.runs
|
|
163
|
+
.filter((r) => r.skipped !== null)
|
|
164
|
+
.map((r) => `${r.source_command} → ${String(r.skipped)}`);
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
// `off` is not "the same loop with a flag" — on the off path the stop
|
|
168
|
+
// handler never reaches this function at all, so the baseline is the
|
|
169
|
+
// empty interval, measured to keep the harness's own overhead visible.
|
|
170
|
+
const t1 = performance.now();
|
|
171
|
+
offSamples.push(performance.now() - t1);
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
const row = (mode: 'off' | 'shadow', xs: number[]): BenchRow => ({
|
|
175
|
+
concern: 'verify-before-complete',
|
|
176
|
+
mode,
|
|
177
|
+
runs: xs.length,
|
|
178
|
+
p50_ms: Math.round(percentile(xs, 50) * 1000) / 1000,
|
|
179
|
+
p95_ms: Math.round(percentile(xs, 95) * 1000) / 1000,
|
|
180
|
+
max_ms: Math.round(Math.max(...xs, 0) * 1000) / 1000,
|
|
181
|
+
commands: mode === 'shadow' ? commands : [],
|
|
182
|
+
skipped: mode === 'shadow' ? skipped : [],
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
return { off: row('off', offSamples), shadow: row('shadow', shadowSamples) };
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
export function render(rows: { off: BenchRow; shadow: BenchRow }): string {
|
|
189
|
+
const line = (r: BenchRow): string =>
|
|
190
|
+
`| ${r.concern} | ${r.mode} | ${String(r.runs)} | ${r.p50_ms.toFixed(3)} | ` +
|
|
191
|
+
`${r.p95_ms.toFixed(3)} | ${r.max_ms.toFixed(3)} |`;
|
|
192
|
+
const out: string[] = [
|
|
193
|
+
'',
|
|
194
|
+
`fixture: ${String(FIXTURE_FILE_COUNT)} TypeScript files, consumer-shaped project`,
|
|
195
|
+
'',
|
|
196
|
+
'| concern | mode | runs | p50_ms | p95_ms | max_ms |',
|
|
197
|
+
'|---|---|---|---|---|---|',
|
|
198
|
+
line(rows.off),
|
|
199
|
+
line(rows.shadow),
|
|
200
|
+
'',
|
|
201
|
+
`delta p95 (shadow − off): ${(rows.shadow.p95_ms - rows.off.p95_ms).toFixed(3)} ms`,
|
|
202
|
+
'',
|
|
203
|
+
`commands executed: ${rows.shadow.commands.length === 0 ? '(none)' : rows.shadow.commands.join(' · ')}`,
|
|
204
|
+
`skipped: ${rows.shadow.skipped.length === 0 ? '(none)' : rows.shadow.skipped.join(' · ')}`,
|
|
205
|
+
'',
|
|
206
|
+
];
|
|
207
|
+
return out.join('\n');
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
export function main(argv: readonly string[]): number {
|
|
211
|
+
const runsIdx = argv.indexOf('--runs');
|
|
212
|
+
const parsed = runsIdx === -1 ? NaN : Number(argv[runsIdx + 1]);
|
|
213
|
+
const iterations = Number.isFinite(parsed) && parsed > 0 ? Math.trunc(parsed) : 20;
|
|
214
|
+
const asJson = argv.includes('--json');
|
|
215
|
+
|
|
216
|
+
let root: string;
|
|
217
|
+
try {
|
|
218
|
+
root = buildFixture();
|
|
219
|
+
} catch (err) {
|
|
220
|
+
process.stderr.write(`bench_touched_file_quality: could not build the fixture — ${String(err)}\n`);
|
|
221
|
+
return 2;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
const rows = measure(root, iterations);
|
|
225
|
+
process.stdout.write(asJson ? `${JSON.stringify(rows, null, 2)}\n` : render(rows));
|
|
226
|
+
|
|
227
|
+
try {
|
|
228
|
+
fs.rmSync(root, { recursive: true, force: true });
|
|
229
|
+
} catch {
|
|
230
|
+
// A leftover temp directory is not a failed measurement.
|
|
231
|
+
}
|
|
232
|
+
return 0;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
const _entry = process.argv[1];
|
|
236
|
+
if (_entry !== undefined && path.resolve(_entry) === path.resolve(fileURLToPath(import.meta.url))) {
|
|
237
|
+
process.exit(main(process.argv.slice(2)));
|
|
238
|
+
}
|
|
@@ -44,6 +44,10 @@ import {
|
|
|
44
44
|
DEFAULT_PROJECTS_ROOT,
|
|
45
45
|
projectStoreSlug,
|
|
46
46
|
scanTranscripts,
|
|
47
|
+
measureBytesPerToken,
|
|
48
|
+
derivedBytes,
|
|
49
|
+
type BytesPerToken,
|
|
50
|
+
type DerivedBytes,
|
|
47
51
|
type BucketAggregate,
|
|
48
52
|
type TranscriptBucket,
|
|
49
53
|
type TranscriptRecord,
|
|
@@ -764,11 +768,38 @@ export interface Report {
|
|
|
764
768
|
council_mispricing: CouncilMispricingResult;
|
|
765
769
|
worktree_fragmentation: WorktreeFragmentationResult;
|
|
766
770
|
prefix_stability: PrefixStabilityResult;
|
|
771
|
+
/**
|
|
772
|
+
* Provider bytes per bucket — DERIVED, and labelled so on every value
|
|
773
|
+
* (`road-to-a-bytes-row-that-exists` Phase 2, metric
|
|
774
|
+
* `provider-bytes-per-call`).
|
|
775
|
+
*
|
|
776
|
+
* `null` when this corpus supplies no bytes-per-token factor. That is the
|
|
777
|
+
* honest outcome and it is emitted as `null` rather than as a figure from
|
|
778
|
+
* some other corpus: the factor is a property of the content it was
|
|
779
|
+
* measured on, and no constant lives in this file or in
|
|
780
|
+
* `_lib/cc_transcript.ts` for it to fall back to.
|
|
781
|
+
*
|
|
782
|
+
* LIMIT, stated where the number is rather than only in the registry: the
|
|
783
|
+
* factor is measured over ASSISTANT OUTPUT content, which is the only text
|
|
784
|
+
* a transcript carries. The request's system prompt, tool definitions and
|
|
785
|
+
* prior turns are not in the transcript at all (the same limitation
|
|
786
|
+
* `preamble_byte_census` records), so the factor is an output-side ratio
|
|
787
|
+
* applied to an input-side token count. That is why the value is `derived`
|
|
788
|
+
* and not `measured`, and why it must never be quoted as a wire figure.
|
|
789
|
+
*/
|
|
790
|
+
provider_bytes: {
|
|
791
|
+
factor: BytesPerToken | null;
|
|
792
|
+
main: DerivedBytes | null;
|
|
793
|
+
subagent: DerivedBytes | null;
|
|
794
|
+
};
|
|
767
795
|
claims: Claim[];
|
|
768
796
|
}
|
|
769
797
|
|
|
770
798
|
export function buildReport(opts: Options): Report {
|
|
771
|
-
|
|
799
|
+
// `measureBytes` is the only change to this scan: the token columns below
|
|
800
|
+
// are computed from the same `usage` blocks as before and are unaffected.
|
|
801
|
+
const scan = scanTranscripts({ root: opts.root, maxAgeDays: opts.maxAgeDays, measureBytes: true });
|
|
802
|
+
const bytesFactor = measureBytesPerToken(scan.records);
|
|
772
803
|
const buckets = aggregateByBucket(scan.records);
|
|
773
804
|
const subagentColdStart = computeColdStarts(scan.records);
|
|
774
805
|
const byAgent = aggregateByAgent(scan.records);
|
|
@@ -822,6 +853,11 @@ export function buildReport(opts: Options): Report {
|
|
|
822
853
|
council_mispricing: councilMispricing,
|
|
823
854
|
worktree_fragmentation: worktreeFragmentation,
|
|
824
855
|
prefix_stability: prefixStability,
|
|
856
|
+
provider_bytes: {
|
|
857
|
+
factor: bytesFactor,
|
|
858
|
+
main: derivedBytes(billableInputTokens(buckets.main), bytesFactor),
|
|
859
|
+
subagent: derivedBytes(billableInputTokens(buckets.subagent), bytesFactor),
|
|
860
|
+
},
|
|
825
861
|
claims,
|
|
826
862
|
};
|
|
827
863
|
}
|
|
@@ -851,6 +887,30 @@ export function renderText(r: Report): string {
|
|
|
851
887
|
out.push(` ${ps.reason}`);
|
|
852
888
|
out.push('');
|
|
853
889
|
|
|
890
|
+
const pb = r.provider_bytes;
|
|
891
|
+
out.push('Provider bytes (DERIVED - never a counted wire figure):');
|
|
892
|
+
if (pb.factor === null) {
|
|
893
|
+
out.push(' basis: unavailable - this corpus supplied no bytes-per-token factor');
|
|
894
|
+
out.push(' no figure is emitted; a ratio from another corpus would not be this one');
|
|
895
|
+
} else {
|
|
896
|
+
out.push(
|
|
897
|
+
` factor: ${pb.factor.bytes_per_token.toFixed(4)} bytes/token (basis: ${pb.factor.basis},`
|
|
898
|
+
+ ` ${pb.factor.content_bytes} content bytes / ${pb.factor.output_tokens} output tokens`
|
|
899
|
+
+ ` over ${pb.factor.records} records)`,
|
|
900
|
+
);
|
|
901
|
+
for (const bucket of ['main', 'subagent'] as const) {
|
|
902
|
+
const d = pb[bucket];
|
|
903
|
+
out.push(
|
|
904
|
+
d === null
|
|
905
|
+
? ` ${bucket}: basis: unavailable`
|
|
906
|
+
: ` ${bucket}: ${d.bytes} bytes (basis: ${d.basis}, from ${d.tokens} billable input tokens)`,
|
|
907
|
+
);
|
|
908
|
+
}
|
|
909
|
+
out.push(' the factor is measured over assistant OUTPUT content; the request payload is');
|
|
910
|
+
out.push(' not in any transcript, so this is an estimate of volume, not a wire measurement');
|
|
911
|
+
}
|
|
912
|
+
out.push('');
|
|
913
|
+
|
|
854
914
|
out.push('By bucket:');
|
|
855
915
|
for (const bucket of ['main', 'subagent'] as const) {
|
|
856
916
|
const b = r.buckets[bucket];
|
|
@@ -0,0 +1,287 @@
|
|
|
1
|
+
#!/usr/bin/env tsx
|
|
2
|
+
/**
|
|
3
|
+
* Where an artifact declares `inputs:`, its `argument-hint` is DERIVED from
|
|
4
|
+
* that declaration — and a hand-written hint on the same artifact is a
|
|
5
|
+
* conflict, not a merge.
|
|
6
|
+
*
|
|
7
|
+
* road-to-an-invocation-contract-that-reaches-the-wire 3.1.
|
|
8
|
+
*
|
|
9
|
+
* WHY A CONFLICT RATHER THAN A MERGE
|
|
10
|
+
*
|
|
11
|
+
* The tree already answers "what does this take?" in prose, through
|
|
12
|
+
* `argument-hint`, which nothing validates. Adding a structured declaration
|
|
13
|
+
* beside it creates a SECOND authority for the same question, and two surfaces
|
|
14
|
+
* that can answer one question drift — which is the failure this whole roadmap
|
|
15
|
+
* exists to make unrepresentable (Risk 1). Making the derived direction
|
|
16
|
+
* one-way, and a disagreement a build failure, is what keeps the second
|
|
17
|
+
* authority from forming. Merging the two would BE the second authority.
|
|
18
|
+
*
|
|
19
|
+
* An artifact with no declaration is untouched: its hand-written hint stays
|
|
20
|
+
* exactly as it is, because there is nothing to derive from and no conflict to
|
|
21
|
+
* have. That is why the 43 hintless commands are a generation gap that closes
|
|
22
|
+
* as declarations land, rather than 43 prose edits nobody reviewed.
|
|
23
|
+
*
|
|
24
|
+
* THE FORM, AND WHY IT ROUND-TRIPS
|
|
25
|
+
*
|
|
26
|
+
* `<name>` required · `[name]` optional · `:a|b` appended for an enum. The
|
|
27
|
+
* corpus already writes `[path]` and `[--force]` in exactly this shape, so the
|
|
28
|
+
* generated hint is not a new dialect. {@link parseHint} recovers the name,
|
|
29
|
+
* requiredness and enum from the rendered string, and the round-trip is
|
|
30
|
+
* asserted rather than assumed — a generator whose output its own parser cannot
|
|
31
|
+
* read would make the conflict check unfalsifiable.
|
|
32
|
+
*
|
|
33
|
+
* Exit codes: 0 in sync · 1 a conflict or a missing derived hint · 2 unreadable.
|
|
34
|
+
*/
|
|
35
|
+
|
|
36
|
+
import fs from 'node:fs';
|
|
37
|
+
import os from 'node:os';
|
|
38
|
+
import path from 'node:path';
|
|
39
|
+
import { fileURLToPath, pathToFileURL } from 'node:url';
|
|
40
|
+
|
|
41
|
+
import * as yaml from 'js-yaml';
|
|
42
|
+
|
|
43
|
+
import { GateLedger } from './_lib/gate_ledger.js';
|
|
44
|
+
import { runGateCli, runSelfTest } from './_lib/gate_self_test.js';
|
|
45
|
+
import { assertScanned, reportScanned } from './_lib/scan_scope.js';
|
|
46
|
+
|
|
47
|
+
const _HERE = fileURLToPath(import.meta.url);
|
|
48
|
+
const ROOT = path.resolve(path.dirname(_HERE), '..', '..');
|
|
49
|
+
|
|
50
|
+
export const GATE = 'check_argument_hint';
|
|
51
|
+
|
|
52
|
+
export interface InputDecl {
|
|
53
|
+
readonly name: string;
|
|
54
|
+
readonly type: string;
|
|
55
|
+
readonly required?: boolean;
|
|
56
|
+
readonly enum?: readonly string[];
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/** Render the canonical hint for a declaration. */
|
|
60
|
+
export function hintFor(inputs: readonly InputDecl[]): string {
|
|
61
|
+
return inputs
|
|
62
|
+
.map((i) => {
|
|
63
|
+
const body = i.enum && i.enum.length > 0 ? `${i.name}:${i.enum.join('|')}` : i.name;
|
|
64
|
+
return i.required === true ? `<${body}>` : `[${body}]`;
|
|
65
|
+
})
|
|
66
|
+
.join(' ');
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export interface ParsedHint {
|
|
70
|
+
readonly name: string;
|
|
71
|
+
readonly required: boolean;
|
|
72
|
+
readonly enum?: readonly string[];
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/** Recover declarations from a rendered hint. The inverse of {@link hintFor}. */
|
|
76
|
+
export function parseHint(hint: string): ParsedHint[] {
|
|
77
|
+
const out: ParsedHint[] = [];
|
|
78
|
+
for (const m of hint.matchAll(/([<[])([a-z][a-z0-9_]*)(?::([^\]>]+))?([\]>])/g)) {
|
|
79
|
+
const open = m[1]!;
|
|
80
|
+
const close = m[4]!;
|
|
81
|
+
if ((open === '<') !== (close === '>')) continue;
|
|
82
|
+
const parsed: ParsedHint = {
|
|
83
|
+
name: m[2]!,
|
|
84
|
+
required: open === '<',
|
|
85
|
+
...(m[3] === undefined ? {} : { enum: m[3].split('|') }),
|
|
86
|
+
};
|
|
87
|
+
out.push(parsed);
|
|
88
|
+
}
|
|
89
|
+
return out;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/** Frontmatter of one artifact, or `null` when it has none or it is malformed. */
|
|
93
|
+
function frontmatter(text: string): Record<string, unknown> | null {
|
|
94
|
+
const m = /^---\n([\s\S]*?)\n---/.exec(text);
|
|
95
|
+
if (m === null) return null;
|
|
96
|
+
try {
|
|
97
|
+
const fm = yaml.load(m[1]!);
|
|
98
|
+
return fm !== null && typeof fm === 'object' ? (fm as Record<string, unknown>) : null;
|
|
99
|
+
} catch {
|
|
100
|
+
return null;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
export function declaredInputs(fm: Record<string, unknown> | null): InputDecl[] | null {
|
|
105
|
+
if (fm === null) return null;
|
|
106
|
+
const raw = fm['inputs'];
|
|
107
|
+
if (!Array.isArray(raw)) return null;
|
|
108
|
+
const out: InputDecl[] = [];
|
|
109
|
+
for (const item of raw) {
|
|
110
|
+
if (item === null || typeof item !== 'object') continue;
|
|
111
|
+
const r = item as Record<string, unknown>;
|
|
112
|
+
if (typeof r['name'] !== 'string' || typeof r['type'] !== 'string') continue;
|
|
113
|
+
out.push({
|
|
114
|
+
name: r['name'],
|
|
115
|
+
type: r['type'],
|
|
116
|
+
...(typeof r['required'] === 'boolean' ? { required: r['required'] } : {}),
|
|
117
|
+
...(Array.isArray(r['enum'])
|
|
118
|
+
? { enum: r['enum'].filter((x): x is string => typeof x === 'string') }
|
|
119
|
+
: {}),
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
return out;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
export type FindingKind = 'conflict' | 'missing';
|
|
126
|
+
|
|
127
|
+
export interface Finding {
|
|
128
|
+
readonly file: string;
|
|
129
|
+
readonly kind: FindingKind;
|
|
130
|
+
readonly derived: string;
|
|
131
|
+
/** The hand-written hint, for a conflict. */
|
|
132
|
+
readonly written?: string;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/** Compare one artifact's declaration against its hint. */
|
|
136
|
+
export function checkArtifact(text: string, file: string): Finding | null {
|
|
137
|
+
const fm = frontmatter(text);
|
|
138
|
+
const inputs = declaredInputs(fm);
|
|
139
|
+
if (inputs === null || inputs.length === 0) return null;
|
|
140
|
+
const derived = hintFor(inputs);
|
|
141
|
+
const written = fm?.['argument-hint'];
|
|
142
|
+
if (typeof written !== 'string') return { file, kind: 'missing', derived };
|
|
143
|
+
if (written.trim() !== derived) return { file, kind: 'conflict', derived, written };
|
|
144
|
+
return null;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
function walk(dir: string, match: (n: string) => boolean, out: string[] = []): string[] {
|
|
148
|
+
if (!fs.existsSync(dir)) return out;
|
|
149
|
+
for (const e of fs.readdirSync(dir, { withFileTypes: true })) {
|
|
150
|
+
const p = path.join(dir, e.name);
|
|
151
|
+
if (e.isDirectory()) walk(p, match, out);
|
|
152
|
+
else if (match(e.name)) out.push(p);
|
|
153
|
+
}
|
|
154
|
+
return out;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* COMMANDS ONLY, and the reason is structural rather than a scoping preference:
|
|
159
|
+
* `argument-hint` is a key of `command.schema.json` and of no other schema. A
|
|
160
|
+
* skill cannot carry one, so reporting a skill that declares `inputs:` as
|
|
161
|
+
* "missing its hint" would demand a field the schema forbids. Skills still get
|
|
162
|
+
* their declaration onto the wire — that is `to_mcp_prompt_meta`'s job (3.2),
|
|
163
|
+
* which reads the declaration directly and needs no hint at all.
|
|
164
|
+
*/
|
|
165
|
+
export function scan(root: string): { findings: Finding[]; scanned: number; declaring: number } {
|
|
166
|
+
const files = walk(path.join(root, 'src', 'domains'), (n) => n === 'command.md').sort();
|
|
167
|
+
|
|
168
|
+
const findings: Finding[] = [];
|
|
169
|
+
let declaring = 0;
|
|
170
|
+
for (const f of files) {
|
|
171
|
+
const text = fs.readFileSync(f, 'utf8');
|
|
172
|
+
const inputs = declaredInputs(frontmatter(text));
|
|
173
|
+
if (inputs !== null && inputs.length > 0) declaring += 1;
|
|
174
|
+
const finding = checkArtifact(text, path.relative(root, f));
|
|
175
|
+
if (finding !== null) findings.push(finding);
|
|
176
|
+
}
|
|
177
|
+
return { findings, scanned: files.length, declaring };
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
export function main(argv: readonly string[]): number {
|
|
181
|
+
if (argv.includes('--self-test')) return selfTest();
|
|
182
|
+
const rootIdx = argv.indexOf('--root');
|
|
183
|
+
const root = rootIdx === -1 ? ROOT : (argv[rootIdx + 1] ?? ROOT);
|
|
184
|
+
|
|
185
|
+
const { findings, scanned, declaring } = scan(root);
|
|
186
|
+
const ledger = new GateLedger(GATE);
|
|
187
|
+
ledger.plan(findings.map((f) => f.file));
|
|
188
|
+
for (const f of findings) ledger.fail(f.file, f.kind);
|
|
189
|
+
|
|
190
|
+
// A gate that read nothing has not passed. This fires BEFORE the verdict,
|
|
191
|
+
// because certifying against an empty corpus is the false green the coverage
|
|
192
|
+
// manifest exists to refuse — named by the provider-diverse ratification
|
|
193
|
+
// review as one condition that would have flipped its verdict.
|
|
194
|
+
assertScanned({ gate: GATE, scanned: scanned, units: 'artifact(s)', roots: ['src/domains'] });
|
|
195
|
+
|
|
196
|
+
reportScanned({
|
|
197
|
+
gate: GATE,
|
|
198
|
+
scanned,
|
|
199
|
+
units: 'artifact(s)',
|
|
200
|
+
roots: ['src/domains'],
|
|
201
|
+
});
|
|
202
|
+
ledger.report();
|
|
203
|
+
|
|
204
|
+
if (findings.length > 0) {
|
|
205
|
+
for (const f of findings) {
|
|
206
|
+
if (f.kind === 'conflict') {
|
|
207
|
+
process.stdout.write(
|
|
208
|
+
`❌ ${GATE}: ${f.file} has a hand-written \`argument-hint\` that contradicts ` +
|
|
209
|
+
`its declaration.\n written: ${f.written ?? ''}\n derived: ${f.derived}\n`,
|
|
210
|
+
);
|
|
211
|
+
} else {
|
|
212
|
+
process.stdout.write(
|
|
213
|
+
`❌ ${GATE}: ${f.file} declares \`inputs:\` but carries no \`argument-hint\`.\n` +
|
|
214
|
+
` derived: ${f.derived}\n`,
|
|
215
|
+
);
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
process.stdout.write(
|
|
219
|
+
'\nWhere a declaration exists the hint is derived from it, one way. Fix the ' +
|
|
220
|
+
'declaration, or delete the hand-written hint — never reconcile the two by ' +
|
|
221
|
+
'hand, which is the second authority this check exists to prevent.\n',
|
|
222
|
+
);
|
|
223
|
+
return 1;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
process.stdout.write(
|
|
227
|
+
`✅ ${GATE}: every derived \`argument-hint\` matches its declaration ` +
|
|
228
|
+
`(${String(declaring)} of ${String(scanned)} artifact(s) declare \`inputs:\`).\n`,
|
|
229
|
+
);
|
|
230
|
+
return 0;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
/**
|
|
234
|
+
* A self-test is what proves a gate DISCRIMINATES. An enforced scan floor only
|
|
235
|
+
* proves it read something; the verdict has to move.
|
|
236
|
+
*/
|
|
237
|
+
function selfTest(): number {
|
|
238
|
+
const plant = (name: string, fm: string): string => {
|
|
239
|
+
const dir = fs.mkdtempSync(path.join(os.tmpdir(), `arg-hint-${name}-`));
|
|
240
|
+
const cmd = path.join(dir, 'src', 'domains', 'probe-pack', 'probe');
|
|
241
|
+
fs.mkdirSync(cmd, { recursive: true });
|
|
242
|
+
fs.writeFileSync(path.join(cmd, 'command.md'), `---\nname: probe\n${fm}---\n\nbody\n`, 'utf-8');
|
|
243
|
+
return dir;
|
|
244
|
+
};
|
|
245
|
+
|
|
246
|
+
const run = (root: string): number =>
|
|
247
|
+
runGateCli(ROOT, path.join('src', 'scripts', 'check_argument_hint.ts'), ['--root', root], ROOT);
|
|
248
|
+
|
|
249
|
+
return runSelfTest({
|
|
250
|
+
gate: GATE,
|
|
251
|
+
minCases: 5,
|
|
252
|
+
minRejectCases: 3,
|
|
253
|
+
cases: [
|
|
254
|
+
{
|
|
255
|
+
name: 'an empty corpus is refused, not certified green',
|
|
256
|
+
expect: 'reject',
|
|
257
|
+
run: () => run(fs.mkdtempSync(path.join(os.tmpdir(), 'arg-hint-empty-'))),
|
|
258
|
+
},
|
|
259
|
+
{
|
|
260
|
+
name: 'a hint matching its declaration passes',
|
|
261
|
+
expect: 'accept',
|
|
262
|
+
run: () =>
|
|
263
|
+
run(plant('match', 'argument-hint: "<a>"\ninputs:\n - name: a\n type: string\n required: true\n')),
|
|
264
|
+
},
|
|
265
|
+
{
|
|
266
|
+
name: 'a hand-written hint contradicting the declaration fails',
|
|
267
|
+
expect: 'reject',
|
|
268
|
+
run: () =>
|
|
269
|
+
run(plant('conflict', 'argument-hint: "[other]"\ninputs:\n - name: a\n type: string\n required: true\n')),
|
|
270
|
+
},
|
|
271
|
+
{
|
|
272
|
+
name: 'a declaration with no hint at all fails',
|
|
273
|
+
expect: 'reject',
|
|
274
|
+
run: () => run(plant('missing', 'inputs:\n - name: a\n type: string\n')),
|
|
275
|
+
},
|
|
276
|
+
{
|
|
277
|
+
name: 'an artifact with no declaration keeps its free-text hint',
|
|
278
|
+
expect: 'accept',
|
|
279
|
+
run: () => run(plant('nodecl', 'argument-hint: "[free text]"\n')),
|
|
280
|
+
},
|
|
281
|
+
],
|
|
282
|
+
});
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
if (process.argv[1] && import.meta.url === pathToFileURL(path.resolve(process.argv[1])).href) {
|
|
286
|
+
process.exit(main(process.argv.slice(2)));
|
|
287
|
+
}
|