@event4u/agent-config 14.20.0 → 14.21.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.
Files changed (100) hide show
  1. package/.augment-plugin/marketplace.json +3 -3
  2. package/.augment-plugin/plugin.json +1 -1
  3. package/.claude-plugin/marketplace.json +1 -1
  4. package/CHANGELOG.md +243 -0
  5. package/README.md +1 -1
  6. package/agents/templates/.ai-council.yml.example +10 -0
  7. package/dist/agent-src/commands/analyze/inbox.md +1 -1
  8. package/dist/agent-src/commands/analyze/{reference-repo.md → repo.md} +247 -32
  9. package/dist/agent-src/commands/analyze/roadmap-repos.md +129 -0
  10. package/dist/agent-src/commands/analyze.md +12 -7
  11. package/dist/agent-src/commands/feature/plan.md +55 -16
  12. package/dist/agent-src/commands/feature/refactor.md +8 -3
  13. package/dist/agent-src/commands/humanize.md +48 -4
  14. package/dist/agent-src/contexts/execution/contract-decision-sheet.md +22 -1
  15. package/dist/agent-src/contexts/execution/host-capability-manifest.md +4 -1
  16. package/dist/agent-src/contexts/execution/roadmap-process-loop.md +35 -2
  17. package/dist/agent-src/contexts/execution/terminal-states.md +4 -1
  18. package/dist/agent-src/rules/evaluator-independence.md +4 -4
  19. package/dist/agent-src/rules/external-reference-deep-dive.md +2 -2
  20. package/dist/agent-src/skills/competitive-positioning/SKILL.md +2 -2
  21. package/dist/agent-src/skills/humanizer/references/anti-aiisms.md +27 -11
  22. package/dist/agent-src/skills/learning-to-rule-or-skill/SKILL.md +1 -1
  23. package/dist/agent-src/skills/markitdown/SKILL.md +1 -1
  24. package/dist/agent-src/skills/repomix-packer/SKILL.md +1 -1
  25. package/dist/agent-src/skills/technical-specification/SKILL.md +4 -0
  26. package/dist/agent-src/templates/agents/agent-project-settings.example.yml +1 -1
  27. package/dist/agent-src/templates/features.md +5 -0
  28. package/dist/agent-src/templates/roadmaps.md +15 -0
  29. package/dist/cli-delegate/{chunk-KPBWFOPZ.js → chunk-2FTMENJL.js} +194 -37
  30. package/dist/cli-delegate/{chunk-PI2GU3DP.js → chunk-2TAQ2K4V.js} +4 -1
  31. package/dist/cli-delegate/{chunk-C6IPZRDA.js → chunk-643Z7FIC.js} +1 -1
  32. package/dist/cli-delegate/{chunk-NUMQHLS5.js → chunk-J3RFNKG4.js} +21 -2
  33. package/dist/cli-delegate/cmd_conformance.js +17 -3
  34. package/dist/cli-delegate/cmd_doctor.js +3 -3
  35. package/dist/cli-delegate/cmd_export.js +2 -2
  36. package/dist/cli-delegate/cmd_handoff.js +1 -1
  37. package/dist/cli-delegate/cmd_prune.js +2 -2
  38. package/dist/cli-delegate/cmd_settings_migrate.js +2 -2
  39. package/dist/cli-delegate/cmd_sync.js +2 -2
  40. package/dist/cli-delegate/cmd_uninstall.js +2 -2
  41. package/dist/cli-delegate/cmd_validate.js +2 -2
  42. package/dist/discovery/deprecation-report.md +1 -1
  43. package/dist/discovery/discovery-manifest.json +56 -25
  44. package/dist/discovery/discovery-manifest.json.sha256 +1 -1
  45. package/dist/discovery/discovery-manifest.summary.md +3 -3
  46. package/dist/discovery/dormancy-report.md +1 -1
  47. package/dist/discovery/orphan-report.md +1 -1
  48. package/dist/discovery/packs.json +7 -6
  49. package/dist/discovery/trust-report.md +2 -2
  50. package/dist/discovery/workspaces.json +6 -5
  51. package/dist/hooks/dispatch.js +479 -241
  52. package/dist/install/install.mjs +4 -1
  53. package/dist/mcp/registry-manifest.json +2 -2
  54. package/dist/mcp/server.json +2 -2
  55. package/dist/mcp/server.mjs +313 -63
  56. package/dist/scripts/ai_council/content_ceiling.js +63 -0
  57. package/dist/scripts/ai_council/seat_policy.js +106 -0
  58. package/dist/scripts/ai_council/transport_resolver.js +21 -0
  59. package/llms.txt +14 -14
  60. package/package.json +1 -1
  61. package/src/config/gate-violation-baselines.json +3 -3
  62. package/src/config/release-gate-locality.yml +4 -3
  63. package/src/scripts/_lib/blocked_by_marker.ts +189 -0
  64. package/src/scripts/_lib/host_capability.ts +38 -1
  65. package/src/scripts/_lib/release_highlights.ts +19 -211
  66. package/src/scripts/_lib/release_material.ts +27 -77
  67. package/src/scripts/_lib/structured_ask.ts +117 -0
  68. package/src/scripts/_lib/tty_prompt.ts +76 -0
  69. package/src/scripts/ai_council/api_transport.ts +163 -0
  70. package/src/scripts/ai_council/clients.ts +58 -63
  71. package/src/scripts/ai_council/config.ts +13 -0
  72. package/src/scripts/ai_council/content_ceiling.ts +79 -0
  73. package/src/scripts/ai_council/jury_aggregate.ts +178 -0
  74. package/src/scripts/ai_council/seat_policy.ts +137 -0
  75. package/src/scripts/ai_council/status_surface.ts +79 -0
  76. package/src/scripts/ai_council/transport_resolver.ts +59 -1
  77. package/src/scripts/ai_tells_rules.ts +446 -5
  78. package/src/scripts/ask_block_census.ts +499 -0
  79. package/src/scripts/bench_humanizer_eval.ts +264 -40
  80. package/src/scripts/bench_prose_tells_fp.ts +198 -0
  81. package/src/scripts/check_branch_work_committed.ts +234 -0
  82. package/src/scripts/check_pack_size.ts +1 -1
  83. package/src/scripts/check_release_highlights.ts +0 -157
  84. package/src/scripts/council_cli.ts +18 -27
  85. package/src/scripts/detect_ai_tells.ts +142 -20
  86. package/src/scripts/harvest_reference_tokens.ts +698 -0
  87. package/src/scripts/hook_manifest.json +1 -1
  88. package/src/scripts/hook_manifest.yaml +31 -1
  89. package/src/scripts/hooks/concern_registry.ts +2 -0
  90. package/src/scripts/hooks/delegation_nudge_hook.ts +45 -1
  91. package/src/scripts/hooks/one_question_per_ask_hook.ts +191 -0
  92. package/src/scripts/install-hooks.sh +52 -0
  93. package/src/scripts/lint_roadmap_blockers.ts +51 -1
  94. package/src/scripts/migrate_command_suggestions.ts +1 -1
  95. package/src/scripts/probe_unblocked_ask.ts +135 -2
  96. package/src/scripts/release.ts +26 -71
  97. package/src/scripts/release_drill.ts +6 -10
  98. package/src/scripts/release_env.ts +1 -0
  99. package/src/scripts/release_publication.ts +34 -29
  100. package/src/scripts/self_review_gate.ts +409 -15
