@event4u/agent-config 1.16.0 → 1.18.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 (224) hide show
  1. package/.agent-src/commands/{agents-audit.md → agents/audit.md} +4 -3
  2. package/.agent-src/commands/{agents-cleanup.md → agents/cleanup.md} +12 -6
  3. package/.agent-src/commands/{agents-prepare.md → agents/prepare.md} +4 -3
  4. package/.agent-src/commands/agents.md +46 -0
  5. package/.agent-src/commands/{chat-history-checkpoint.md → chat-history/checkpoint.md} +4 -4
  6. package/.agent-src/commands/{chat-history-clear.md → chat-history/clear.md} +4 -4
  7. package/.agent-src/commands/{chat-history-resume.md → chat-history/resume.md} +4 -4
  8. package/.agent-src/commands/chat-history/show.md +107 -0
  9. package/.agent-src/commands/chat-history.md +33 -89
  10. package/.agent-src/commands/{commit-in-chunks.md → commit/in-chunks.md} +15 -13
  11. package/.agent-src/commands/commit.md +22 -2
  12. package/.agent-src/commands/{context-create.md → context/create.md} +4 -3
  13. package/.agent-src/commands/{context-refactor.md → context/refactor.md} +4 -3
  14. package/.agent-src/commands/context.md +44 -0
  15. package/.agent-src/commands/{copilot-agents-init.md → copilot-agents/init.md} +4 -3
  16. package/.agent-src/commands/{copilot-agents-optimize.md → copilot-agents/optimize.md} +4 -3
  17. package/.agent-src/commands/copilot-agents.md +44 -0
  18. package/.agent-src/commands/council/default.md +221 -0
  19. package/.agent-src/commands/{council-design.md → council/design.md} +6 -5
  20. package/.agent-src/commands/{council-optimize.md → council/optimize.md} +7 -6
  21. package/.agent-src/commands/{council-pr.md → council/pr.md} +6 -5
  22. package/.agent-src/commands/council.md +47 -212
  23. package/.agent-src/commands/{create-pr-description.md → create-pr/description-only.md} +4 -2
  24. package/.agent-src/commands/create-pr.md +26 -5
  25. package/.agent-src/commands/{feature-dev.md → feature/dev.md} +5 -10
  26. package/.agent-src/commands/{feature-explore.md → feature/explore.md} +4 -8
  27. package/.agent-src/commands/{feature-plan.md → feature/plan.md} +4 -8
  28. package/.agent-src/commands/{feature-refactor.md → feature/refactor.md} +4 -8
  29. package/.agent-src/commands/{feature-roadmap.md → feature/roadmap.md} +6 -10
  30. package/.agent-src/commands/feature.md +6 -12
  31. package/.agent-src/commands/{fix-ci.md → fix/ci.md} +4 -8
  32. package/.agent-src/commands/{fix-portability.md → fix/portability.md} +4 -8
  33. package/.agent-src/commands/{fix-pr-bot-comments.md → fix/pr-bots.md} +4 -8
  34. package/.agent-src/commands/{fix-pr-developer-comments.md → fix/pr-developers.md} +4 -8
  35. package/.agent-src/commands/{fix-pr-comments.md → fix/pr.md} +7 -11
  36. package/.agent-src/commands/{fix-references.md → fix/refs.md} +4 -8
  37. package/.agent-src/commands/{fix-seeder.md → fix/seeder.md} +4 -8
  38. package/.agent-src/commands/fix.md +7 -13
  39. package/.agent-src/commands/{do-and-judge.md → judge/on-diff.md} +4 -3
  40. package/.agent-src/commands/judge/solo.md +90 -0
  41. package/.agent-src/commands/{do-in-steps.md → judge/steps.md} +4 -3
  42. package/.agent-src/commands/judge.md +35 -70
  43. package/.agent-src/commands/{memory-add.md → memory/add.md} +4 -3
  44. package/.agent-src/commands/{memory-full.md → memory/load.md} +4 -3
  45. package/.agent-src/commands/{memory-promote.md → memory/promote.md} +4 -3
  46. package/.agent-src/commands/{propose-memory.md → memory/propose.md} +4 -3
  47. package/.agent-src/commands/memory.md +48 -0
  48. package/.agent-src/commands/{module-create.md → module/create.md} +4 -3
  49. package/.agent-src/commands/{module-explore.md → module/explore.md} +4 -3
  50. package/.agent-src/commands/module.md +44 -0
  51. package/.agent-src/commands/{optimize-agents.md → optimize/agents.md} +4 -8
  52. package/.agent-src/commands/{optimize-augmentignore.md → optimize/augmentignore.md} +4 -9
  53. package/.agent-src/commands/{optimize-rtk-filters.md → optimize/rtk.md} +4 -8
  54. package/.agent-src/commands/{optimize-skills.md → optimize/skills.md} +4 -8
  55. package/.agent-src/commands/optimize.md +4 -10
  56. package/.agent-src/commands/{override-create.md → override/create.md} +4 -3
  57. package/.agent-src/commands/{override-manage.md → override/manage.md} +4 -3
  58. package/.agent-src/commands/override.md +44 -0
  59. package/.agent-src/commands/{roadmap-create.md → roadmap/create.md} +4 -3
  60. package/.agent-src/commands/{roadmap-execute.md → roadmap/execute.md} +4 -3
  61. package/.agent-src/commands/roadmap.md +44 -0
  62. package/.agent-src/commands/{tests-create.md → tests/create.md} +4 -3
  63. package/.agent-src/commands/{tests-execute.md → tests/execute.md} +4 -3
  64. package/.agent-src/commands/tests.md +44 -0
  65. package/.agent-src/contexts/communication/rules-auto/artifact-engagement-recording-mechanics.md +72 -0
  66. package/.agent-src/contexts/communication/rules-auto/augment-portability-mechanics.md +79 -0
  67. package/.agent-src/contexts/communication/rules-auto/augment-source-of-truth-mechanics.md +98 -0
  68. package/.agent-src/contexts/communication/rules-auto/cli-output-handling-mechanics.md +87 -0
  69. package/.agent-src/contexts/communication/rules-auto/command-suggestion-policy-mechanics.md +62 -0
  70. package/.agent-src/contexts/communication/rules-auto/docs-sync-mechanics.md +78 -0
  71. package/.agent-src/contexts/communication/rules-auto/package-ci-checks-mechanics.md +85 -0
  72. package/.agent-src/contexts/communication/rules-auto/review-routing-awareness-mechanics.md +65 -0
  73. package/.agent-src/contexts/communication/rules-auto/roadmap-progress-sync-mechanics.md +78 -0
  74. package/.agent-src/contexts/communication/rules-auto/skill-quality-mechanics.md +62 -0
  75. package/.agent-src/contexts/communication/rules-auto/slash-command-routing-policy-mechanics.md +55 -0
  76. package/.agent-src/contexts/communication/rules-auto/ui-audit-gate-mechanics.md +53 -0
  77. package/.agent-src/contexts/communication/rules-auto/user-interaction-mechanics.md +77 -0
  78. package/.agent-src/contexts/judges/no-consolidate-rationale.md +102 -0
  79. package/.agent-src/contexts/judges/persona-voice-rubric.md +140 -0
  80. package/.agent-src/rules/artifact-engagement-recording.md +13 -69
  81. package/.agent-src/rules/ask-when-uncertain.md +27 -42
  82. package/.agent-src/rules/augment-portability.md +15 -61
  83. package/.agent-src/rules/augment-source-of-truth.md +27 -93
  84. package/.agent-src/rules/cli-output-handling.md +10 -76
  85. package/.agent-src/rules/command-suggestion-policy.md +18 -59
  86. package/.agent-src/rules/commit-conventions.md +17 -14
  87. package/.agent-src/rules/context-hygiene.md +6 -0
  88. package/.agent-src/rules/direct-answers.md +35 -59
  89. package/.agent-src/rules/docker-commands.md +5 -5
  90. package/.agent-src/rules/docs-sync.md +15 -69
  91. package/.agent-src/rules/language-and-tone.md +48 -72
  92. package/.agent-src/rules/missing-tool-handling.md +28 -22
  93. package/.agent-src/rules/no-cheap-questions.md +39 -53
  94. package/.agent-src/rules/no-roadmap-references.md +73 -0
  95. package/.agent-src/rules/onboarding-gate.md +7 -0
  96. package/.agent-src/rules/package-ci-checks.md +21 -61
  97. package/.agent-src/rules/preservation-guard.md +64 -29
  98. package/.agent-src/rules/review-routing-awareness.md +24 -43
  99. package/.agent-src/rules/roadmap-progress-sync.md +31 -65
  100. package/.agent-src/rules/rule-type-governance.md +28 -0
  101. package/.agent-src/rules/security-sensitive-stop.md +8 -8
  102. package/.agent-src/rules/skill-quality.md +16 -48
  103. package/.agent-src/rules/slash-command-routing-policy.md +7 -4
  104. package/.agent-src/rules/think-before-action.md +52 -42
  105. package/.agent-src/rules/tool-safety.md +19 -16
  106. package/.agent-src/rules/ui-audit-gate.md +24 -38
  107. package/.agent-src/rules/user-interaction.md +13 -68
  108. package/.agent-src/skills/ai-council/SKILL.md +2 -0
  109. package/.agent-src/skills/api-testing/SKILL.md +1 -1
  110. package/.agent-src/skills/check-refs/SKILL.md +59 -40
  111. package/.agent-src/skills/conventional-commits-writing/SKILL.md +86 -28
  112. package/.agent-src/skills/copilot-agents-optimization/SKILL.md +5 -5
  113. package/.agent-src/skills/developer-like-execution/SKILL.md +4 -4
  114. package/.agent-src/skills/finishing-a-development-branch/SKILL.md +101 -65
  115. package/.agent-src/skills/flux/SKILL.md +30 -10
  116. package/.agent-src/skills/github-ci/SKILL.md +2 -2
  117. package/.agent-src/skills/judge-code-quality/SKILL.md +7 -8
  118. package/.agent-src/skills/judge-security-auditor/SKILL.md +4 -5
  119. package/.agent-src/skills/judge-test-coverage/SKILL.md +3 -4
  120. package/.agent-src/skills/lint-skills/SKILL.md +57 -39
  121. package/.agent-src/skills/md-language-check/SKILL.md +61 -39
  122. package/.agent-src/skills/override-management/SKILL.md +5 -5
  123. package/.agent-src/skills/quality-tools/SKILL.md +2 -2
  124. package/.agent-src/skills/react-shadcn-ui/SKILL.md +116 -43
  125. package/.agent-src/skills/readme-reviewer/SKILL.md +30 -29
  126. package/.agent-src/skills/readme-writing/SKILL.md +78 -53
  127. package/.agent-src/skills/readme-writing-package/SKILL.md +50 -47
  128. package/.agent-src/skills/receiving-code-review/SKILL.md +52 -47
  129. package/.agent-src/skills/refine-prompt/SKILL.md +0 -1
  130. package/.agent-src/skills/requesting-code-review/SKILL.md +35 -30
  131. package/.agent-src/skills/security/SKILL.md +7 -2
  132. package/.agent-src/skills/security-audit/SKILL.md +7 -3
  133. package/.agent-src/skills/systematic-debugging/SKILL.md +68 -60
  134. package/.agent-src/skills/test-driven-development/SKILL.md +59 -57
  135. package/.agent-src/skills/test-performance/SKILL.md +0 -1
  136. package/.agent-src/skills/traefik/SKILL.md +4 -4
  137. package/.agent-src/skills/verify-completion-evidence/SKILL.md +28 -26
  138. package/.agent-src/templates/roadmaps.md +4 -0
  139. package/.claude-plugin/marketplace.json +22 -11
  140. package/AGENTS.md +2 -2
  141. package/CHANGELOG.md +125 -1
  142. package/README.md +18 -17
  143. package/docs/architecture.md +4 -6
  144. package/docs/catalog.md +67 -39
  145. package/docs/contracts/STABILITY.md +13 -7
  146. package/docs/contracts/adr-chat-history-split.md +1 -3
  147. package/docs/contracts/adr-command-suggestion.md +0 -2
  148. package/docs/contracts/adr-implement-ticket-runtime.md +1 -2
  149. package/docs/contracts/adr-product-ui-track.md +3 -6
  150. package/docs/contracts/adr-prompt-driven-execution.md +3 -4
  151. package/docs/contracts/agent-memory-contract.md +6 -11
  152. package/docs/contracts/artifact-engagement-flow.md +6 -9
  153. package/docs/contracts/command-clusters.md +56 -46
  154. package/docs/contracts/command-suggestion-flow.md +1 -3
  155. package/docs/contracts/context-paths.md +99 -0
  156. package/docs/contracts/file-ownership-matrix.json +6722 -0
  157. package/docs/contracts/file-ownership-matrix.md +134 -0
  158. package/docs/contracts/implement-ticket-flow.md +6 -9
  159. package/docs/contracts/linear-ai-rules-inclusion.md +0 -1
  160. package/docs/contracts/linear-ai-three-layers.md +0 -2
  161. package/docs/contracts/load-context-budget-model.md +258 -0
  162. package/docs/contracts/load-context-schema.md +21 -3
  163. package/docs/contracts/roadmap-complexity-standard.md +137 -0
  164. package/docs/contracts/rule-interactions.md +0 -1
  165. package/docs/contracts/rule-priority-hierarchy.md +1 -1
  166. package/docs/contracts/ui-track-flow.md +7 -17
  167. package/docs/customization.md +2 -0
  168. package/docs/getting-started.md +5 -4
  169. package/docs/guidelines/agent-infra/ask-when-uncertain-demos.md +134 -0
  170. package/docs/guidelines/agent-infra/asking-and-brevity-examples.md +100 -0
  171. package/docs/guidelines/agent-infra/direct-answers-demos.md +145 -0
  172. package/docs/guidelines/agent-infra/verify-before-complete-demos.md +128 -0
  173. package/package.json +1 -1
  174. package/scripts/_phase2_shim_helper.py +109 -0
  175. package/scripts/agent-config +30 -0
  176. package/scripts/ai_council/one_off_archive/2026-05/README.md +45 -0
  177. package/scripts/ai_council/one_off_archive/2026-05/_one_off_2a4_acceptance.py +208 -0
  178. package/scripts/ai_council/one_off_archive/2026-05/_one_off_budget_v2_audit.py +206 -0
  179. package/scripts/ai_council/one_off_archive/2026-05/_one_off_context_layer_v1_estimate.py +67 -0
  180. package/scripts/ai_council/one_off_archive/2026-05/_one_off_context_layer_v1_review.py +292 -0
  181. package/scripts/ai_council/one_off_archive/2026-05/_one_off_followups_review.py +259 -0
  182. package/scripts/ai_council/one_off_archive/2026-05/_one_off_nondestructive_inline_audit.py +209 -0
  183. package/scripts/ai_council/one_off_archive/2026-05/_one_off_phase4_dispatch_latency.py +108 -0
  184. package/scripts/ai_council/one_off_archive/2026-05/_one_off_phase6_trigger_jaccard.py +92 -0
  185. package/scripts/ai_council/one_off_archive/2026-05/_one_off_phase_2a_budget_rebalance.py +257 -0
  186. package/scripts/ai_council/one_off_archive/2026-05/_one_off_phase_2a_post_revert.py +197 -0
  187. package/scripts/ai_council/one_off_archive/2026-05/_one_off_rule_hardening_v1.py +251 -0
  188. package/scripts/ai_council/one_off_archive/2026-05/_one_off_structural_open_questions.py +232 -0
  189. package/scripts/ai_council/one_off_archive/2026-05/_one_off_structural_optimization.py +144 -0
  190. package/scripts/ai_council/one_off_archive/2026-05/_one_off_structural_v3_gaps.py +252 -0
  191. package/scripts/ai_council/one_off_archive/2026-05/_one_off_structural_v3_review.py +240 -0
  192. package/scripts/build_rule_trigger_matrix.py +360 -0
  193. package/scripts/check_always_budget.py +402 -45
  194. package/scripts/check_cluster_patterns.py +159 -0
  195. package/scripts/check_command_count_messaging.py +14 -7
  196. package/scripts/check_context_paths.py +201 -0
  197. package/scripts/check_no_roadmap_refs.py +155 -0
  198. package/scripts/check_one_off_location.py +81 -0
  199. package/scripts/check_phase_coupling.py +148 -0
  200. package/scripts/check_portability.py +2 -0
  201. package/scripts/check_references.py +35 -2
  202. package/scripts/check_safety_floor_untouched.py +125 -0
  203. package/scripts/command_suggester/loader.py +4 -1
  204. package/scripts/compress.py +64 -15
  205. package/scripts/context_hygiene_hook.py +173 -0
  206. package/scripts/generate_index.py +6 -2
  207. package/scripts/generate_ownership_matrix.py +323 -0
  208. package/scripts/hooks/augment-context-hygiene.sh +55 -0
  209. package/scripts/hooks/augment-onboarding-gate.sh +55 -0
  210. package/scripts/hooks/augment-roadmap-progress.sh +57 -0
  211. package/scripts/install.py +105 -45
  212. package/scripts/lint_examples.py +98 -0
  213. package/scripts/lint_no_new_atomic_commands.py +12 -11
  214. package/scripts/lint_roadmap_complexity.py +127 -0
  215. package/scripts/onboarding_gate_hook.py +137 -0
  216. package/scripts/requirements-evals.txt +1 -0
  217. package/scripts/roadmap_progress_hook.py +159 -0
  218. package/scripts/schemas/command.schema.json +4 -3
  219. package/scripts/schemas/rule.schema.json +5 -0
  220. package/scripts/skill_linter.py +1 -0
  221. package/scripts/sync_agent_settings.py +25 -2
  222. package/scripts/update_counts.py +7 -0
  223. /package/scripts/ai_council/{_one_off_rebalancing_audit.py → one_off_archive/2026-05/_one_off_rebalancing_audit.py} +0 -0
  224. /package/scripts/ai_council/{_one_off_roundtrip.py → one_off_archive/2026-05/_one_off_roundtrip.py} +0 -0
