claude-code-conductor 2.25.0__tar.gz → 2.26.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 (194) hide show
  1. {claude_code_conductor-2.25.0 → claude_code_conductor-2.26.0}/.claude/hooks/select_tier.py +185 -25
  2. {claude_code_conductor-2.25.0 → claude_code_conductor-2.26.0}/CHANGELOG.md +23 -0
  3. {claude_code_conductor-2.25.0 → claude_code_conductor-2.26.0}/PKG-INFO +2 -2
  4. {claude_code_conductor-2.25.0 → claude_code_conductor-2.26.0}/README.md +1 -1
  5. {claude_code_conductor-2.25.0 → claude_code_conductor-2.26.0}/src/c3/__init__.py +1 -1
  6. {claude_code_conductor-2.25.0 → claude_code_conductor-2.26.0}/src/c3/db.py +10 -0
  7. {claude_code_conductor-2.25.0 → claude_code_conductor-2.26.0}/tests/hooks/test_select_tier.py +831 -0
  8. claude_code_conductor-2.26.0/tests/hooks/test_select_tier_escalation.py +464 -0
  9. {claude_code_conductor-2.25.0 → claude_code_conductor-2.26.0}/tests/test_db.py +19 -0
  10. claude_code_conductor-2.25.0/tests/hooks/test_select_tier_escalation.py +0 -229
  11. {claude_code_conductor-2.25.0 → claude_code_conductor-2.26.0}/.claude/CLAUDE.md +0 -0
  12. {claude_code_conductor-2.25.0 → claude_code_conductor-2.26.0}/.claude/agents/architect.md +0 -0
  13. {claude_code_conductor-2.25.0 → claude_code_conductor-2.26.0}/.claude/agents/code-reviewer.md +0 -0
  14. {claude_code_conductor-2.25.0 → claude_code_conductor-2.26.0}/.claude/agents/developer.md +0 -0
  15. {claude_code_conductor-2.25.0 → claude_code_conductor-2.26.0}/.claude/agents/doc-writer.md +0 -0
  16. {claude_code_conductor-2.25.0 → claude_code_conductor-2.26.0}/.claude/agents/interviewer.md +0 -0
  17. {claude_code_conductor-2.25.0 → claude_code_conductor-2.26.0}/.claude/agents/planner.md +0 -0
  18. {claude_code_conductor-2.25.0 → claude_code_conductor-2.26.0}/.claude/agents/project-setup.md +0 -0
  19. {claude_code_conductor-2.25.0 → claude_code_conductor-2.26.0}/.claude/agents/security-reviewer.md +0 -0
  20. {claude_code_conductor-2.25.0 → claude_code_conductor-2.26.0}/.claude/agents/systematic-debugger.md +0 -0
  21. {claude_code_conductor-2.25.0 → claude_code_conductor-2.26.0}/.claude/agents/tester.md +0 -0
  22. {claude_code_conductor-2.25.0 → claude_code_conductor-2.26.0}/.claude/agents/wt_developer.md +0 -0
  23. {claude_code_conductor-2.25.0 → claude_code_conductor-2.26.0}/.claude/agents/wt_systematic-debugger.md +0 -0
  24. {claude_code_conductor-2.25.0 → claude_code_conductor-2.26.0}/.claude/agents/wt_tester.md +0 -0
  25. {claude_code_conductor-2.25.0 → claude_code_conductor-2.26.0}/.claude/breaking-changes.txt +0 -0
  26. {claude_code_conductor-2.25.0 → claude_code_conductor-2.26.0}/.claude/deletions.txt +0 -0
  27. {claude_code_conductor-2.25.0 → claude_code_conductor-2.26.0}/.claude/docs/config-policy.md +0 -0
  28. {claude_code_conductor-2.25.0 → claude_code_conductor-2.26.0}/.claude/docs/parallel-agents-setup.md +0 -0
  29. {claude_code_conductor-2.25.0 → claude_code_conductor-2.26.0}/.claude/docs/platform-adapters.md +0 -0
  30. {claude_code_conductor-2.25.0 → claude_code_conductor-2.26.0}/.claude/docs/settings.json.md +0 -0
  31. {claude_code_conductor-2.25.0 → claude_code_conductor-2.26.0}/.claude/hooks/_hook_utils.py +0 -0
  32. {claude_code_conductor-2.25.0 → claude_code_conductor-2.26.0}/.claude/hooks/check_agent_invocation.py +0 -0
  33. {claude_code_conductor-2.25.0 → claude_code_conductor-2.26.0}/.claude/hooks/consolidate_memory.py +0 -0
  34. {claude_code_conductor-2.25.0 → claude_code_conductor-2.26.0}/.claude/hooks/permission_handler.py +0 -0
  35. {claude_code_conductor-2.25.0 → claude_code_conductor-2.26.0}/.claude/hooks/permission_handler_toast.py +0 -0
  36. {claude_code_conductor-2.25.0 → claude_code_conductor-2.26.0}/.claude/hooks/planner_check.py +0 -0
  37. {claude_code_conductor-2.25.0 → claude_code_conductor-2.26.0}/.claude/hooks/post_tool.py +0 -0
  38. {claude_code_conductor-2.25.0 → claude_code_conductor-2.26.0}/.claude/hooks/pre_compact.py +0 -0
  39. {claude_code_conductor-2.25.0 → claude_code_conductor-2.26.0}/.claude/hooks/pre_tool.py +0 -0
  40. {claude_code_conductor-2.25.0 → claude_code_conductor-2.26.0}/.claude/hooks/recall_inject.py +0 -0
  41. {claude_code_conductor-2.25.0 → claude_code_conductor-2.26.0}/.claude/hooks/restore_session.py +0 -0
  42. {claude_code_conductor-2.25.0 → claude_code_conductor-2.26.0}/.claude/hooks/session_start.py +0 -0
  43. {claude_code_conductor-2.25.0 → claude_code_conductor-2.26.0}/.claude/hooks/session_stop.py +0 -0
  44. {claude_code_conductor-2.25.0 → claude_code_conductor-2.26.0}/.claude/hooks/session_utils.py +0 -0
  45. {claude_code_conductor-2.25.0 → claude_code_conductor-2.26.0}/.claude/hooks/statusline.py +0 -0
  46. {claude_code_conductor-2.25.0 → claude_code_conductor-2.26.0}/.claude/hooks/stop.py +0 -0
  47. {claude_code_conductor-2.25.0 → claude_code_conductor-2.26.0}/.claude/hooks/worktree_guard.py +0 -0
  48. {claude_code_conductor-2.25.0 → claude_code_conductor-2.26.0}/.claude/memory/.gitkeep +0 -0
  49. {claude_code_conductor-2.25.0 → claude_code_conductor-2.26.0}/.claude/permission_rules.json +0 -0
  50. {claude_code_conductor-2.25.0 → claude_code_conductor-2.26.0}/.claude/rules/promoted/index.md +0 -0
  51. {claude_code_conductor-2.25.0 → claude_code_conductor-2.26.0}/.claude/settings.json +0 -0
  52. {claude_code_conductor-2.25.0 → claude_code_conductor-2.26.0}/.claude/skills/codex-review/SKILL.md +0 -0
  53. {claude_code_conductor-2.25.0 → claude_code_conductor-2.26.0}/.claude/skills/dev-workflow/SKILL.md +0 -0
  54. {claude_code_conductor-2.25.0 → claude_code_conductor-2.26.0}/.claude/skills/dev-workflow/references/code-review-checklist.md +0 -0
  55. {claude_code_conductor-2.25.0 → claude_code_conductor-2.26.0}/.claude/skills/dev-workflow/references/plan-design-guidelines.md +0 -0
  56. {claude_code_conductor-2.25.0 → claude_code_conductor-2.26.0}/.claude/skills/dev-workflow/references/security-review-checklist.md +0 -0
  57. {claude_code_conductor-2.25.0 → claude_code_conductor-2.26.0}/.claude/skills/dev-workflow/scripts/record_review_decision.py +0 -0
  58. {claude_code_conductor-2.25.0 → claude_code_conductor-2.26.0}/.claude/skills/dev-workflow/scripts/record_tier_outcome.py +0 -0
  59. {claude_code_conductor-2.25.0 → claude_code_conductor-2.26.0}/.claude/skills/dev-workflow/scripts/review_hint_inject.py +0 -0
  60. {claude_code_conductor-2.25.0 → claude_code_conductor-2.26.0}/.claude/skills/develop/SKILL.md +0 -0
  61. {claude_code_conductor-2.25.0 → claude_code_conductor-2.26.0}/.claude/skills/doc/SKILL.md +0 -0
  62. {claude_code_conductor-2.25.0 → claude_code_conductor-2.26.0}/.claude/skills/extract-lib/SKILL.md +0 -0
  63. {claude_code_conductor-2.25.0 → claude_code_conductor-2.26.0}/.claude/skills/init-session/SKILL.md +0 -0
  64. {claude_code_conductor-2.25.0 → claude_code_conductor-2.26.0}/.claude/skills/mcp-config/SKILL.md +0 -0
  65. {claude_code_conductor-2.25.0 → claude_code_conductor-2.26.0}/.claude/skills/parallel-agents/SKILL.md +0 -0
  66. {claude_code_conductor-2.25.0 → claude_code_conductor-2.26.0}/.claude/skills/pattern-status/SKILL.md +0 -0
  67. {claude_code_conductor-2.25.0 → claude_code_conductor-2.26.0}/.claude/skills/promote-pattern/SKILL.md +0 -0
  68. {claude_code_conductor-2.25.0 → claude_code_conductor-2.26.0}/.claude/skills/recall/SKILL.md +0 -0
  69. {claude_code_conductor-2.25.0 → claude_code_conductor-2.26.0}/.claude/skills/report-timestamp/SKILL.md +0 -0
  70. {claude_code_conductor-2.25.0 → claude_code_conductor-2.26.0}/.claude/skills/report-timestamp/scripts/get_timestamp.py +0 -0
  71. {claude_code_conductor-2.25.0 → claude_code_conductor-2.26.0}/.claude/skills/review-phase/SKILL.md +0 -0
  72. {claude_code_conductor-2.25.0 → claude_code_conductor-2.26.0}/.claude/skills/setup/SKILL.md +0 -0
  73. {claude_code_conductor-2.25.0 → claude_code_conductor-2.26.0}/.claude/skills/setup/reference.md +0 -0
  74. {claude_code_conductor-2.25.0 → claude_code_conductor-2.26.0}/.claude/skills/setup/templates/coding-standards-template.md +0 -0
  75. {claude_code_conductor-2.25.0 → claude_code_conductor-2.26.0}/.claude/skills/setup/templates/project-conventions-template.md +0 -0
  76. {claude_code_conductor-2.25.0 → claude_code_conductor-2.26.0}/.claude/skills/start/SKILL.md +0 -0
  77. {claude_code_conductor-2.25.0 → claude_code_conductor-2.26.0}/.claude/state/.gitkeep +0 -0
  78. {claude_code_conductor-2.25.0 → claude_code_conductor-2.26.0}/.gitignore +0 -0
  79. {claude_code_conductor-2.25.0 → claude_code_conductor-2.26.0}/LICENSE +0 -0
  80. {claude_code_conductor-2.25.0 → claude_code_conductor-2.26.0}/LICENSES/chroma-hnswlib-LICENSE +0 -0
  81. {claude_code_conductor-2.25.0 → claude_code_conductor-2.26.0}/LICENSES/chroma-hnswlib-NOTICE +0 -0
  82. {claude_code_conductor-2.25.0 → claude_code_conductor-2.26.0}/LICENSES/fastembed-LICENSE +0 -0
  83. {claude_code_conductor-2.25.0 → claude_code_conductor-2.26.0}/LICENSES/fastembed-NOTICE +0 -0
  84. {claude_code_conductor-2.25.0 → claude_code_conductor-2.26.0}/LICENSES/onnxruntime-LICENSE +0 -0
  85. {claude_code_conductor-2.25.0 → claude_code_conductor-2.26.0}/LICENSES/paraphrase-multilingual-MiniLM-L12-v2-LICENSE +0 -0
  86. {claude_code_conductor-2.25.0 → claude_code_conductor-2.26.0}/hatch_build.py +0 -0
  87. {claude_code_conductor-2.25.0 → claude_code_conductor-2.26.0}/pyproject.toml +0 -0
  88. {claude_code_conductor-2.25.0 → claude_code_conductor-2.26.0}/src/c3/__main__.py +0 -0
  89. {claude_code_conductor-2.25.0 → claude_code_conductor-2.26.0}/src/c3/_excludes.py +0 -0
  90. {claude_code_conductor-2.25.0 → claude_code_conductor-2.26.0}/src/c3/_terminal.py +0 -0
  91. {claude_code_conductor-2.25.0 → claude_code_conductor-2.26.0}/src/c3/adapters.py +0 -0
  92. {claude_code_conductor-2.25.0 → claude_code_conductor-2.26.0}/src/c3/cli.py +0 -0
  93. {claude_code_conductor-2.25.0 → claude_code_conductor-2.26.0}/src/c3/cli_ask.py +0 -0
  94. {claude_code_conductor-2.25.0 → claude_code_conductor-2.26.0}/src/c3/cli_doctor.py +0 -0
  95. {claude_code_conductor-2.25.0 → claude_code_conductor-2.26.0}/src/c3/cli_init.py +0 -0
  96. {claude_code_conductor-2.25.0 → claude_code_conductor-2.26.0}/src/c3/cli_list.py +0 -0
  97. {claude_code_conductor-2.25.0 → claude_code_conductor-2.26.0}/src/c3/cli_plan.py +0 -0
  98. {claude_code_conductor-2.25.0 → claude_code_conductor-2.26.0}/src/c3/cli_recall.py +0 -0
  99. {claude_code_conductor-2.25.0 → claude_code_conductor-2.26.0}/src/c3/cli_tier.py +0 -0
  100. {claude_code_conductor-2.25.0 → claude_code_conductor-2.26.0}/src/c3/cli_update.py +0 -0
  101. {claude_code_conductor-2.25.0 → claude_code_conductor-2.26.0}/src/c3/embedding.py +0 -0
  102. {claude_code_conductor-2.25.0 → claude_code_conductor-2.26.0}/src/c3/mcp_server.py +0 -0
  103. {claude_code_conductor-2.25.0 → claude_code_conductor-2.26.0}/src/c3/migrate.py +0 -0
  104. {claude_code_conductor-2.25.0 → claude_code_conductor-2.26.0}/src/c3/migrations/001_initial.sql +0 -0
  105. {claude_code_conductor-2.25.0 → claude_code_conductor-2.26.0}/src/c3/migrations/002_agent_cost_runs.sql +0 -0
  106. {claude_code_conductor-2.25.0 → claude_code_conductor-2.26.0}/src/c3/migrations/003_tier_cost.sql +0 -0
  107. {claude_code_conductor-2.25.0 → claude_code_conductor-2.26.0}/src/c3/migrations/README.md +0 -0
  108. {claude_code_conductor-2.25.0 → claude_code_conductor-2.26.0}/src/c3/migrations/__init__.py +0 -0
  109. {claude_code_conductor-2.25.0 → claude_code_conductor-2.26.0}/src/c3/paths.py +0 -0
  110. {claude_code_conductor-2.25.0 → claude_code_conductor-2.26.0}/src/c3/plan_validator.py +0 -0
  111. {claude_code_conductor-2.25.0 → claude_code_conductor-2.26.0}/src/c3/platforms.py +0 -0
  112. {claude_code_conductor-2.25.0 → claude_code_conductor-2.26.0}/src/c3/pricing.py +0 -0
  113. {claude_code_conductor-2.25.0 → claude_code_conductor-2.26.0}/src/c3/question.py +0 -0
  114. {claude_code_conductor-2.25.0 → claude_code_conductor-2.26.0}/src/c3/recall_chunker.py +0 -0
  115. {claude_code_conductor-2.25.0 → claude_code_conductor-2.26.0}/src/c3/recall_index.py +0 -0
  116. {claude_code_conductor-2.25.0 → claude_code_conductor-2.26.0}/src/c3/usage_ingester.py +0 -0
  117. {claude_code_conductor-2.25.0 → claude_code_conductor-2.26.0}/tests/__init__.py +0 -0
  118. {claude_code_conductor-2.25.0 → claude_code_conductor-2.26.0}/tests/conftest.py +0 -0
  119. {claude_code_conductor-2.25.0 → claude_code_conductor-2.26.0}/tests/fixtures/usage/README.md +0 -0
  120. {claude_code_conductor-2.25.0 → claude_code_conductor-2.26.0}/tests/fixtures/usage/mainline.jsonl +0 -0
  121. {claude_code_conductor-2.25.0 → claude_code_conductor-2.26.0}/tests/fixtures/usage/subagents/agent-deadbeef.jsonl +0 -0
  122. {claude_code_conductor-2.25.0 → claude_code_conductor-2.26.0}/tests/fixtures/usage/subagents/agent-deadbeef.meta.json +0 -0
  123. {claude_code_conductor-2.25.0 → claude_code_conductor-2.26.0}/tests/hooks/__init__.py +0 -0
  124. {claude_code_conductor-2.25.0 → claude_code_conductor-2.26.0}/tests/hooks/test_check_agent_invocation.py +0 -0
  125. {claude_code_conductor-2.25.0 → claude_code_conductor-2.26.0}/tests/hooks/test_consolidate_memory.py +0 -0
  126. {claude_code_conductor-2.25.0 → claude_code_conductor-2.26.0}/tests/hooks/test_hook_utils.py +0 -0
  127. {claude_code_conductor-2.25.0 → claude_code_conductor-2.26.0}/tests/hooks/test_permission_handler.py +0 -0
  128. {claude_code_conductor-2.25.0 → claude_code_conductor-2.26.0}/tests/hooks/test_permission_handler_toast.py +0 -0
  129. {claude_code_conductor-2.25.0 → claude_code_conductor-2.26.0}/tests/hooks/test_pip_reinstall_reminder.py +0 -0
  130. {claude_code_conductor-2.25.0 → claude_code_conductor-2.26.0}/tests/hooks/test_planner_check.py +0 -0
  131. {claude_code_conductor-2.25.0 → claude_code_conductor-2.26.0}/tests/hooks/test_planner_check_dev.py +0 -0
  132. {claude_code_conductor-2.25.0 → claude_code_conductor-2.26.0}/tests/hooks/test_post_tool.py +0 -0
  133. {claude_code_conductor-2.25.0 → claude_code_conductor-2.26.0}/tests/hooks/test_pre_tool.py +0 -0
  134. {claude_code_conductor-2.25.0 → claude_code_conductor-2.26.0}/tests/hooks/test_recall_inject.py +0 -0
  135. {claude_code_conductor-2.25.0 → claude_code_conductor-2.26.0}/tests/hooks/test_record_review_decision.py +0 -0
  136. {claude_code_conductor-2.25.0 → claude_code_conductor-2.26.0}/tests/hooks/test_record_tier_outcome.py +0 -0
  137. {claude_code_conductor-2.25.0 → claude_code_conductor-2.26.0}/tests/hooks/test_restore_session.py +0 -0
  138. {claude_code_conductor-2.25.0 → claude_code_conductor-2.26.0}/tests/hooks/test_review_hint_inject.py +0 -0
  139. {claude_code_conductor-2.25.0 → claude_code_conductor-2.26.0}/tests/hooks/test_session_start.py +0 -0
  140. {claude_code_conductor-2.25.0 → claude_code_conductor-2.26.0}/tests/hooks/test_session_stop.py +0 -0
  141. {claude_code_conductor-2.25.0 → claude_code_conductor-2.26.0}/tests/hooks/test_session_utils.py +0 -0
  142. {claude_code_conductor-2.25.0 → claude_code_conductor-2.26.0}/tests/hooks/test_settings_local_absolute_paths.py +0 -0
  143. {claude_code_conductor-2.25.0 → claude_code_conductor-2.26.0}/tests/hooks/test_similarity_boost.py +0 -0
  144. {claude_code_conductor-2.25.0 → claude_code_conductor-2.26.0}/tests/hooks/test_statusline.py +0 -0
  145. {claude_code_conductor-2.25.0 → claude_code_conductor-2.26.0}/tests/hooks/test_statusline_template_sync.py +0 -0
  146. {claude_code_conductor-2.25.0 → claude_code_conductor-2.26.0}/tests/hooks/test_sync_check.py +0 -0
  147. {claude_code_conductor-2.25.0 → claude_code_conductor-2.26.0}/tests/hooks/test_template_guard.py +0 -0
  148. {claude_code_conductor-2.25.0 → claude_code_conductor-2.26.0}/tests/skills/__init__.py +0 -0
  149. {claude_code_conductor-2.25.0 → claude_code_conductor-2.26.0}/tests/skills/_skill_helpers.py +0 -0
  150. {claude_code_conductor-2.25.0 → claude_code_conductor-2.26.0}/tests/skills/test_dev_workflow_no_task_type.py +0 -0
  151. {claude_code_conductor-2.25.0 → claude_code_conductor-2.26.0}/tests/skills/test_init_session_no_task_type.py +0 -0
  152. {claude_code_conductor-2.25.0 → claude_code_conductor-2.26.0}/tests/skills/test_planner_lightweight.py +0 -0
  153. {claude_code_conductor-2.25.0 → claude_code_conductor-2.26.0}/tests/skills/test_recall_skill.py +0 -0
  154. {claude_code_conductor-2.25.0 → claude_code_conductor-2.26.0}/tests/skills/test_session_backlog_reconciliation.py +0 -0
  155. {claude_code_conductor-2.25.0 → claude_code_conductor-2.26.0}/tests/skills/test_setup_templates.py +0 -0
  156. {claude_code_conductor-2.25.0 → claude_code_conductor-2.26.0}/tests/skills/test_start_skill_bugfix_flow.py +0 -0
  157. {claude_code_conductor-2.25.0 → claude_code_conductor-2.26.0}/tests/skills/test_start_skill_new_flow.py +0 -0
  158. {claude_code_conductor-2.25.0 → claude_code_conductor-2.26.0}/tests/skills/test_start_skill_security_audit_phase.py +0 -0
  159. {claude_code_conductor-2.25.0 → claude_code_conductor-2.26.0}/tests/test_adapters.py +0 -0
  160. {claude_code_conductor-2.25.0 → claude_code_conductor-2.26.0}/tests/test_cli_ask.py +0 -0
  161. {claude_code_conductor-2.25.0 → claude_code_conductor-2.26.0}/tests/test_cli_entry.py +0 -0
  162. {claude_code_conductor-2.25.0 → claude_code_conductor-2.26.0}/tests/test_cli_init.py +0 -0
  163. {claude_code_conductor-2.25.0 → claude_code_conductor-2.26.0}/tests/test_cli_list.py +0 -0
  164. {claude_code_conductor-2.25.0 → claude_code_conductor-2.26.0}/tests/test_cli_plan.py +0 -0
  165. {claude_code_conductor-2.25.0 → claude_code_conductor-2.26.0}/tests/test_cli_recall.py +0 -0
  166. {claude_code_conductor-2.25.0 → claude_code_conductor-2.26.0}/tests/test_cli_tier.py +0 -0
  167. {claude_code_conductor-2.25.0 → claude_code_conductor-2.26.0}/tests/test_cli_update_breaking_changes.py +0 -0
  168. {claude_code_conductor-2.25.0 → claude_code_conductor-2.26.0}/tests/test_cli_update_deletions.py +0 -0
  169. {claude_code_conductor-2.25.0 → claude_code_conductor-2.26.0}/tests/test_docstring_consistency.py +0 -0
  170. {claude_code_conductor-2.25.0 → claude_code_conductor-2.26.0}/tests/test_embedding.py +0 -0
  171. {claude_code_conductor-2.25.0 → claude_code_conductor-2.26.0}/tests/test_excludes.py +0 -0
  172. {claude_code_conductor-2.25.0 → claude_code_conductor-2.26.0}/tests/test_extract_breaking_changes.py +0 -0
  173. {claude_code_conductor-2.25.0 → claude_code_conductor-2.26.0}/tests/test_mcp_server_elicit.py +0 -0
  174. {claude_code_conductor-2.25.0 → claude_code_conductor-2.26.0}/tests/test_migrate.py +0 -0
  175. {claude_code_conductor-2.25.0 → claude_code_conductor-2.26.0}/tests/test_paths.py +0 -0
  176. {claude_code_conductor-2.25.0 → claude_code_conductor-2.26.0}/tests/test_plan_validator.py +0 -0
  177. {claude_code_conductor-2.25.0 → claude_code_conductor-2.26.0}/tests/test_pre_compact.py +0 -0
  178. {claude_code_conductor-2.25.0 → claude_code_conductor-2.26.0}/tests/test_pre_tool_hook.py +0 -0
  179. {claude_code_conductor-2.25.0 → claude_code_conductor-2.26.0}/tests/test_precompact_additional.py +0 -0
  180. {claude_code_conductor-2.25.0 → claude_code_conductor-2.26.0}/tests/test_precompact_toctou_fixes.py +0 -0
  181. {claude_code_conductor-2.25.0 → claude_code_conductor-2.26.0}/tests/test_pricing.py +0 -0
  182. {claude_code_conductor-2.25.0 → claude_code_conductor-2.26.0}/tests/test_recall_chunker.py +0 -0
  183. {claude_code_conductor-2.25.0 → claude_code_conductor-2.26.0}/tests/test_recall_index.py +0 -0
  184. {claude_code_conductor-2.25.0 → claude_code_conductor-2.26.0}/tests/test_references_migration.py +0 -0
  185. {claude_code_conductor-2.25.0 → claude_code_conductor-2.26.0}/tests/test_session_utils_additional.py +0 -0
  186. {claude_code_conductor-2.25.0 → claude_code_conductor-2.26.0}/tests/test_skill_no_builtin_conflict.py +0 -0
  187. {claude_code_conductor-2.25.0 → claude_code_conductor-2.26.0}/tests/test_statusline.py +0 -0
  188. {claude_code_conductor-2.25.0 → claude_code_conductor-2.26.0}/tests/test_stop_additional.py +0 -0
  189. {claude_code_conductor-2.25.0 → claude_code_conductor-2.26.0}/tests/test_stop_hook.py +0 -0
  190. {claude_code_conductor-2.25.0 → claude_code_conductor-2.26.0}/tests/test_stop_precompact_fixes.py +0 -0
  191. {claude_code_conductor-2.25.0 → claude_code_conductor-2.26.0}/tests/test_sync_template_stop.py +0 -0
  192. {claude_code_conductor-2.25.0 → claude_code_conductor-2.26.0}/tests/test_template_pre_tool_hook.py +0 -0
  193. {claude_code_conductor-2.25.0 → claude_code_conductor-2.26.0}/tests/test_usage_ingester.py +0 -0
  194. {claude_code_conductor-2.25.0 → claude_code_conductor-2.26.0}/tests/test_worktree_guard.py +0 -0