@@ -1 +1 @@
1
- {"fingerprint":"8ca65564:83643","manifest":{"schema_version":1,"concerns":{"chat-history":{"script":"src/scripts/chat_history.ts","args":["hook-dispatch"],"fail_closed":false,"severity":"advisory","needs_payload_bodies":["result"]},"hot-context":{"script":"src/scripts/hot_context_hook.ts","args":[],"fail_closed":false,"severity":"advisory"},"handoff-context":{"script":"src/scripts/handoff_context_hook.ts","args":[],"fail_closed":false,"severity":"advisory"},"roadmap-progress":{"script":"src/scripts/roadmap_progress_hook.ts","args":[],"fail_closed":false,"severity":"advisory","needs_payload_bodies":["input"]},"onboarding-gate":{"script":"src/scripts/onboarding_gate_hook.ts","args":[],"fail_closed":false,"severity":"advisory"},"context-hygiene":{"script":"src/scripts/context_hygiene_hook.ts","args":[],"fail_closed":false,"severity":"advisory"},"verify-before-complete":{"script":"src/scripts/before_complete_hook.ts","args":[],"fail_closed":false,"severity":"advisory","needs_payload_bodies":["input","result"]},"ship-diff-volume":{"script":"src/scripts/hooks/ship_diff_volume_hook.ts","args":[],"fail_closed":false,"severity":"advisory","needs_payload_bodies":["input"]},"minimal-safe-diff":{"script":"src/scripts/minimal_safe_diff_hook.ts","args":[],"fail_closed":false,"severity":"advisory","needs_payload_bodies":["input"]},"injection-scan":{"script":"src/scripts/injection_scan_hook.ts","args":[],"fail_closed":false,"severity":"advisory","needs_payload_bodies":["input","result"]},"block-no-verify":{"script":"src/scripts/hooks/block_no_verify.ts","args":[],"fail_closed":true,"severity":"blocking","needs_payload_bodies":["input"]},"block-kernel-rule-writes":{"script":"src/scripts/hooks/block_kernel_rule_writes.ts","args":[],"fail_closed":true,"severity":"blocking","needs_payload_bodies":["input"]},"block-speaking-inbox-dir":{"script":"src/scripts/hooks/block_speaking_inbox_dir.ts","args":[],"fail_closed":false,"severity":"blocking","needs_payload_bodies":["input"]},"block-config-weakening":{"script":"src/scripts/hooks/block_config_weakening.ts","args":[],"fail_closed":false,"severity":"blocking","needs_payload_bodies":["input"]},"rtk-wrap":{"script":"src/scripts/hooks/rtk_wrap_hook.ts","args":[],"fail_closed":false,"severity":"advisory","needs_payload_bodies":["input"]},"design-slop":{"script":"src/scripts/hooks/design_slop_hook.ts","args":[],"fail_closed":false,"severity":"advisory","needs_payload_bodies":["input"]},"design-pass":{"script":"src/scripts/hooks/design_pass_hook.ts","args":[],"fail_closed":false,"severity":"advisory","needs_payload_bodies":["input"]},"design-pass-stop":{"script":"src/scripts/hooks/design_pass_hook.ts","args":["--slot","stop"],"fail_closed":false,"severity":"advisory"},"ui-route-nudge":{"script":"src/scripts/hooks/ui_route_nudge_hook.ts","args":[],"fail_closed":false,"severity":"advisory","needs_payload_bodies":["input"]},"suggestion-capture":{"script":"src/scripts/hooks/suggestion_capture_hook.ts","args":[],"fail_closed":false,"severity":"advisory"},"code-graph-nudge":{"script":"src/scripts/hooks/code_graph_nudge_hook.ts","args":[],"fail_closed":false,"severity":"advisory","tools":["Grep","Glob","Read"],"needs_payload_bodies":["input"]},"memory-learn":{"script":"src/scripts/memory_learn_hook.ts","args":[],"fail_closed":false,"severity":"advisory"},"first-run-gate":{"script":"src/scripts/first_run_gate_hook.ts","args":[],"fail_closed":false,"severity":"advisory"},"profile-staleness":{"script":"src/scripts/profile_staleness_hook.ts","args":[],"fail_closed":false,"severity":"advisory"},"wrapper-freshness":{"script":"src/scripts/wrapper_freshness_hook.ts","args":[],"fail_closed":false,"severity":"advisory"},"surface-probe":{"script":"src/scripts/surface_probe_hook.ts","args":[],"fail_closed":false,"severity":"advisory"},"team-review-gate":{"script":"src/scripts/team_review_gate_hook.ts","args":[],"fail_closed":false,"severity":"advisory"},"pr-url-reminder":{"script":"src/scripts/pr_url_reminder_hook.ts","args":[],"fail_closed":false,"severity":"advisory","needs_payload_bodies":["input","result"]},"push-settle":{"script":"src/scripts/hooks/push_settle_hook.ts","args":[],"fail_closed":false,"severity":"advisory","needs_payload_bodies":["input","result"]},"language-mirror":{"script":"src/scripts/language_mirror_hook.ts","args":[],"fail_closed":false,"severity":"advisory"},"git-authorization":{"script":"src/scripts/git_authorization_hook.ts","args":[],"fail_closed":false,"severity":"advisory"},"evidence-independence":{"script":"src/scripts/hooks/evidence_independence.ts","args":[],"fail_closed":false,"severity":"blocking","needs_payload_bodies":["input"]},"session-canary":{"script":"src/scripts/session_canary_hook.ts","args":[],"fail_closed":false,"severity":"advisory"},"council-availability":{"script":"src/scripts/council_availability_hook.ts","args":[],"fail_closed":false,"severity":"advisory"},"telemetry-disclosure":{"script":"src/scripts/telemetry_disclosure_hook.ts","args":[],"fail_closed":false,"severity":"advisory"},"telemetry-flush":{"script":"src/scripts/hooks/telemetry_flush_hook.ts","args":[],"fail_closed":false,"severity":"advisory"},"self-repair":{"script":"src/scripts/self_repair_hook.ts","args":[],"fail_closed":false,"severity":"advisory"},"session-register":{"script":"src/scripts/session_register_hook.ts","args":[],"fail_closed":false,"severity":"advisory"},"orchestration-record":{"script":"src/scripts/hooks/orchestration_record_hook.ts","args":[],"fail_closed":false,"severity":"advisory","tools":["Agent","Task"],"needs_payload_bodies":["input","result"]},"telemetry-usage":{"script":"src/scripts/hooks/telemetry_usage_hook.ts","args":[],"fail_closed":false,"severity":"advisory","tools":["Skill"],"needs_payload_bodies":["input"]},"delegation-nudge":{"script":"src/scripts/hooks/delegation_nudge_hook.ts","args":[],"fail_closed":false,"severity":"advisory","nudge_rank":1},"skill-route":{"script":"src/scripts/hooks/skill_route_hook.ts","args":[],"fail_closed":false,"severity":"advisory","nudge_rank":2},"rule-inject":{"script":"src/scripts/hooks/rule_inject_hook.ts","args":[],"fail_closed":false,"severity":"advisory","needs_payload_bodies":["input"]},"end-review-nudge":{"script":"src/scripts/hooks/end_review_nudge_hook.ts","args":[],"fail_closed":false,"severity":"advisory","skip_on_refusal_retry":true},"turn-end-gate":{"script":"src/scripts/hooks/turn_end_gate_hook.ts","args":[],"fail_closed":false,"severity":"blocking"},"comment-discipline":{"script":"src/scripts/hooks/comment_discipline_hook.ts","args":[],"fail_closed":false,"severity":"advisory","tools":["Write","Edit"],"needs_payload_bodies":["input"]},"edit-shape":{"script":"src/scripts/hooks/edit_shape_hook.ts","args":[],"fail_closed":false,"severity":"advisory","tools":["Write"],"needs_payload_bodies":["input"]},"reread-guard":{"script":"src/scripts/hooks/reread_guard_hook.ts","args":[],"fail_closed":false,"severity":"advisory","tools":["Read","Edit","Write"],"needs_payload_bodies":["input"]},"session-eol":{"script":"src/scripts/hooks/session_eol_hook.ts","args":[],"fail_closed":false,"severity":"advisory"},"run-continuation":{"script":"src/scripts/hooks/run_continuation_hook.ts","args":[],"fail_closed":false,"severity":"blocking"},"interruption-ledger":{"script":"src/scripts/hooks/interruption_ledger_hook.ts","args":[],"fail_closed":false,"severity":"advisory","skip_on_refusal_retry":true},"subagent-ledger":{"script":"src/scripts/hooks/subagent_ledger_hook.ts","args":[],"fail_closed":false,"severity":"advisory"},"tool-result-bytes":{"script":"src/scripts/hooks/tool_result_bytes_hook.ts","args":[],"fail_closed":false,"severity":"advisory"},"spawn-guard-shadow":{"script":"src/scripts/hooks/spawn_guard_shadow_hook.ts","args":[],"fail_closed":false,"severity":"advisory","tools":["Agent","Task"]},"source-first-gate":{"script":"src/scripts/hooks/source_first_gate_hook.ts","args":[],"fail_closed":false,"severity":"advisory","needs_payload_bodies":["input"]},"journal-record":{"script":"src/scripts/hooks/journal_record_hook.ts","args":[],"fail_closed":false,"severity":"advisory"}},"roles":{"worker":{"drop":["delegation-nudge","skill-route","end-review-nudge","council-availability","team-review-gate","self-repair","session-eol","interruption-ledger"]}},"platforms":{"augment":{"session_start":["chat-history","hot-context","handoff-context","session-canary","council-availability","telemetry-disclosure","first-run-gate","onboarding-gate","verify-before-complete","minimal-safe-diff","profile-staleness","wrapper-freshness","surface-probe","session-register"],"session_end":["chat-history","memory-learn","session-register","roadmap-progress","telemetry-flush"],"stop":["chat-history","hot-context","verify-before-complete","self-repair","session-register","roadmap-progress","design-pass-stop"],"pre_tool_use":["block-no-verify","evidence-independence","block-kernel-rule-writes","block-config-weakening","block-speaking-inbox-dir","rtk-wrap","design-slop","ui-route-nudge","code-graph-nudge","ship-diff-volume","reread-guard"],"post_tool_use":["chat-history","roadmap-progress","context-hygiene","verify-before-complete","minimal-safe-diff","injection-scan","pr-url-reminder","push-settle","orchestration-record","telemetry-usage","tool-result-bytes","edit-shape","comment-discipline","design-pass"]},"claude":{"session_start":["chat-history","hot-context","handoff-context","session-canary","council-availability","telemetry-disclosure","first-run-gate","onboarding-gate","verify-before-complete","minimal-safe-diff","profile-staleness","wrapper-freshness","surface-probe","session-register","journal-record"],"session_end":["chat-history","memory-learn","session-register","roadmap-progress","telemetry-flush","journal-record"],"stop":["chat-history","hot-context","verify-before-complete","team-review-gate","end-review-nudge","turn-end-gate","self-repair","session-register","session-eol","interruption-ledger","roadmap-progress","design-pass-stop","suggestion-capture","journal-record","run-continuation"],"user_prompt_submit":["chat-history","verify-before-complete","minimal-safe-diff","language-mirror","delegation-nudge","skill-route","git-authorization","session-canary","self-repair","session-register","rule-inject","suggestion-capture","journal-record"],"pre_tool_use":["block-no-verify","evidence-independence","block-kernel-rule-writes","block-config-weakening","block-speaking-inbox-dir","rtk-wrap","design-slop","ui-route-nudge","code-graph-nudge","ship-diff-volume","reread-guard","spawn-guard-shadow","source-first-gate","rule-inject"],"post_tool_use":["chat-history","roadmap-progress","context-hygiene","verify-before-complete","minimal-safe-diff","injection-scan","pr-url-reminder","push-settle","orchestration-record","telemetry-usage","tool-result-bytes","edit-shape","comment-discipline","language-mirror","design-pass","journal-record"],"pre_compact":["language-mirror","hot-context","rule-inject","journal-record"],"subagent_start":["subagent-ledger","journal-record"],"subagent_stop":["subagent-ledger","journal-record"]},"cowork":{"session_start":["chat-history","hot-context","handoff-context","session-canary","council-availability","telemetry-disclosure","first-run-gate","onboarding-gate","verify-before-complete","minimal-safe-diff","profile-staleness","wrapper-freshness","surface-probe","session-register"],"session_end":["chat-history","memory-learn","session-register","roadmap-progress","telemetry-flush"],"stop":["chat-history","hot-context","verify-before-complete","self-repair","session-register","roadmap-progress","design-pass-stop"],"user_prompt_submit":["chat-history","verify-before-complete","minimal-safe-diff","language-mirror","git-authorization","session-canary","self-repair","session-register"],"pre_tool_use":["block-no-verify","evidence-independence","block-kernel-rule-writes","block-config-weakening","block-speaking-inbox-dir","rtk-wrap","design-slop","ui-route-nudge","code-graph-nudge","ship-diff-volume","reread-guard","spawn-guard-shadow","source-first-gate"],"post_tool_use":["chat-history","roadmap-progress","context-hygiene","verify-before-complete","minimal-safe-diff","injection-scan","pr-url-reminder","push-settle","orchestration-record","telemetry-usage","tool-result-bytes","edit-shape","comment-discipline","design-pass"],"subagent_start":["subagent-ledger"],"subagent_stop":["subagent-ledger"]},"cursor":{"session_start":["chat-history","hot-context","handoff-context","session-canary","council-availability","telemetry-disclosure","first-run-gate","onboarding-gate","verify-before-complete","minimal-safe-diff","profile-staleness","wrapper-freshness","surface-probe","session-register"],"session_end":["chat-history","memory-learn","session-register","roadmap-progress","telemetry-flush"],"stop":["chat-history","hot-context","verify-before-complete","self-repair","session-register","roadmap-progress","design-pass-stop"],"user_prompt_submit":["chat-history","verify-before-complete","minimal-safe-diff","language-mirror","git-authorization","session-canary","self-repair","session-register"],"post_tool_use":["chat-history","roadmap-progress","context-hygiene","verify-before-complete","minimal-safe-diff","injection-scan","pr-url-reminder","push-settle","orchestration-record","telemetry-usage","tool-result-bytes","edit-shape","comment-discipline","design-pass"]},"cline":{"session_start":["chat-history","hot-context","handoff-context","session-canary","council-availability","telemetry-disclosure","first-run-gate","onboarding-gate","verify-before-complete","minimal-safe-diff","profile-staleness","wrapper-freshness","surface-probe","session-register"],"session_end":["chat-history","memory-learn","session-register","roadmap-progress","telemetry-flush"],"stop":["chat-history","hot-context","verify-before-complete","self-repair","session-register","roadmap-progress","design-pass-stop"],"user_prompt_submit":["chat-history","verify-before-complete","minimal-safe-diff","language-mirror","git-authorization","session-canary","self-repair","session-register"],"post_tool_use":["chat-history","roadmap-progress","context-hygiene","verify-before-complete","minimal-safe-diff","injection-scan","pr-url-reminder","push-settle","orchestration-record","telemetry-usage","tool-result-bytes","edit-shape","comment-discipline","design-pass"]},"windsurf":{"session_start":["chat-history","hot-context","handoff-context","session-canary","council-availability","telemetry-disclosure","first-run-gate","onboarding-gate","verify-before-complete","profile-staleness","wrapper-freshness","surface-probe","session-register"],"stop":["chat-history","hot-context","verify-before-complete","self-repair","session-register","design-pass-stop"],"user_prompt_submit":["chat-history","verify-before-complete","language-mirror","git-authorization","session-canary","self-repair","session-register"]},"gemini":{"session_start":["chat-history","hot-context","handoff-context","session-canary","council-availability","telemetry-disclosure","first-run-gate","onboarding-gate","verify-before-complete","minimal-safe-diff","profile-staleness","wrapper-freshness","surface-probe","session-register"],"session_end":["chat-history","memory-learn","session-register","roadmap-progress","telemetry-flush"],"stop":["chat-history","hot-context","verify-before-complete","self-repair","session-register","roadmap-progress","design-pass-stop"],"user_prompt_submit":["chat-history","verify-before-complete","minimal-safe-diff","language-mirror","git-authorization","session-canary","self-repair","session-register"],"post_tool_use":["chat-history","roadmap-progress","context-hygiene","verify-before-complete","minimal-safe-diff","injection-scan","pr-url-reminder","push-settle","orchestration-record","telemetry-usage","tool-result-bytes","edit-shape","comment-discipline","design-pass"]},"copilot":{"fallback_only":true}},"native_event_aliases":{"augment":{"SessionStart":"session_start","SessionEnd":"session_end","Stop":"stop","PostToolUse":"post_tool_use","PreToolUse":"pre_tool_use"},"claude":{"SessionStart":"session_start","SessionEnd":"session_end","Stop":"stop","UserPromptSubmit":"user_prompt_submit","PostToolUse":"post_tool_use","PreToolUse":"pre_tool_use","PreCompact":"pre_compact","SubagentStart":"subagent_start","SubagentStop":"subagent_stop"},"cowork":{"SessionStart":"session_start","SessionEnd":"session_end","Stop":"stop","UserPromptSubmit":"user_prompt_submit","PostToolUse":"post_tool_use","PreToolUse":"pre_tool_use","PreCompact":"pre_compact","SubagentStart":"subagent_start","SubagentStop":"subagent_stop"},"cursor":{"sessionStart":"session_start","sessionEnd":"session_end","stop":"stop","beforeSubmitPrompt":"user_prompt_submit","postToolUse":"post_tool_use","preToolUse":"pre_tool_use","preCompact":"pre_compact"},"cline":{"TaskStart":"session_start","TaskResume":"session_start","TaskComplete":"session_end","TaskCancel":"stop","UserPromptSubmit":"user_prompt_submit","PostToolUse":"post_tool_use","PreToolUse":"pre_tool_use","PreCompact":"pre_compact"},"windsurf":{"pre_user_prompt":"user_prompt_submit","post_cascade_response":"stop","post_setup_worktree":"session_start"},"gemini":{"SessionStart":"session_start","SessionEnd":"session_end","BeforeAgent":"user_prompt_submit","AfterAgent":"stop","BeforeTool":"pre_tool_use","AfterTool":"post_tool_use"}}}}
1
+ {"fingerprint":"5a4e9186:85470","manifest":{"schema_version":1,"concerns":{"chat-history":{"script":"src/scripts/chat_history.ts","args":["hook-dispatch"],"fail_closed":false,"severity":"advisory","needs_payload_bodies":["result"]},"hot-context":{"script":"src/scripts/hot_context_hook.ts","args":[],"fail_closed":false,"severity":"advisory"},"handoff-context":{"script":"src/scripts/handoff_context_hook.ts","args":[],"fail_closed":false,"severity":"advisory"},"roadmap-progress":{"script":"src/scripts/roadmap_progress_hook.ts","args":[],"fail_closed":false,"severity":"advisory","needs_payload_bodies":["input"]},"onboarding-gate":{"script":"src/scripts/onboarding_gate_hook.ts","args":[],"fail_closed":false,"severity":"advisory"},"context-hygiene":{"script":"src/scripts/context_hygiene_hook.ts","args":[],"fail_closed":false,"severity":"advisory"},"verify-before-complete":{"script":"src/scripts/before_complete_hook.ts","args":[],"fail_closed":false,"severity":"advisory","needs_payload_bodies":["input","result"]},"ship-diff-volume":{"script":"src/scripts/hooks/ship_diff_volume_hook.ts","args":[],"fail_closed":false,"severity":"advisory","needs_payload_bodies":["input"]},"minimal-safe-diff":{"script":"src/scripts/minimal_safe_diff_hook.ts","args":[],"fail_closed":false,"severity":"advisory","needs_payload_bodies":["input"]},"injection-scan":{"script":"src/scripts/injection_scan_hook.ts","args":[],"fail_closed":false,"severity":"advisory","needs_payload_bodies":["input","result"]},"block-no-verify":{"script":"src/scripts/hooks/block_no_verify.ts","args":[],"fail_closed":true,"severity":"blocking","needs_payload_bodies":["input"]},"block-kernel-rule-writes":{"script":"src/scripts/hooks/block_kernel_rule_writes.ts","args":[],"fail_closed":true,"severity":"blocking","needs_payload_bodies":["input"]},"one-question-per-ask":{"script":"src/scripts/hooks/one_question_per_ask_hook.ts","args":[],"fail_closed":false,"severity":"blocking","tools":["AskUserQuestion","AskQuestion","UserQuestion","ask_user_question","ask_question","user_question"],"needs_payload_bodies":["input"]},"block-speaking-inbox-dir":{"script":"src/scripts/hooks/block_speaking_inbox_dir.ts","args":[],"fail_closed":false,"severity":"blocking","needs_payload_bodies":["input"]},"block-config-weakening":{"script":"src/scripts/hooks/block_config_weakening.ts","args":[],"fail_closed":false,"severity":"blocking","needs_payload_bodies":["input"]},"rtk-wrap":{"script":"src/scripts/hooks/rtk_wrap_hook.ts","args":[],"fail_closed":false,"severity":"advisory","needs_payload_bodies":["input"]},"design-slop":{"script":"src/scripts/hooks/design_slop_hook.ts","args":[],"fail_closed":false,"severity":"advisory","needs_payload_bodies":["input"]},"design-pass":{"script":"src/scripts/hooks/design_pass_hook.ts","args":[],"fail_closed":false,"severity":"advisory","needs_payload_bodies":["input"]},"design-pass-stop":{"script":"src/scripts/hooks/design_pass_hook.ts","args":["--slot","stop"],"fail_closed":false,"severity":"advisory"},"ui-route-nudge":{"script":"src/scripts/hooks/ui_route_nudge_hook.ts","args":[],"fail_closed":false,"severity":"advisory","needs_payload_bodies":["input"]},"suggestion-capture":{"script":"src/scripts/hooks/suggestion_capture_hook.ts","args":[],"fail_closed":false,"severity":"advisory"},"code-graph-nudge":{"script":"src/scripts/hooks/code_graph_nudge_hook.ts","args":[],"fail_closed":false,"severity":"advisory","tools":["Grep","Glob","Read"],"needs_payload_bodies":["input"]},"memory-learn":{"script":"src/scripts/memory_learn_hook.ts","args":[],"fail_closed":false,"severity":"advisory"},"first-run-gate":{"script":"src/scripts/first_run_gate_hook.ts","args":[],"fail_closed":false,"severity":"advisory"},"profile-staleness":{"script":"src/scripts/profile_staleness_hook.ts","args":[],"fail_closed":false,"severity":"advisory"},"wrapper-freshness":{"script":"src/scripts/wrapper_freshness_hook.ts","args":[],"fail_closed":false,"severity":"advisory"},"surface-probe":{"script":"src/scripts/surface_probe_hook.ts","args":[],"fail_closed":false,"severity":"advisory"},"team-review-gate":{"script":"src/scripts/team_review_gate_hook.ts","args":[],"fail_closed":false,"severity":"advisory"},"pr-url-reminder":{"script":"src/scripts/pr_url_reminder_hook.ts","args":[],"fail_closed":false,"severity":"advisory","needs_payload_bodies":["input","result"]},"push-settle":{"script":"src/scripts/hooks/push_settle_hook.ts","args":[],"fail_closed":false,"severity":"advisory","needs_payload_bodies":["input","result"]},"language-mirror":{"script":"src/scripts/language_mirror_hook.ts","args":[],"fail_closed":false,"severity":"advisory"},"git-authorization":{"script":"src/scripts/git_authorization_hook.ts","args":[],"fail_closed":false,"severity":"advisory"},"evidence-independence":{"script":"src/scripts/hooks/evidence_independence.ts","args":[],"fail_closed":false,"severity":"blocking","needs_payload_bodies":["input"]},"session-canary":{"script":"src/scripts/session_canary_hook.ts","args":[],"fail_closed":false,"severity":"advisory"},"council-availability":{"script":"src/scripts/council_availability_hook.ts","args":[],"fail_closed":false,"severity":"advisory"},"telemetry-disclosure":{"script":"src/scripts/telemetry_disclosure_hook.ts","args":[],"fail_closed":false,"severity":"advisory"},"telemetry-flush":{"script":"src/scripts/hooks/telemetry_flush_hook.ts","args":[],"fail_closed":false,"severity":"advisory"},"self-repair":{"script":"src/scripts/self_repair_hook.ts","args":[],"fail_closed":false,"severity":"advisory"},"session-register":{"script":"src/scripts/session_register_hook.ts","args":[],"fail_closed":false,"severity":"advisory"},"orchestration-record":{"script":"src/scripts/hooks/orchestration_record_hook.ts","args":[],"fail_closed":false,"severity":"advisory","tools":["Agent","Task"],"needs_payload_bodies":["input","result"]},"telemetry-usage":{"script":"src/scripts/hooks/telemetry_usage_hook.ts","args":[],"fail_closed":false,"severity":"advisory","tools":["Skill"],"needs_payload_bodies":["input"]},"delegation-nudge":{"script":"src/scripts/hooks/delegation_nudge_hook.ts","args":[],"fail_closed":false,"severity":"advisory","nudge_rank":1},"skill-route":{"script":"src/scripts/hooks/skill_route_hook.ts","args":[],"fail_closed":false,"severity":"advisory","nudge_rank":2},"rule-inject":{"script":"src/scripts/hooks/rule_inject_hook.ts","args":[],"fail_closed":false,"severity":"advisory","needs_payload_bodies":["input"]},"end-review-nudge":{"script":"src/scripts/hooks/end_review_nudge_hook.ts","args":[],"fail_closed":false,"severity":"advisory","skip_on_refusal_retry":true},"turn-end-gate":{"script":"src/scripts/hooks/turn_end_gate_hook.ts","args":[],"fail_closed":false,"severity":"blocking"},"comment-discipline":{"script":"src/scripts/hooks/comment_discipline_hook.ts","args":[],"fail_closed":false,"severity":"advisory","tools":["Write","Edit"],"needs_payload_bodies":["input"]},"edit-shape":{"script":"src/scripts/hooks/edit_shape_hook.ts","args":[],"fail_closed":false,"severity":"advisory","tools":["Write"],"needs_payload_bodies":["input"]},"reread-guard":{"script":"src/scripts/hooks/reread_guard_hook.ts","args":[],"fail_closed":false,"severity":"advisory","tools":["Read","Edit","Write"],"needs_payload_bodies":["input"]},"session-eol":{"script":"src/scripts/hooks/session_eol_hook.ts","args":[],"fail_closed":false,"severity":"advisory"},"run-continuation":{"script":"src/scripts/hooks/run_continuation_hook.ts","args":[],"fail_closed":false,"severity":"blocking"},"interruption-ledger":{"script":"src/scripts/hooks/interruption_ledger_hook.ts","args":[],"fail_closed":false,"severity":"advisory","skip_on_refusal_retry":true},"subagent-ledger":{"script":"src/scripts/hooks/subagent_ledger_hook.ts","args":[],"fail_closed":false,"severity":"advisory"},"tool-result-bytes":{"script":"src/scripts/hooks/tool_result_bytes_hook.ts","args":[],"fail_closed":false,"severity":"advisory"},"spawn-guard-shadow":{"script":"src/scripts/hooks/spawn_guard_shadow_hook.ts","args":[],"fail_closed":false,"severity":"advisory","tools":["Agent","Task"]},"source-first-gate":{"script":"src/scripts/hooks/source_first_gate_hook.ts","args":[],"fail_closed":false,"severity":"advisory","needs_payload_bodies":["input"]},"journal-record":{"script":"src/scripts/hooks/journal_record_hook.ts","args":[],"fail_closed":false,"severity":"advisory"}},"roles":{"worker":{"drop":["delegation-nudge","skill-route","end-review-nudge","council-availability","team-review-gate","self-repair","session-eol","interruption-ledger"]}},"platforms":{"augment":{"session_start":["chat-history","hot-context","handoff-context","session-canary","council-availability","telemetry-disclosure","first-run-gate","onboarding-gate","verify-before-complete","minimal-safe-diff","profile-staleness","wrapper-freshness","surface-probe","session-register"],"session_end":["chat-history","memory-learn","session-register","roadmap-progress","telemetry-flush"],"stop":["chat-history","hot-context","verify-before-complete","self-repair","session-register","roadmap-progress","design-pass-stop"],"pre_tool_use":["block-no-verify","evidence-independence","block-kernel-rule-writes","block-config-weakening","block-speaking-inbox-dir","rtk-wrap","design-slop","ui-route-nudge","code-graph-nudge","ship-diff-volume","reread-guard"],"post_tool_use":["chat-history","roadmap-progress","context-hygiene","verify-before-complete","minimal-safe-diff","injection-scan","pr-url-reminder","push-settle","orchestration-record","telemetry-usage","tool-result-bytes","edit-shape","comment-discipline","design-pass"]},"claude":{"session_start":["chat-history","hot-context","handoff-context","session-canary","council-availability","telemetry-disclosure","first-run-gate","onboarding-gate","verify-before-complete","minimal-safe-diff","profile-staleness","wrapper-freshness","surface-probe","session-register","journal-record"],"session_end":["chat-history","memory-learn","session-register","roadmap-progress","telemetry-flush","journal-record"],"stop":["chat-history","hot-context","verify-before-complete","team-review-gate","end-review-nudge","turn-end-gate","self-repair","session-register","session-eol","interruption-ledger","roadmap-progress","design-pass-stop","suggestion-capture","journal-record","run-continuation"],"user_prompt_submit":["chat-history","verify-before-complete","minimal-safe-diff","language-mirror","delegation-nudge","skill-route","git-authorization","session-canary","self-repair","session-register","rule-inject","suggestion-capture","journal-record"],"pre_tool_use":["block-no-verify","evidence-independence","block-kernel-rule-writes","block-config-weakening","block-speaking-inbox-dir","one-question-per-ask","rtk-wrap","design-slop","ui-route-nudge","code-graph-nudge","ship-diff-volume","reread-guard","spawn-guard-shadow","source-first-gate","rule-inject"],"post_tool_use":["chat-history","roadmap-progress","context-hygiene","verify-before-complete","minimal-safe-diff","injection-scan","pr-url-reminder","push-settle","orchestration-record","telemetry-usage","tool-result-bytes","edit-shape","comment-discipline","language-mirror","design-pass","journal-record"],"pre_compact":["language-mirror","hot-context","rule-inject","journal-record"],"subagent_start":["subagent-ledger","journal-record"],"subagent_stop":["subagent-ledger","journal-record"]},"cowork":{"session_start":["chat-history","hot-context","handoff-context","session-canary","council-availability","telemetry-disclosure","first-run-gate","onboarding-gate","verify-before-complete","minimal-safe-diff","profile-staleness","wrapper-freshness","surface-probe","session-register"],"session_end":["chat-history","memory-learn","session-register","roadmap-progress","telemetry-flush"],"stop":["chat-history","hot-context","verify-before-complete","self-repair","session-register","roadmap-progress","design-pass-stop"],"user_prompt_submit":["chat-history","verify-before-complete","minimal-safe-diff","language-mirror","git-authorization","session-canary","self-repair","session-register"],"pre_tool_use":["block-no-verify","evidence-independence","block-kernel-rule-writes","block-config-weakening","block-speaking-inbox-dir","rtk-wrap","design-slop","ui-route-nudge","code-graph-nudge","ship-diff-volume","reread-guard","spawn-guard-shadow","source-first-gate"],"post_tool_use":["chat-history","roadmap-progress","context-hygiene","verify-before-complete","minimal-safe-diff","injection-scan","pr-url-reminder","push-settle","orchestration-record","telemetry-usage","tool-result-bytes","edit-shape","comment-discipline","design-pass"],"subagent_start":["subagent-ledger"],"subagent_stop":["subagent-ledger"]},"cursor":{"session_start":["chat-history","hot-context","handoff-context","session-canary","council-availability","telemetry-disclosure","first-run-gate","onboarding-gate","verify-before-complete","minimal-safe-diff","profile-staleness","wrapper-freshness","surface-probe","session-register"],"session_end":["chat-history","memory-learn","session-register","roadmap-progress","telemetry-flush"],"stop":["chat-history","hot-context","verify-before-complete","self-repair","session-register","roadmap-progress","design-pass-stop"],"user_prompt_submit":["chat-history","verify-before-complete","minimal-safe-diff","language-mirror","git-authorization","session-canary","self-repair","session-register"],"post_tool_use":["chat-history","roadmap-progress","context-hygiene","verify-before-complete","minimal-safe-diff","injection-scan","pr-url-reminder","push-settle","orchestration-record","telemetry-usage","tool-result-bytes","edit-shape","comment-discipline","design-pass"]},"cline":{"session_start":["chat-history","hot-context","handoff-context","session-canary","council-availability","telemetry-disclosure","first-run-gate","onboarding-gate","verify-before-complete","minimal-safe-diff","profile-staleness","wrapper-freshness","surface-probe","session-register"],"session_end":["chat-history","memory-learn","session-register","roadmap-progress","telemetry-flush"],"stop":["chat-history","hot-context","verify-before-complete","self-repair","session-register","roadmap-progress","design-pass-stop"],"user_prompt_submit":["chat-history","verify-before-complete","minimal-safe-diff","language-mirror","git-authorization","session-canary","self-repair","session-register"],"post_tool_use":["chat-history","roadmap-progress","context-hygiene","verify-before-complete","minimal-safe-diff","injection-scan","pr-url-reminder","push-settle","orchestration-record","telemetry-usage","tool-result-bytes","edit-shape","comment-discipline","design-pass"]},"windsurf":{"session_start":["chat-history","hot-context","handoff-context","session-canary","council-availability","telemetry-disclosure","first-run-gate","onboarding-gate","verify-before-complete","profile-staleness","wrapper-freshness","surface-probe","session-register"],"stop":["chat-history","hot-context","verify-before-complete","self-repair","session-register","design-pass-stop"],"user_prompt_submit":["chat-history","verify-before-complete","language-mirror","git-authorization","session-canary","self-repair","session-register"]},"gemini":{"session_start":["chat-history","hot-context","handoff-context","session-canary","council-availability","telemetry-disclosure","first-run-gate","onboarding-gate","verify-before-complete","minimal-safe-diff","profile-staleness","wrapper-freshness","surface-probe","session-register"],"session_end":["chat-history","memory-learn","session-register","roadmap-progress","telemetry-flush"],"stop":["chat-history","hot-context","verify-before-complete","self-repair","session-register","roadmap-progress","design-pass-stop"],"user_prompt_submit":["chat-history","verify-before-complete","minimal-safe-diff","language-mirror","git-authorization","session-canary","self-repair","session-register"],"post_tool_use":["chat-history","roadmap-progress","context-hygiene","verify-before-complete","minimal-safe-diff","injection-scan","pr-url-reminder","push-settle","orchestration-record","telemetry-usage","tool-result-bytes","edit-shape","comment-discipline","design-pass"]},"copilot":{"fallback_only":true}},"native_event_aliases":{"augment":{"SessionStart":"session_start","SessionEnd":"session_end","Stop":"stop","PostToolUse":"post_tool_use","PreToolUse":"pre_tool_use"},"claude":{"SessionStart":"session_start","SessionEnd":"session_end","Stop":"stop","UserPromptSubmit":"user_prompt_submit","PostToolUse":"post_tool_use","PreToolUse":"pre_tool_use","PreCompact":"pre_compact","SubagentStart":"subagent_start","SubagentStop":"subagent_stop"},"cowork":{"SessionStart":"session_start","SessionEnd":"session_end","Stop":"stop","UserPromptSubmit":"user_prompt_submit","PostToolUse":"post_tool_use","PreToolUse":"pre_tool_use","PreCompact":"pre_compact","SubagentStart":"subagent_start","SubagentStop":"subagent_stop"},"cursor":{"sessionStart":"session_start","sessionEnd":"session_end","stop":"stop","beforeSubmitPrompt":"user_prompt_submit","postToolUse":"post_tool_use","preToolUse":"pre_tool_use","preCompact":"pre_compact"},"cline":{"TaskStart":"session_start","TaskResume":"session_start","TaskComplete":"session_end","TaskCancel":"stop","UserPromptSubmit":"user_prompt_submit","PostToolUse":"post_tool_use","PreToolUse":"pre_tool_use","PreCompact":"pre_compact"},"windsurf":{"pre_user_prompt":"user_prompt_submit","post_cascade_response":"stop","post_setup_worktree":"session_start"},"gemini":{"SessionStart":"session_start","SessionEnd":"session_end","BeforeAgent":"user_prompt_submit","AfterAgent":"stop","BeforeTool":"pre_tool_use","AfterTool":"post_tool_use"}}}}
@@ -187,6 +187,36 @@ concerns:
187
187
  fail_closed: true
188
188
  severity: blocking
189
189
  needs_payload_bodies: [input]
190
+ # road-to-asked-not-parked Phase 5.1 — one question per structured-ask call.
191
+ # PreToolUse guard: DENIES a call to a host's native question picker whose
192
+ # payload carries more than one question. `ask-when-uncertain`'s Iron Law is
193
+ # one question per turn and `user-interaction` narrows "one" to one decision
194
+ # point; a picker makes N-in-one cheap, and the user then answers a form
195
+ # instead of a question. Denies with a reason rather than truncating to the
196
+ # first question — a truncation hides the decisions that were dropped.
197
+ #
198
+ # fail_closed: false, DELIBERATELY, and the direction is the opposite of
199
+ # block-no-verify's. There the guard must not become the bypass. Here a
200
+ # parse failure means an unrecognised picker shape, and blocking what it
201
+ # cannot read would turn an unknown payload into a wedged session for a
202
+ # SHAPE defect, not a safety one. The hook allows what it cannot parse and
203
+ # says so in its own header.
204
+ #
205
+ # It fires on nothing today, and that is the honest state rather than a
206
+ # defect: `_lib/structured_ask.ts` carries no OBSERVED per-host picker, so
207
+ # the `tools:` filter below lists the candidate NAMES that library matches —
208
+ # it is a narrowing filter, never a claim that any host emits one of them.
209
+ # Bound on `claude` only: it is the one platform that both binds
210
+ # pre_tool_use and honours a deny (hook-architecture-v1.md § Which hosts
211
+ # carry pre_tool_use), and a deny bound where the verdict is discarded would
212
+ # be dead weight wearing a guard's name.
213
+ one-question-per-ask:
214
+ script: src/scripts/hooks/one_question_per_ask_hook.ts
215
+ args: []
216
+ fail_closed: false
217
+ severity: blocking
218
+ tools: [AskUserQuestion, AskQuestion, UserQuestion, ask_user_question, ask_question, user_question]
219
+ needs_payload_bodies: [input]
190
220
  # road-to-source-silence Phase 4.2 — the write-time half of source
191
221
  # confidentiality. Every other gate in that programme catches the QUOTE of a
192
222
  # speaking inbox directory name; this catches the NAME, at the only moment
@@ -1189,7 +1219,7 @@ platforms:
1189
1219
  session_end: [chat-history, memory-learn, session-register, roadmap-progress, telemetry-flush, journal-record]
1190
1220
  stop: [chat-history, hot-context, verify-before-complete, team-review-gate, end-review-nudge, turn-end-gate, self-repair, session-register, session-eol, interruption-ledger, roadmap-progress, design-pass-stop, suggestion-capture, journal-record, run-continuation]
1191
1221
  user_prompt_submit: [chat-history, verify-before-complete, minimal-safe-diff, language-mirror, delegation-nudge, skill-route, git-authorization, session-canary, self-repair, session-register, rule-inject, suggestion-capture, journal-record]
1192
- pre_tool_use: [block-no-verify, evidence-independence, block-kernel-rule-writes, block-config-weakening, block-speaking-inbox-dir, rtk-wrap, design-slop, ui-route-nudge, code-graph-nudge, ship-diff-volume, reread-guard, spawn-guard-shadow, source-first-gate, rule-inject]
1222
+ pre_tool_use: [block-no-verify, evidence-independence, block-kernel-rule-writes, block-config-weakening, block-speaking-inbox-dir, one-question-per-ask, rtk-wrap, design-slop, ui-route-nudge, code-graph-nudge, ship-diff-volume, reread-guard, spawn-guard-shadow, source-first-gate, rule-inject]
1193
1223
  post_tool_use: [chat-history, roadmap-progress, context-hygiene, verify-before-complete, minimal-safe-diff, injection-scan, pr-url-reminder, push-settle, orchestration-record, telemetry-usage, tool-result-bytes, edit-shape, comment-discipline, language-mirror, design-pass, journal-record]
1194
1224
  # `language-mirror` — round-5 § 6.1. `pre_compact` sets a pin-lost marker;
1195
1225
  # the `post_tool_use` entry above re-emits the pin exactly once while that
@@ -54,6 +54,7 @@ import { main as blockNoVerifyMain } from './block_no_verify.js';
54
54
  import { main as blockKernelRuleWritesMain } from './block_kernel_rule_writes.js';
55
55
  import { main as blockConfigWeakeningMain } from './block_config_weakening.js';
56
56
  import { main as blockSpeakingInboxDirMain } from './block_speaking_inbox_dir.js';
57
+ import { main as oneQuestionPerAskMain } from './one_question_per_ask_hook.js';
57
58
  import { main as rtkWrapMain } from './rtk_wrap_hook.js';
58
59
  import { _main as designPassMain } from './design_pass_hook.js';
59
60
  import { main as designSlopMain } from './design_slop_hook.js';
@@ -115,6 +116,7 @@ export const CONCERN_REGISTRY: Readonly<Record<string, ConcernMain>> = {
115
116
  'src/scripts/hooks/block_kernel_rule_writes.ts': blockKernelRuleWritesMain as ConcernMain,
116
117
  'src/scripts/hooks/block_config_weakening.ts': blockConfigWeakeningMain as ConcernMain,
117
118
  'src/scripts/hooks/block_speaking_inbox_dir.ts': blockSpeakingInboxDirMain as ConcernMain,
119
+ 'src/scripts/hooks/one_question_per_ask_hook.ts': oneQuestionPerAskMain as ConcernMain,
118
120
  'src/scripts/hooks/rtk_wrap_hook.ts': rtkWrapMain as ConcernMain,
119
121
  'src/scripts/hooks/design_pass_hook.ts': designPassMain as ConcernMain,
120
122
  'src/scripts/hooks/design_slop_hook.ts': designSlopMain as ConcernMain,
@@ -375,6 +375,33 @@ export function buildNudgeLine(
375
375
  `${classification.reason}.</delegation-nudge>`
376
376
  );
377
377
  }
378
+ // Rung 4 (1.3): a contested-judgment verdict names the council's own entry
379
+ // point. The carrier NEVER runs it — `council_cli run` spends a metered or
380
+ // subscription seat, which is Hard-Floor reserved and is never inferred from
381
+ // a hook line.
382
+ if (rung === 4) {
383
+ return (
384
+ `<delegation-nudge>rung-4: council. This is contested judgment, not a ` +
385
+ `slice to dispatch — route it to the council yourself via ` +
386
+ "`./scripts-run src/scripts/council_cli run --input <file>` " +
387
+ "(check reachability first with `agent-config council:status`; the file " +
388
+ `path is the input, never an inline question). Not a spawn, and not run ` +
389
+ `for you — ${classification.reason}.</delegation-nudge>`
390
+ );
391
+ }
392
+ // Rung 3 (1.3): slices that must communicate DURING the run. The pointer
393
+ // names the host teams primitive; the fallback when the host has none is the
394
+ // same one-completion path rung 0.5 cites.
395
+ if (rung === 3) {
396
+ return (
397
+ `<delegation-nudge>rung-3: team. These slices must see each other's state ` +
398
+ `during the run, so a set of independent subagent spawns cannot express ` +
399
+ `it — use the host teams primitive, or fall back to ` +
400
+ "`./scripts-run src/scripts/ask_transport \"<question>\"` for a bounded " +
401
+ `sub-question. Not a spawn, and not run for you — ` +
402
+ `${classification.reason}.</delegation-nudge>`
403
+ );
404
+ }
378
405
  // Rung 1 (single bounded slice) carries no do-in-steps/do-in-parallel
379
406
  // mode of its own — `classification.mode` is `null` for that shape.
380
407
  const modeLabel = classification.mode ?? "single-slice";
@@ -437,8 +464,25 @@ export function classifyPrompt(
437
464
  // surfaces. Silence here also guarantees a question-shaped prompt can
438
465
  // never produce a spawn nudge ("the carrier stops nudging full spawns
439
466
  // for question-shaped slices").
467
+ // Rung 3/4: these used to be discarded by the same `verdict !== "subagent"`
468
+ // return as rung 0/0.5, so a RESOLVED council verdict produced no output on
469
+ // the only runtime carrier.
470
+ //
471
+ // What they emit is a POINTER, and every field here is chosen so it cannot
472
+ // read as a spawn authorisation: `delegable` stays false, the action stays
473
+ // `ask` (the existing token for "a verdict, never a speculative spawn"),
474
+ // the slice count is 0, and buildNudgeLine's rung-3/4 branch names an
475
+ // entry point rather than a dispatch.
476
+ if (ladder.verdict === "team" || ladder.verdict === "council") {
477
+ return {
478
+ classification: { delegable: false, action: "ask", mode: null, reason: ladder.reason },
479
+ sliceCount: 0,
480
+ tier: recommendSliceTier(downshift, separate_quota_pool),
481
+ rung: ladder.rung,
482
+ };
483
+ }
440
484
  if (ladder.verdict !== "subagent") {
441
- return null; // rung-0 script, rung-0.5 ask-transport, rung-3/4 team/council, or ∅ user-ask/in-session
485
+ return null; // rung-0 script, rung-0.5 ask-transport, or ∅ user-ask/in-session
442
486
  }
443
487
  const tier = recommendSliceTier(downshift, separate_quota_pool);
444
488
  // Rung 1 (single bounded slice) has no explicit slice count of its own —
@@ -0,0 +1,191 @@
1
+ #!/usr/bin/env tsx
2
+ /**
3
+ * PreToolUse guard: one question per structured-ask call.
4
+ *
5
+ * road-to-asked-not-parked 5.1. `ask-when-uncertain`'s Iron Law is one
6
+ * question per turn, and `user-interaction` § question pacing narrows what
7
+ * "one" means: one decision point, answerable with one reply. A host's native
8
+ * question picker makes it cheap to violate that — a payload can carry N
9
+ * questions in one call, and the user then answers a form instead of a
10
+ * question.
11
+ *
12
+ * DENY, NEVER TRUNCATE. Silently keeping the first question and dropping the
13
+ * rest would hide exactly the decisions the user was owed; the deny message
14
+ * names the count so the caller can split the ask instead of guessing what
15
+ * happened.
16
+ *
17
+ * WHAT IT SEES, honestly. `_lib/structured_ask.ts` carries no observed
18
+ * per-host tool, so this guard matches on a name SHAPE and is filtered by the
19
+ * manifest's per-concern `tools:` key to the same candidate names. On every
20
+ * host measured today it therefore fires on nothing — the concern exists so
21
+ * that the first host to ship a picker meets the rule already in force, not
22
+ * because a violation has been observed.
23
+ *
24
+ * ENFORCEMENT REACH, also honestly. `fail_closed: false` and the exit-1 deny
25
+ * are only a deny where the host both binds `pre_tool_use` AND honours the
26
+ * dispatcher's verdict. `hook-architecture-v1.md` § Which hosts carry
27
+ * pre_tool_use is the table; `agent-config hooks:status` answers it for the
28
+ * host actually running. This file claims no more than that.
29
+ *
30
+ * A payload whose shape is not recognised at all (`countStructuredAskQuestions`
31
+ * returns -1) is ALLOWED. A guard that blocks what it cannot parse would turn
32
+ * an unknown picker shape into a wedged session, and the failure it guards
33
+ * against — too many questions — is a shape defect, not a safety one.
34
+ *
35
+ * Exit codes (docs/contracts/hook-architecture-v1.md):
36
+ * 0 — allow
37
+ * 1 — block (the call carries more than one question)
38
+ */
39
+ import { fileURLToPath, pathToFileURL } from 'node:url';
40
+
41
+ import { countStructuredAskQuestions, isStructuredAskTool } from '../_lib/structured_ask.js';
42
+ import { readHookStdin } from './hook_stdin.js';
43
+
44
+ const _HERE = fileURLToPath(import.meta.url);
45
+
46
+ type JsonObject = Record<string, unknown>;
47
+
48
+ function _isObject(v: unknown): v is JsonObject {
49
+ return typeof v === 'object' && v !== null && !Array.isArray(v);
50
+ }
51
+
52
+ export interface AskCall {
53
+ readonly tool: string;
54
+ readonly questions: number;
55
+ }
56
+
57
+ /** Read (tool name, question count) off a PreToolUse envelope. */
58
+ export function extractAskCall(envelope: JsonObject): AskCall {
59
+ const payload = _isObject(envelope['payload']) ? envelope['payload'] : envelope;
60
+ const nameVal =
61
+ payload['tool_name'] ??
62
+ payload['toolName'] ??
63
+ payload['tool'] ??
64
+ envelope['tool_name'] ??
65
+ envelope['tool'];
66
+ const tool = typeof nameVal === 'string' ? nameVal : '';
67
+ const ti = _isObject(payload['tool_input'])
68
+ ? payload['tool_input']
69
+ : _isObject(envelope['tool_input'])
70
+ ? envelope['tool_input']
71
+ : null;
72
+ return { tool, questions: ti === null ? -1 : countStructuredAskQuestions(ti) };
73
+ }
74
+
75
+ /** The verdict, separated from I/O so the fixtures exercise the decision itself. */
76
+ export function verdict(call: AskCall): { block: boolean; reason: string } {
77
+ if (call.tool === '' || !isStructuredAskTool(call.tool)) {
78
+ return { block: false, reason: 'not a structured-ask call' };
79
+ }
80
+ if (call.questions < 0) {
81
+ return { block: false, reason: 'payload shape not recognised — allowed, never guessed' };
82
+ }
83
+ if (call.questions <= 1) {
84
+ return { block: false, reason: 'one question' };
85
+ }
86
+ return {
87
+ block: true,
88
+ reason:
89
+ `${call.tool} carries ${String(call.questions)} questions in one call. ` +
90
+ 'One decision per ask: put the first question, wait for the answer, then ' +
91
+ 'the next. The call is denied rather than truncated — dropping the extra ' +
92
+ 'questions would hide the decisions the user is owed.',
93
+ };
94
+ }
95
+
96
+ export function main(argv?: string[]): number {
97
+ const args = argv ?? process.argv.slice(2);
98
+ for (const a of args) {
99
+ if (a === '--self-test') {
100
+ return selfTest();
101
+ }
102
+ }
103
+ const raw = readHookStdin();
104
+ if (!raw.trim()) {
105
+ return 0;
106
+ }
107
+ let envelope: JsonObject;
108
+ try {
109
+ const parsed: unknown = JSON.parse(raw);
110
+ envelope = _isObject(parsed) ? parsed : {};
111
+ } catch {
112
+ return 0;
113
+ }
114
+ const v = verdict(extractAskCall(envelope));
115
+ if (v.block) {
116
+ process.stderr.write(`one-question-per-ask: BLOCKED — ${v.reason}\n`);
117
+ return 1;
118
+ }
119
+ return 0;
120
+ }
121
+
122
+ export function selfTest(): number {
123
+ const cases: Array<[string, JsonObject, boolean]> = [
124
+ [
125
+ 'two questions in one call is denied',
126
+ { tool_name: 'AskUserQuestion', tool_input: { questions: [{}, {}] } },
127
+ true,
128
+ ],
129
+ [
130
+ 'four questions is denied',
131
+ { tool_name: 'AskUserQuestion', tool_input: { questions: [{}, {}, {}, {}] } },
132
+ true,
133
+ ],
134
+ [
135
+ 'one question passes',
136
+ { tool_name: 'AskUserQuestion', tool_input: { questions: [{}] } },
137
+ false,
138
+ ],
139
+ [
140
+ 'a single-question field passes',
141
+ { tool_name: 'ask_user_question', tool_input: { question: 'which one?' } },
142
+ false,
143
+ ],
144
+ [
145
+ 'an empty ask passes — malformed, but not this guard\'s failure',
146
+ { tool_name: 'AskUserQuestion', tool_input: { questions: [] } },
147
+ false,
148
+ ],
149
+ [
150
+ 'an unrecognised payload shape passes rather than wedging the session',
151
+ { tool_name: 'AskUserQuestion', tool_input: { something: 'else' } },
152
+ false,
153
+ ],
154
+ ['an ordinary tool is never seen', { tool_name: 'Bash', tool_input: { command: 'ls' } }, false],
155
+ [
156
+ 'a Write with two questions in its body is not an ask call',
157
+ { tool_name: 'Write', tool_input: { questions: [{}, {}] } },
158
+ false,
159
+ ],
160
+ ['an empty envelope passes', {}, false],
161
+ ];
162
+ let failed = 0;
163
+ for (const [name, envelope, want] of cases) {
164
+ const got = verdict(extractAskCall(envelope)).block;
165
+ const ok = got === want;
166
+ process.stdout.write(
167
+ `${ok ? '✅' : '❌'} ${name} — block=${String(got)}` +
168
+ (ok ? '\n' : ` (wanted ${String(want)})\n`),
169
+ );
170
+ if (!ok) failed += 1;
171
+ }
172
+ const positives = cases.filter((c) => c[2]).length;
173
+ if (positives < 2) {
174
+ process.stderr.write(
175
+ '❌ one_question_per_ask --self-test: fewer than 2 deny cases — a guard never ' +
176
+ 'seen refuse has unknown sensitivity.\n',
177
+ );
178
+ return 1;
179
+ }
180
+ process.stdout.write(
181
+ `\none_question_per_ask --self-test: ${String(cases.length - failed)}/${String(cases.length)} ` +
182
+ `case(s) behaved (${String(positives)} deny, ${String(cases.length - positives)} allow)\n`,
183
+ );
184
+ return failed > 0 ? 1 : 0;
185
+ }
186
+
187
+ if (process.argv[1] !== undefined && import.meta.url === pathToFileURL(process.argv[1]).href) {
188
+ process.exit(main());
189
+ }
190
+
191
+ export { _HERE };
@@ -152,6 +152,58 @@ elif ! ./scripts-run src/scripts/check_branch_freshness --quiet; then
152
152
  exit 1
153
153
  fi
154
154
 
155
+ # BRANCH WORK COMMITTED — after base freshness, before everything else.
156
+ #
157
+ # Ordering is deliberate in BOTH directions. It runs AFTER base freshness
158
+ # because the remedy there (`task push-ready`) merges, and a merge changes the
159
+ # working tree this gate reads — checking first would answer against a tree the
160
+ # operator is about to replace. It runs BEFORE the remaining gates because they
161
+ # all answer against the working tree, and a tree carrying unfinished work
162
+ # makes their verdicts describe something that is not being pushed.
163
+ #
164
+ # Measured twice, and both placements were wrong for a different reason.
165
+ # Placing it FIRST reded tests/scripts/prepush_base_freshness.test.ts, which
166
+ # executes the whole hook and asserts the freshness block is reached. Placing
167
+ # it between the next block's comment header and that block's `echo` reded
168
+ # check_installed_hooks_fresh's advisory pin, whose extraction runs from that
169
+ # header to the following task-availability check and so swallowed this block's
170
+ # `exit 1`. A block goes BEFORE a neighbour's comment header, never between the
171
+ # header and its code.
172
+ #
173
+ # And this paragraph may NOT name that header literally: the pin locates it with
174
+ # a plain indexOf over the rendered hook, so a comment quoting the string
175
+ # becomes the first match and truncates the block to nothing. An anchor that is
176
+ # also content is not an anchor — spelled out here because the obvious edit to
177
+ # this comment is to put the string back in for clarity.
178
+ #
179
+ # The defect it exists for, measured 2026-09-07: a reconciled baseline was
180
+ # written into gate-violation-baselines.json AFTER `git add`, so
181
+ # `git commit --no-edit` captured the staged side, the edit stayed in the tree,
182
+ # and the push shipped a branch whose commits contradicted it. CI cannot see
183
+ # this class at all — it checks out the commit, not the tree the edit is in.
184
+ #
185
+ # It blocks only what it can attribute to THIS branch (staged paths, and dirty
186
+ # paths this branch's own commits touch). A gate script's report output and a
187
+ # parallel session's edit are named and waved through, which is what keeps this
188
+ # from becoming the blanket clean-tree rule that would train the operator to
189
+ # set the skip variable.
190
+ echo "🔍 Branch work committed — is any of this branch's own work still uncommitted?"
191
+ if [ "${AGENT_CONFIG_SKIP_PREPUSH_WORKTREE:-}" = "1" ]; then
192
+ echo "⏭️ skipped via AGENT_CONFIG_SKIP_PREPUSH_WORKTREE=1"
193
+ elif [ ! -x ./scripts-run ]; then
194
+ echo "⚠️ ./scripts-run not found — skipping the worktree check for this push."
195
+ elif ! ./scripts-run src/scripts/check_branch_work_committed --quiet; then
196
+ echo ""
197
+ echo " Push blocked — this branch's own work is not all committed, so the"
198
+ echo " pushed branch would carry commits its own tree contradicts."
199
+ echo ""
200
+ echo " Commit them, or 'git restore' whatever was not meant to land."
201
+ echo ""
202
+ echo " This hook refuses; it never commits for you. Bypass a genuine WIP"
203
+ echo " push with AGENT_CONFIG_SKIP_PREPUSH_WORKTREE=1."
204
+ exit 1
205
+ fi
206
+
155
207
  # INSTALLED-HOOK FRESHNESS — ADVISORY, and deliberately AFTER base freshness.
156
208
  #
157
209
  # What it answers: are the hooks in .git/hooks still what THIS checkout's
@@ -14,6 +14,19 @@
14
14
  * (`- **Run:**`). A gate that claims to be executable without naming the
15
15
  * command is the same defect as a decision with no option set: it reads
16
16
  * as actionable and is not.
17
+ * 4. An annotation pointing at a USER-DECISION blocker (one whose `Owner:`
18
+ * is the maintainer, the user, or the owner) carries an `asked:` field
19
+ * recording whether the question was put and, when it was not, why —
20
+ * `<!-- blocked-by: <id> | asked: no — <reason> -->`. A decision only the
21
+ * user can make, filed in a roadmap without ever being put, is the defect
22
+ * road-to-asked-not-parked exists to stop; without this field a marker
23
+ * cannot distinguish a declined decision from an unoffered one.
24
+ *
25
+ * HARD, not ratcheted, and it can be: no active roadmap carries a real
26
+ * checkbox annotation today, so on the day it ships the rule fires on
27
+ * nothing — the same "no backlog to grandfather" argument the `Class:`
28
+ * contract above makes. `later/` and `archive/` are outside this gate's
29
+ * glob and are untouched by it.
17
30
  *
18
31
  * Fenced code blocks are stripped before scanning so a roadmap that shows
19
32
  * the `## Blockers` shape as a documentation example is not flagged.
@@ -42,7 +55,19 @@ const BLOCKER_HEADING_RE = /^###[ \t]+blocker:[ \t]*(.+?)[ \t]*$/gim;
42
55
  // wrapped continuation line or inline-code documentation example of the
43
56
  // syntax (as this very lint script's own roadmap step describes it) must
44
57
  // not be mistaken for a live cross-reference.
45
- const BLOCKED_BY_LINE_RE = /^-[ \t]*\[[ xX~-]\].*<!--[ \t]*blocked-by:[ \t]*([a-z0-9-]+)[ \t]*-->/i;
58
+ const BLOCKED_BY_LINE_RE =
59
+ /^-[ \t]*\[[ xX~-]\].*<!--[ \t]*blocked-by:[ \t]*([a-z0-9-]+)[ \t]*(?:\|[ \t]*asked:[ \t]*(yes|no)[ \t]*(?:[\u2014-][ \t]*([^>]*?))?[ \t]*)?-->/i;
60
+
61
+ /**
62
+ * The owners whose blockers are the USER-DECISION class.
63
+ *
64
+ * Read off `Owner:` rather than guessed from prose: `terminal-states.md`
65
+ * defines `blocked` to include "a decision only the user can make", and the
66
+ * owner field is the only place a roadmap says which blockers those are.
67
+ * `council`, `implementer` and `agent` are deliberately outside the class —
68
+ * those are not decisions the user is waiting to be asked.
69
+ */
70
+ const USER_DECISION_OWNER_RE = /^-[ \t]*\*\*Owner:\*\*[ \t]*(maintainer|user|owner)\b/im;
46
71
 
47
72
  const REQUIRED_FIELDS: ReadonlyArray<readonly [string, RegExp]> = [
48
73
  ['Status', /^-[ \t]*\*\*Status:\*\*/im],
@@ -154,6 +179,7 @@ function _scanBoth(rawText: string): ScanResult {
154
179
  const decidability: Violation[] = [];
155
180
  const text = _stripFencedCode(rawText);
156
181
  const declaredIds = new Set<string>();
182
+ const userDecisionIds = new Set<string>();
157
183
 
158
184
  const sectionMatch = BLOCKERS_SECTION_RE.exec(text);
159
185
  if (sectionMatch) {
@@ -181,6 +207,9 @@ function _scanBoth(rawText: string): ScanResult {
181
207
  declaredIds.add(cur.id);
182
208
  const bodyEnd = i + 1 < heads.length ? (heads[i + 1] as { start: number }).start : section.length;
183
209
  const body = section.slice(cur.end, bodyEnd);
210
+ if (USER_DECISION_OWNER_RE.test(body)) {
211
+ userDecisionIds.add(cur.id);
212
+ }
184
213
  const missing = REQUIRED_FIELDS.filter(([, re]) => !re.test(body)).map(([name]) => name);
185
214
  if (missing.length) {
186
215
  violations.push({
@@ -256,6 +285,27 @@ function _scanBoth(rawText: string): ScanResult {
256
285
  `(no matching '### blocker: ${id}' in this file)`,
257
286
  });
258
287
  }
288
+ if (userDecisionIds.has(id)) {
289
+ const asked = m[2] === undefined ? null : (m[2] as string).toLowerCase();
290
+ const reason = ((m[3] as string | undefined) ?? '').trim();
291
+ if (asked === null) {
292
+ violations.push({
293
+ line: i + 1,
294
+ message:
295
+ `blocked-by '${id}' is a user-decision blocker and carries no ` +
296
+ 'asked: field — write `| asked: yes` when the question was put, ' +
297
+ 'or `| asked: no — <reason>` when it was not',
298
+ });
299
+ } else if (asked === 'no' && reason === '') {
300
+ violations.push({
301
+ line: i + 1,
302
+ message:
303
+ `blocked-by '${id}' says asked: no with no reason — a marker that ` +
304
+ 'does not say why the question was never put is the parking lot ' +
305
+ 'this field exists to end',
306
+ });
307
+ }
308
+ }
259
309
  }
260
310
  violations.sort((a, b) => a.line - b.line);
261
311
  decidability.sort((a, b) => a.line - b.line);
@@ -73,7 +73,7 @@ export const ELIGIBLE: Record<string, [string, string]> = {
73
73
  'audit my agent docs, check the state of the agents/ directory',
74
74
  'stale files under agents/ or recent edits to .augment/ without doc updates',
75
75
  ],
76
- 'analyze-reference-repo': [
76
+ 'analyze-repo': [
77
77
  "look at how X does this, compare with that other repo, study this competitor's approach",
78
78
  'external repo URL or path mentioned in the prompt',
79
79
  ],