@@ -0,0 +1,197 @@
1
+ """Council adjudication of post-revert always-budget contract.
2
+
3
+ Phase 2A executed R4 (revert) per the prior council verdict. The
4
+ three slimmed always-rules and their mechanics contexts have been
5
+ restored; mechanics-context directory removed. Measured state on
6
+ this branch is now 47,448 / 49,000 chars = 96.8 % — strictly better
7
+ than `main` at 100.6 % which currently passes via the G3 tolerance
8
+ band.
9
+
10
+ The strict 90 % FAIL gate in scripts/check_always_budget.py was
11
+ written assuming Phase 2A would succeed in dropping utilization
12
+ below 90 %. Phase 2A is now structurally infeasible under model (b)
13
+ (per the previous council finding) and the cap-tightening was
14
+ deferred to Phase 5. Branch must unblock CI without regressing the
15
+ contract spirit.
16
+
17
+ Council task: pick the smallest viable reconciliation.
18
+ """
19
+ from __future__ import annotations
20
+
21
+ import sys
22
+ from pathlib import Path
23
+
24
+ from scripts.ai_council.bundler import bundle_files
25
+ from scripts.ai_council.clients import (
26
+ AnthropicClient,
27
+ OpenAIClient,
28
+ load_anthropic_key,
29
+ load_openai_key,
30
+ )
31
+ from scripts.ai_council.orchestrator import (
32
+ CostBudget,
33
+ CouncilQuestion,
34
+ consult,
35
+ estimate,
36
+ )
37
+ from scripts.ai_council.pricing import estimate_cost, load_prices
38
+ from scripts.ai_council.project_context import detect_project_context
39
+ from scripts.ai_council.session import SessionManifest, save as save_session
40
+
41
+ REPO_ROOT = Path(__file__).resolve().parents[2]
42
+ ARTEFACTS = [
43
+ REPO_ROOT / "docs/contracts/load-context-budget-model.md",
44
+ REPO_ROOT / "scripts/check_always_budget.py",
45
+ ]
46
+
47
+ ORIGINAL_ASK = (
48
+ "Phase 2A reverted (R4) per prior council verdict. Branch budget is "
49
+ "96.8 % (gap-zone FAIL); main is 100.6 % (PASS via G3 band). Branch "
50
+ "is strictly better than main yet rejected by the strict 90 % gate. "
51
+ "Pick the smallest contract reconciliation to unblock CI."
52
+ )
53
+
54
+ REVIEW_PROMPT = """\
55
+ # Council Adjudication — Post-Revert Always-Budget Reconciliation
56
+
57
+ ## Current state (after R4 revert is committed locally)
58
+
59
+ ```
60
+ FAIL always-rule extended budget: 47,448 / 49,000 chars (96.8%)
61
+ thresholds: warn 80% · fail 90% · per-rule ≤ 6,000 (ext) ·
62
+ top-3 ≤ 24,500 (ext) · depth ≤ 2 · G3 band ≤ +2%
63
+ ```
64
+
65
+ `main` (last green): **49,311 / 49,000 = 100.6 %** — passes because
66
+ the linter only rejects 90–100 % (gap zone) and > 102 %; 100–102 %
67
+ is the documented G3 tolerance band.
68
+
69
+ This branch is objectively closer to the cap than `main` but
70
+ rejected. The 90 % gate was written under the assumption Phase 2A
71
+ would land below 90 %. Phase 2A is structurally infeasible under
72
+ model (b) (prior council finding); roadmap re-routes the trim to
73
+ Phase 5 via either model (c) shared-divisor or shared-mechanics
74
+ consolidation.
75
+
76
+ ## Fixed option set (pick exactly one)
77
+
78
+ - **A1 — Recovery-band carve-out.** Extend the linter so "current
79
+ pct ≤ last-green-`main` pct AND pct ≤ 100 %" becomes a documented
80
+ `WARN (recovery band)`, not FAIL. Persists until Phase 5
81
+ re-tightens. No baseline regression possible; needs `main`-pct
82
+ lookup (committed scalar in repo or CI artifact).
83
+ - **A2 — Lower FAIL_THRESHOLD to 100 %.** Drop the 90 % gate to
84
+ match the contract's spirit ("< cap is acceptable; > cap +2 %
85
+ fails"). Phase 5 re-tightens to 85 %/95 % per its own task list.
86
+ Smallest diff. Risk: removes the early-warning gate.
87
+ - **A3 — Trim ~3.4k chars from current rules.** Find another
88
+ candidate (none of the three Phase-2A targets, since 2A proved
89
+ extraction adds overhead). Risk: the next-largest rules touch
90
+ the safety floor (Q3=A locked).
91
+ - **A4 — Bump TOTAL_CAP to 53,000 + keep 90 % FAIL.** Rewrites the
92
+ contract's total cap upward; freezes current state at ~89.5 %.
93
+ Defers Phase 5 trim to a separate roadmap. Cleanest CI but
94
+ contract drift.
95
+ - **A5 — Mark phase as `irreducible-at-current-method` and freeze
96
+ the linter at current state.** Pin a `CURRENT_BASELINE = 47_448`
97
+ ceiling alongside the 90 % gate; PASS while pct ≤ baseline,
98
+ FAIL on regression. Deflects Phase 5 work upstream into model (c).
99
+
100
+ ## Constraints
101
+
102
+ - Safety-floor rules (`non-destructive-by-default`, `commit-policy`,
103
+ `scope-control`, `verify-before-complete`) are Q3=A locked and
104
+ may not be slimmed.
105
+ - `road-to-structural-optimization` Phase 5 owns the long-term
106
+ trim — do not duplicate work into Phase 2A.
107
+ - The four other phases (1, 2B, 3, 4, 6) on this branch are
108
+ blocked by this CI gate; the choice gates roadmap throughput.
109
+
110
+ ## Output Contract (STRICT)
111
+
112
+ ```
113
+ ### Verdict
114
+ **Choice:** <A1 | A2 | A3 | A4 | A5>
115
+ **One-sentence rationale:** <≤ 30 words>
116
+ ```
117
+
118
+ ```
119
+ ### Required follow-up actions (numbered, ≤ 4)
120
+ 1. <smallest concrete step, files named>
121
+ 2. <...>
122
+ ```
123
+
124
+ ```
125
+ ### Risk note
126
+ **Single biggest risk of the chosen option:** <one sentence>
127
+ **Mitigation:** <one sentence>
128
+ ```
129
+
130
+ ```
131
+ ### Contract amendment needed?
132
+ **Amend load-context-budget-model.md?** <YES — section · NO>
133
+ **Amend road-to-structural-optimization Phase 5 success criterion?**
134
+ <YES — new criterion in 1 line · NO>
135
+ ```
136
+
137
+ Be decisive — total response ≤ 800 words. Artefacts follow verbatim.
138
+ """
139
+
140
+
141
+ def main() -> int:
142
+ anthropic = AnthropicClient(api_key=load_anthropic_key(), model="claude-sonnet-4-5")
143
+ openai = OpenAIClient(api_key=load_openai_key(), model="gpt-4o")
144
+ members = [anthropic, openai]
145
+
146
+ context = bundle_files(ARTEFACTS)
147
+ project = detect_project_context(REPO_ROOT)
148
+ table = load_prices()
149
+
150
+ user_prompt = REVIEW_PROMPT + "\n\n---\n\n" + context.text
151
+
152
+ question = CouncilQuestion(mode="files", user_prompt=user_prompt, max_tokens=2048)
153
+ estimates = estimate(question, members, table, project=project, original_ask=ORIGINAL_ASK)
154
+ print("=== ESTIMATE (single round) ===")
155
+ total_est = 0.0
156
+ for c, e in zip(members, estimates):
157
+ print(f" {c.name}/{c.model}: ~{e.input_tokens} in + {e.output_tokens} out = ${e.total_usd:.4f}")
158
+ total_est += e.total_usd
159
+ print(f" TOTAL per round (max): ${total_est:.4f}")
160
+
161
+ budget = CostBudget(max_input_tokens=200_000, max_output_tokens=80_000, max_calls=20, max_total_usd=2.50)
162
+ rounds_collected: list[list] = []
163
+
164
+ def _on_round_complete(round_idx, round_responses) -> None:
165
+ rounds_collected.append(list(round_responses))
166
+ print(f"=== ROUND {round_idx + 1} COMPLETE ===")
167
+ for r in round_responses:
168
+ if r.error:
169
+ print(f" [error] {r.provider}/{r.model}: {r.error}")
170
+ continue
171
+ a = estimate_cost(r.provider, r.model, r.input_tokens, r.output_tokens, table)
172
+ print(f" [done] {r.provider}/{r.model}: {r.input_tokens} in / {r.output_tokens} out · ${a.total_usd:.4f}")
173
+
174
+ print("=== CONSULT (1 round, post-revert reconciliation) ===")
175
+ consult(members, question, budget, rounds=1, on_round_complete=_on_round_complete,
176
+ table=table, project=project, original_ask=ORIGINAL_ASK)
177
+ if not rounds_collected:
178
+ return 1
179
+ actual = sum(estimate_cost(r.provider, r.model, r.input_tokens, r.output_tokens, table).total_usd
180
+ for rr in rounds_collected for r in rr if not r.error)
181
+ print(f"=== TOTAL ACTUAL: ${actual:.4f} ===")
182
+ final = rounds_collected[-1]
183
+ if not [r for r in final if not r.error]:
184
+ return 1
185
+ manifest = SessionManifest(
186
+ mode="files", artefact="agents/roadmaps/road-to-structural-optimization.md",
187
+ original_ask=ORIGINAL_ASK, members=[f"{r.provider}/{r.model}" for r in final],
188
+ rounds=len(rounds_collected), cost_usd_estimated=total_est, cost_usd_actual=actual,
189
+ extra={"purpose": "Post-revert always-budget contract reconciliation"},
190
+ )
191
+ sd = save_session(manifest=manifest, responses=rounds_collected)
192
+ print(f"[saved] {sd.relative_to(REPO_ROOT)}/")
193
+ return 0
194
+
195
+
196
+ if __name__ == "__main__":
197
+ raise SystemExit(main())
@@ -0,0 +1,251 @@
1
+ """Council review of road-to-rule-hardening.md v1.
2
+
3
+ Three independent self-check rules silently skipped within one
4
+ session despite being valid, loaded, and active. Host agent drafted
5
+ a 6-phase lightweight roadmap proposing a 3-tier hardening model
6
+ (Mechanical / Nudge / Inherent-soft).
7
+
8
+ Council task: validate the architecture and the pilot order before
9
+ the host agent autonomously implements Tier 1 hooks.
10
+
11
+ Invocation:
12
+ .venv/bin/python -m scripts.ai_council._one_off_rule_hardening_v1
13
+ """
14
+ from __future__ import annotations
15
+
16
+ import sys
17
+ from pathlib import Path
18
+
19
+ from scripts.ai_council.bundler import bundle_prompt
20
+ from scripts.ai_council.clients import (
21
+ AnthropicClient,
22
+ OpenAIClient,
23
+ load_anthropic_key,
24
+ load_openai_key,
25
+ )
26
+ from scripts.ai_council.orchestrator import (
27
+ CostBudget,
28
+ CouncilQuestion,
29
+ consult,
30
+ estimate,
31
+ )
32
+ from scripts.ai_council.pricing import estimate_cost, load_prices
33
+ from scripts.ai_council.project_context import detect_project_context
34
+ from scripts.ai_council.session import SessionManifest, save as save_session
35
+
36
+ REPO_ROOT = Path(__file__).resolve().parents[2]
37
+ ROADMAP_PATH = REPO_ROOT / "agents/roadmaps/road-to-rule-hardening.md"
38
+
39
+ ORIGINAL_ASK = (
40
+ "Three independent self-check rules silently skipped within one "
41
+ "session: model-recommendation (task-start gate), context-hygiene "
42
+ "(turn-count handoff), roadmap-progress-sync (file-write side "
43
+ "effect). All valid, loaded, active. Host agent drafted a 6-phase "
44
+ "lightweight roadmap proposing a 3-tier hardening model. Council "
45
+ "task: validate the architecture and the pilot ordering before "
46
+ "implementation."
47
+ )
48
+
49
+ PROMPT_HEADER = """\
50
+ # Council Review — road-to-rule-hardening.md v1
51
+
52
+ ## Background (verbatim, do not re-frame)
53
+
54
+ Within a single session the host agent observed three rules failing
55
+ the same way:
56
+
57
+ | Rule | Trigger that should have fired | What happened |
58
+ |---|---|---|
59
+ | `model-recommendation` | Opus recommendation at task-start | silently skipped |
60
+ | `context-hygiene` | Handoff at turn-count >= 20/40/60 | silently skipped |
61
+ | `roadmap-progress-sync` | Regenerate dashboard on roadmap touch | silently skipped |
62
+
63
+ All three are valid auto-load rules in `.augment/rules/`, all three
64
+ are part of the active rule set surfaced to the agent. None of them
65
+ fired. Hypothesis: they share a structural property — the trigger
66
+ is observable only inside the agent, the check runs in the agent's
67
+ head, no deterministic gate sits between decision and output. When
68
+ the agent is in flow (multi-tool work, file edits, council
69
+ orchestration), the self-check is the first thing to be dropped.
70
+
71
+ The host agent drafted a 6-phase lightweight roadmap proposing a
72
+ 3-tier model:
73
+
74
+ - **Tier 1 — Mechanical.** Hook + deterministic check.
75
+ Agent-independent.
76
+ - **Tier 2 — Nudge.** Hook detects, marker injected, agent
77
+ formulates the response.
78
+ - **Tier 3 — Inherent soft.** No platform mechanism exists. Either
79
+ accept as self-check, convert to user-invoked `/`-command, or
80
+ deprecate.
81
+
82
+ Pilot order proposed by user: roadmap-progress-sync (1) → onboarding-gate
83
+ (3) → context-hygiene (2). Hook surface available today: Augment
84
+ PostToolUse / Stop, Claude Code Stop / SessionStart. Cursor / Cline /
85
+ Windsurf parity is explicitly out of scope for this roadmap.
86
+
87
+ Existing precedent: `chat-history-cadence` is the only rule already
88
+ mechanically hardened (heartbeat marker pattern). Inventory:
89
+ 57 rules total, 18 contain self-check phrases (`MUST`, `MANDATORY`,
90
+ `pre-send`, `before drafting`), 6 mention hooks today.
91
+
92
+ ## Your task
93
+
94
+ Review road-to-rule-hardening.md v1 (full text appended below).
95
+ Be adversarial — the host will autonomously execute the pilots, so
96
+ catch architectural mistakes now, not after Phase 4.
97
+
98
+ 1. **Three-tier model:** is Mechanical / Nudge / Inherent-soft the
99
+ right partition, or does it collapse meaningful distinctions?
100
+ Specifically: should "Tier 2 Nudge" exist at all, or is it just a
101
+ weaker Tier 1?
102
+ 2. **Pilot order (1, 3, 2):** does roadmap-progress-sync prove the
103
+ pattern, or is it too narrow to generalise? Is per-turn counter
104
+ (context-hygiene) actually feasible cross-platform, or should it
105
+ move to Tier 3?
106
+ 3. **Failure-class generalisation:** are there self-check rules in
107
+ the inventory that the audit will MISS because they fire so
108
+ rarely the agent has not yet observed a skip? Name 1-2 likely
109
+ candidates.
110
+ 4. **Cross-platform scope:** roadmap defers Cursor/Cline/Windsurf.
111
+ Is this honest scope or hidden tech debt that will silently
112
+ block Phase 4 rollout?
113
+ 5. **Tier 3 disposition:** the roadmap allows accept-as-soft as a
114
+ valid disposition. Is that a real choice, or a way to declare
115
+ victory without solving anything?
116
+
117
+ ## Output contract (STRICT)
118
+
119
+ For EACH of the six phases:
120
+
121
+ ```
122
+ ### Phase N — <title>
123
+
124
+ **Verdict:** <ACCEPT | PARTIAL | REJECT>
125
+ **What v1 gets right (1 sentence):** ...
126
+ **What v1 misses or over-reaches (1-2 sentences):** ...
127
+ **Concrete change to v2 (binding):** ...
128
+ ```
129
+
130
+ Then five answers to the questions above (numbered 1-5, ≤ 3 sentences
131
+ each).
132
+
133
+ Then a final block:
134
+
135
+ ```
136
+ ### Greenlight verdict
137
+
138
+ <one of: FULL GREENLIGHT — proceed with pilots / CONDITIONAL GREENLIGHT
139
+ — apply N revisions then proceed / BLOCKED — major rework needed>
140
+
141
+ **Binding revisions for v2 (numbered, ≤ 6):** ...
142
+ **Pilot order recommendation:** <1,3,2 | 1,2,3 | 3,1,2 | other>
143
+ **One-line architectural risk you would still proceed with:** ...
144
+ ```
145
+
146
+ Total response budget: ≤ 1500 words. Do not re-write the roadmap.
147
+ """
148
+
149
+
150
+ def _read(path: Path) -> str:
151
+ return path.read_text(encoding="utf-8") if path.exists() else ""
152
+
153
+
154
+ def main() -> int:
155
+ anthropic = AnthropicClient(api_key=load_anthropic_key(), model="claude-sonnet-4-5")
156
+ openai = OpenAIClient(api_key=load_openai_key(), model="gpt-4o")
157
+ members = [anthropic, openai]
158
+
159
+ roadmap_text = _read(ROADMAP_PATH)
160
+ if not roadmap_text:
161
+ print(f"[error] roadmap not found: {ROADMAP_PATH}", file=sys.stderr)
162
+ return 1
163
+
164
+ bundle_text = "\n\n---\n\n".join([
165
+ PROMPT_HEADER,
166
+ "## Roadmap v1 (verbatim, the artefact to validate)\n\n" + roadmap_text,
167
+ ])
168
+ context = bundle_prompt(bundle_text)
169
+ project = detect_project_context(REPO_ROOT)
170
+ table = load_prices()
171
+
172
+ question = CouncilQuestion(
173
+ mode="prompt",
174
+ user_prompt=context.text,
175
+ max_tokens=4096,
176
+ )
177
+
178
+ estimates = estimate(
179
+ question, members, table, project=project, original_ask=ORIGINAL_ASK,
180
+ )
181
+ print("=== ESTIMATE (single round, max tokens) ===")
182
+ total_est = 0.0
183
+ for c, e in zip(members, estimates):
184
+ print(f" {c.name}/{c.model}: ~{e.input_tokens} in + {e.output_tokens} out = ${e.total_usd:.4f}")
185
+ total_est += e.total_usd
186
+ print(f" TOTAL per round (max): ${total_est:.4f}")
187
+ print()
188
+
189
+ budget = CostBudget(
190
+ max_input_tokens=200_000,
191
+ max_output_tokens=80_000,
192
+ max_calls=20,
193
+ max_total_usd=2.50,
194
+ )
195
+
196
+ rounds_collected: list[list] = []
197
+
198
+ def _on_round_complete(round_idx: int, round_responses) -> None:
199
+ rounds_collected.append(list(round_responses))
200
+ print(f"=== ROUND {round_idx + 1} COMPLETE ===")
201
+ for r in round_responses:
202
+ if r.error:
203
+ print(f" [error] {r.provider}/{r.model}: {r.error}")
204
+ continue
205
+ actual = estimate_cost(r.provider, r.model, r.input_tokens, r.output_tokens, table)
206
+ print(f" [done] {r.provider}/{r.model}: {r.input_tokens} in / "
207
+ f"{r.output_tokens} out · {r.latency_ms} ms · ${actual.total_usd:.4f}")
208
+ print()
209
+
210
+ print("=== CONSULT (1 round) ===")
211
+ consult(
212
+ members, question, budget,
213
+ rounds=1,
214
+ on_round_complete=_on_round_complete,
215
+ table=table, project=project, original_ask=ORIGINAL_ASK,
216
+ )
217
+
218
+ if not rounds_collected:
219
+ print("[error] no rounds completed", file=sys.stderr)
220
+ return 1
221
+
222
+ actual_total = 0.0
223
+ for round_responses in rounds_collected:
224
+ for r in round_responses:
225
+ if r.error:
226
+ continue
227
+ actual = estimate_cost(r.provider, r.model, r.input_tokens, r.output_tokens, table)
228
+ actual_total += actual.total_usd
229
+ print(f"=== TOTAL ACTUAL: ${actual_total:.4f} ===")
230
+
231
+ final_round = rounds_collected[-1]
232
+ if not [r for r in final_round if not r.error]:
233
+ return 1
234
+
235
+ manifest = SessionManifest(
236
+ mode="prompt",
237
+ artefact=str(ROADMAP_PATH.relative_to(REPO_ROOT)),
238
+ original_ask=ORIGINAL_ASK,
239
+ members=[f"{r.provider}/{r.model}" for r in final_round],
240
+ rounds=len(rounds_collected),
241
+ cost_usd_estimated=total_est,
242
+ cost_usd_actual=actual_total,
243
+ extra={"purpose": "Council review of road-to-rule-hardening v1"},
244
+ )
245
+ session_dir = save_session(manifest=manifest, responses=rounds_collected)
246
+ print(f"[saved] {session_dir.relative_to(REPO_ROOT)}/")
247
+ return 1 if any(r.error for round_r in rounds_collected for r in round_r) else 0
248
+
249
+
250
+ if __name__ == "__main__":
251
+ raise SystemExit(main())
@@ -0,0 +1,232 @@
1
+ """One-off council run for the three open questions in road-to-structural-optimization.md v2.
2
+
3
+ Forces a STRUCTURED multiple-choice verdict per question across 2 rounds
4
+ (debate mode). Saves the session under agents/council-sessions/.
5
+
6
+ Invocation:
7
+ .venv/bin/python -m scripts.ai_council._one_off_structural_open_questions
8
+ """
9
+ from __future__ import annotations
10
+
11
+ import sys
12
+ from pathlib import Path
13
+
14
+ from scripts.ai_council.bundler import bundle_roadmap
15
+ from scripts.ai_council.clients import (
16
+ AnthropicClient,
17
+ OpenAIClient,
18
+ load_anthropic_key,
19
+ load_openai_key,
20
+ )
21
+ from scripts.ai_council.orchestrator import (
22
+ CostBudget,
23
+ CouncilQuestion,
24
+ consult,
25
+ estimate,
26
+ )
27
+ from scripts.ai_council.pricing import estimate_cost, load_prices
28
+ from scripts.ai_council.project_context import detect_project_context
29
+ from scripts.ai_council.session import SessionManifest, save as save_session
30
+
31
+ REPO_ROOT = Path(__file__).resolve().parents[2]
32
+ ROADMAP_PATH = REPO_ROOT / "agents/roadmaps/road-to-structural-optimization.md"
33
+
34
+ ORIGINAL_ASK = (
35
+ "Lock the three open design questions on road-to-structural-optimization.md v2 "
36
+ "with binding A/B verdicts + 2-3 sentence rationale each. The roadmap text "
37
+ "is the context. Be decisive — say A or B (or C with new option). Avoid "
38
+ "'depends' or 'further investigation needed'."
39
+ )
40
+
41
+ OPEN_QUESTIONS_PROMPT = """\
42
+ # Lock-the-Decision Council Round
43
+
44
+ You have already reviewed road-to-structural-optimization.md v2 in two prior \
45
+ rounds (architectural / sequencing critique). The roadmap author now needs \
46
+ **binding verdicts** on the three open design questions. Stop re-reviewing the \
47
+ roadmap. Pick A, B, or propose C with explicit justification.
48
+
49
+ ## Output Contract (STRICT)
50
+
51
+ For each question, produce exactly this block:
52
+
53
+ ```
54
+ ### Q<n>: <short title>
55
+
56
+ **Verdict:** <A | B | C>
57
+ **Confidence:** <Low | Medium | High>
58
+ **Rationale (2-4 sentences):** <why this option, what failure mode of the other you avoid>
59
+ **Risk if wrong:** <one sentence — what breaks if your verdict is the wrong call>
60
+ **Rollback if wrong:** <one sentence — how to recover if production reveals the choice was bad>
61
+ ```
62
+
63
+ If you propose C (new option), keep the same block structure.
64
+
65
+ ## Q1 — Phase 3a Skill Consolidation Shape
66
+
67
+ The four `judge-*` skills (`judge-bug-hunter`, `judge-code-quality`, \
68
+ `judge-security-auditor`, `judge-test-coverage`) share procedure but \
69
+ have distinct persona voices. Two consolidation shapes:
70
+
71
+ - **A.** Keep four separate skills. Extract the shared procedure to \
72
+ `contexts/judges/judge-shared-procedure.md`. Each skill's SKILL.md \
73
+ loads the context via `load_context:` and adds its persona-specific \
74
+ delta (review heuristics, persona prompt, examples).
75
+ - **B.** Single skill `judge` with `mode:` parameter \
76
+ (`mode: bug-hunter | code-quality | security-auditor | test-coverage`). \
77
+ One SKILL.md dispatches; persona contexts live at \
78
+ `contexts/judges/personas/<mode>.md` and are loaded based on `mode:`.
79
+
80
+ **Decision criterion:** which preserves persona voice better at LLM \
81
+ runtime, and which is more maintainable when a fifth judge persona is \
82
+ added in 6 months?
83
+
84
+ ## Q2 — Phase 6 chat-history Rule Consolidation Shape
85
+
86
+ Three rules (`chat-history-cadence`, `chat-history-ownership`, \
87
+ `chat-history-visibility`) overlap on triggers and surface but each \
88
+ encodes a distinct concern. Two consolidation shapes:
89
+
90
+ - **A.** One rule `chat-history` + three contexts \
91
+ (`contexts/chat-history/cadence.md`, `.../ownership.md`, \
92
+ `.../visibility.md`). The rule body holds the unified trigger language \
93
+ and routes to the right context section based on the matched anchor.
94
+ - **B.** Router rule `chat-history` + three thin specialist rules \
95
+ (`chat-history-cadence` etc.) reduced to <30 LOC each. Router fires \
96
+ first, dispatches to one specialist based on signal type \
97
+ (heartbeat / ownership-detection / cadence-decision).
98
+
99
+ **Decision criterion:** which is more maintainable when a fourth concern \
100
+ (e.g., `chat-history-archive` for log rotation) is added in 12 months, \
101
+ and which has lower cognitive load for an agent reading the rule first \
102
+ time mid-task?
103
+
104
+ ## Q3 — Phase 5 Safety-Floor Rule Endorsement
105
+
106
+ Phase 5 tightens the always-rule budget. The four safety-floor rules are:
107
+
108
+ - `non-destructive-by-default` (~4,607 chars)
109
+ - `commit-policy` (~2,800 chars)
110
+ - `scope-control` (~3,900 chars)
111
+ - `verify-before-complete` (~3,200 chars)
112
+
113
+ Should these be in scope for slimming?
114
+
115
+ - **A.** Endorse keeping all four UNTOUCHED. Slimming risks weakening Iron \
116
+ Laws under budget pressure. Phase 5 hits target without them.
117
+ - **B.** Allow slimming with stricter 2A.4-style obligation-diff (every \
118
+ MUST/NEVER preserved verbatim, mechanics moved to context). Treat them \
119
+ like normal always-rules.
120
+
121
+ **Decision criterion:** is the marginal budget gain worth the residual \
122
+ risk of an Iron Law regression slipping through the obligation-diff \
123
+ gate?
124
+
125
+ ## Final Output
126
+
127
+ After the three blocks, add:
128
+
129
+ ```
130
+ ### Cross-question coupling
131
+
132
+ <2-3 sentences: do your verdicts on Q1/Q2/Q3 reinforce or conflict with \
133
+ each other? Are there hidden dependencies between them?>
134
+ ```
135
+
136
+ Do not write an executive summary. Do not re-review v2. Pick, justify, \
137
+ ship. Total response budget: ≤ 1500 words.
138
+ """
139
+
140
+
141
+ def main() -> int:
142
+ anthropic = AnthropicClient(api_key=load_anthropic_key(), model="claude-sonnet-4-5")
143
+ openai = OpenAIClient(api_key=load_openai_key(), model="gpt-4o")
144
+ members = [anthropic, openai]
145
+
146
+ context = bundle_roadmap(ROADMAP_PATH)
147
+ project = detect_project_context(REPO_ROOT)
148
+ table = load_prices()
149
+
150
+ user_prompt = OPEN_QUESTIONS_PROMPT + "\n\n---\n\n" + context.text
151
+
152
+ question = CouncilQuestion(
153
+ mode="roadmap",
154
+ user_prompt=user_prompt,
155
+ max_tokens=4096,
156
+ )
157
+
158
+ estimates = estimate(
159
+ question, members, table, project=project, original_ask=ORIGINAL_ASK,
160
+ )
161
+ print("=== ESTIMATE (single round, max tokens) ===")
162
+ total_est = 0.0
163
+ for c, e in zip(members, estimates):
164
+ print(f" {c.name}/{c.model}: ~{e.input_tokens} in + {e.output_tokens} out = ${e.total_usd:.4f}")
165
+ total_est += e.total_usd
166
+ print(f" TOTAL per round (max): ${total_est:.4f}")
167
+ print(f" TOTAL 2 rounds (max): ${total_est * 2:.4f}")
168
+ print()
169
+
170
+ budget = CostBudget(
171
+ max_input_tokens=200_000,
172
+ max_output_tokens=80_000,
173
+ max_calls=20,
174
+ max_total_usd=2.50,
175
+ )
176
+
177
+ rounds_collected: list[list] = []
178
+
179
+ def _on_round_complete(round_idx: int, round_responses) -> None:
180
+ rounds_collected.append(list(round_responses))
181
+ print(f"=== ROUND {round_idx + 1} COMPLETE ===")
182
+ for r in round_responses:
183
+ if r.error:
184
+ print(f" [error] {r.provider}/{r.model}: {r.error}")
185
+ continue
186
+ actual = estimate_cost(r.provider, r.model, r.input_tokens, r.output_tokens, table)
187
+ print(f" [done] {r.provider}/{r.model}: {r.input_tokens} in / "
188
+ f"{r.output_tokens} out · {r.latency_ms} ms · ${actual.total_usd:.4f}")
189
+ print()
190
+
191
+ print("=== CONSULT (2 rounds, debate mode) ===")
192
+ consult(
193
+ members, question, budget,
194
+ rounds=2,
195
+ on_round_complete=_on_round_complete,
196
+ table=table, project=project, original_ask=ORIGINAL_ASK,
197
+ )
198
+
199
+ if not rounds_collected:
200
+ print("[error] no rounds completed", file=sys.stderr)
201
+ return 1
202
+
203
+ actual_total = 0.0
204
+ for round_responses in rounds_collected:
205
+ for r in round_responses:
206
+ if r.error:
207
+ continue
208
+ actual = estimate_cost(r.provider, r.model, r.input_tokens, r.output_tokens, table)
209
+ actual_total += actual.total_usd
210
+ print(f"=== TOTAL ACTUAL: ${actual_total:.4f} (across {len(rounds_collected)} rounds) ===")
211
+
212
+ final_round = rounds_collected[-1]
213
+ if not [r for r in final_round if not r.error]:
214
+ return 1
215
+
216
+ manifest = SessionManifest(
217
+ mode="roadmap",
218
+ artefact=str(ROADMAP_PATH.relative_to(REPO_ROOT)),
219
+ original_ask=ORIGINAL_ASK,
220
+ members=[f"{r.provider}/{r.model}" for r in final_round],
221
+ rounds=len(rounds_collected),
222
+ cost_usd_estimated=total_est * 2,
223
+ cost_usd_actual=actual_total,
224
+ extra={"purpose": "council lock on three open questions of structural-optimization v2"},
225
+ )
226
+ session_dir = save_session(manifest=manifest, responses=rounds_collected)
227
+ print(f"[saved] {session_dir.relative_to(REPO_ROOT)}/")
228
+ return 1 if any(r.error for round_r in rounds_collected for r in round_r) else 0
229
+
230
+
231
+ if __name__ == "__main__":
232
+ raise SystemExit(main())