@@ -49,9 +49,13 @@ try:
49
49
  from c3 import db as _c3_db_const # type: ignore[import-not-found]
50
50
  LEARNING_THRESHOLD: int = _c3_db_const.LEARNING_THRESHOLD
51
51
  EPSILON: float = _c3_db_const.EPSILON_TIEBREAK
52
+ ESCALATION_THRESHOLD: float = _c3_db_const.ESCALATION_THRESHOLD_DEFAULT
53
+ COST_LAMBDA_DEFAULT: float | None = _c3_db_const.COST_LAMBDA_DEFAULT
52
54
  except ImportError:
53
55
  LEARNING_THRESHOLD = 30
54
56
  EPSILON = 0.05
57
+ ESCALATION_THRESHOLD = 0.5
58
+ COST_LAMBDA_DEFAULT = None
55
59
 
56
60
  # 複雑度推定のキーワード
57
61
  SIMPLE_KEYWORDS = frozenset({
@@ -127,12 +131,16 @@ class SelectionResult(NamedTuple):
127
131
  cost_tiebreak: Thompson 分岐で cost tie-break が発動した場合 True。
128
132
  contenders: 拮抗判定に入った tier のタプル(observability/デバッグ用)。
129
133
  frozen 安全のため list ではなく tuple を使用。
134
+ cost_weighted: λ>0 全 tier weighting が適用された場合 True(v2.26.0)。
135
+ lam=None(env 未設定)または cost_map=None の場合は False のまま。
136
+ uniform 分岐では常に False(探索保護・不可侵)。
130
137
  """
131
138
 
132
139
  tier: str
133
140
  mode: str
134
141
  cost_tiebreak: bool = False
135
142
  contenders: tuple[str, ...] = ()
143
+ cost_weighted: bool = False
136
144
 
137
145
 
138
146
  def _cost_tiebreak(
@@ -140,41 +148,79 @@ def _cost_tiebreak(
140
148
  cost_map: dict[str, float] | None,
141
149
  *,
142
150
  epsilon: float = EPSILON,
151
+ lam: float | None = None,
143
152
  ) -> tuple[str, bool, tuple[str, ...]]:
144
- """Thompson サンプル拮抗群内で min-max 正規化コストが最安の tier を返す。
153
+ """Thompson サンプルから cost を考慮して最適な tier を返す(3 経路)。
154
+
155
+ lam(λ)の値によって 3 つの経路に分岐する:
156
+ - 経路 0(cost_map is None or lam == 0): cost を見ない。argmax(sample) を返す。
157
+ lam=None を渡しても cost_map が None なら経路 0。lam=0.0 の明示オプトも経路 0。
158
+ - 経路 1(lam is None・既定): v2.25.0 の ε-gated min-max 最安(後方互換)。
159
+ contenders ≤ 1 は argmax、複数 contenders は min-max 正規化コスト最安を選ぶ。
160
+ lam=None(env 未設定センチネル)がデフォルト→ v2.25.0 挙動と完全一致。
161
+ - 経路 2(lam > 0): 全 tier weighting。
162
+ score[t] = sample[t] - lam * cost_norm[t] で全 tier を比較し最大を選ぶ。
163
+ cost_norm は全 tier の min-max 正規化(最安→0・最高→1)。
145
164
 
146
165
  Args:
147
166
  samples: {tier: beta_sample} の dict(Thompson Sampling 結果)。
148
- cost_map: {tier: cost} の dict。None なら cost を見ず従来挙動。
167
+ cost_map: {tier: cost} の dict。None なら cost を見ず従来挙動(経路 0)。
149
168
  cost は実測 rate_usd_per_mtok または静的参照単価(ハイブリッド)。
150
169
  v2.24.0 で rate 化(USD/MTok)により実測・静的とも同次元で整合済み。
151
- ``cost_map`` は None、または contenders 全件をキーとして含む dict
152
- 渡すこと。partial dict を渡すと ``cost_map[t]`` で KeyError が発生する。
170
+ ``cost_map`` は None、または samples の全 tier キーを含む dict を渡すこと。
171
+ partial dict を渡すと ``cost_map[t]`` で KeyError が発生する。
153
172
  ``select_tier_detailed`` 経由では呼び出し側(main)が全 TIERS 分を
154
173
  構築して保証する。
155
- epsilon: 拮抗判定の閾値(デフォルト EPSILON=0.05)。
174
+ epsilon: 拮抗判定の閾値(デフォルト EPSILON=0.05)。経路 0/1 で使用。
175
+ 経路 2 では contenders 算出にのみ使用(選択自体は全 tier score 比較)。
176
+ lam: cost weighting 係数(λ)。None=センチネル(経路 1・後方互換)、
177
+ 0.0=cost 無視明示(経路 0)、0 < lam <= 1=全 tier weighting(経路 2)。
178
+ デフォルト None で既存 2 引数呼び出しの挙動・シグネチャを完全不変にする。
156
179
 
157
180
  Returns:
158
181
  (chosen, did_tiebreak, contenders) のタプル。
159
182
  - chosen: 選択された tier 名。
160
- - did_tiebreak: cost tie-break が発動した場合 True。
161
- - contenders: 拮抗判定に入った tier のタプル。
183
+ - did_tiebreak: cost が選択に影響した場合 True。
184
+ 経路 1: contenders min-max で安い方を選んだ場合 True。
185
+ 経路 2: 全 tier weighting で argmax(sample) と異なる選択になった場合 True。
186
+ - contenders: ε 拮抗判定に入った tier のタプル(observability 用)。
162
187
  """
163
188
  max_sample = max(samples.values())
164
189
  contenders = [t for t in samples if max_sample - samples[t] <= epsilon]
165
190
 
166
- if len(contenders) <= 1 or cost_map is None:
167
- # 従来挙動と完全一致: max(samples, key=lambda t: samples[t]) と同じ式
191
+ # 経路 0: cost を見ない(cost_map なし or λ=0 明示)。
192
+ # None == 0 Python では False のため lam == 0 は float 0.0 のみ真(意図通り)。
193
+ if cost_map is None or lam == 0:
168
194
  chosen = max(samples, key=lambda t: samples[t])
169
195
  return chosen, False, tuple(contenders)
170
196
 
171
- # 拮抗群内で min-max 正規化コストを計算し最安 tier を選ぶ
172
- costs = {t: cost_map[t] for t in contenders}
197
+ # 経路 1(lam=None・既定): v2.25.0 の ε-gated min-max 最安(現行ロジック完全踏襲)。
198
+ if lam is None:
199
+ if len(contenders) <= 1:
200
+ chosen = max(samples, key=lambda t: samples[t])
201
+ return chosen, False, tuple(contenders)
202
+ # 拮抗群内で min-max 正規化コストを計算し最安 tier を選ぶ
203
+ costs = {t: cost_map[t] for t in contenders}
204
+ lo, hi = min(costs.values()), max(costs.values())
205
+ norm = {t: ((costs[t] - lo) / (hi - lo) if hi > lo else 0.0) for t in contenders}
206
+ # 同値安定 tie-break: norm 同値時はサンプル大(=従来選好)を優先 → 決定論
207
+ # 注: 全 tier コスト同値(hi == lo → norm 全 0.0)でも did_tiebreak=True を返す。
208
+ # これは v2.25.0 のバイト互換維持のため意図的(フラグ意味の精緻化=同値時 False は
209
+ # 後方互換を崩すため v2.27.0+ で扱う)。[CR-Q-001]
210
+ chosen = min(contenders, key=lambda t: (norm[t], -samples[t]))
211
+ return chosen, True, tuple(contenders)
212
+
213
+ # 経路 2(lam > 0): 全 tier weighting。
214
+ # cost_norm は全 tier で min-max 正規化(最安→0・最高→1)。
215
+ costs = {t: cost_map[t] for t in samples}
173
216
  lo, hi = min(costs.values()), max(costs.values())
174
- norm = {t: ((costs[t] - lo) / (hi - lo) if hi > lo else 0.0) for t in contenders}
175
- # 同値安定 tie-break: norm 同値時はサンプル大(=従来選好)を優先 決定論
176
- chosen = min(contenders, key=lambda t: (norm[t], -samples[t]))
177
- return chosen, True, tuple(contenders)
217
+ norm = {t: ((costs[t] - lo) / (hi - lo) if hi > lo else 0.0) for t in samples}
218
+ score = {t: samples[t] - lam * norm[t] for t in samples}
219
+ # 同点は sample 大優先(決定論)
220
+ chosen = max(samples, key=lambda t: (score[t], samples[t]))
221
+ pure_max = max(samples, key=lambda t: samples[t])
222
+ cost_tiebreak = chosen != pure_max
223
+ return chosen, cost_tiebreak, tuple(contenders)
178
224
 
179
225
 
180
226
  def _prompt_prefix_and_hash(prompt: str) -> tuple[str, str]:
@@ -298,6 +344,7 @@ def select_tier_detailed(
298
344
  rng: random.Random | None = None,
299
345
  cost_map: dict[str, float] | None = None,
300
346
  epsilon: float | None = None,
347
+ lam: float | None = None,
301
348
  ) -> SelectionResult:
302
349
  """Beta サンプリングまたは uniform 選択で推奨 Tier を SelectionResult で返す。
303
350
 
@@ -311,15 +358,20 @@ def select_tier_detailed(
311
358
  (呼び出し側が全 TIERS 分を構築して保証する)。
312
359
  uniform 分岐では cost_map の有無に関わらず完全無視する(探索保護)。
313
360
  epsilon: 拮抗判定閾値。None なら module 定数 EPSILON を使う(C3_TIER_EPSILON で上書き可)。
361
+ lam: cost weighting 係数(λ)。None=センチネル(v2.25.0 ε-gated 後方互換)、
362
+ 0.0=cost 無視明示、0<lam<=1=全 tier weighting 発動(C3_TIER_COST_LAMBDA で上書き可)。
363
+ None(デフォルト)では env 未設定時と完全一致する(後方互換の核心)。
364
+ uniform 分岐では lam の値に関わらず完全無視する(探索保護・不可侵)。
314
365
 
315
366
  Returns:
316
- SelectionResult(tier, mode, cost_tiebreak, contenders)。
367
+ SelectionResult(tier, mode, cost_tiebreak, contenders, cost_weighted)。
317
368
  mode は ``"thompson"`` / ``"uniform"``。
369
+ cost_weighted は lam>0 かつ cost_map が有効な場合のみ True。
318
370
  """
319
371
  rng = rng or random
320
372
  total_trials = sum(p[2] for p in params.values())
321
373
  if total_trials < LEARNING_THRESHOLD:
322
- # uniform: cost を完全無視・従来挙動完全維持
374
+ # uniform: cost を完全無視・従来挙動完全維持(不可侵)
323
375
  return SelectionResult(rng.choice(TIERS), "uniform", False, ())
324
376
 
325
377
  # Thompson Sampling: rng の消費順序を従来 select_tier と完全一致させる
@@ -328,8 +380,9 @@ def select_tier_detailed(
328
380
  for tier, p in params.items()
329
381
  }
330
382
  eff_epsilon = epsilon if epsilon is not None else EPSILON
331
- chosen, did_tiebreak, contenders = _cost_tiebreak(samples, cost_map, epsilon=eff_epsilon)
332
- return SelectionResult(chosen, "thompson", did_tiebreak, contenders)
383
+ chosen, did_tiebreak, contenders = _cost_tiebreak(samples, cost_map, epsilon=eff_epsilon, lam=lam)
384
+ cost_weighted = (cost_map is not None and lam is not None and lam > 0)
385
+ return SelectionResult(chosen, "thompson", did_tiebreak, contenders, cost_weighted)
333
386
 
334
387
 
335
388
  def select_tier(
@@ -338,6 +391,7 @@ def select_tier(
338
391
  rng: random.Random | None = None,
339
392
  cost_map: dict[str, float] | None = None,
340
393
  epsilon: float | None = None,
394
+ lam: float | None = None,
341
395
  ) -> tuple[str, str]:
342
396
  """Beta サンプリングまたは uniform 選択で推奨 Tier を返す。
343
397
 
@@ -350,13 +404,15 @@ def select_tier(
350
404
  uniform 分岐では cost_map の有無に関わらず完全無視する。
351
405
  詳細は :func:`select_tier_detailed` を参照。
352
406
  epsilon: 拮抗判定閾値。None なら module 定数 EPSILON を使う。
407
+ lam: cost weighting 係数(λ)。select_tier_detailed に委譲する。
408
+ None=センチネル(v2.25.0 後方互換)、0.0=cost 無視、0<lam<=1=全 tier weighting。
353
409
 
354
410
  Returns:
355
411
  ``(tier, mode)`` のタプル。``mode`` は ``"thompson"`` / ``"uniform"`` で、
356
412
  プロンプトに「学習データ収集中」と表示するかの分岐に使う。
357
413
  戻り値型は v2.22.0 以前と完全に不変。
358
414
  """
359
- result = select_tier_detailed(params, rng=rng, cost_map=cost_map, epsilon=epsilon)
415
+ result = select_tier_detailed(params, rng=rng, cost_map=cost_map, epsilon=epsilon, lam=lam)
360
416
  return result.tier, result.mode
361
417
 
362
418
 
@@ -368,7 +424,7 @@ _ESCALATION_MAP: dict[str, str] = {
368
424
  }
369
425
 
370
426
  # Phase 2-B: failure rate がこの値以上で escalation 判定。
371
- ESCALATION_THRESHOLD = 0.5
427
+ # SSOT: db.ESCALATION_THRESHOLD_DEFAULT 由来(import 部で取得)。C3_ESCALATION_THRESHOLD env で上書き可(v2.26.0)。
372
428
 
373
429
 
374
430
  def _db_failure_rate(complexity: str, tier: str) -> tuple:
@@ -387,6 +443,7 @@ def maybe_escalate(
387
443
  chosen_tier: str,
388
444
  *,
389
445
  failure_rate_fn=None,
446
+ threshold: float | None = None,
390
447
  ) -> tuple[str, str | None]:
391
448
  """Phase 2-B: failure rate が高ければ 1 段昇格する。
392
449
 
@@ -396,6 +453,9 @@ def maybe_escalate(
396
453
  failure_rate_fn: テスト用に注入可能な
397
454
  ``(complexity, tier) -> (rate_or_None, sample_count)``。
398
455
  省略時は :func:`_db_failure_rate` を使う。
456
+ threshold: escalation 閾値(failure rate がこの値以上で昇格)。
457
+ None のとき module 定数 ``ESCALATION_THRESHOLD`` を使う。
458
+ ``main()`` は ``_resolve_escalation_threshold()`` で解決した値を渡す。
399
459
 
400
460
  Returns:
401
461
  ``(effective_tier, escalation_reason)``。
@@ -407,7 +467,8 @@ def maybe_escalate(
407
467
 
408
468
  effective_fn = failure_rate_fn or _db_failure_rate
409
469
  rate, samples = effective_fn(complexity, chosen_tier)
410
- if rate is None or rate < ESCALATION_THRESHOLD:
470
+ eff_threshold = threshold if threshold is not None else ESCALATION_THRESHOLD
471
+ if rate is None or rate < eff_threshold:
411
472
  return chosen_tier, None
412
473
 
413
474
  escalated = _ESCALATION_MAP[chosen_tier]
@@ -429,6 +490,8 @@ def write_tier_selection(
429
490
  prompt_hash: str | None = None,
430
491
  session_id: str | None = None,
431
492
  cost_tiebreak: bool = False,
493
+ cost_weighted: bool = False,
494
+ cost_lambda: float | None = None,
432
495
  ) -> None:
433
496
  """直近の選択結果を ``tier_selection.json`` に書く。
434
497
 
@@ -448,6 +511,14 @@ def write_tier_selection(
448
511
  ``cost_tiebreak`` を任意で含める(v2.23.0)。
449
512
  Thompson Sampling の拮抗群内で cost tie-break が発動した場合のみ True。
450
513
  False のときはキー自体を省略する(escalated/session_id と同パターン)。
514
+
515
+ ``cost_weighted`` を任意で含める(v2.26.0)。
516
+ λ>0 の全 tier weighting が適用された場合のみ True。
517
+ False のときはキー自体を省略する(cost_tiebreak と同パターン)。
518
+
519
+ ``cost_lambda`` を任意で含める(v2.26.0)。
520
+ ``_resolve_cost_lambda()`` で解決した λ 値(None 以外のとき出力)。
521
+ None のときはキー自体を省略する(env 未設定時の後方互換)。
451
522
  """
452
523
  os.makedirs(os.path.dirname(TIER_SELECTION_PATH), exist_ok=True)
453
524
  payload: dict[str, object] = {
@@ -471,6 +542,10 @@ def write_tier_selection(
471
542
  payload["session_id"] = session_id
472
543
  if cost_tiebreak:
473
544
  payload["cost_tiebreak"] = True
545
+ if cost_weighted:
546
+ payload["cost_weighted"] = True
547
+ if cost_lambda is not None:
548
+ payload["cost_lambda"] = cost_lambda
474
549
  try:
475
550
  with open(TIER_SELECTION_PATH, "w", encoding="utf-8") as f:
476
551
  json.dump(payload, f, ensure_ascii=False)
@@ -488,11 +563,16 @@ def build_additional_context(
488
563
  escalation_reason: str | None = None,
489
564
  complexity_source: str | None = None,
490
565
  cost_tiebreak: bool = False,
566
+ cost_weighted: bool = False,
491
567
  ) -> str:
492
568
  """親 Claude に追加注入する文字列を組み立てる。
493
569
 
494
570
  ``cost_tiebreak`` が True のとき、suffix に cost-aware 発動を示す文言を追加する(v2.23.0)。
495
571
  False のときは不変(既存文言と完全一致)。
572
+
573
+ ``cost_weighted`` が True のとき、cost-weighted 文言を suffix に追加する(v2.26.0)。
574
+ True のときは cost_tiebreak の文言より優先される(λ>0 全 tier weighting を明示)。
575
+ False のときは cost_tiebreak による既存文言のみ(v2.25.0 以前と完全一致)。
496
576
  """
497
577
  trials = sum(p[2] for p in params.values())
498
578
  if mode == "uniform":
@@ -506,7 +586,9 @@ def build_additional_context(
506
586
  suffix += f" [Phase 2-B 昇格: {escalation_reason}]"
507
587
  if complexity_source:
508
588
  suffix += f" [複雑度判定: {complexity_source}]"
509
- if cost_tiebreak:
589
+ if cost_weighted:
590
+ suffix += " [cost-weighted: 成功率とコストを加重して選択]"
591
+ elif cost_tiebreak:
510
592
  suffix += " [cost-aware: 成功率拮抗のため低コスト Tier を選択]"
511
593
 
512
594
  return (
@@ -564,6 +646,79 @@ def _resolve_epsilon() -> float:
564
646
  return x
565
647
 
566
648
 
649
+ def _resolve_escalation_threshold() -> float:
650
+ """``C3_ESCALATION_THRESHOLD`` を安全に解決する。
651
+
652
+ 不正値(非数値 / 0 以下 / 1 超 / NaN)は受け付けず、stderr 警告 + デフォルト(ESCALATION_THRESHOLD)に戻す。
653
+ 未設定 / 空文字は無警告でデフォルトを返す。
654
+ 妥当域: 0 < x <= 1(_resolve_epsilon と同じ範囲)。区間表記: (0, 1](x=0 拒否のため半開区間)。
655
+ """
656
+ raw = os.environ.get("C3_ESCALATION_THRESHOLD")
657
+ if raw is None or raw == "":
658
+ return ESCALATION_THRESHOLD
659
+ try:
660
+ x = float(raw)
661
+ except ValueError:
662
+ print(
663
+ f"[select_tier:escalation] invalid C3_ESCALATION_THRESHOLD={raw!r}, "
664
+ f"using default {ESCALATION_THRESHOLD}",
665
+ file=sys.stderr,
666
+ )
667
+ return ESCALATION_THRESHOLD
668
+ if math.isnan(x):
669
+ print(
670
+ f"[select_tier:escalation] C3_ESCALATION_THRESHOLD={raw!r} is NaN, "
671
+ f"using default {ESCALATION_THRESHOLD}",
672
+ file=sys.stderr,
673
+ )
674
+ return ESCALATION_THRESHOLD
675
+ if x <= 0 or x > 1:
676
+ print(
677
+ f"[select_tier:escalation] C3_ESCALATION_THRESHOLD={x!r} out of range (0, 1], "
678
+ f"using default {ESCALATION_THRESHOLD}",
679
+ file=sys.stderr,
680
+ )
681
+ return ESCALATION_THRESHOLD
682
+ return x
683
+
684
+
685
+ def _resolve_cost_lambda() -> float | None:
686
+ """``C3_TIER_COST_LAMBDA`` を安全に解決する。
687
+
688
+ 不正値(非数値 / 0 未満 / 1 超 / NaN)は受け付けず、stderr 警告 + デフォルト(COST_LAMBDA_DEFAULT)に戻す。
689
+ 未設定 / 空文字は無警告でデフォルト(None)を返す。
690
+ 妥当域: 0 <= x <= 1(x == 0 は許容=cost 無視の明示オプト・_resolve_epsilon と異なり下限を含む)。区間表記: [0, 1](x=0 許容のため閉区間)。
691
+ 戻り値が None の場合は v2.25.0 互換の ε tie-break 経路を維持する(センチネル)。
692
+ """
693
+ raw = os.environ.get("C3_TIER_COST_LAMBDA")
694
+ if raw is None or raw == "":
695
+ return COST_LAMBDA_DEFAULT
696
+ try:
697
+ x = float(raw)
698
+ except ValueError:
699
+ print(
700
+ f"[select_tier:cost_lambda] invalid C3_TIER_COST_LAMBDA={raw!r}, "
701
+ f"using default {COST_LAMBDA_DEFAULT}",
702
+ file=sys.stderr,
703
+ )
704
+ return COST_LAMBDA_DEFAULT
705
+ if math.isnan(x):
706
+ print(
707
+ f"[select_tier:cost_lambda] C3_TIER_COST_LAMBDA={raw!r} is NaN, "
708
+ f"using default {COST_LAMBDA_DEFAULT}",
709
+ file=sys.stderr,
710
+ )
711
+ return COST_LAMBDA_DEFAULT
712
+ if x < 0 or x > 1:
713
+ print(
714
+ f"[select_tier:cost_lambda] C3_TIER_COST_LAMBDA={x!r} out of range [0, 1], "
715
+ f"using default {COST_LAMBDA_DEFAULT}",
716
+ file=sys.stderr,
717
+ )
718
+ return COST_LAMBDA_DEFAULT
719
+ return x
720
+
721
+
567
722
  def main() -> int:
568
723
  try:
569
724
  payload = json.loads(sys.stdin.read())
@@ -619,12 +774,14 @@ def main() -> int:
619
774
  cost_map = None
620
775
 
621
776
  eps = _resolve_epsilon()
622
- result = select_tier_detailed(params, cost_map=cost_map, epsilon=eps)
777
+ lam = _resolve_cost_lambda()
778
+ result = select_tier_detailed(params, cost_map=cost_map, epsilon=eps, lam=lam)
623
779
  tier, mode = result.tier, result.mode
624
780
  cost_tiebreak = result.cost_tiebreak
625
781
 
626
782
  # Phase 2-B: failure rate に基づく escalation
627
- effective_tier, escalation_reason = maybe_escalate(complexity, tier)
783
+ esc_thr = _resolve_escalation_threshold()
784
+ effective_tier, escalation_reason = maybe_escalate(complexity, tier, threshold=esc_thr)
628
785
  escalated = effective_tier != tier
629
786
 
630
787
  write_tier_selection(
@@ -634,6 +791,8 @@ def main() -> int:
634
791
  prompt_hash=prompt_hash,
635
792
  session_id=session_id,
636
793
  cost_tiebreak=cost_tiebreak,
794
+ cost_weighted=result.cost_weighted,
795
+ cost_lambda=lam,
637
796
  )
638
797
 
639
798
  context_text = build_additional_context(
@@ -641,6 +800,7 @@ def main() -> int:
641
800
  escalation_reason=escalation_reason,
642
801
  complexity_source=complexity_source,
643
802
  cost_tiebreak=cost_tiebreak,
803
+ cost_weighted=result.cost_weighted,
644
804
  )
645
805
  output = {
646
806
  "hookSpecificOutput": {
@@ -1,5 +1,28 @@
1
1
  # Changelog
2
2
 
3
+ ## [2.26.0] - 2026-05-26
4
+
5
+ **cost-weighted Thompson 本格統合(全 tier)・ESCALATION_THRESHOLD 調整可能化**: Thompson Sampling のサンプル値を全 tier でコスト重み付けして routing する機能を導入。failure-rate escalation 閾値を環境変数で調整可能にする。環境変数 3 種すべて未設定で v2.25.0 と完全一致。**破壊的変更なし**。
6
+
7
+ ### 機能追加
8
+
9
+ - **`.claude/hooks/select_tier.py`: cost-weighted Thompson Sampling(全 tier 対象)**: スコアを `score = sample − λ·cost_norm`(cost_norm は全 tier の min-max 正規化)とし最大 tier を選ぶ routing を導入。λ は環境変数 `C3_TIER_COST_LAMBDA`(0〜1)で設定。λ>0 で発動し、安い tier が成功率優位な tier に勝ちうる(成功率 vs コストのトレードオフ)。λ=0 明示でコスト無視(純 Thompson)。`db.COST_LAMBDA_DEFAULT`(None)が SSOT。
10
+
11
+ - **`.claude/hooks/select_tier.py`: `C3_ESCALATION_THRESHOLD` 対応**: failure-rate escalation の閾値を環境変数 `C3_ESCALATION_THRESHOLD`(0 < x ≤ 1)で設定可能に。`db.ESCALATION_THRESHOLD_DEFAULT`(0.5)が SSOT。NaN・範囲外・非数値は default 値に fallback。
12
+
13
+ ### 変更
14
+
15
+ - **`.claude/hooks/select_tier.py`**: `SelectionResult` に `cost_weighted: bool` / `cost_lambda: float | None` を末尾追加(既存フィールド不変)。`write_tier_selection`/`build_additional_context` に cost-weighted 発動時 `cost_weighted` / `cost_lambda` を記録(既存 `cost_tiebreak` キーは不変)。
16
+
17
+ - **`src/c3/db.py`**: `COST_LAMBDA_DEFAULT = None`・`ESCALATION_THRESHOLD_DEFAULT = 0.5` 定数を追加(環境変数オーバーライドの SSOT)。
18
+
19
+ ### 後方互換
20
+
21
+ - `C3_TIER_COST_LAMBDA` 未設定(デフォルト None)時は v2.25.0 の ε tie-break 挙動を完全維持(routing 出力はバイト互換)。
22
+ - `C3_TIER_EPSILON`・`C3_ESCALATION_THRESHOLD` 未設定時も v2.25.0 と完全一致。
23
+ - 既存関数シグネチャ不変(`select_tier_detailed`/`select_tier` の λ は optional kwarg・`SelectionResult` は末尾フィールド追加)。
24
+ - migration 不要(v2.22.0 の 003 で列確保済み)。**破壊的変更なし**。
25
+
3
26
  ## [2.25.0] - 2026-05-26
4
27
 
5
28
  **tier_bandit cost 蓄積・EPSILON 調整可能化・例外ログ統一**: v2.22.0 で列確保済みの `tier_bandit.total_cost_usd`/`cost_samples` へ実測値を materialize する同期関数を追加。cost-aware tie-break の拮抗判定閾値を定数 SSOT 化し環境変数で上書き可能にする。db.py 既存 6 関数の例外ログを型名統一(SR-R-001)。routing 挙動は不変。cost-weighted Thompson 本格統合は v2.26.0。
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: claude-code-conductor
3
- Version: 2.25.0
3
+ Version: 2.26.0
4
4
  Summary: Multi-agent orchestration framework for Claude Code with Codex/Cursor adapters (C3)
5
5
  Project-URL: Homepage, https://github.com/satoh-y-0323/claude-code-conductor
6
6
  Project-URL: Repository, https://github.com/satoh-y-0323/claude-code-conductor
@@ -201,7 +201,7 @@ C3 のスラッシュコマンドはすべてスキル(`skills/{name}/SKILL.md
201
201
  | `c3 recall search "<query>"` または `c3 recall "<query>"` | `.claude/memory/sessions/` 等から類似チャンクを意味検索 |
202
202
  | `c3 recall rebuild [--force]` | HNSW インデックスを再構築(初回は fastembed が ~220MB のモデルを取得) |
203
203
  | `c3 recall stats` | チャンク数・モデル名・最終 rebuild 日時を表示 |
204
- | `c3 tier stats` | tier-routing(複雑度に応じた Tier 自動ルーティング)の学習データ・Tier 別コストを表形式で表示(`--json` で機械可読出力・`--recent N` で直近 outcome 件数指定) |
204
+ | `c3 tier stats` | tier-routing(複雑度に応じた Tier 自動ルーティング)の学習データ・Tier 別コストを表形式で表示(`--json` で機械可読出力・`--recent N` で直近 outcome 件数指定)。ルーティング挙動は環境変数 `C3_TIER_COST_LAMBDA`(cost-weighted の重み・v2.26.0〜)/ `C3_TIER_EPSILON` / `C3_ESCALATION_THRESHOLD` で調整可([CLI リファレンス](https://satoh-y-0323.github.io/claude-code-conductor/cli-reference/)参照) |
205
205
 
206
206
  ### 基本的な使い方
207
207
 
@@ -154,7 +154,7 @@ C3 のスラッシュコマンドはすべてスキル(`skills/{name}/SKILL.md
154
154
  | `c3 recall search "<query>"` または `c3 recall "<query>"` | `.claude/memory/sessions/` 等から類似チャンクを意味検索 |
155
155
  | `c3 recall rebuild [--force]` | HNSW インデックスを再構築(初回は fastembed が ~220MB のモデルを取得) |
156
156
  | `c3 recall stats` | チャンク数・モデル名・最終 rebuild 日時を表示 |
157
- | `c3 tier stats` | tier-routing(複雑度に応じた Tier 自動ルーティング)の学習データ・Tier 別コストを表形式で表示(`--json` で機械可読出力・`--recent N` で直近 outcome 件数指定) |
157
+ | `c3 tier stats` | tier-routing(複雑度に応じた Tier 自動ルーティング)の学習データ・Tier 別コストを表形式で表示(`--json` で機械可読出力・`--recent N` で直近 outcome 件数指定)。ルーティング挙動は環境変数 `C3_TIER_COST_LAMBDA`(cost-weighted の重み・v2.26.0〜)/ `C3_TIER_EPSILON` / `C3_ESCALATION_THRESHOLD` で調整可([CLI リファレンス](https://satoh-y-0323.github.io/claude-code-conductor/cli-reference/)参照) |
158
158
 
159
159
  ### 基本的な使い方
160
160
 
@@ -1,3 +1,3 @@
1
1
  """Claude Code Conductor (C3) - multi-agent orchestration framework for Claude Code."""
2
2
 
3
- __version__ = "2.25.0"
3
+ __version__ = "2.26.0"
@@ -40,6 +40,16 @@ LEARNING_THRESHOLD = 30
40
40
  # 過大にすると成功率を犠牲にするリスク、過小にすると無発動になる。
41
41
  # C3_TIER_EPSILON 環境変数で上書き可(v2.25.0)。
42
42
  EPSILON_TIEBREAK = 0.05
43
+ # cost-weighted Thompson の重み係数 λ の既定値。
44
+ # None = v2.25.0 互換モード(ε tie-break を維持し全 tier weighting を発動しない)。
45
+ # C3_TIER_COST_LAMBDA 環境変数で上書き可(v2.26.0)。
46
+ # λ>0 で全 tier の score=sample-λ*cost_norm weighting が発動、λ=0 明示で cost 無視(純 Thompson)。
47
+ # 本定数が SSOT。
48
+ COST_LAMBDA_DEFAULT = None
49
+ # failure rate がこの値以上で 1 段上位 tier へ escalation する閾値。
50
+ # C3_ESCALATION_THRESHOLD 環境変数で上書き可(v2.26.0)。
51
+ # 本定数が SSOT(select_tier.py はここから参照)。
52
+ ESCALATION_THRESHOLD_DEFAULT = 0.5
43
53
 
44
54
 
45
55
  def _apply_busy_timeout(conn: sqlite3.Connection) -> None: