claude-code-conductor 2.52.1__tar.gz → 2.54.0__tar.gz

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 (231) hide show
  1. {claude_code_conductor-2.52.1 → claude_code_conductor-2.54.0}/.claude/CLAUDE.md +4 -0
  2. claude_code_conductor-2.54.0/.claude/docs/autonomous-mode-onboarding.md +102 -0
  3. {claude_code_conductor-2.52.1 → claude_code_conductor-2.54.0}/.claude/hooks/select_tier.py +74 -9
  4. {claude_code_conductor-2.52.1 → claude_code_conductor-2.54.0}/.claude/hooks/tier_autoapply.py +82 -8
  5. {claude_code_conductor-2.52.1 → claude_code_conductor-2.54.0}/.claude/hooks/tier_gap_check.py +4 -3
  6. claude_code_conductor-2.54.0/.claude/skills/autonomous-mode/SKILL.md +348 -0
  7. claude_code_conductor-2.54.0/.claude/skills/autonomous-mode/scripts/mode_line.py +188 -0
  8. {claude_code_conductor-2.52.1 → claude_code_conductor-2.54.0}/.claude/skills/dev-workflow/SKILL.md +48 -5
  9. {claude_code_conductor-2.52.1 → claude_code_conductor-2.54.0}/.claude/skills/dev-workflow/scripts/record_agent_outcome.py +113 -22
  10. {claude_code_conductor-2.52.1 → claude_code_conductor-2.54.0}/.claude/skills/init-session/SKILL.md +1 -1
  11. {claude_code_conductor-2.52.1 → claude_code_conductor-2.54.0}/.claude/skills/parallel-agents/SKILL.md +41 -16
  12. {claude_code_conductor-2.52.1 → claude_code_conductor-2.54.0}/.gitignore +0 -1
  13. {claude_code_conductor-2.52.1 → claude_code_conductor-2.54.0}/CHANGELOG.md +42 -0
  14. {claude_code_conductor-2.52.1 → claude_code_conductor-2.54.0}/PKG-INFO +1 -1
  15. {claude_code_conductor-2.52.1 → claude_code_conductor-2.54.0}/hatch_build.py +0 -2
  16. {claude_code_conductor-2.52.1 → claude_code_conductor-2.54.0}/src/c3/__init__.py +1 -1
  17. {claude_code_conductor-2.52.1 → claude_code_conductor-2.54.0}/src/c3/_db_params.py +32 -0
  18. {claude_code_conductor-2.52.1 → claude_code_conductor-2.54.0}/src/c3/_excludes.py +0 -2
  19. {claude_code_conductor-2.52.1 → claude_code_conductor-2.54.0}/src/c3/adapters.py +46 -6
  20. {claude_code_conductor-2.52.1 → claude_code_conductor-2.54.0}/src/c3/db.py +35 -18
  21. {claude_code_conductor-2.52.1 → claude_code_conductor-2.54.0}/tests/hooks/test_record_agent_outcome.py +243 -0
  22. {claude_code_conductor-2.52.1 → claude_code_conductor-2.54.0}/tests/hooks/test_select_tier.py +143 -2
  23. {claude_code_conductor-2.52.1 → claude_code_conductor-2.54.0}/tests/hooks/test_tier_autoapply.py +296 -0
  24. claude_code_conductor-2.54.0/tests/skills/test_marker_compliance.py +153 -0
  25. {claude_code_conductor-2.52.1 → claude_code_conductor-2.54.0}/tests/test_adapters.py +103 -0
  26. {claude_code_conductor-2.52.1 → claude_code_conductor-2.54.0}/tests/test_cli_init.py +32 -0
  27. {claude_code_conductor-2.52.1 → claude_code_conductor-2.54.0}/tests/test_cli_tier.py +4 -1
  28. {claude_code_conductor-2.52.1 → claude_code_conductor-2.54.0}/tests/test_db.py +151 -0
  29. {claude_code_conductor-2.52.1 → claude_code_conductor-2.54.0}/tests/test_excludes.py +13 -8
  30. claude_code_conductor-2.54.0/tests/test_mode_line.py +318 -0
  31. {claude_code_conductor-2.52.1 → claude_code_conductor-2.54.0}/.claude/agents/architect.md +0 -0
  32. {claude_code_conductor-2.52.1 → claude_code_conductor-2.54.0}/.claude/agents/code-reviewer.md +0 -0
  33. {claude_code_conductor-2.52.1 → claude_code_conductor-2.54.0}/.claude/agents/design-critic.md +0 -0
  34. {claude_code_conductor-2.52.1 → claude_code_conductor-2.54.0}/.claude/agents/developer.md +0 -0
  35. {claude_code_conductor-2.52.1 → claude_code_conductor-2.54.0}/.claude/agents/doc-writer.md +0 -0
  36. {claude_code_conductor-2.52.1 → claude_code_conductor-2.54.0}/.claude/agents/interviewer.md +0 -0
  37. {claude_code_conductor-2.52.1 → claude_code_conductor-2.54.0}/.claude/agents/planner.md +0 -0
  38. {claude_code_conductor-2.52.1 → claude_code_conductor-2.54.0}/.claude/agents/project-setup.md +0 -0
  39. {claude_code_conductor-2.52.1 → claude_code_conductor-2.54.0}/.claude/agents/security-reviewer.md +0 -0
  40. {claude_code_conductor-2.52.1 → claude_code_conductor-2.54.0}/.claude/agents/systematic-debugger.md +0 -0
  41. {claude_code_conductor-2.52.1 → claude_code_conductor-2.54.0}/.claude/agents/tester.md +0 -0
  42. {claude_code_conductor-2.52.1 → claude_code_conductor-2.54.0}/.claude/agents/wt_developer.md +0 -0
  43. {claude_code_conductor-2.52.1 → claude_code_conductor-2.54.0}/.claude/agents/wt_systematic-debugger.md +0 -0
  44. {claude_code_conductor-2.52.1 → claude_code_conductor-2.54.0}/.claude/agents/wt_tester.md +0 -0
  45. {claude_code_conductor-2.52.1 → claude_code_conductor-2.54.0}/.claude/breaking-changes.txt +0 -0
  46. {claude_code_conductor-2.52.1 → claude_code_conductor-2.54.0}/.claude/deletions.txt +0 -0
  47. {claude_code_conductor-2.52.1 → claude_code_conductor-2.54.0}/.claude/docs/config-policy.md +0 -0
  48. {claude_code_conductor-2.52.1 → claude_code_conductor-2.54.0}/.claude/docs/nul-boundary.md +0 -0
  49. {claude_code_conductor-2.52.1 → claude_code_conductor-2.54.0}/.claude/docs/parallel-agents-setup.md +0 -0
  50. {claude_code_conductor-2.52.1 → claude_code_conductor-2.54.0}/.claude/docs/platform-adapters.md +0 -0
  51. {claude_code_conductor-2.52.1 → claude_code_conductor-2.54.0}/.claude/docs/settings.json.md +0 -0
  52. {claude_code_conductor-2.52.1 → claude_code_conductor-2.54.0}/.claude/hooks/_hook_utils.py +0 -0
  53. {claude_code_conductor-2.52.1 → claude_code_conductor-2.54.0}/.claude/hooks/check_agent_invocation.py +0 -0
  54. {claude_code_conductor-2.52.1 → claude_code_conductor-2.54.0}/.claude/hooks/consolidate_memory.py +0 -0
  55. {claude_code_conductor-2.52.1 → claude_code_conductor-2.54.0}/.claude/hooks/permission_handler.py +0 -0
  56. {claude_code_conductor-2.52.1 → claude_code_conductor-2.54.0}/.claude/hooks/permission_handler_toast.py +0 -0
  57. {claude_code_conductor-2.52.1 → claude_code_conductor-2.54.0}/.claude/hooks/planner_check.py +0 -0
  58. {claude_code_conductor-2.52.1 → claude_code_conductor-2.54.0}/.claude/hooks/post_tool.py +0 -0
  59. {claude_code_conductor-2.52.1 → claude_code_conductor-2.54.0}/.claude/hooks/pre_compact.py +0 -0
  60. {claude_code_conductor-2.52.1 → claude_code_conductor-2.54.0}/.claude/hooks/pre_tool.py +0 -0
  61. {claude_code_conductor-2.52.1 → claude_code_conductor-2.54.0}/.claude/hooks/recall_autorebuild.py +0 -0
  62. {claude_code_conductor-2.52.1 → claude_code_conductor-2.54.0}/.claude/hooks/recall_inject.py +0 -0
  63. {claude_code_conductor-2.52.1 → claude_code_conductor-2.54.0}/.claude/hooks/restore_session.py +0 -0
  64. {claude_code_conductor-2.52.1 → claude_code_conductor-2.54.0}/.claude/hooks/session_start.py +0 -0
  65. {claude_code_conductor-2.52.1 → claude_code_conductor-2.54.0}/.claude/hooks/session_stop.py +0 -0
  66. {claude_code_conductor-2.52.1 → claude_code_conductor-2.54.0}/.claude/hooks/session_utils.py +0 -0
  67. {claude_code_conductor-2.52.1 → claude_code_conductor-2.54.0}/.claude/hooks/statusline.py +0 -0
  68. {claude_code_conductor-2.52.1 → claude_code_conductor-2.54.0}/.claude/hooks/stop.py +0 -0
  69. {claude_code_conductor-2.52.1 → claude_code_conductor-2.54.0}/.claude/hooks/worktree_guard.py +0 -0
  70. {claude_code_conductor-2.52.1 → claude_code_conductor-2.54.0}/.claude/memory/.gitkeep +0 -0
  71. {claude_code_conductor-2.52.1 → claude_code_conductor-2.54.0}/.claude/permission_rules.json +0 -0
  72. {claude_code_conductor-2.52.1 → claude_code_conductor-2.54.0}/.claude/rules/promoted/index.md +0 -0
  73. {claude_code_conductor-2.52.1 → claude_code_conductor-2.54.0}/.claude/settings.json +0 -0
  74. {claude_code_conductor-2.52.1 → claude_code_conductor-2.54.0}/.claude/skills/brainstorm/SKILL.md +0 -0
  75. {claude_code_conductor-2.52.1 → claude_code_conductor-2.54.0}/.claude/skills/codex-review/SKILL.md +0 -0
  76. {claude_code_conductor-2.52.1 → claude_code_conductor-2.54.0}/.claude/skills/dev-workflow/references/code-review-checklist.md +0 -0
  77. {claude_code_conductor-2.52.1 → claude_code_conductor-2.54.0}/.claude/skills/dev-workflow/references/design-critic-rubric.md +0 -0
  78. {claude_code_conductor-2.52.1 → claude_code_conductor-2.54.0}/.claude/skills/dev-workflow/references/design-rubric.md +0 -0
  79. {claude_code_conductor-2.52.1 → claude_code_conductor-2.54.0}/.claude/skills/dev-workflow/references/interview-rubric.md +0 -0
  80. {claude_code_conductor-2.52.1 → claude_code_conductor-2.54.0}/.claude/skills/dev-workflow/references/plan-design-guidelines.md +0 -0
  81. {claude_code_conductor-2.52.1 → claude_code_conductor-2.54.0}/.claude/skills/dev-workflow/references/security-review-checklist.md +0 -0
  82. {claude_code_conductor-2.52.1 → claude_code_conductor-2.54.0}/.claude/skills/dev-workflow/scripts/record_review_decision.py +0 -0
  83. {claude_code_conductor-2.52.1 → claude_code_conductor-2.54.0}/.claude/skills/dev-workflow/scripts/review_hint_inject.py +0 -0
  84. {claude_code_conductor-2.52.1 → claude_code_conductor-2.54.0}/.claude/skills/develop/SKILL.md +0 -0
  85. {claude_code_conductor-2.52.1 → claude_code_conductor-2.54.0}/.claude/skills/doc/SKILL.md +0 -0
  86. {claude_code_conductor-2.52.1 → claude_code_conductor-2.54.0}/.claude/skills/extract-lib/SKILL.md +0 -0
  87. {claude_code_conductor-2.52.1 → claude_code_conductor-2.54.0}/.claude/skills/init-session/scripts/session_guard.py +0 -0
  88. {claude_code_conductor-2.52.1 → claude_code_conductor-2.54.0}/.claude/skills/mcp-config/SKILL.md +0 -0
  89. {claude_code_conductor-2.52.1 → claude_code_conductor-2.54.0}/.claude/skills/pattern-status/SKILL.md +0 -0
  90. {claude_code_conductor-2.52.1 → claude_code_conductor-2.54.0}/.claude/skills/promote-pattern/SKILL.md +0 -0
  91. {claude_code_conductor-2.52.1 → claude_code_conductor-2.54.0}/.claude/skills/recall/SKILL.md +0 -0
  92. {claude_code_conductor-2.52.1 → claude_code_conductor-2.54.0}/.claude/skills/report-timestamp/SKILL.md +0 -0
  93. {claude_code_conductor-2.52.1 → claude_code_conductor-2.54.0}/.claude/skills/report-timestamp/scripts/get_timestamp.py +0 -0
  94. {claude_code_conductor-2.52.1 → claude_code_conductor-2.54.0}/.claude/skills/review-phase/SKILL.md +0 -0
  95. {claude_code_conductor-2.52.1 → claude_code_conductor-2.54.0}/.claude/skills/setup/SKILL.md +0 -0
  96. {claude_code_conductor-2.52.1 → claude_code_conductor-2.54.0}/.claude/skills/setup/reference.md +0 -0
  97. {claude_code_conductor-2.52.1 → claude_code_conductor-2.54.0}/.claude/skills/setup/templates/coding-standards-template.md +0 -0
  98. {claude_code_conductor-2.52.1 → claude_code_conductor-2.54.0}/.claude/skills/setup/templates/project-conventions-template.md +0 -0
  99. {claude_code_conductor-2.52.1 → claude_code_conductor-2.54.0}/.claude/skills/start/SKILL.md +0 -0
  100. {claude_code_conductor-2.52.1 → claude_code_conductor-2.54.0}/.claude/state/.gitkeep +0 -0
  101. {claude_code_conductor-2.52.1 → claude_code_conductor-2.54.0}/ARCHITECTURE.md +0 -0
  102. {claude_code_conductor-2.52.1 → claude_code_conductor-2.54.0}/LICENSE +0 -0
  103. {claude_code_conductor-2.52.1 → claude_code_conductor-2.54.0}/LICENSES/fastembed-LICENSE +0 -0
  104. {claude_code_conductor-2.52.1 → claude_code_conductor-2.54.0}/LICENSES/fastembed-NOTICE +0 -0
  105. {claude_code_conductor-2.52.1 → claude_code_conductor-2.54.0}/LICENSES/numpy-LICENSE +0 -0
  106. {claude_code_conductor-2.52.1 → claude_code_conductor-2.54.0}/LICENSES/onnxruntime-LICENSE +0 -0
  107. {claude_code_conductor-2.52.1 → claude_code_conductor-2.54.0}/LICENSES/paraphrase-multilingual-MiniLM-L12-v2-LICENSE +0 -0
  108. {claude_code_conductor-2.52.1 → claude_code_conductor-2.54.0}/README.md +0 -0
  109. {claude_code_conductor-2.52.1 → claude_code_conductor-2.54.0}/pyproject.toml +0 -0
  110. {claude_code_conductor-2.52.1 → claude_code_conductor-2.54.0}/src/c3/__main__.py +0 -0
  111. {claude_code_conductor-2.52.1 → claude_code_conductor-2.54.0}/src/c3/_terminal.py +0 -0
  112. {claude_code_conductor-2.52.1 → claude_code_conductor-2.54.0}/src/c3/cli.py +0 -0
  113. {claude_code_conductor-2.52.1 → claude_code_conductor-2.54.0}/src/c3/cli_ask.py +0 -0
  114. {claude_code_conductor-2.52.1 → claude_code_conductor-2.54.0}/src/c3/cli_doctor.py +0 -0
  115. {claude_code_conductor-2.52.1 → claude_code_conductor-2.54.0}/src/c3/cli_init.py +0 -0
  116. {claude_code_conductor-2.52.1 → claude_code_conductor-2.54.0}/src/c3/cli_list.py +0 -0
  117. {claude_code_conductor-2.52.1 → claude_code_conductor-2.54.0}/src/c3/cli_metrics.py +0 -0
  118. {claude_code_conductor-2.52.1 → claude_code_conductor-2.54.0}/src/c3/cli_plan.py +0 -0
  119. {claude_code_conductor-2.52.1 → claude_code_conductor-2.54.0}/src/c3/cli_recall.py +0 -0
  120. {claude_code_conductor-2.52.1 → claude_code_conductor-2.54.0}/src/c3/cli_run.py +0 -0
  121. {claude_code_conductor-2.52.1 → claude_code_conductor-2.54.0}/src/c3/cli_tier.py +0 -0
  122. {claude_code_conductor-2.52.1 → claude_code_conductor-2.54.0}/src/c3/cli_update.py +0 -0
  123. {claude_code_conductor-2.52.1 → claude_code_conductor-2.54.0}/src/c3/embedding.py +0 -0
  124. {claude_code_conductor-2.52.1 → claude_code_conductor-2.54.0}/src/c3/gitutil.py +0 -0
  125. {claude_code_conductor-2.52.1 → claude_code_conductor-2.54.0}/src/c3/mcp_server.py +0 -0
  126. {claude_code_conductor-2.52.1 → claude_code_conductor-2.54.0}/src/c3/migrate.py +0 -0
  127. {claude_code_conductor-2.52.1 → claude_code_conductor-2.54.0}/src/c3/migrations/001_initial.sql +0 -0
  128. {claude_code_conductor-2.52.1 → claude_code_conductor-2.54.0}/src/c3/migrations/002_agent_cost_runs.sql +0 -0
  129. {claude_code_conductor-2.52.1 → claude_code_conductor-2.54.0}/src/c3/migrations/003_tier_cost.sql +0 -0
  130. {claude_code_conductor-2.52.1 → claude_code_conductor-2.54.0}/src/c3/migrations/004_agent_outcomes.sql +0 -0
  131. {claude_code_conductor-2.52.1 → claude_code_conductor-2.54.0}/src/c3/migrations/005_drop_agent_tier_bandit.sql +0 -0
  132. {claude_code_conductor-2.52.1 → claude_code_conductor-2.54.0}/src/c3/migrations/006_review_decisions_severity.sql +0 -0
  133. {claude_code_conductor-2.52.1 → claude_code_conductor-2.54.0}/src/c3/migrations/README.md +0 -0
  134. {claude_code_conductor-2.52.1 → claude_code_conductor-2.54.0}/src/c3/migrations/__init__.py +0 -0
  135. {claude_code_conductor-2.52.1 → claude_code_conductor-2.54.0}/src/c3/paths.py +0 -0
  136. {claude_code_conductor-2.52.1 → claude_code_conductor-2.54.0}/src/c3/plan_validator.py +0 -0
  137. {claude_code_conductor-2.52.1 → claude_code_conductor-2.54.0}/src/c3/platforms.py +0 -0
  138. {claude_code_conductor-2.52.1 → claude_code_conductor-2.54.0}/src/c3/pricing.py +0 -0
  139. {claude_code_conductor-2.52.1 → claude_code_conductor-2.54.0}/src/c3/question.py +0 -0
  140. {claude_code_conductor-2.52.1 → claude_code_conductor-2.54.0}/src/c3/recall_chunker.py +0 -0
  141. {claude_code_conductor-2.52.1 → claude_code_conductor-2.54.0}/src/c3/recall_index.py +0 -0
  142. {claude_code_conductor-2.52.1 → claude_code_conductor-2.54.0}/src/c3/usage_ingester.py +0 -0
  143. {claude_code_conductor-2.52.1 → claude_code_conductor-2.54.0}/tests/__init__.py +0 -0
  144. {claude_code_conductor-2.52.1 → claude_code_conductor-2.54.0}/tests/_pre_compact_helpers.py +0 -0
  145. {claude_code_conductor-2.52.1 → claude_code_conductor-2.54.0}/tests/conftest.py +0 -0
  146. {claude_code_conductor-2.52.1 → claude_code_conductor-2.54.0}/tests/fixtures/usage/README.md +0 -0
  147. {claude_code_conductor-2.52.1 → claude_code_conductor-2.54.0}/tests/fixtures/usage/mainline.jsonl +0 -0
  148. {claude_code_conductor-2.52.1 → claude_code_conductor-2.54.0}/tests/fixtures/usage/subagents/agent-deadbeef.jsonl +0 -0
  149. {claude_code_conductor-2.52.1 → claude_code_conductor-2.54.0}/tests/fixtures/usage/subagents/agent-deadbeef.meta.json +0 -0
  150. {claude_code_conductor-2.52.1 → claude_code_conductor-2.54.0}/tests/hooks/__init__.py +0 -0
  151. {claude_code_conductor-2.52.1 → claude_code_conductor-2.54.0}/tests/hooks/test_check_agent_invocation.py +0 -0
  152. {claude_code_conductor-2.52.1 → claude_code_conductor-2.54.0}/tests/hooks/test_consolidate_memory.py +0 -0
  153. {claude_code_conductor-2.52.1 → claude_code_conductor-2.54.0}/tests/hooks/test_hook_utils.py +0 -0
  154. {claude_code_conductor-2.52.1 → claude_code_conductor-2.54.0}/tests/hooks/test_permission_handler.py +0 -0
  155. {claude_code_conductor-2.52.1 → claude_code_conductor-2.54.0}/tests/hooks/test_permission_handler_toast.py +0 -0
  156. {claude_code_conductor-2.52.1 → claude_code_conductor-2.54.0}/tests/hooks/test_pip_reinstall_reminder.py +0 -0
  157. {claude_code_conductor-2.52.1 → claude_code_conductor-2.54.0}/tests/hooks/test_planner_check.py +0 -0
  158. {claude_code_conductor-2.52.1 → claude_code_conductor-2.54.0}/tests/hooks/test_planner_check_dev.py +0 -0
  159. {claude_code_conductor-2.52.1 → claude_code_conductor-2.54.0}/tests/hooks/test_post_tool.py +0 -0
  160. {claude_code_conductor-2.52.1 → claude_code_conductor-2.54.0}/tests/hooks/test_pre_tool.py +0 -0
  161. {claude_code_conductor-2.52.1 → claude_code_conductor-2.54.0}/tests/hooks/test_recall_autorebuild.py +0 -0
  162. {claude_code_conductor-2.52.1 → claude_code_conductor-2.54.0}/tests/hooks/test_recall_inject.py +0 -0
  163. {claude_code_conductor-2.52.1 → claude_code_conductor-2.54.0}/tests/hooks/test_record_review_decision.py +0 -0
  164. {claude_code_conductor-2.52.1 → claude_code_conductor-2.54.0}/tests/hooks/test_restore_session.py +0 -0
  165. {claude_code_conductor-2.52.1 → claude_code_conductor-2.54.0}/tests/hooks/test_review_hint_inject.py +0 -0
  166. {claude_code_conductor-2.52.1 → claude_code_conductor-2.54.0}/tests/hooks/test_select_tier_escalation.py +0 -0
  167. {claude_code_conductor-2.52.1 → claude_code_conductor-2.54.0}/tests/hooks/test_session_start.py +0 -0
  168. {claude_code_conductor-2.52.1 → claude_code_conductor-2.54.0}/tests/hooks/test_session_stop.py +0 -0
  169. {claude_code_conductor-2.52.1 → claude_code_conductor-2.54.0}/tests/hooks/test_session_utils.py +0 -0
  170. {claude_code_conductor-2.52.1 → claude_code_conductor-2.54.0}/tests/hooks/test_settings_local_absolute_paths.py +0 -0
  171. {claude_code_conductor-2.52.1 → claude_code_conductor-2.54.0}/tests/hooks/test_settings_tier_autoapply_registration.py +0 -0
  172. {claude_code_conductor-2.52.1 → claude_code_conductor-2.54.0}/tests/hooks/test_similarity_boost.py +0 -0
  173. {claude_code_conductor-2.52.1 → claude_code_conductor-2.54.0}/tests/hooks/test_statusline.py +0 -0
  174. {claude_code_conductor-2.52.1 → claude_code_conductor-2.54.0}/tests/hooks/test_statusline_template_sync.py +0 -0
  175. {claude_code_conductor-2.52.1 → claude_code_conductor-2.54.0}/tests/hooks/test_sync_check.py +0 -0
  176. {claude_code_conductor-2.52.1 → claude_code_conductor-2.54.0}/tests/hooks/test_template_guard.py +0 -0
  177. {claude_code_conductor-2.52.1 → claude_code_conductor-2.54.0}/tests/hooks/test_tier_gap_check.py +0 -0
  178. {claude_code_conductor-2.52.1 → claude_code_conductor-2.54.0}/tests/hooks/test_tier_security_fixes.py +0 -0
  179. {claude_code_conductor-2.52.1 → claude_code_conductor-2.54.0}/tests/skills/__init__.py +0 -0
  180. {claude_code_conductor-2.52.1 → claude_code_conductor-2.54.0}/tests/skills/_skill_helpers.py +0 -0
  181. {claude_code_conductor-2.52.1 → claude_code_conductor-2.54.0}/tests/skills/test_dev_workflow_no_task_type.py +0 -0
  182. {claude_code_conductor-2.52.1 → claude_code_conductor-2.54.0}/tests/skills/test_init_session_no_task_type.py +0 -0
  183. {claude_code_conductor-2.52.1 → claude_code_conductor-2.54.0}/tests/skills/test_parallel_agents_skill_tier.py +0 -0
  184. {claude_code_conductor-2.52.1 → claude_code_conductor-2.54.0}/tests/skills/test_planner_lightweight.py +0 -0
  185. {claude_code_conductor-2.52.1 → claude_code_conductor-2.54.0}/tests/skills/test_recall_skill.py +0 -0
  186. {claude_code_conductor-2.52.1 → claude_code_conductor-2.54.0}/tests/skills/test_session_backlog_reconciliation.py +0 -0
  187. {claude_code_conductor-2.52.1 → claude_code_conductor-2.54.0}/tests/skills/test_session_guard.py +0 -0
  188. {claude_code_conductor-2.52.1 → claude_code_conductor-2.54.0}/tests/skills/test_setup_templates.py +0 -0
  189. {claude_code_conductor-2.52.1 → claude_code_conductor-2.54.0}/tests/skills/test_start_skill_bugfix_flow.py +0 -0
  190. {claude_code_conductor-2.52.1 → claude_code_conductor-2.54.0}/tests/skills/test_start_skill_new_flow.py +0 -0
  191. {claude_code_conductor-2.52.1 → claude_code_conductor-2.54.0}/tests/skills/test_start_skill_security_audit_phase.py +0 -0
  192. {claude_code_conductor-2.52.1 → claude_code_conductor-2.54.0}/tests/test_check_deletions.py +0 -0
  193. {claude_code_conductor-2.52.1 → claude_code_conductor-2.54.0}/tests/test_cli_ask.py +0 -0
  194. {claude_code_conductor-2.52.1 → claude_code_conductor-2.54.0}/tests/test_cli_doctor.py +0 -0
  195. {claude_code_conductor-2.52.1 → claude_code_conductor-2.54.0}/tests/test_cli_doctor_launcher.py +0 -0
  196. {claude_code_conductor-2.52.1 → claude_code_conductor-2.54.0}/tests/test_cli_entry.py +0 -0
  197. {claude_code_conductor-2.52.1 → claude_code_conductor-2.54.0}/tests/test_cli_list.py +0 -0
  198. {claude_code_conductor-2.52.1 → claude_code_conductor-2.54.0}/tests/test_cli_metrics.py +0 -0
  199. {claude_code_conductor-2.52.1 → claude_code_conductor-2.54.0}/tests/test_cli_plan.py +0 -0
  200. {claude_code_conductor-2.52.1 → claude_code_conductor-2.54.0}/tests/test_cli_recall.py +0 -0
  201. {claude_code_conductor-2.52.1 → claude_code_conductor-2.54.0}/tests/test_cli_run.py +0 -0
  202. {claude_code_conductor-2.52.1 → claude_code_conductor-2.54.0}/tests/test_cli_update_breaking_changes.py +0 -0
  203. {claude_code_conductor-2.52.1 → claude_code_conductor-2.54.0}/tests/test_cli_update_deletions.py +0 -0
  204. {claude_code_conductor-2.52.1 → claude_code_conductor-2.54.0}/tests/test_docstring_consistency.py +0 -0
  205. {claude_code_conductor-2.52.1 → claude_code_conductor-2.54.0}/tests/test_embedding.py +0 -0
  206. {claude_code_conductor-2.52.1 → claude_code_conductor-2.54.0}/tests/test_extract_breaking_changes.py +0 -0
  207. {claude_code_conductor-2.52.1 → claude_code_conductor-2.54.0}/tests/test_gitutil.py +0 -0
  208. {claude_code_conductor-2.52.1 → claude_code_conductor-2.54.0}/tests/test_mcp_server_elicit.py +0 -0
  209. {claude_code_conductor-2.52.1 → claude_code_conductor-2.54.0}/tests/test_migrate.py +0 -0
  210. {claude_code_conductor-2.52.1 → claude_code_conductor-2.54.0}/tests/test_no_bare_python_launcher.py +0 -0
  211. {claude_code_conductor-2.52.1 → claude_code_conductor-2.54.0}/tests/test_nul_boundary_lint.py +0 -0
  212. {claude_code_conductor-2.52.1 → claude_code_conductor-2.54.0}/tests/test_paths.py +0 -0
  213. {claude_code_conductor-2.52.1 → claude_code_conductor-2.54.0}/tests/test_plan_validator.py +0 -0
  214. {claude_code_conductor-2.52.1 → claude_code_conductor-2.54.0}/tests/test_pre_compact.py +0 -0
  215. {claude_code_conductor-2.52.1 → claude_code_conductor-2.54.0}/tests/test_pre_tool_hook.py +0 -0
  216. {claude_code_conductor-2.52.1 → claude_code_conductor-2.54.0}/tests/test_precompact_additional.py +0 -0
  217. {claude_code_conductor-2.52.1 → claude_code_conductor-2.54.0}/tests/test_precompact_toctou_fixes.py +0 -0
  218. {claude_code_conductor-2.52.1 → claude_code_conductor-2.54.0}/tests/test_pricing.py +0 -0
  219. {claude_code_conductor-2.52.1 → claude_code_conductor-2.54.0}/tests/test_recall_chunker.py +0 -0
  220. {claude_code_conductor-2.52.1 → claude_code_conductor-2.54.0}/tests/test_recall_index.py +0 -0
  221. {claude_code_conductor-2.52.1 → claude_code_conductor-2.54.0}/tests/test_references_migration.py +0 -0
  222. {claude_code_conductor-2.52.1 → claude_code_conductor-2.54.0}/tests/test_session_utils_additional.py +0 -0
  223. {claude_code_conductor-2.52.1 → claude_code_conductor-2.54.0}/tests/test_skill_no_builtin_conflict.py +0 -0
  224. {claude_code_conductor-2.52.1 → claude_code_conductor-2.54.0}/tests/test_statusline.py +0 -0
  225. {claude_code_conductor-2.52.1 → claude_code_conductor-2.54.0}/tests/test_stop_additional.py +0 -0
  226. {claude_code_conductor-2.52.1 → claude_code_conductor-2.54.0}/tests/test_stop_hook.py +0 -0
  227. {claude_code_conductor-2.52.1 → claude_code_conductor-2.54.0}/tests/test_stop_precompact_fixes.py +0 -0
  228. {claude_code_conductor-2.52.1 → claude_code_conductor-2.54.0}/tests/test_sync_template_stop.py +0 -0
  229. {claude_code_conductor-2.52.1 → claude_code_conductor-2.54.0}/tests/test_template_pre_tool_hook.py +0 -0
  230. {claude_code_conductor-2.52.1 → claude_code_conductor-2.54.0}/tests/test_usage_ingester.py +0 -0
  231. {claude_code_conductor-2.52.1 → claude_code_conductor-2.54.0}/tests/test_worktree_guard.py +0 -0
@@ -31,6 +31,8 @@
31
31
 
32
32
  コンテキストに応じて選択肢を追加してよい。
33
33
 
34
+ 自律モード(autonomous-mode skill・opt-in 必須)が有効な場合のみ、上記の承認ゲートは同 skill のゲート対応表に従って客観条件へ付け替わる。既定は常に HITL であり、opt-in なしに挙動が変わることはない(ただしこれは文書規約レベルの不変則であり、モード行挿入自体を機械的に承認と紐付ける仕組みではない。詳細は SKILL.md「モード行挿入の前提条件(不変則)」を参照)。
35
+
34
36
  ## Compact Instructions
35
37
 
36
38
  ### KEEP(保持する)
@@ -61,4 +63,6 @@
61
63
  - **`Skill` ツール / `/<skill>`** の参照は、Codex では `.agents/skills/<name>/SKILL.md`、Cursor では `.claude/skills/<name>/SKILL.md` を直接読み込む。OpenCode では `.opencode/agents/c3-skill-<name>.md`(`.claude/skills/<name>/SKILL.md` を本文に埋め込み済み)を `@mention` で起動する(スラッシュコマンド自動展開は Claude Code 専用機能)
62
64
  - **`isolation: worktree`** / **`permissionMode`** / **`tools` 制限** など agent フロントマターの一部キーは Claude Code 仕様。adapter 側では読み替え不能なものは無視される(OpenCode adapter は全 agent に `bash/read/edit/write/websearch` を一律付与する)
63
65
 
66
+ - **自律モード**: autonomous-mode は Claude Code 専用。Codex / Cursor / OpenCode では自律宣言は常に無効=HITL で動作する(モード行の検証は `mode_line.py`・Bash 経由に依存し、他プラットフォームで安全に再現できないため。検証できない → HITL の fail-closed 原則がそのまま正しい挙動になる)。adapter 生成物にも autonomous-mode skill は写像されない。
67
+
64
68
  レポート(`.claude/reports/`)・state(`.claude/state/`)・memory(`.claude/agent-memory/`)のファイル名と書き込み先は全プラットフォーム共通。adapter 生成物の詳細は `c3 init --platform codex|cursor|opencode` で出力される `AGENTS.md` / `.cursor/rules/c3-core.mdc` / `.opencode/agents/` を参照。
@@ -0,0 +1,102 @@
1
+ # 自律モード オンボーディング
2
+
3
+ C3 の「自律モード(autonomous mode)」を初めて使う人向けの導入ガイド。
4
+ **手順と心構え**だけを書く。数値・条件・文法の厳密な定義は規約 SSOT である
5
+ `.claude/skills/autonomous-mode/SKILL.md` を参照すること(本文書は規約を再定義しない)。
6
+
7
+ > このガイドは `.claude/docs/` 配下の人間向けリファレンス。エージェントが実行時に読む必要はない。
8
+
9
+ ---
10
+
11
+ ## ① 自律モードとは
12
+
13
+ 自律モードは、C3 標準ワークフローの承認ゲート(レポート承認・テスト承認・findings 分岐など)を、
14
+ ユーザーが承認した**委任プラン**に従って客観条件で自動進行させる運転モードである。
15
+
16
+ - **既定は常に HITL(Human In The Loop)**。何もしなければ従来どおり各フェーズで承認を求める。
17
+ - 有効化には**二重の opt-in** が必要:
18
+ 1. プランモードで「資源同意節を含む委任プラン」をユーザーが承認する
19
+ 2. その承認直後に、親 Claude がセッションファイルへ**モード行**を挿入する
20
+ - opt-in なしに挙動が変わることはない(誤発動ゼロを最優先に設計されている)。
21
+ ただしこれは文書規約レベルの不変則であり、モード行の挿入自体がセレモニー経由であることを機械検証する仕組みではない
22
+ (既知の限界は SKILL.md「モード行挿入の前提条件(不変則)」を参照)。
23
+
24
+ ---
25
+
26
+ ## ② 正しい始め方
27
+
28
+ **プランモードを先に通すのが唯一の正しい入口**。順序を守ること。
29
+
30
+ 1. **プランモードで委任プランを作る**。プランには固定様式の `## 資源同意` 節を含める
31
+ (ハード上限・起動体数の見込み・「承認をもって資源消費に同意」の 3 点。様式は SKILL.md の
32
+ 「委任プランの必須節(資源同意)」を参照)。
33
+ 2. **プランを承認する**。この承認が「資源消費への同意」の成立点になる。
34
+ 3. 承認直後に、親 Claude が `現在地:` 行の直後へモード行を挿入する。初期形は
35
+ `モード: 自律 plan=<委任プランの絶対パス> cycles=C-3/0,E/0`(`cycles=` は opt-in 時に発効し初期値は両ゲート 0)。
36
+
37
+ **よくある誤り**:
38
+
39
+ - **`/start` を先に叩くのは誤り**。標準ワークフローを HITL で走らせてしまい、自律モードにはならない。
40
+ 自律運転は「プランモード承認 → モード行挿入」を経てから、init-session(セッション交代・コンパクト後)が
41
+ モード行を読んで継続する形で成立する。
42
+ - 資源同意節を欠くプランで opt-in を成立させてはならない(欠落時は人間へ確認=関所 2)。
43
+
44
+ ---
45
+
46
+ ## ③ 質問が来るのは設計どおり
47
+
48
+ 自律運転中でも人間に質問が返ってくることがある。これは**故障ではなく設計どおりの安全装置**である。
49
+ 以下の 2 類型(人間の関所)は自律モードでも自動選択せず、必ず人間が判断する。
50
+
51
+ | 類型 | 具体例 | なぜ人間のままか |
52
+ |---|---|---|
53
+ | **非可逆操作** | git commit / push / tag / release・ファイル削除 | 取り消せない操作は最後の人間判断を残す(検証用ビルド足場の作成・後始末は含まない) |
54
+ | **情報不足の質問** | task-question(このタスクに不足する情報)/ axis-question(以後の全タスクに効く方針) | 情報の欠落は自動では埋められない |
55
+
56
+ 加えて、E フェーズ最終承認後の**引き継ぎバックログ照合**と**コミット提案**はコミット直前=人間の関所領域であり、
57
+ 自律でも AskUserQuestion を出して自動選択しない。
58
+
59
+ 「質問が来た=暴走していない」と受け止めてよい。
60
+
61
+ ---
62
+
63
+ ## ④ 止まり方(上限到達時の流れ)
64
+
65
+ 自律運転は無限に回らない。C-3 監査・E レビューにはサイクル上限があり、到達すると次の流れで止まる。
66
+
67
+ 1. **上限到達**(例: C-3 が上限サイクルまで回っても High/Medium が 0 に収束しない)
68
+ 2. **状態保全**: ワーキングツリー・レポート群をそのまま残す(調査可能な形で保全)
69
+ 3. **報告**: 収束または打ち切りで初めてまとめて人間へ報告する(逐一停止はしない)
70
+ 4. **裁定**: 人間が続行・方針変更・打ち切りを判断する
71
+ 5. **再開**: 裁定を受けて運転を継続、または HITL へ復帰する
72
+
73
+ 実例(B1 実走): E→C 差し戻し後に同一カウンタで早期に上限へ到達し、運転が止まった事例がある。
74
+ この経験から「差し戻しごとに小上限の別枠を付与する」規定が入った(詳細と数値は SKILL.md 参照)。
75
+ 止まること自体は異常ではなく、上限に守られて安全側に倒れた結果である。
76
+
77
+ ---
78
+
79
+ ## ⑤ C-3 収束 ≠ 欠陥ゼロ
80
+
81
+ **C-3 監査が収束しても、それは「欠陥がゼロになった」ことを意味しない。**
82
+ C-3 の収束条件が保証する射程は、**その時点の計画の健全性**に限られる。
83
+
84
+ - **実測の裏付け**: C-3 が収束(High/Medium 0)した後の E レビューで、実装バグが実際に発見された事例がある。
85
+ 収束は「設計・計画レベルで High/Medium の指摘が消えた」ことであって、実装が正しいことの証明ではない。
86
+ - **構造的な限界**: C-3 を担う design-critic は **Bash を持たず、コードを実行して検証できない**
87
+ (静的な読解のみ)。エスケープ処理・パーサ・状態機械のような組み合わせロジックの欠陥は、
88
+ 静的読解では原理的に取りこぼしうる。
89
+ - **最後の網は E の実行検証**: テスト実行を伴う E フェーズ(およびテスト全緑を客観条件とする D)が、
90
+ 実装バグに対する最後の防波堤になる。C-3 収束を「もう安全」と読み替えないこと。
91
+
92
+ ---
93
+
94
+ ## ⑥ 従量課金ユーザー向け注記
95
+
96
+ `## 資源同意` 節への承認は、**費用への同意を兼ねる**。
97
+
98
+ - **定額プラン**では、資源同意は主に「残枠(サイクル回数)の消費」を意味する。
99
+ - **従量課金(API 等)**では、資源同意は**費用の発生への同意**を意味する。
100
+ - **重要**: ハード上限が担保するのは**サイクル回数**であって費用ではない。
101
+ D のタスク数はプラン依存で可変、stuck 時は systematic-debugger が加算され、E→C 差し戻しごとに D 相当が再走する。
102
+ **費用の上界は規約では担保されない**。従量課金で使う場合は、この点を理解した上で opt-in すること。
@@ -12,9 +12,17 @@ tier-routing MVP: タスクの複雑度を簡易ヒューリスティックで
12
12
  推奨の提示と tier_selection.json への記録のみを担い、model の注入は
13
13
  tier_autoapply.py が行う。明示指定された `model:` は tier_autoapply が
14
14
  尊重して上書きしない。agent の `model:` フロントマター自体は変更しない
15
- - **やらない**: developer / wt_developer 以外の role への適用、
15
+ - **やる(ADR-3〜ADR-5 拡張)**: tester(Red) 推奨を additive な ``roles.tester``
16
+ キーとして tier_selection.json に併記する。tester / wt_tester は test- タスク
17
+ (Red フェーズ)に限り tier_autoapply が機械適用する(D-3/D-5 等の非 Red 起動は
18
+ 従来どおり frontmatter 任せ)。
19
+ - **やらない**: developer / wt_developer / tester(Red) 以外の role への適用、
16
20
  フォールバック(Haiku 失敗→Sonnet 自動昇格)
17
21
 
22
+ 【opus 固定不変則(ADR-6)】機械適用(APPLY_ROLES / RED_APPLY_ROLES)に追加できるのは
23
+ frontmatter ``model: sonnet`` の role のみ。opus frontmatter の agent(architect /
24
+ planner / design-critic / doc-writer / project-setup)は tier レバーを持たず恒久対象外。
25
+
18
26
  学習データ(帰属機械化・フェーズ3):
19
27
  - 結果は ``.claude/state/tier_selection.json`` に直近 1 件のみ書き込む
20
28
  - Agent 起動時に ``tier_autoapply.py`` が実適用 model を
@@ -451,15 +459,20 @@ _ESCALATION_MAP: dict[str, str] = {
451
459
  # SSOT: db.ESCALATION_THRESHOLD_DEFAULT 由来(import 部で取得)。C3_ESCALATION_THRESHOLD env で上書き可(v2.26.0)。
452
460
 
453
461
 
454
- def _db_failure_rate(complexity: str, tier: str) -> tuple:
462
+ def _db_failure_rate(complexity: str, tier: str, role: str = "developer") -> tuple:
455
463
  """DB から failure rate を読み取るデフォルト実装。
456
464
 
465
+ ``role`` は集計対象の agent role(既定 ``"developer"``・後方互換)。
466
+ ADR-5: tester 推奨の escalation では ``role="tester"`` を渡し
467
+ ``read_agent_failure_rate("tester", ...)`` を引く(role 別 gate 集合は
468
+ db 側 ``bandit_gates_for_role`` が解決する)。
469
+
457
470
  c3_db のインポートに失敗した場合は ``(None, 0)`` を返す。
458
471
  """
459
472
  c3_db = _load_c3_db_module()
460
473
  if c3_db is None:
461
474
  return None, 0
462
- return c3_db.read_agent_failure_rate("developer", complexity, tier)
475
+ return c3_db.read_agent_failure_rate(role, complexity, tier)
463
476
 
464
477
 
465
478
  def maybe_escalate(
@@ -468,6 +481,7 @@ def maybe_escalate(
468
481
  *,
469
482
  failure_rate_fn=None,
470
483
  threshold: float | None = None,
484
+ role: str = "developer",
471
485
  ) -> tuple[str, str | None]:
472
486
  """Phase 2-B: failure rate が高ければ 1 段昇格する。
473
487
 
@@ -476,10 +490,15 @@ def maybe_escalate(
476
490
  chosen_tier: select_tier が選んだ tier。
477
491
  failure_rate_fn: テスト用に注入可能な
478
492
  ``(complexity, tier) -> (rate_or_None, sample_count)``。
479
- 省略時は :func:`_db_failure_rate` を使う。
493
+ 省略時は :func:`_db_failure_rate` を使う。既存の注入契約(2 引数)を
494
+ 保つため、注入時は ``role`` を渡さない(テストは戻り値を固定するため
495
+ role 分岐は不要)。role は既定実装 ``_db_failure_rate`` へのみ透過する。
480
496
  threshold: escalation 閾値(failure rate がこの値以上で昇格)。
481
497
  None のとき module 定数 ``ESCALATION_THRESHOLD`` を使う。
482
498
  ``main()`` は ``_resolve_escalation_threshold()`` で解決した値を渡す。
499
+ role: 集計対象の agent role(既定 ``"developer"``)。ADR-5: tester 推奨の
500
+ escalation では ``role="tester"`` を渡して ``_db_failure_rate`` 経由で
501
+ tester セルの failure rate を引く。
483
502
 
484
503
  Returns:
485
504
  ``(effective_tier, escalation_reason)``。
@@ -489,8 +508,10 @@ def maybe_escalate(
489
508
  if chosen_tier not in _ESCALATION_MAP:
490
509
  return chosen_tier, None
491
510
 
492
- effective_fn = failure_rate_fn or _db_failure_rate
493
- rate, samples = effective_fn(complexity, chosen_tier)
511
+ if failure_rate_fn is not None:
512
+ rate, samples = failure_rate_fn(complexity, chosen_tier)
513
+ else:
514
+ rate, samples = _db_failure_rate(complexity, chosen_tier, role)
494
515
  eff_threshold = threshold if threshold is not None else ESCALATION_THRESHOLD
495
516
  if rate is None or rate < eff_threshold:
496
517
  return chosen_tier, None
@@ -516,6 +537,7 @@ def write_tier_selection(
516
537
  cost_tiebreak: bool = False,
517
538
  cost_weighted: bool = False,
518
539
  cost_lambda: float | None = None,
540
+ roles: dict[str, dict] | None = None,
519
541
  ) -> None:
520
542
  """直近の選択結果を ``tier_selection.json`` に書く。
521
543
 
@@ -543,6 +565,13 @@ def write_tier_selection(
543
565
  ``cost_lambda`` を任意で含める(v2.26.0)。
544
566
  ``_resolve_cost_lambda()`` で解決した λ 値(None 以外のとき出力)。
545
567
  None のときはキー自体を省略する(env 未設定時の後方互換)。
568
+
569
+ ``roles`` を任意で含める(ADR-3・additive role 別推奨)。
570
+ ``{"tester": {"tier": <実効 tier>, "mode": <mode>, "escalated"?: True}}`` の形。
571
+ None(渡されない)のときはキー自体を省略する(session_id / cost_tiebreak と
572
+ 同じ additive-omit パターン=トップレベルの bit 一致を保つ後方互換の核心)。
573
+ トップレベルの ``tier`` / ``mode`` は現行どおり developer 推奨を書き、
574
+ ``roles.tester`` は新読者(tier_autoapply 注入・record 優先 3)だけが見る。
546
575
  """
547
576
  os.makedirs(os.path.dirname(TIER_SELECTION_PATH), exist_ok=True)
548
577
  payload: dict[str, object] = {
@@ -570,6 +599,8 @@ def write_tier_selection(
570
599
  payload["cost_weighted"] = True
571
600
  if cost_lambda is not None:
572
601
  payload["cost_lambda"] = cost_lambda
602
+ if roles is not None:
603
+ payload["roles"] = roles
573
604
  try:
574
605
  with open(TIER_SELECTION_PATH, "w", encoding="utf-8") as f:
575
606
  json.dump(payload, f, ensure_ascii=False)
@@ -588,6 +619,7 @@ def build_additional_context(
588
619
  complexity_source: str | None = None,
589
620
  cost_tiebreak: bool = False,
590
621
  cost_weighted: bool = False,
622
+ tester_tier: str | None = None,
591
623
  ) -> str:
592
624
  """親 Claude に追加注入する文字列を組み立てる。
593
625
 
@@ -597,6 +629,11 @@ def build_additional_context(
597
629
  ``cost_weighted`` が True のとき、cost-weighted 文言を suffix に追加する(v2.26.0)。
598
630
  True のときは cost_tiebreak の文言より優先される(λ>0 全 tier weighting を明示)。
599
631
  False のときは cost_tiebreak による既存文言のみ(v2.25.0 以前と完全一致)。
632
+
633
+ ``tester_tier`` が渡された場合、tester(Red) 推奨 Tier を併記する(ADR-4)。
634
+ None(既定)のときは併記行を省略する(build_additional_context を直接呼ぶ
635
+ 既存テストの後方互換)。tester / wt_tester は test- タスク(Red)に限り機械適用
636
+ 対象であることを対象説明に明記する。
600
637
  """
601
638
  trials = sum(p[2] for p in params.values())
602
639
  if mode == "uniform":
@@ -615,6 +652,10 @@ def build_additional_context(
615
652
  elif cost_tiebreak:
616
653
  suffix += " [cost-aware: 成功率拮抗のため低コスト Tier を選択]"
617
654
 
655
+ tester_note = ""
656
+ if tester_tier is not None:
657
+ tester_note = f" tester(Red) 推奨 Tier: {tester_tier}。"
658
+
618
659
  return (
619
660
  f"[tier-routing 推奨] 複雑度: {complexity} / 推奨 Tier: {tier}({confidence}・developer 基準)。"
620
661
  f" developer / wt_developer を Agent ツールで起動する際は、PreToolUse hook"
@@ -622,9 +663,12 @@ def build_additional_context(
622
663
  f"(親 Claude が model: を転記する必要はありません・学習データ収集中の期間も含め常に適用)。"
623
664
  f" 推奨と異なる Tier を使いたい場合のみ、Agent 呼び出し時に model: を明示指定してください"
624
665
  f"(明示指定は尊重され hook に上書きされません。fork は model 上書き不可のため対象外)。"
625
- f" 対象は developer / wt_developer のみ。tester 等の他 role、および親 Claude"
626
- f" ペルソナで動かす role(interviewer / architect / planner)は"
627
- f" tier レバーが無いため対象外で従来どおりとする。{suffix}"
666
+ f"{tester_note}"
667
+ f" tester / wt_tester は test- タスク(Red フェーズ)に限り機械適用対象です"
668
+ f"(C3_TASK_ID: test-... マーカー付き起動のみ・D-3/D-5 等の非 Red 起動は"
669
+ f" 従来どおり frontmatter 任せ)。親 Claude ペルソナで動かす role"
670
+ f"(interviewer / architect / planner)は tier レバーが無いため対象外で"
671
+ f" 従来どおりとする。{suffix}"
628
672
  )
629
673
 
630
674
 
@@ -814,6 +858,25 @@ def main() -> int:
814
858
  effective_tier, escalation_reason = maybe_escalate(complexity, tier, threshold=esc_thr)
815
859
  escalated = effective_tier != tier
816
860
 
861
+ # ADR-3/ADR-4/ADR-5: tester(Red) 推奨を additive に算出する。complexity /
862
+ # cost_map / epsilon / lam は developer と同一解決値を使う(per-prompt 分類・
863
+ # DC-AS-001)。escalation は role="tester" で tester セルの failure rate を引く。
864
+ # developer 推奨を先に確定してから算出するため、tester 側の rng 消費は
865
+ # developer の結果に影響しない(トップレベル bit 一致の後方互換を保つ)。
866
+ if c3_db is None:
867
+ tester_params = {t: (1.0, 1.0, 0) for t in TIERS}
868
+ else:
869
+ tester_params = c3_db.read_agent_tier_params("tester", complexity)
870
+ tester_result = select_tier_detailed(tester_params, cost_map=cost_map, epsilon=eps, lam=lam)
871
+ tester_effective, _tester_esc_reason = maybe_escalate(
872
+ complexity, tester_result.tier, threshold=esc_thr, role="tester",
873
+ )
874
+ tester_escalated = tester_effective != tester_result.tier
875
+ tester_entry: dict[str, object] = {"tier": tester_effective, "mode": tester_result.mode}
876
+ if tester_escalated:
877
+ tester_entry["escalated"] = True
878
+ roles = {"tester": tester_entry}
879
+
817
880
  write_tier_selection(
818
881
  complexity, effective_tier, mode,
819
882
  escalated=escalated, escalation_reason=escalation_reason,
@@ -823,6 +886,7 @@ def main() -> int:
823
886
  cost_tiebreak=cost_tiebreak,
824
887
  cost_weighted=result.cost_weighted,
825
888
  cost_lambda=lam,
889
+ roles=roles,
826
890
  )
827
891
 
828
892
  context_text = build_additional_context(
@@ -831,6 +895,7 @@ def main() -> int:
831
895
  complexity_source=complexity_source,
832
896
  cost_tiebreak=cost_tiebreak,
833
897
  cost_weighted=result.cost_weighted,
898
+ tester_tier=tester_effective,
834
899
  )
835
900
  output = {
836
901
  "hookSpecificOutput": {
@@ -12,6 +12,10 @@ check_agent は reviewer 系のみ)のため実行順序に依存しない(
12
12
  tier_selection.json から有効 tier を解決できたとき、`updatedInput` で
13
13
  `model:{推奨tier}` を注入した(source=injected・permissionDecision は
14
14
  T0 実測により省略形を正とした)。
15
+ - `RED_APPLY_ROLES = {tester, wt_tester}` かつ `model` 無指定かつ
16
+ `C3_TASK_ID:` マーカーが `test-` で始まりかつ `roles.tester.tier` を解決できた
17
+ ときのみ注入した(Red 限定・ADR-2)。confirm-/impl-/マーカー無し・roles 欠落は
18
+ 注入せず記録のみ(frontmatter の既定が実効・fail-safe)。
15
19
  - 明示 `model` 指定時は素通り(source=explicit・明示尊重)。
16
20
  - tier_selection 不在/破損/非文字列 tier のときは注入せず素通り
17
21
  (source=frontmatter-default・frontmatter の sonnet が実効するため)。
@@ -81,7 +85,19 @@ TIER_SELECTION_PATH = os.path.join(_CLAUDE_DIR, "state", "tier_selection.json")
81
85
  APPLIED_STATE_PATH = os.path.join(_CLAUDE_DIR, "state", "tier_autoapply.jsonl")
82
86
 
83
87
  # §3-2 ロール分岐表の定数。
88
+ # APPLY_ROLES: 無条件 APPLY(起動フェーズを問わず tier_selection.json のトップレベル
89
+ # tier を機械適用する)role 集合。
90
+ # RED_APPLY_ROLES: Red フェーズ(test- タスク)限定で機械適用する role 集合(ADR-2)。
91
+ # 注入条件は「role ∈ RED_APPLY_ROLES かつ C3_TASK_ID マーカーが test- 開始かつ
92
+ # roles.tester.tier 解決可」の 3 条件全成立時のみ。D-3/D-5 等の非 Red 起動には
93
+ # test- マーカーを付与しない運用不変則(dev-workflow SKILL)と組で NF-2 を守る。
94
+ #
95
+ # 【opus 固定不変則(ADR-6)】APPLY_ROLES / RED_APPLY_ROLES に追加できるのは
96
+ # frontmatter model: sonnet の role のみ。opus frontmatter の agent(architect /
97
+ # planner / design-critic / doc-writer / project-setup)は tier レバーを持たず
98
+ # 恒久対象外(機械検査テストで frontmatter が sonnet であることを CI 回帰網に固定)。
84
99
  APPLY_ROLES = frozenset({"developer", "wt_developer"})
100
+ RED_APPLY_ROLES = frozenset({"tester", "wt_tester"})
85
101
  LAUNCH_LOG_ROLES = frozenset({"developer", "wt_developer", "tester", "wt_tester"})
86
102
  # wt_* → 無印への正規化(record 側 role 語彙・agent_outcomes.role と一致・§0-4)。
87
103
  _ROLE_NORMALIZE = {"wt_developer": "developer", "wt_tester": "tester"}
@@ -99,9 +115,12 @@ _ROTATE_TAIL_LINES = 500
99
115
 
100
116
  _PROMPT_PREFIX_MAX_CHARS = 200
101
117
 
102
- # T8: 起動プロンプト先頭の C3_TASK_ID マーカー抽出用(§3-1)。行頭アンカー +
103
- # allowlist + 上限200字で誤抽出・秘密混入を構造排除する(record MAX_TASK_LEN=200 と整合)。
104
- _TASK_ID_MARKER_RE = re.compile(r'^C3_TASK_ID:[ ]([A-Za-z0-9._\-]{1,200})[ ]*$', re.MULTILINE)
118
+ # T8: 起動プロンプト先頭の C3_TASK_ID マーカー抽出用(§3-1・SR-AI-001 で \A 化)。
119
+ # 文字列先頭アンカー \A + allowlist + 上限200字で誤抽出・秘密混入を構造排除する
120
+ # (record MAX_TASK_LEN=200 と整合)。re.MULTILINE の行頭 ^ は本文孤立行・フェンス内・
121
+ # 2 行目マーカーを誤抽出するため撤廃し、マーカーは「文字列先頭 1 行目のみ」を唯一の
122
+ # 正当配置に統一する(parallel/逐次とも 1 行目マーカー・2 行目以降にガード指示・§2-3 改訂 7)。
123
+ _TASK_ID_MARKER_RE = re.compile(r'\AC3_TASK_ID:[ ]([A-Za-z0-9._\-]{1,200})[ ]*(?:\r?\n|\Z)')
105
124
 
106
125
 
107
126
  def _load_pricing_module():
@@ -176,7 +195,9 @@ def _clean_prompt_prefix(prompt: object) -> str:
176
195
  def _extract_task_id(prompt: object) -> str | None:
177
196
  """起動プロンプトから C3_TASK_ID マーカー(最初の 1 個)を抽出した(§3)。
178
197
 
179
- 許容文字集合 [A-Za-z0-9._-]・行頭アンカー・上限200字で誤抽出と秘密混入を防ぐ。
198
+ 許容文字集合 [A-Za-z0-9._-]・文字列先頭アンカー \\A・上限200字で誤抽出と秘密混入を防ぐ。
199
+ マーカーは「プロンプト文字列の先頭 1 行目」にある場合のみ抽出成立する(本文孤立行・
200
+ フェンス内・2 行目以降は非マッチ=None・SR-AI-001)。
180
201
  prompt_prefix の mask→truncate パイプラインとは独立(正規表現自体がサニタイザ・§3-3)。
181
202
  非文字列・不一致は None(→ jsonl は task_id: null で従来挙動・逐次経路も None)。
182
203
  """
@@ -221,6 +242,34 @@ def _resolve_selection_tier(c3_pricing) -> str | None:
221
242
  return None
222
243
 
223
244
 
245
+ def _resolve_roles_tier(c3_pricing, role: str) -> str | None:
246
+ """tier_selection.json の ``roles.<role>.tier`` を正規化 tier に解決した(ADR-3)。
247
+
248
+ Red 限定注入の tier 源。トップレベル ``tier`` ではなく additive な
249
+ ``roles`` キー配下を読む。``roles`` 欠落・``roles.<role>`` 破損・非文字列 tier・
250
+ 正規化不能は全て None を返し、呼び出し側は注入せず frontmatter-default に落ちる
251
+ (fail-safe が安全側に一致)。
252
+ """
253
+ if c3_pricing is None:
254
+ return None
255
+ selection = _read_selection()
256
+ if selection is None:
257
+ return None
258
+ roles = selection.get("roles")
259
+ if not isinstance(roles, dict):
260
+ return None
261
+ entry = roles.get(role)
262
+ if not isinstance(entry, dict):
263
+ return None
264
+ raw = entry.get("tier")
265
+ if not isinstance(raw, str):
266
+ return None
267
+ resolved = c3_pricing.resolve_tier(raw)
268
+ if resolved in _VALID_TIERS:
269
+ return resolved
270
+ return None
271
+
272
+
224
273
  def _rotate_if_needed(path: str) -> None:
225
274
  """applied-state が 1MB を超えていたら末尾500行へ切り詰めた(§3-4・失敗時は無視)。"""
226
275
  try:
@@ -351,9 +400,14 @@ def main() -> None:
351
400
  model_val = tool_input.get("model")
352
401
  has_explicit_model = isinstance(model_val, str) and model_val.strip() != ""
353
402
 
403
+ # task_id は注入判定(RED_APPLY_ROLES の test- プレフィックス条件)と row 記録の
404
+ # 双方で使うため先に抽出する(§3-1・ADR-2)。
405
+ prompt = tool_input.get("prompt")
406
+ task_id = _extract_task_id(prompt)
407
+
354
408
  inject = False
355
409
  if has_explicit_model:
356
- # 明示尊重: 注入せず素通りし explicit で記録した。
410
+ # 明示尊重: 注入せず素通りし explicit で記録した(RED_APPLY_ROLES でも不変)。
357
411
  source = "explicit"
358
412
  model_applied: str | None = model_val
359
413
  elif subagent_type in APPLY_ROLES:
@@ -367,12 +421,28 @@ def main() -> None:
367
421
  # tier_selection 不在/破損/非文字列: frontmatter の既定が実効するため記録のみ。
368
422
  source = "frontmatter-default"
369
423
  model_applied = None
424
+ elif subagent_type in RED_APPLY_ROLES:
425
+ # tester/wt_tester: Red 限定注入(ADR-2)。C3_TASK_ID マーカーが test- 開始
426
+ # かつ roles.tester.tier が解決可のときのみ注入。confirm-/impl-/マーカー無し・
427
+ # roles 欠落/破損は注入せず記録のみ(frontmatter の既定が実効・fail-safe 一致)。
428
+ if isinstance(task_id, str) and task_id.startswith("test-"):
429
+ c3_pricing = _load_pricing_module()
430
+ tier = _resolve_roles_tier(c3_pricing, role_recorded)
431
+ if tier is not None:
432
+ inject = True
433
+ source = "injected"
434
+ model_applied = tier
435
+ else:
436
+ source = "frontmatter-default"
437
+ model_applied = None
438
+ else:
439
+ source = "frontmatter-default"
440
+ model_applied = None
370
441
  else:
371
- # tester/wt_tester: 注入対象外(記録のみ)。frontmatter の既定が実効した。
442
+ # LAUNCH_LOG_ROLES のうち上記いずれにも該当しない role(現状なし・防御)。
372
443
  source = "frontmatter-default"
373
444
  model_applied = None
374
445
 
375
- prompt = tool_input.get("prompt")
376
446
  row = {
377
447
  "ts": datetime.now(timezone.utc).isoformat(timespec="seconds"),
378
448
  "session_id": session_id,
@@ -381,7 +451,11 @@ def main() -> None:
381
451
  "model_applied": model_applied,
382
452
  "source": source,
383
453
  "prompt_prefix": _clean_prompt_prefix(prompt),
384
- "task_id": _extract_task_id(prompt),
454
+ # SR-K-003 前提: task_id は _TASK_ID_MARKER_RE の allowlist [A-Za-z0-9._-] を
455
+ # 通過済みのため秘密混入が構造的に不可能で _mask_secrets を適用していない。
456
+ # 許容文字集合が緩和される場合(記号・空白等を許す等)は、prompt_prefix と同様に
457
+ # _mask_secrets 適用が必要になる(マスク非対称の申し送り)。
458
+ "task_id": task_id,
385
459
  }
386
460
  _append_applied_state(row)
387
461
 
@@ -44,9 +44,10 @@ TIER_SELECTION_PATH = os.path.join(_CLAUDE_DIR, "state", "tier_selection.json")
44
44
 
45
45
  # roll 対象: developer のみ(tester は除外)。
46
46
  # 理由: tier_autoapply.py LAUNCH_LOG_ROLES に tester を含めて起動ログは記録するが、
47
- # dev-workflow の記録契約上 tester の outcome 記録(D-5)は成功時 1 回が上限。
48
- # tester の起動(Red フェーズでの テスト実行・confirm 起動など)は複数回のため、
49
- # 起動 N >> 記録 M となり常時 K' > 0 で誤警告が発火する(カーディナリティ不一致)。
47
+ # dev-workflow の記録契約上 tester の outcome 記録は D-1(Red 限定・条件 1〜4)と
48
+ # D-5(最終確認)に限られ、tester の起動回数(Red フェーズでのテスト実行・confirm
49
+ # 起動・D-3 など複数回)には遠く及ばない。したがって起動 N >> 記録 M となり常時
50
+ # K' > 0 で誤警告が発火する(カーディナリティ不一致)ため tester は依然除外する。
50
51
  # CR F-1 で構造的誤検知として developer のみに限定した(起動ログ記録は維持)。
51
52
  _EVALUATED_ROLES = frozenset({"developer"})
52
53
  # 直近5分は中間状態として除外