phronomy 0.26.0 → 0.28.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 (557) hide show
  1. checksums.yaml +4 -4
  2. data/.mutant.yml +9 -9
  3. data/CHANGELOG.md +92 -0
  4. data/CONTRIBUTING.md +8 -8
  5. data/README.md +13 -3
  6. data/VERIFY.sh +27 -27
  7. data/benchmark/bench_agent_invoke.rb +26 -47
  8. data/benchmark/bench_context_assembler.rb +17 -15
  9. data/benchmark/bench_regression.rb +1 -1
  10. data/benchmark/bench_tool_schema.rb +1 -1
  11. data/docs/architecture/agent-chat-and-state-ownership.md +153 -0
  12. data/docs/architecture/agent-configuration-and-tool-binding.md +139 -0
  13. data/docs/architecture/agent-context.md +4 -2
  14. data/docs/architecture/agent-transition-ownership.md +13 -0
  15. data/docs/architecture/backend-groups.md +152 -0
  16. data/docs/architecture/before-llm-input.md +9 -3
  17. data/docs/architecture/context-management.md +31 -1
  18. data/docs/architecture/context-preparation-steps.md +90 -0
  19. data/docs/architecture/entry-action-and-team-wording.md +72 -0
  20. data/docs/architecture/execution-abstraction-review.md +88 -0
  21. data/docs/architecture/execution-boundaries.md +28 -0
  22. data/docs/architecture/execution-metadata-and-values.md +86 -0
  23. data/docs/architecture/generator-verifier-ownership.md +111 -0
  24. data/docs/architecture/multi-agent-handoff.md +11 -4
  25. data/docs/architecture/persistence-refactoring-plan.md +50 -0
  26. data/docs/architecture/persistence.md +45 -4
  27. data/docs/architecture/r8-unit1.md +104 -0
  28. data/docs/architecture/r8-unit10.md +72 -0
  29. data/docs/architecture/r8-unit11.md +71 -0
  30. data/docs/architecture/r8-unit12.md +67 -0
  31. data/docs/architecture/r8-unit13.md +61 -0
  32. data/docs/architecture/r8-unit14.md +72 -0
  33. data/docs/architecture/r8-unit15.md +65 -0
  34. data/docs/architecture/r8-unit16.md +54 -0
  35. data/docs/architecture/r8-unit17.md +73 -0
  36. data/docs/architecture/r8-unit18.md +92 -0
  37. data/docs/architecture/r8-unit19.md +61 -0
  38. data/docs/architecture/r8-unit2.md +55 -0
  39. data/docs/architecture/r8-unit20.md +51 -0
  40. data/docs/architecture/r8-unit21.md +79 -0
  41. data/docs/architecture/r8-unit22.md +74 -0
  42. data/docs/architecture/r8-unit23.md +81 -0
  43. data/docs/architecture/r8-unit3.md +130 -0
  44. data/docs/architecture/r8-unit4.md +79 -0
  45. data/docs/architecture/r8-unit5.md +115 -0
  46. data/docs/architecture/r8-unit6.md +71 -0
  47. data/docs/architecture/r8-unit7.md +70 -0
  48. data/docs/architecture/r8-unit8.md +78 -0
  49. data/docs/architecture/r8-unit9.md +73 -0
  50. data/docs/architecture/refactoring-closure.md +343 -0
  51. data/docs/architecture/remaining-refactoring-plan.md +390 -0
  52. data/docs/architecture/rubyllm-2-token-ownership.md +82 -0
  53. data/docs/architecture/storage-execution-boundaries.md +54 -0
  54. data/docs/architecture/tool-schema-recording-gap.md +56 -0
  55. data/docs/architecture/tracing.md +2 -2
  56. data/docs/architecture/workflow-terminal-ownership-design.md +104 -0
  57. data/docs/architecture.md +222 -0
  58. data/docs/decisions/014-unified-persistence-durable-state.md +11 -0
  59. data/docs/decisions/015-tool-public-facade-and-rbs-boundary.md +3 -3
  60. data/docs/decisions/024-event-loop-single-writer-agent-runtime.md +5 -1
  61. data/docs/decisions/025-process-local-agent-ownership-and-runtime-admission.md +13 -3
  62. data/docs/decisions/026-workflow-runtime-admission-and-durable-terminal-barrier.md +5 -1
  63. data/docs/decisions/027-llm-adapter-provider-boundary.md +2 -0
  64. data/docs/decisions/030-agent-handoff-domain-and-durable-responsibility.md +7 -0
  65. data/docs/decisions/031-durable-multi-agent-coordination.md +7 -0
  66. data/docs/decisions/032-storage-backend-composition.md +85 -0
  67. data/docs/decisions/033-domain-persistence-ownership.md +79 -0
  68. data/docs/decisions/034-handoff-runner-coordination-ownership.md +78 -0
  69. data/docs/decisions/035-tool-executor-capability-ownership.md +68 -0
  70. data/docs/decisions/036-context-contract-ownership.md +86 -0
  71. data/docs/decisions/037-common-definition-ownership.md +62 -0
  72. data/docs/decisions/038-responsibility-based-source-layout.md +145 -0
  73. data/docs/decisions/039-runtime-configuration-lifecycle-ownership.md +82 -0
  74. data/docs/decisions/040-configuration-default-composition.md +105 -0
  75. data/docs/decisions/041-feature-owned-identity-registries.md +100 -0
  76. data/docs/decisions/042-feature-owned-execution-state.md +106 -0
  77. data/docs/decisions/043-storage-execution-constraint-notifications.md +75 -0
  78. data/docs/decisions/044-agent-default-and-one-shot-composition.md +106 -0
  79. data/docs/decisions/045-worker-input-restriction-ownership.md +104 -0
  80. data/docs/decisions/046-agent-responsibility-layout-and-shared-records.md +110 -0
  81. data/docs/decisions/047-recovered-execution-continuation-contract.md +116 -0
  82. data/docs/decisions/048-dispatch-preparation-worker-ownership.md +120 -0
  83. data/docs/decisions/049-initial-preparation-worker-ownership.md +111 -0
  84. data/docs/decisions/050-approval-resume-snapshot-and-commit-ownership.md +98 -0
  85. data/docs/decisions/051-execution-outcome-worker-ownership.md +153 -0
  86. data/docs/decisions/052-tool-invocation-restoration-ownership.md +92 -0
  87. data/docs/decisions/053-shared-state-coordination-ownership.md +71 -0
  88. data/docs/decisions/054-workflow-terminal-save-single-owner.md +76 -0
  89. data/docs/decisions/055-terminal-observer-failure-settlement.md +60 -0
  90. data/docs/decisions/056-workflow-terminal-policy-ownership.md +87 -0
  91. data/docs/decisions/057-storage-transaction-boundaries.md +73 -0
  92. data/docs/decisions/058-neutral-storage-primitives.md +83 -0
  93. data/docs/decisions/059-backend-contracts-and-async-clients.md +74 -0
  94. data/docs/decisions/060-runtime-settings-and-application-configuration.md +86 -0
  95. data/docs/decisions/061-persistence-failure-contracts.md +89 -0
  96. data/docs/decisions/062-content-store-service.md +52 -0
  97. data/docs/decisions/063-execution-contracts-and-services.md +88 -0
  98. data/docs/decisions/064-agent-execution-and-multi-agent-responsibility.md +36 -0
  99. data/docs/decisions/065-vector-and-embeddings-common-operations.md +38 -0
  100. data/docs/decisions/066-llm-and-tool-operation-contracts.md +20 -0
  101. data/docs/decisions/067-agent-progress-and-engine-connection.md +29 -0
  102. data/docs/decisions/068-agent-tool-child-progress-and-tool-operation.md +36 -0
  103. data/docs/decisions/README.md +52 -6
  104. data/docs/design/durable-semantic-coordination/IMPLEMENTATION_DESIGN_V2.md +6 -0
  105. data/docs/design/durable-semantic-coordination/IMPLEMENTATION_REPORT.md +6 -0
  106. data/docs/execution-boundaries-preview.md +45 -0
  107. data/docs/features.md +16 -5
  108. data/docs/getting-started.md +11 -8
  109. data/docs/migrations/0.15.md +5 -0
  110. data/docs/migrations/0.22.md +2 -2
  111. data/docs/migrations/durable-semantic-coordination-v2.md +8 -0
  112. data/docs/migrations/handoff-runner-multi-agent.md +37 -0
  113. data/docs/migrations/neutral-storage-spi.md +43 -0
  114. data/docs/migrations/parallel-tool-chat-removal.md +49 -0
  115. data/docs/migrations/persistence-failure-contracts.md +67 -0
  116. data/docs/migrations/r8-unit10.md +36 -0
  117. data/docs/migrations/r8-unit11.md +33 -0
  118. data/docs/migrations/r8-unit12.md +31 -0
  119. data/docs/migrations/r8-unit13.md +36 -0
  120. data/docs/migrations/r8-unit14.md +31 -0
  121. data/docs/migrations/r8-unit15.md +31 -0
  122. data/docs/migrations/r8-unit16.md +26 -0
  123. data/docs/migrations/r8-unit17.md +28 -0
  124. data/docs/migrations/r8-unit18.md +29 -0
  125. data/docs/migrations/r8-unit19.md +28 -0
  126. data/docs/migrations/r8-unit20.md +24 -0
  127. data/docs/migrations/r8-unit21.md +28 -0
  128. data/docs/migrations/r8-unit22.md +29 -0
  129. data/docs/migrations/r8-unit23.md +20 -0
  130. data/docs/migrations/r8-unit4.md +67 -0
  131. data/docs/migrations/r8-unit5.md +75 -0
  132. data/docs/migrations/r8-unit6.md +109 -0
  133. data/docs/migrations/r8-unit7.md +31 -0
  134. data/docs/migrations/r8-unit8.md +33 -0
  135. data/docs/migrations/r8-unit9.md +28 -0
  136. data/docs/migrations/shared-state-multi-agent.md +44 -0
  137. data/docs/migrations/storage-async-client.md +103 -0
  138. data/docs/migrations/storage-backend-composition.md +117 -0
  139. data/docs/migrations/storage-transaction-boundaries.md +74 -0
  140. data/docs/migrations/vector-async-clients.md +110 -0
  141. data/docs/persistence-backends.md +190 -215
  142. data/docs/runtime-and-concurrency.md +142 -32
  143. data/lib/phronomy/agent/admission.rb +78 -0
  144. data/lib/phronomy/{agent_already_exists_error.rb → agent/agent_already_exists_error.rb} +2 -0
  145. data/lib/phronomy/{agent_busy_error.rb → agent/agent_busy_error.rb} +2 -0
  146. data/lib/phronomy/{agent_purged_error.rb → agent/agent_purged_error.rb} +2 -0
  147. data/lib/phronomy/agent/api/agent.rb +17 -0
  148. data/lib/phronomy/{execution_rehydration_required_error.rb → agent/api/execution_rehydration_required_error.rb} +2 -0
  149. data/lib/phronomy/agent/async_event_api.rb +38 -33
  150. data/lib/phronomy/agent/base.rb +106 -294
  151. data/lib/phronomy/agent/before_llm_input.rb +64 -0
  152. data/lib/phronomy/{agent.rb → agent/composition/run_once.rb} +4 -13
  153. data/lib/phronomy/agent/context_candidate_resolver.rb +2 -2
  154. data/lib/phronomy/agent/context_importer.rb +2 -2
  155. data/lib/phronomy/agent/{context_assembler.rb → context_preparation.rb} +157 -288
  156. data/lib/phronomy/agent/control_request.rb +21 -0
  157. data/lib/phronomy/agent/{agent_execution.rb → execution/agent_execution.rb} +8 -4
  158. data/lib/phronomy/agent/{agent_invocation.rb → execution/agent_invocation.rb} +32 -63
  159. data/lib/phronomy/agent/execution/approval_resume_commit.rb +108 -0
  160. data/lib/phronomy/agent/execution/dispatch_preparation.rb +195 -0
  161. data/lib/phronomy/agent/{exact_execution.rb → execution/exact_execution.rb} +43 -23
  162. data/lib/phronomy/agent/{execution_cancellation.rb → execution/execution_cancellation.rb} +8 -5
  163. data/lib/phronomy/agent/execution/execution_coordinator.rb +1744 -0
  164. data/lib/phronomy/agent/execution/execution_failure.rb +30 -0
  165. data/lib/phronomy/agent/execution/execution_metadata.rb +54 -0
  166. data/lib/phronomy/agent/execution/execution_outcome_committer.rb +288 -0
  167. data/lib/phronomy/agent/execution/execution_registry.rb +463 -0
  168. data/lib/phronomy/agent/execution/execution_session_runner.rb +113 -0
  169. data/lib/phronomy/agent/execution/initial_preparation.rb +323 -0
  170. data/lib/phronomy/agent/execution/invocation_actions.rb +368 -0
  171. data/lib/phronomy/agent/execution/invocation_transitions.rb +124 -0
  172. data/lib/phronomy/agent/execution/runtime_record_encoder.rb +210 -0
  173. data/lib/phronomy/agent/execution_change.rb +161 -0
  174. data/lib/phronomy/agent/execution_environment.rb +36 -0
  175. data/lib/phronomy/agent/execution_extension_state.rb +21 -0
  176. data/lib/phronomy/agent/execution_observation.rb +35 -0
  177. data/lib/phronomy/agent/filterable.rb +182 -0
  178. data/lib/phronomy/agent/{handoff_context.rb → handoff/transfer_context.rb} +6 -6
  179. data/lib/phronomy/agent/{handoff_projection.rb → handoff/transfer_projection.rb} +14 -33
  180. data/lib/phronomy/agent/handoff_error.rb +7 -0
  181. data/lib/phronomy/agent/{journal_projection.rb → journal/journal_projection.rb} +4 -0
  182. data/lib/phronomy/agent/{journal_record.rb → journal/journal_record.rb} +3 -3
  183. data/lib/phronomy/agent/{llm_call_record.rb → journal/llm_call_record.rb} +2 -2
  184. data/lib/phronomy/agent/knowledge_item.rb +13 -0
  185. data/lib/phronomy/agent/{agent_root.rb → lifecycle/agent_root.rb} +6 -2
  186. data/lib/phronomy/agent/lifecycle/default_persistence.rb +29 -0
  187. data/lib/phronomy/{engine/runtime/agent_ownership_registry.rb → agent/lifecycle/ownership_registry.rb} +24 -15
  188. data/lib/phronomy/agent/persistence/agent_repository.rb +69 -0
  189. data/lib/phronomy/agent/persistence/cancellation_repository.rb +51 -0
  190. data/lib/phronomy/agent/persistence/codec.rb +338 -0
  191. data/lib/phronomy/agent/persistence/execution_repository.rb +124 -0
  192. data/lib/phronomy/agent/persistence/journal_repository.rb +63 -0
  193. data/lib/phronomy/agent/persistence/records.rb +33 -0
  194. data/lib/phronomy/agent/persistence/retention_repository.rb +70 -0
  195. data/lib/phronomy/agent/persistence/storage_schema.rb +29 -0
  196. data/lib/phronomy/agent/persistence/watermark.rb +29 -0
  197. data/lib/phronomy/agent/recovery/invocation_restorer.rb +124 -0
  198. data/lib/phronomy/agent/{recovery_coordinator → recovery/recovery_coordinator}/continuation.rb +28 -51
  199. data/lib/phronomy/agent/{recovery_coordinator → recovery/recovery_coordinator}/installation.rb +50 -55
  200. data/lib/phronomy/agent/{recovery_coordinator → recovery/recovery_coordinator}/resolution.rb +38 -43
  201. data/lib/phronomy/agent/{recovery_coordinator.rb → recovery/recovery_coordinator.rb} +26 -23
  202. data/lib/phronomy/agent/recovery/recovery_rules.rb +119 -0
  203. data/lib/phronomy/agent/recovery/recovery_support.rb +224 -0
  204. data/lib/phronomy/agent/reserved_execution.rb +16 -0
  205. data/lib/phronomy/agent/retention.rb +17 -0
  206. data/lib/phronomy/agent/runtime_binding/engine_environment.rb +60 -0
  207. data/lib/phronomy/agent/runtime_binding/engine_session_builder.rb +34 -0
  208. data/lib/phronomy/agent/runtime_binding/phase_machine_builder.rb +64 -0
  209. data/lib/phronomy/agent/runtime_binding/tool_session_builder.rb +34 -0
  210. data/lib/phronomy/agent/{ruby_llm_materializer.rb → runtime_input.rb} +19 -39
  211. data/lib/phronomy/agent/saved_context_reader.rb +55 -0
  212. data/lib/phronomy/agent/settings.rb +47 -0
  213. data/lib/phronomy/agent/state_writer.rb +166 -0
  214. data/lib/phronomy/agent/store.rb +253 -0
  215. data/lib/phronomy/{stream_callback_error.rb → agent/stream_callback_error.rb} +2 -0
  216. data/lib/phronomy/agent/{approval_evaluation_request.rb → tool_execution/approval_evaluation_request.rb} +1 -12
  217. data/lib/phronomy/agent/{tool_approval_request.rb → tool_execution/tool_approval_request.rb} +1 -10
  218. data/lib/phronomy/agent/tool_execution/tool_binding.rb +30 -0
  219. data/lib/phronomy/agent/{tool_invocation.rb → tool_execution/tool_invocation.rb} +114 -248
  220. data/lib/phronomy/agent/tool_execution/tool_invocation_actions.rb +107 -0
  221. data/lib/phronomy/agent/tool_execution/tool_invocation_transitions.rb +70 -0
  222. data/lib/phronomy/common/configuration_error.rb +7 -0
  223. data/lib/phronomy/common/error.rb +5 -0
  224. data/lib/phronomy/{agent → common/values}/immutable.rb +9 -1
  225. data/lib/phronomy/common/values/serializable.rb +32 -0
  226. data/lib/phronomy/configuration/runtime_settings.rb +49 -0
  227. data/lib/phronomy/content_store/storage_schema.rb +12 -0
  228. data/lib/phronomy/content_store/stored_contents.rb +44 -0
  229. data/lib/phronomy/context/assembly.rb +202 -0
  230. data/lib/phronomy/{context_budget_exceeded_error.rb → context/budget_exceeded_error.rb} +5 -1
  231. data/lib/phronomy/context/candidate.rb +51 -0
  232. data/lib/phronomy/context/constraint.rb +47 -0
  233. data/lib/phronomy/{agent → context}/context_plan.rb +2 -2
  234. data/lib/phronomy/{agent → context}/context_plan_validator.rb +3 -3
  235. data/lib/phronomy/{agent → context}/context_policy.rb +1 -1
  236. data/lib/phronomy/{agent → context}/context_policy_input.rb +7 -7
  237. data/lib/phronomy/{agent → context}/context_policy_input_builder.rb +1 -1
  238. data/lib/phronomy/context/default_policy.rb +140 -0
  239. data/lib/phronomy/context/final_budget_validator.rb +33 -0
  240. data/lib/phronomy/{agent → context}/llm_input_build_context.rb +2 -2
  241. data/lib/phronomy/{agent → context}/llm_input_manifest.rb +21 -21
  242. data/lib/phronomy/{agent → context}/llm_input_patch.rb +3 -3
  243. data/lib/phronomy/context/manifest_error.rb +10 -0
  244. data/lib/phronomy/context/prompt_template.rb +98 -0
  245. data/lib/phronomy/{vector_store → documents}/loader/base.rb +1 -1
  246. data/lib/phronomy/{vector_store → documents}/loader/csv_loader.rb +2 -2
  247. data/lib/phronomy/{vector_store → documents}/loader/markdown_loader.rb +3 -3
  248. data/lib/phronomy/{vector_store → documents}/loader/plain_text_loader.rb +2 -2
  249. data/lib/phronomy/{vector_store → documents}/splitter/base.rb +1 -1
  250. data/lib/phronomy/{vector_store → documents}/splitter/fixed_size_splitter.rb +2 -2
  251. data/lib/phronomy/{vector_store → documents}/splitter/recursive_splitter.rb +2 -2
  252. data/lib/phronomy/embeddings/async/async_client.rb +44 -0
  253. data/lib/phronomy/embeddings/backends/ruby_llm_embeddings.rb +48 -0
  254. data/lib/phronomy/embeddings/base.rb +43 -0
  255. data/lib/phronomy/embeddings/invalid_result_error.rb +11 -0
  256. data/lib/phronomy/embeddings/transport_error.rb +11 -0
  257. data/lib/phronomy/engine/concurrency/offload_pool.rb +39 -20
  258. data/lib/phronomy/engine/concurrency/pool_registry.rb +47 -12
  259. data/lib/phronomy/{diagnostics.rb → engine/diagnostics.rb} +1 -1
  260. data/lib/phronomy/engine/event_loop.rb +164 -630
  261. data/lib/phronomy/engine/execution_binding.rb +23 -0
  262. data/lib/phronomy/engine/execution_receiver_binding.rb +43 -0
  263. data/lib/phronomy/engine/fsm_protocol.rb +9 -0
  264. data/lib/phronomy/engine/fsm_session.rb +37 -30
  265. data/lib/phronomy/engine/metrics.rb +28 -0
  266. data/lib/phronomy/engine/runtime/timer_queue.rb +1 -1
  267. data/lib/phronomy/engine/runtime.rb +104 -95
  268. data/lib/phronomy/engine/terminal_decision.rb +7 -0
  269. data/lib/phronomy/execution/async_operation.rb +41 -0
  270. data/lib/phronomy/execution/backpressure_error.rb +7 -0
  271. data/lib/phronomy/{blocking.rb → execution/blocking.rb} +2 -2
  272. data/lib/phronomy/execution/cancellation_error.rb +7 -0
  273. data/lib/phronomy/{engine → execution}/concurrency/cancellation_token.rb +5 -1
  274. data/lib/phronomy/{engine → execution}/concurrency/deadline.rb +0 -17
  275. data/lib/phronomy/{engine → execution}/concurrency/physical_completion_task.rb +1 -1
  276. data/lib/phronomy/{engine → execution}/concurrency/result_collector.rb +1 -1
  277. data/lib/phronomy/{engine → execution}/concurrency/result_composition.rb +33 -12
  278. data/lib/phronomy/{engine/concurrency/subscriptions.rb → execution/concurrency/result_subscriptions.rb} +14 -18
  279. data/lib/phronomy/execution/concurrency/subscriptions.rb +25 -0
  280. data/lib/phronomy/execution/concurrency/worker_input_restricted.rb +14 -0
  281. data/lib/phronomy/execution/event_loop_reentrancy_error.rb +8 -0
  282. data/lib/phronomy/{execution.rb → execution/execution.rb} +57 -30
  283. data/lib/phronomy/{execution_cancellation_error.rb → execution/execution_cancellation_error.rb} +2 -0
  284. data/lib/phronomy/execution/execution_receiver.rb +78 -0
  285. data/lib/phronomy/execution/execution_scope_state.rb +35 -0
  286. data/lib/phronomy/{execution_timeout_error.rb → execution/execution_timeout_error.rb} +2 -0
  287. data/lib/phronomy/{invalid_async_entry_action_error.rb → execution/invalid_async_entry_action_error.rb} +2 -0
  288. data/lib/phronomy/{invalid_async_transition_action_error.rb → execution/invalid_async_transition_action_error.rb} +2 -0
  289. data/lib/phronomy/{invalid_async_workflow_action_error.rb → execution/invalid_async_workflow_action_error.rb} +2 -0
  290. data/lib/phronomy/{invocation_context.rb → execution/invocation_context.rb} +0 -15
  291. data/lib/phronomy/execution/invocation_controls.rb +73 -0
  292. data/lib/phronomy/execution/pool_shutdown_error.rb +7 -0
  293. data/lib/phronomy/execution/recursion_limit_error.rb +7 -0
  294. data/lib/phronomy/execution/runnable.rb +24 -0
  295. data/lib/phronomy/execution/runtime_shutdown_error.rb +7 -0
  296. data/lib/phronomy/execution/runtime_shutdown_reentrancy_error.rb +7 -0
  297. data/lib/phronomy/execution/scheduler_reentrancy_error.rb +9 -0
  298. data/lib/phronomy/{engine → execution}/task_result.rb +7 -3
  299. data/lib/phronomy/execution/timeout_error.rb +7 -0
  300. data/lib/phronomy/execution/wait_policy.rb +24 -0
  301. data/lib/phronomy/filter/filter_block_error.rb +14 -0
  302. data/lib/phronomy/generation/generator_verifier/agent_operation.rb +65 -0
  303. data/lib/phronomy/generation/generator_verifier/agent_result_receiver.rb +89 -0
  304. data/lib/phronomy/generation/generator_verifier/default_parser.rb +27 -0
  305. data/lib/phronomy/generation/generator_verifier/pipeline_state.rb +57 -0
  306. data/lib/phronomy/generation/generator_verifier/workflow_builder.rb +112 -0
  307. data/lib/phronomy/generation/generator_verifier.rb +118 -0
  308. data/lib/phronomy/generation/low_confidence_error.rb +14 -0
  309. data/lib/phronomy/llm_adapter/async/async_client.rb +47 -0
  310. data/lib/phronomy/llm_adapter/authentication_error.rb +9 -0
  311. data/lib/phronomy/llm_adapter/backends/ruby_llm.rb +183 -0
  312. data/lib/phronomy/llm_adapter/base.rb +49 -68
  313. data/lib/phronomy/llm_adapter/context_length_error.rb +9 -0
  314. data/lib/phronomy/llm_adapter/invalid_result_error.rb +10 -0
  315. data/lib/phronomy/llm_adapter/message.rb +62 -0
  316. data/lib/phronomy/llm_adapter/rate_limit_error.rb +9 -0
  317. data/lib/phronomy/llm_adapter/request.rb +79 -0
  318. data/lib/phronomy/llm_adapter/response.rb +36 -0
  319. data/lib/phronomy/llm_adapter/stream_chunk.rb +18 -0
  320. data/lib/phronomy/llm_adapter/token_usage.rb +64 -0
  321. data/lib/phronomy/llm_adapter/transport_error.rb +9 -0
  322. data/lib/phronomy/llm_adapter.rb +3 -16
  323. data/lib/phronomy/llm_context_window/token_budget.rb +6 -7
  324. data/lib/phronomy/multi_agent/admission_registry.rb +15 -2
  325. data/lib/phronomy/multi_agent/durable_subagent_coordinator.rb +108 -84
  326. data/lib/phronomy/multi_agent/execution_environment.rb +29 -0
  327. data/lib/phronomy/{agent → multi_agent}/handoff.rb +2 -2
  328. data/lib/phronomy/{agent → multi_agent}/handoff_capability_factory.rb +21 -2
  329. data/lib/phronomy/multi_agent/handoff_participant.rb +79 -0
  330. data/lib/phronomy/{agent → multi_agent}/handoff_policy.rb +1 -1
  331. data/lib/phronomy/multi_agent/handoff_runner.rb +156 -0
  332. data/lib/phronomy/{agent → multi_agent}/handoff_state.rb +2 -2
  333. data/lib/phronomy/multi_agent/orchestrator.rb +61 -75
  334. data/lib/phronomy/multi_agent/persistence/codec.rb +75 -0
  335. data/lib/phronomy/multi_agent/persistence/handoff_state_repository.rb +77 -0
  336. data/lib/phronomy/multi_agent/persistence/records.rb +27 -0
  337. data/lib/phronomy/multi_agent/persistence/storage_schema.rb +21 -0
  338. data/lib/phronomy/multi_agent/persistence/team_execution_repository.rb +124 -0
  339. data/lib/phronomy/multi_agent/persistence/team_repository.rb +69 -0
  340. data/lib/phronomy/multi_agent/reserved_child_admission.rb +88 -0
  341. data/lib/phronomy/multi_agent/runtime_binding/engine_environment.rb +35 -0
  342. data/lib/phronomy/{agent → multi_agent}/shared_state.rb +56 -39
  343. data/lib/phronomy/multi_agent/store.rb +156 -0
  344. data/lib/phronomy/multi_agent/team_coordinator.rb +87 -75
  345. data/lib/phronomy/multi_agent/team_execution.rb +1 -1
  346. data/lib/phronomy/{engine/runtime → multi_agent}/team_ownership_registry.rb +5 -5
  347. data/lib/phronomy/multi_agent/team_root.rb +1 -1
  348. data/lib/phronomy/output_parser/parse_error.rb +7 -0
  349. data/lib/phronomy/persistence/content_repository.rb +26 -0
  350. data/lib/phronomy/persistence/errors.rb +16 -0
  351. data/lib/phronomy/persistence/migration/initial_format_migration.rb +21 -21
  352. data/lib/phronomy/persistence/persistence.rb +23 -0
  353. data/lib/phronomy/persistence/save_outcome.rb +24 -0
  354. data/lib/phronomy/persistence/snapshot_comparison.rb +81 -0
  355. data/lib/phronomy/persistence/storage_boundary.rb +32 -0
  356. data/lib/phronomy/persistence/transaction.rb +86 -0
  357. data/lib/phronomy/persistence_composition/storage_schema.rb +29 -0
  358. data/lib/phronomy/persistence_composition/stores.rb +34 -0
  359. data/lib/phronomy/persistence_composition/unit4_migration.rb +276 -0
  360. data/lib/phronomy/runtime_composition/agent_defaults.rb +11 -0
  361. data/lib/phronomy/runtime_composition/configuration.rb +146 -0
  362. data/lib/phronomy/runtime_composition/configuration_defaults.rb +9 -0
  363. data/lib/phronomy/runtime_composition/evaluation_defaults.rb +7 -0
  364. data/lib/phronomy/runtime_composition/execution_defaults.rb +5 -0
  365. data/lib/phronomy/runtime_composition/generation_defaults.rb +6 -0
  366. data/lib/phronomy/runtime_composition/global_configuration.rb +38 -0
  367. data/lib/phronomy/runtime_composition/global_runtime.rb +19 -0
  368. data/lib/phronomy/runtime_composition/multi_agent_defaults.rb +9 -0
  369. data/lib/phronomy/runtime_composition/workflow_defaults.rb +4 -0
  370. data/lib/phronomy/storage/async/async_client.rb +60 -0
  371. data/lib/phronomy/storage/backend.rb +107 -0
  372. data/lib/phronomy/storage/backends/in_memory.rb +157 -0
  373. data/lib/phronomy/storage/blob_conflict_error.rb +10 -0
  374. data/lib/phronomy/storage/blobs.rb +31 -0
  375. data/lib/phronomy/storage/condition.rb +25 -0
  376. data/lib/phronomy/storage/condition_failed_error.rb +16 -0
  377. data/lib/phronomy/storage/conflict_error.rb +9 -0
  378. data/lib/phronomy/{persistence → storage}/durable_record.rb +12 -12
  379. data/lib/phronomy/storage/entry.rb +33 -0
  380. data/lib/phronomy/storage/guard_ref.rb +13 -0
  381. data/lib/phronomy/storage/not_found_error.rb +9 -0
  382. data/lib/phronomy/storage/record_codec.rb +177 -0
  383. data/lib/phronomy/storage/records.rb +61 -0
  384. data/lib/phronomy/storage/resource.rb +126 -0
  385. data/lib/phronomy/storage/scope.rb +25 -0
  386. data/lib/phronomy/storage/serialization_error.rb +9 -0
  387. data/lib/phronomy/storage/streams.rb +44 -0
  388. data/lib/phronomy/storage/transaction_error.rb +10 -0
  389. data/lib/phronomy/storage/unique_constraint_error.rb +17 -0
  390. data/lib/phronomy/storage/unsupported_backend_error.rb +9 -0
  391. data/lib/phronomy/storage/validation.rb +53 -0
  392. data/lib/phronomy/storage/view.rb +131 -0
  393. data/lib/phronomy/testing/eval/metrics.rb +1 -1
  394. data/lib/phronomy/testing/eval/scorer/llm_judge.rb +19 -3
  395. data/lib/phronomy/testing/persistence_contract/a_content_store.rb +1 -1
  396. data/lib/phronomy/testing/persistence_contract/a_journal_repository.rb +2 -2
  397. data/lib/phronomy/testing/persistence_contract/a_persistence_backend.rb +54 -48
  398. data/lib/phronomy/testing/persistence_contract/a_workflow_state_repository.rb +1 -1
  399. data/lib/phronomy/testing/persistence_contract/an_agent_repository.rb +1 -1
  400. data/lib/phronomy/testing/persistence_contract/an_execution_repository.rb +5 -5
  401. data/lib/phronomy/testing/persistence_contract/coordination_repositories.rb +52 -46
  402. data/lib/phronomy/testing/persistence_contract/neutral_storage_primitives.rb +263 -0
  403. data/lib/phronomy/testing/persistence_contract/storage_transaction_boundaries.rb +124 -0
  404. data/lib/phronomy/testing/persistence_contract.rb +4 -0
  405. data/lib/phronomy/tool/authorization.rb +77 -0
  406. data/lib/phronomy/tool/base.rb +549 -9
  407. data/lib/phronomy/tool/call_request.rb +40 -0
  408. data/lib/phronomy/{agent/tool_definition_set.rb → tool/definition_set.rb} +16 -12
  409. data/lib/phronomy/tool/operation.rb +88 -0
  410. data/lib/phronomy/tool/schema.rb +214 -0
  411. data/lib/phronomy/tool/settings.rb +31 -0
  412. data/lib/phronomy/tool/tool_error.rb +7 -0
  413. data/lib/phronomy/{agent → tool}/tool_executor.rb +10 -7
  414. data/lib/phronomy/tools/agent.rb +22 -90
  415. data/lib/phronomy/tools/mcp.rb +21 -14
  416. data/lib/phronomy/tools/vector_search.rb +4 -4
  417. data/lib/phronomy/tracing/automatic.rb +11 -6
  418. data/lib/phronomy/tracing/base.rb +1 -1
  419. data/lib/phronomy/tracing/observation.rb +37 -0
  420. data/lib/phronomy/tracing/settings.rb +36 -0
  421. data/lib/phronomy/vector_store/{async_backend.rb → async/async_client.rb} +35 -29
  422. data/lib/phronomy/vector_store/{in_memory.rb → backends/in_memory.rb} +12 -10
  423. data/lib/phronomy/vector_store/{pgvector.rb → backends/pgvector.rb} +44 -16
  424. data/lib/phronomy/vector_store/{redis_search.rb → backends/redis_search.rb} +74 -37
  425. data/lib/phronomy/vector_store/base.rb +118 -49
  426. data/lib/phronomy/vector_store/invalid_result_error.rb +12 -0
  427. data/lib/phronomy/vector_store.rb +2 -17
  428. data/lib/phronomy/version.rb +1 -1
  429. data/lib/phronomy/workflow/completion.rb +11 -0
  430. data/lib/phronomy/{workflow.rb → workflow/execution/workflow.rb} +10 -8
  431. data/lib/phronomy/workflow/execution/workflow_action_rules.rb +67 -0
  432. data/lib/phronomy/{workflow_context.rb → workflow/execution/workflow_context.rb} +5 -1
  433. data/lib/phronomy/workflow/execution/workflow_context_ownership_error.rb +7 -0
  434. data/lib/phronomy/workflow/execution/workflow_execution_environment.rb +27 -0
  435. data/lib/phronomy/workflow/execution/workflow_execution_registry.rb +186 -0
  436. data/lib/phronomy/{workflow_runner.rb → workflow/execution/workflow_runner.rb} +145 -115
  437. data/lib/phronomy/workflow/execution/workflow_settings.rb +28 -0
  438. data/lib/phronomy/workflow/persistence/codec.rb +153 -0
  439. data/lib/phronomy/workflow/persistence/state_repository.rb +63 -0
  440. data/lib/phronomy/workflow/persistence/storage_schema.rb +13 -0
  441. data/lib/phronomy/workflow/runtime_binding/workflow_engine_environment.rb +38 -0
  442. data/lib/phronomy/workflow/runtime_binding/workflow_phase_machine_builder.rb +156 -0
  443. data/lib/phronomy/workflow/runtime_binding/workflow_terminal_policy.rb +40 -0
  444. data/lib/phronomy.rb +97 -98
  445. data/scripts/api_snapshot.rb +36 -16
  446. data/scripts/storage_spi_snapshot.rb +36 -0
  447. data/sig/_private/phronomy/agent/settings.rbs +19 -0
  448. data/sig/_private/phronomy/configuration/runtime_settings.rbs +20 -0
  449. data/sig/_private/phronomy/llm_adapter/async/async_client.rbs +10 -0
  450. data/sig/_private/phronomy/multi_agent/store.rbs +8 -0
  451. data/sig/_private/phronomy/persistence/storage_boundary.rbs +7 -0
  452. data/sig/_private/phronomy/tool/settings.rbs +13 -0
  453. data/sig/_private/phronomy/tracing/settings.rbs +15 -0
  454. data/sig/_private/phronomy/workflow/execution/workflow_settings.rbs +13 -0
  455. data/sig/phronomy/agent/admission.rbs +19 -0
  456. data/sig/phronomy/agent/execution_contract.rbs +132 -0
  457. data/sig/phronomy/agent/execution_environment.rbs +20 -0
  458. data/sig/phronomy/agent/store.rbs +73 -0
  459. data/sig/phronomy/agent.rbs +14 -139
  460. data/sig/phronomy/common.rbs +7 -0
  461. data/sig/phronomy/content_store/contracts.rbs +13 -0
  462. data/sig/phronomy/context.rbs +152 -0
  463. data/sig/phronomy/embeddings/async/async_client.rbs +9 -0
  464. data/sig/phronomy/embeddings/base.rbs +17 -0
  465. data/sig/phronomy/engine/concurrency/timer_bindings.rbs +22 -0
  466. data/sig/phronomy/engine/control_bindings.rbs +11 -0
  467. data/sig/phronomy/engine/control_protocols.rbs +23 -0
  468. data/sig/phronomy/engine/execution_binding.rbs +6 -0
  469. data/sig/phronomy/engine/execution_receiver.rbs +15 -0
  470. data/sig/phronomy/engine/observability.rbs +13 -0
  471. data/sig/phronomy/execution/async_operation.rbs +7 -0
  472. data/sig/phronomy/execution/blocking.rbs +5 -0
  473. data/sig/phronomy/execution/concurrency/cancellation_token.rbs +13 -0
  474. data/sig/phronomy/execution/concurrency/deadline.rbs +10 -0
  475. data/sig/phronomy/execution/concurrency/result_composition.rbs +7 -0
  476. data/sig/phronomy/execution/control_protocols.rbs +18 -0
  477. data/sig/phronomy/execution/errors.rbs +7 -0
  478. data/sig/phronomy/execution/execution.rbs +41 -0
  479. data/sig/phronomy/execution/execution_receiver.rbs +40 -0
  480. data/sig/phronomy/execution/execution_scope_state.rbs +9 -0
  481. data/sig/phronomy/execution/invocation_context.rbs +18 -0
  482. data/sig/phronomy/execution/invocation_controls.rbs +13 -0
  483. data/sig/phronomy/execution/task_result.rbs +29 -0
  484. data/sig/phronomy/extensions.rbs +0 -21
  485. data/sig/phronomy/handoff.rbs +12 -4
  486. data/sig/phronomy/llm_adapter/backends/ruby_llm.rbs +6 -0
  487. data/sig/phronomy/llm_adapter/base.rbs +14 -0
  488. data/sig/phronomy/llm_adapter/usage.rbs +14 -0
  489. data/sig/phronomy/llm_adapter/values.rbs +43 -0
  490. data/sig/phronomy/llm_context_window.rbs +10 -0
  491. data/sig/phronomy/multi_agent/reserved_child_admission.rbs +8 -0
  492. data/sig/phronomy/multi_agent/store.rbs +54 -0
  493. data/sig/phronomy/multi_agent.rbs +24 -3
  494. data/sig/phronomy/persistence/errors.rbs +18 -0
  495. data/sig/phronomy/persistence/migration.rbs +13 -0
  496. data/sig/phronomy/persistence/transaction.rbs +19 -0
  497. data/sig/phronomy/persistence.rbs +3 -185
  498. data/sig/phronomy/persistence_composition.rbs +19 -0
  499. data/sig/phronomy/runtime_composition/configuration.rbs +36 -0
  500. data/sig/phronomy/storage/async/async_client.rbs +8 -0
  501. data/sig/phronomy/storage/backends/in_memory.rbs +9 -0
  502. data/sig/phronomy/storage/contracts.rbs +160 -0
  503. data/sig/phronomy/tool.rbs +58 -5
  504. data/sig/phronomy/tracing/observation.rbs +7 -0
  505. data/sig/phronomy/vector_store/async/async_client.rbs +13 -0
  506. data/sig/phronomy/vector_store/base.rbs +23 -0
  507. data/sig/phronomy/workflow/execution/workflow_execution_environment.rbs +14 -0
  508. data/sig/phronomy/workflow/runtime_binding/workflow_terminal_policy.rbs +7 -0
  509. data/sig/phronomy/workflow/store.rbs +8 -0
  510. data/sig/phronomy/workflow.rbs +1 -1
  511. data/sig/phronomy.rbs +0 -49
  512. metadata +462 -130
  513. data/lib/phronomy/agent/agent_invocation_session_builder.rb +0 -584
  514. data/lib/phronomy/agent/concerns/before_llm_input.rb +0 -66
  515. data/lib/phronomy/agent/concerns/error_translation.rb +0 -45
  516. data/lib/phronomy/agent/concerns/filterable.rb +0 -184
  517. data/lib/phronomy/agent/context/capability/base.rb +0 -507
  518. data/lib/phronomy/agent/context/instruction/prompt_template.rb +0 -102
  519. data/lib/phronomy/agent/context_parts/validators/final_budget_validator.rb +0 -37
  520. data/lib/phronomy/agent/context_policies/default.rb +0 -142
  521. data/lib/phronomy/agent/execution_coordinator.rb +0 -3151
  522. data/lib/phronomy/agent/handoff_execution_coordinator.rb +0 -143
  523. data/lib/phronomy/agent/handoff_request.rb +0 -45
  524. data/lib/phronomy/agent/handoff_runner.rb +0 -178
  525. data/lib/phronomy/agent/phase_machine_builder.rb +0 -152
  526. data/lib/phronomy/agent/provider_call_outcome.rb +0 -106
  527. data/lib/phronomy/agent/recovery_support.rb +0 -504
  528. data/lib/phronomy/agent/selection/candidate.rb +0 -53
  529. data/lib/phronomy/agent/selection/constraint.rb +0 -49
  530. data/lib/phronomy/agent/token_budget_resolver.rb +0 -70
  531. data/lib/phronomy/agent/tool_call_intercepted.rb +0 -29
  532. data/lib/phronomy/agent/tool_invocation_session_builder.rb +0 -276
  533. data/lib/phronomy/configuration.rb +0 -59
  534. data/lib/phronomy/engine/concurrency/cancellation_scope.rb +0 -124
  535. data/lib/phronomy/engine/concurrency/operation_binding.rb +0 -43
  536. data/lib/phronomy/generator_verifier.rb +0 -369
  537. data/lib/phronomy/invalid_context_budget_configuration_error.rb +0 -8
  538. data/lib/phronomy/llm_adapter/ruby_llm.rb +0 -47
  539. data/lib/phronomy/metrics.rb +0 -26
  540. data/lib/phronomy/multi_agent/parallel_tool_chat.rb +0 -116
  541. data/lib/phronomy/persistence/durable_codec.rb +0 -706
  542. data/lib/phronomy/persistence/in_memory.rb +0 -690
  543. data/lib/phronomy/persistence/repository_facades.rb +0 -535
  544. data/lib/phronomy/persistence.rb +0 -276
  545. data/lib/phronomy/recovery.rb +0 -186
  546. data/lib/phronomy/ruby_llm_patches.rb +0 -24
  547. data/lib/phronomy/runnable.rb +0 -54
  548. data/lib/phronomy/token_usage.rb +0 -85
  549. data/lib/phronomy/vector_store/embeddings/base.rb +0 -44
  550. data/lib/phronomy/vector_store/embeddings/ruby_llm_embeddings.rb +0 -47
  551. data/lib/phronomy/workflow/phase_machine_builder.rb +0 -205
  552. data/lib/phronomy/workflow_recovery.rb +0 -123
  553. data/sig/phronomy/llm_adapter.rbs +0 -11
  554. data/sig/phronomy/runtime.rbs +0 -76
  555. /data/lib/phronomy/agent/{llm_operation_result.rb → execution/llm_operation_result.rb} +0 -0
  556. /data/lib/phronomy/{canonical_json.rb → common/canonical_json.rb} +0 -0
  557. /data/lib/phronomy/{event.rb → engine/event.rb} +0 -0
@@ -0,0 +1,73 @@
1
+ # r8 unit17: Domain settings consumption
2
+
3
+ This responsibility-only refactor is based on applied unit16, commit
4
+ `fb551e1a1a8334b2547ecad126dd9c152c1b0f8c` (tree
5
+ `1ddb3b0e3f4eb97c1738ad02f9035eeefa180c90`). It addresses B08.
6
+
7
+ ## Values and composition have different owners
8
+
9
+ Agent::Settings owns Agent option values and the existing stream callback error
10
+ policy validation. WorkflowSettings owns the Workflow progress limit and optional
11
+ state repository. They contain actual domain values, never the application
12
+ Configuration object. Their readers do not select a concrete adapter or backend.
13
+ Configuration remains the application-facing facade and composes these values;
14
+ its existing readers, writers, default values and zero-argument constructor remain.
15
+ The application composition boundary supplies the defaults and lazy providers.
16
+
17
+ The existing MultiAgent::Store receives a provider for the optional configured
18
+ store. It does not construct a fallback. Team still falls back to its fresh-store
19
+ factory; Orchestrator still permits no coordination store unless durable children
20
+ require one. Explicit stores and execution participants keep their priority.
21
+ A single store reader does not require a separate MultiAgent settings class.
22
+
23
+ Logger reads use the existing neutral RuntimeSettings. Agent authorization pool
24
+ size and queue capacity belong to the execution connection, which reads them
25
+ when submitting authorization work to the owning Runtime. Agent retains timeout
26
+ selection, approval evaluation, result interpretation, and operation supervision.
27
+ The private ExecutionEnvironment#submit_authorization operation separates those
28
+ resource choices from ToolInvocation. Generic Tool submission is unchanged.
29
+
30
+ ## Preserve read timing without notifications
31
+
32
+ Each existing read remains at its previous execution boundary. Providers are
33
+ bound without evaluating Configuration or starting Runtime resources. A read
34
+ resolves the current domain values; it does not subscribe, poll, cache, or push
35
+ changes. There is no observer, change event, background task, version counter,
36
+ refresh loop, or new in-flight reconfiguration guarantee.
37
+
38
+ The existing read positions and short-circuit rules remain significant:
39
+
40
+ - Agent class model fallback is read when model is requested. Explicit class
41
+ models keep precedence. Already-created Agent stores are not replaced.
42
+ - Hooks and LLM adapter operations are read at the existing input preparation,
43
+ identity check, and call sites. Hook order and validation remain Agent rules.
44
+ - Workflow limits are read when starting or resuming execution. An admitted
45
+ execution retains its limit; a changed global default does not update it.
46
+ - Explicit nil, per-invocation overrides, configured stores, and fresh fallback
47
+ stores retain their existing meanings. No new defaults are created on reads.
48
+ - Configuration copies duplicate the domain value containers while retaining
49
+ injected component identities, preserving nested scoped overrides and reset.
50
+
51
+ The new domain value types are internal, grouped by responsibility rather than
52
+ one class per setting. Public Configuration continues to offer the same settings;
53
+ applications do not need to inject every value manually. Its private instance
54
+ variables and internal containers are not an application extension API.
55
+
56
+ ## Verification and limits
57
+
58
+ Regression checks cover lazy boot and direct Configuration loading, nested scope
59
+ restoration after failure, reset, component identities, nil, class and invocation
60
+ overrides, hook read timing/order, Workflow admission-time limits, persistent
61
+ Agent stores, and the distinct Team/Orchestrator fallback behavior. Execution
62
+ connection tests verify authorization resource options and owning Runtime.
63
+ Existing failure-policy/logging tests configure values through public writers
64
+ instead of mocking the old composition getter. RBS records the new internal
65
+ boundaries without erasing domain operation types.
66
+
67
+ AST gates reject application Configuration references from Agent, Workflow, and
68
+ MultiAgent domain code, including literal reflective access. They also reject
69
+ pool sizing in domain code. These are targeted regression checks, not a proof of
70
+ all dynamic dependencies or a whole-framework completion claim.
71
+
72
+ B07 remains applied. F01 durable Workflow children and other feature work are
73
+ outside this change. There are no storage schema or public operation changes.
@@ -0,0 +1,92 @@
1
+ # R8 unit18: durable cancellation receipt
2
+
3
+ ## Problem
4
+
5
+ An Orchestrator load can return while recovery of a framework-owned child is still
6
+ in flight. If the child needs external factual resolution, Agent captures an
7
+ immutable terminal command that will retain the active parent in coordination
8
+ wait. A cancelled token supplied to `resume` after command capture previously
9
+ cancelled only the live invocation. The earlier command could then persist a
10
+ false cancellation snapshot and release the owner. Restart lost the request.
11
+
12
+ Controlled scheduling reproduced this in both unit16 and unit17, three times out
13
+ of three. The original example passed 200 natural repetitions. Without the
14
+ applicant's original failure log, equivalence to that initial failure is not
15
+ established. The controlled race is independently demonstrated.
16
+
17
+ ## Ownership
18
+
19
+ Agent owns receipt of cancellation for an exact execution, its existing durable
20
+ cancellation ledger, and persistence of the parent execution. MultiAgent still
21
+ owns the unresolved-child and pending-parent rules. Execution owns notification
22
+ registration and delivery; Engine owns runtime connections. No Agent decision is
23
+ moved into those mechanisms or into neutral Persistence/Storage.
24
+
25
+ `ExactExecution` validates identity, reservation, input and participant binding
26
+ before recording a supplied cancellation through `Store#request_cancellation`.
27
+ The write runs in its existing off-EventLoop preparation, before recovery or
28
+ waiting. If cancellation first becomes visible during EventLoop delivery,
29
+ preparation runs again before the live owner is signalled. Recording errors fail
30
+ the observer and do not proceed to recovery or notification.
31
+
32
+ `ExecutionChange#prepare_in` already reads the monotonic cancellation ledger
33
+ inside the participant transaction. `ExecutionOutcomeCommitter` now uses that
34
+ prepared fact for a pending execution's cancellation metadata. The worker's
35
+ captured command remains immutable; it does not query a live invocation or token.
36
+
37
+ ## Ordering and preserved semantics
38
+
39
+ - Before outcome commit: the transaction sees the accepted ledger entry and saves
40
+ cancellation in both Agent pending metadata and MultiAgent extension state.
41
+ - After outcome commit: the ledger retains newly accepted intent without changing
42
+ execution revision or invalidating the in-flight result. The previously saved
43
+ metadata/extension remain a snapshot; the next recovery/change incorporates the
44
+ ledger. Immediate equality between those snapshots and the ledger is not an API
45
+ guarantee. The ledger is the durable source of accepted cancellation intent.
46
+ - After owner release: receipt records intent before recovery installation.
47
+ - An absent execution is not assigned a cancellation record. A terminal result,
48
+ including one that wins against cancellation receipt, remains unchanged.
49
+ - Unknown child external outcomes still require factual resolution. No LLM replay,
50
+ forced child completion or new recovery capability is introduced.
51
+
52
+ There is no schema change, public API change, new Contract, Registry, subscription
53
+ or polling mechanism. This fixes receipt of cancellation observed by the existing
54
+ exact-execution path; it does not introduce continuous subscription to an incoming
55
+ token after observer registration.
56
+
57
+ ## Verification design
58
+
59
+ Queue gates hold the outcome worker before commit and after commit/before result
60
+ publication. Gates never block EventLoop or hold a storage transaction. Tests
61
+ assert ledger persistence, unchanged revision during receipt, pending snapshots,
62
+ restart preservation, unknown-child activity and zero LLM replay. Additional
63
+ component tests cover validation rejection, write failure, recovery ordering,
64
+ late token observation and terminal-result preservation. The pending commit test
65
+ also covers committed-response loss.
66
+
67
+ The original checkpoint fixture now performs phase inspection and snapshot copy
68
+ under one backend lock, preventing concurrent after-commit hooks from replacing a
69
+ selected checkpoint. Its initial assertion uses the durable ledger because a
70
+ request arriving after a saved waiting snapshot need not rewrite that snapshot.
71
+ Separate deterministic tests assert the snapshot on each side of the commit.
72
+
73
+ ## Unit18 delivery correction
74
+
75
+ The first unit18 version checked the incoming token twice inside delivery: once
76
+ to decide whether to record, and again to decide whether to signal. Cancellation
77
+ between those observations could skip recording but still signal the owner.
78
+ A suspended approval execution then exited without a completion reconciliation,
79
+ leaving the durable ledger empty.
80
+
81
+ Delivery now uses one cancellation observation for both decisions. After finding
82
+ and validating the current owner, an observed cancellation returns to off-loop
83
+ preparation if unrecorded, or signals the owner if already recorded. The separate
84
+ preparation and delivery observations remain intentional: scheduling between those
85
+ stages can change the token. A notification is never authorized by a different
86
+ observation from the one used to enforce its recording prerequisite.
87
+
88
+ Regression tests use the real suspended owner, registry and EventLoop. They
89
+ cancel the incoming token just before delivery or during the owner lookup, and
90
+ cover both successful recording and recording failure. They assert recording
91
+ before notification, no notification on write failure, off-loop persistence and
92
+ unchanged suspended execution contents. No polling or new subscription is added.
@@ -0,0 +1,61 @@
1
+ # R8 unit19: Engine resource lifetime
2
+
3
+ ## Confirmed failures
4
+
5
+ Overlapping first default-pool lookups could construct two pools and retain only
6
+ one. A pool lookup that passed Runtime's state check could also create a pool
7
+ after shutdown had captured its resource list. Both cases left live workers
8
+ outside the claimed completed cleanup.
9
+
10
+ OffloadPool previously returned after each worker join timeout without reporting
11
+ whether workers remained. Runtime interpreted the absence of an exception as
12
+ successful cleanup. A real blocked worker was still active after the default
13
+ 30-second join while Runtime reported terminated, clean and complete.
14
+
15
+ ## Ownership
16
+
17
+ PoolRegistry owns pool creation, registration and closure of that registration.
18
+ The same mutex protects default and named pool construction and the transition
19
+ to a closed registry. Runtime still admits resources during its draining phase
20
+ for previously accepted continuations. PoolRegistry rejects requests after the
21
+ shutdown resource set is captured, including lookups that passed an earlier
22
+ Runtime check.
23
+
24
+ OffloadPool owns worker admission and physical worker lifetime. begin_shutdown
25
+ closes admission without waiting and preserves queue draining. shutdown waits
26
+ using one monotonic deadline; its existing self return is preserved. terminated?
27
+ reports that admission is closed and every owned worker has actually exited.
28
+ TaskResult cancellation or timeout is not proof of physical worker termination.
29
+
30
+ PoolRegistry first closes all pools, then waits outside its registration lock.
31
+ Every pool uses the same absolute deadline. Cleanup continues for the remaining
32
+ pools after an individual error; the first error is propagated after those
33
+ attempts. Runtime still attempts timer cleanup in ensure.
34
+
35
+ Runtime owns the aggregate decision. Its existing stop-phase deadline is shared
36
+ by EventLoop and pool joins. Cleanup is incomplete while any worker remains;
37
+ domain finalization and default-Runtime replacement remain blocked. Runtime's
38
+ existing cached-result behavior is unchanged: an incomplete result is not later
39
+ promoted to complete by calling shutdown again.
40
+
41
+ ## Scope
42
+
43
+ This is an Engine lifecycle correctness fix, not only a file relocation. Pool
44
+ shutdown no longer silently reports completed resource cleanup when workers
45
+ remain. The pool waiting budget is shared instead of being restarted per worker
46
+ or per pool. No worker is forcibly interrupted, and queued accepted work still
47
+ drains. Applications retain responsibility for bounded synchronous operations
48
+ and native I/O timeouts.
49
+
50
+ Agent cancellation persistence, MultiAgent parent/child policy, Workflow
51
+ persistence decisions, C13 result/subscription contracts, settings providers and
52
+ durable formats are unchanged. No new domain Contract or notification mechanism
53
+ is introduced. E03 passive metrics collection remains a separate follow-up.
54
+
55
+ ## Verification
56
+
57
+ Queue-controlled tests reproduce overlapping first pool creation and lookups
58
+ delayed until after shutdown. Real worker gates verify bounded shutdown,
59
+ incomplete results, retained Runtime, withheld finalization and the difference
60
+ between logical cancellation and physical completion. Additional cases preserve
61
+ draining continuations and ensure all resources receive cleanup attempts.
@@ -0,0 +1,55 @@
1
+ # r8 unit 2:親の予約確認とAgent受付
2
+
3
+ この単位はP02/P03の受付境界を実装する。基準はcore `16e6fcb2dd49836735598525114abfc256d0773e`。r8全体やPersistenceの全面整理の完了ではない。
4
+
5
+ ## 責務と操作
6
+
7
+ | 担当 | 公開操作・共通規則 | 依存と内部実装 |
8
+ |---|---|---|
9
+ | 共通Persistence | `atomic`、`Transaction#participate`、`committed?`。同じPersistence、同期thread、有効scope、savepoint、commit応答を検証 | Storageの公開transaction・scope規則を利用。Agent/Team/Workflowや構成担当を選ばない |
10
+ | Agent | `Admission#accept_in`。入力記録・実行ID・Agentの受付とrevision更新を同一scopeへ保存 | Agentの保存担当を使用。親のkind・Team割当・subagent snapshot・Handoff予約を解釈しない |
11
+ | MultiAgent | `ReservedChildAdmission#admit`。親の取消・slot・子IDを検証し、Agent受付を同じscopeへ参加させる | 自分の保存担当が予約の根拠を読み、必要なguardを取得する |
12
+ | 保存担当 | `Agent::Persistence::Admission`、`MultiAgent::Persistence::Reservation` | raw Storage viewはこの境界で使用。ドメイン操作へraw viewを渡さない |
13
+
14
+ AgentのRuntime admission取得、FSM開始、live状態の反映は既存のExecutionCoordinatorが引き続き所有する。新しいAdmissionはその短い保存フェーズだけであり、Agent実行全体を親のDB transactionへ入れない。通常のアプリは新しい参加クラスを実装・生成する必要がない。
15
+
16
+ `phronomy_admission` は内部の現在の配線であり、Procやオブジェクトを保存しない。永続化するのは従来の相関情報と親子IDだけ。Team/subagent/Handoffの開始・再開担当が現在の参加者を渡す。保存済み実行への再接続はExactExecutionの同一ID照合と復旧規則を維持する。
17
+
18
+ ## 保存順序と失敗
19
+
20
+ 1. Agentが既存のRuntime受付を取得し、同期workerで保存操作を開始する。
21
+ 2. MultiAgentが短い`atomic` scopeを開き、親のguardを取得してから予約を読み直す。
22
+ 3. 親の取消・割当・子の識別子を検証する。Agentは同じscopeで入力内容・AgentExecution・AgentRootを保存する。
23
+ 4. commit応答が成功した後に、Agent実行担当だけが受付結果を取得し、準備・FSM・live反映を進める。
24
+
25
+ 参加操作の戻り値はcommit成功を意味しない。`accept_in`はnilを返し、Agent内部の`result`は外側のcommitまで利用できない。二重参加、別Persistence、別thread、終了後scopeは拒否する。同じbackendを包む別Persistenceも同一scopeと扱わない。raw backend transactionの中から新しくcommit所有者を名乗ることも拒否する。
26
+
27
+ 明示的な入れ子はsavepointとして動く。内側が成功しても外側がrollbackした場合は未成立。参加処理中の例外を内側で捕捉しても、失敗したscopeの先行変更をcommitできない。LLM、Tool、scheduler、外部callback、非同期待機を参加処理へ入れない。
28
+
29
+ Storageのscope違反は`Persistence::TransactionError`へcause・backtraceを保持して変換する。この名前の変更は、保存成否が既知であるとの宣言ではない。IOError等の成否不明な保存失敗は変換・自動retryせず、既存のAgent復旧規則へ渡す。今回、一般化した保存成否照合APIは追加していない。
30
+
31
+ ## 取消との競合
32
+
33
+ TeamはTeamRoot、subagentは親AgentRoot、Handoffはrouting recordをguardとする。PostgreSQLではそのguardの行ロックと既存の条件付き更新によって、取消・変更と子受付を順序付ける。子受付側の通常readだけでは、この保証は成立しなかった。
34
+
35
+ Handoff取消側は最初に子の状態を観測し、未完了/不在ならroutingをロックして**子の状態を再取得**する。待機中に子受付がcommitした場合、古い「不在」の判断を捨て、受付済みの子へ公開取消を送る。既に終端の実行への取消は従来どおり結果参照として扱う。
36
+
37
+ InMemoryは共有Monitor、SQLiteはtransactionと書込競合検出、PostgreSQLは行ロックを使用する。SQLiteで競合したtransactionは成功とみなさず、backendの失敗を扱う。分散leaseや外部副作用のexactly-onceは追加しない。実PostgreSQLでの待機順序はexamplesの新しい3件の並行テストで確認する対象であり、InMemory/SQLiteの成功から推定して済ませない。
38
+
39
+ ## API・ファイル変更
40
+
41
+ - Agent::InitialPreparationの`build_admitted_execution`と3種の親検証・kind分岐を削除。Agent自身の受付共通処理とMultiAgentの予約判断へ分離した。
42
+ - 共通の参加frameworkを`persistence/transaction.rb`、Agent受付を`agent/admission.rb`、保存接続を既存の各domainの`persistence/`へ置いた。新しいディレクトリや独立Contractは増やしていない。
43
+ - Storage SPIに同期contextの`transaction_open?`を追加。Storage::Backendの継承実装には共通実装が提供される。継承しない独自SPI実装はこの操作も提供する必要がある。RBS・SPI snapshot・duck-typed backendの検証を更新した。
44
+ - Persistenceの既知scope失敗の公開型を`Persistence::TransactionError`へ統一し、旧Storage例外のaliasは設けない。Storageを直接使う処理では従来のStorage例外を使用する。
45
+ - RBSはsigに配置し、参加者factory、Agent受付、MultiAgentの依存を宣言する。動的な`phronomy_admission`注入も本書と利用箇所で追跡する。
46
+ - 依存解析のExecution境界規則を図のrevision表示名から分離した。unit名の更新で同期backendからExecutionへの禁止規則が解除されないことを回帰テストする。
47
+ - 保存recordの形式、ID、revision規則は変更していない。データ移行は不要。
48
+
49
+ ## 残る課題
50
+
51
+ `Persistence#transaction`とdomain repositoryの一括窓口は現行利用箇所が残るため、この単位では全面削除していない。互換維持のために新しい旧名aliasを追加したものではないが、P01/DP04の完了条件は未達である。次にdomain照会・保存構成を移し、不要な窓口を利用側と同時に削除する。
52
+
53
+ MultiAgentの保存担当にはAgentのexecution/Handoff repositoryへの参照が残る。予約検証の所有者は整理したが、親子の公開投影・認可照会・結果取込まで隠蔽したとは扱わない。P04/F02/F03の残課題として、Agentが公開する操作と、MultiAgentが所有すべき保存形式を確定する。一般的なmetadata getterを足すだけの解決にはしない。
54
+
55
+ Agent/TeamのFSM接続、Workflowのdurableな子連携(P05)、複数記録の保存成否照合(P06)、残りの配置整理、155組・393件の意味的再判定も残る。今回のSVGは実装候補を描き、全体の循環解消を示す構想図にはしない。
@@ -0,0 +1,51 @@
1
+ # R8 unit20: Passive Engine observation
2
+
3
+ ## Problem
4
+
5
+ Metrics.snapshot previously called Runtime.instance, Runtime#offload and
6
+ Runtime#event_loop. A cold snapshot constructed the default Runtime, started
7
+ default-pool workers and started the EventLoop. Looking at an existing Runtime
8
+ could initialize its other resources. The same calls rejected observation after
9
+ shutdown, precisely when diagnostics were useful. Diagnostics.snapshot and dump
10
+ inherited these effects through Metrics.snapshot.
11
+
12
+ ## Responsibility
13
+
14
+ Runtime retains ownership of its singleton and resource references. PoolRegistry
15
+ retains ownership of its default pool. Both provide internal lookup operations
16
+ using their existing mutexes, without construction or admission checks. Runtime's
17
+ existing EventLoop lookup already provides the same behavior. These lookups can
18
+ observe retained resources after shutdown without reopening them.
19
+
20
+ Metrics samples the returned resources and formats the existing ten numeric
21
+ fields. It does not inspect instance variables, decide resource initialization,
22
+ read configuration as a substitute for measurements, or cache Runtime references.
23
+ The test-only singleton lookup delegates to the internal lookup; production code
24
+ does not call a test helper. RBS describes the optional resource references.
25
+
26
+ ## Behavior and scope
27
+
28
+ Missing resources contribute zero. An uninitialized default pool therefore has
29
+ size zero even if configuration would allocate ten workers on first use. For an
30
+ existing pool, size continues to describe configured capacity, including after
31
+ shutdown; it is not a count of living workers. Named pools remain outside these
32
+ default-pool metrics. A subsequent snapshot follows the current default Runtime,
33
+ so a reset neither recreates it nor keeps stale metrics in a cache.
34
+
35
+ Counters remain independent observations. Concurrent activity or Runtime reset
36
+ can occur during a snapshot; no globally atomic observation or lifecycle barrier
37
+ is promised. Resource references are obtained under their owners' existing locks
38
+ and metrics are read after those lookup locks are released. No new lock ordering,
39
+ polling thread, subscription, observer registry or notification mechanism is added.
40
+
41
+ Unit19 pool creation and shutdown rules, cancellation, domain finalization,
42
+ shutdown deadlines and cached shutdown results are unchanged. Contract/domain
43
+ code and dependencies are unchanged. All product-code changes stay in Engine.
44
+
45
+ ## Verification
46
+
47
+ A fresh-process test exercises all three observation entry points and checks that
48
+ no Runtime or thread is created. Tests cover partial initialization, named pools,
49
+ real active/queued/abandoned worker metrics, EventLoop backlog and lag, draining,
50
+ stopping, completed and incomplete shutdown, and default Runtime replacement.
51
+ Queue barriers control concurrent boundaries without relying on chance schedules.
@@ -0,0 +1,79 @@
1
+ # r8 unit21: Tool and Tracing settings ownership
2
+
3
+ This responsibility-only refactor is based on applied unit20, commit
4
+ `bda5da03da5a4da33041953cf0eebaa32de7bb81` (tree
5
+ `dc601f86825116b34ff294200815809ee9e0ea7a`). It addresses B10 from the
6
+ Contract review. It is not a new execution feature or a unit20 regression fix.
7
+
8
+ ## Ownership
9
+
10
+ | Owner | Responsibility |
11
+ | --- | --- |
12
+ | C06 Tool | Own the default result-length value and the existing truncation rules |
13
+ | C15 Tracing | Own tracer access, the recording option and the existing observation/redaction rules |
14
+ | C05 Context | Obtain its default tracer through C15 at Assembly construction; honor explicit injection |
15
+ | Application composition | Select values and concrete tracers, expose the existing Configuration facade, bind lazy accessors |
16
+ | Neutral RuntimeSettings | Retain logger and execution resource sizes/time thresholds |
17
+
18
+ Tool::Settings contains one optional max_result_size value. Tracing::Settings
19
+ contains tracer and trace_pii. These private value containers have no settings
20
+ hierarchy, backend selection, notification service or execution resources.
21
+ Composition supplies them through lazy providers, following the existing Agent
22
+ and Workflow pattern. No Contract receives the whole application Configuration.
23
+ No new logical Contract is introduced merely because values are shared.
24
+
25
+ The public tool_result_max_size, tracer and trace_pii accessors keep their names,
26
+ defaults, writers and return values. Application choices remain application
27
+ choices. Tool truncation and Tracing redaction already belonged to their domains;
28
+ their algorithms are unchanged. Logger access remains neutral and is not moved
29
+ simply because Tracing also uses it for diagnostic messages.
30
+
31
+ This amends ADR-060's earlier grouping of tracer and recording options with
32
+ neutral runtime settings. The static graph treated that container as common;
33
+ its lack of reverse references did not prove that every field belonged there.
34
+
35
+ ## Preserve lifecycle and read positions
36
+
37
+ - Binding providers does not evaluate global configuration or start Runtime.
38
+ - Tool reads its default at the existing result-processing site, after
39
+ synchronous execution or successful asynchronous completion. An explicit
40
+ class limit keeps priority and bypasses the default read. Nil and zero retain
41
+ their existing meanings. Result transformations retain their order and count.
42
+ - Automatic tracing reads settings at span start and retains the same tracer
43
+ and recording flag in its existing handle until finish. A configuration reset
44
+ during execution does not transfer an open span to a different tracer.
45
+ - Observation keeps its existing reads before entering the application block;
46
+ it does not adopt a new snapshot policy or re-read settings after the block.
47
+ - Context::Assembly keeps its constructor-time tracer. Explicit injection,
48
+ including explicit nil, does not resolve the default provider.
49
+ - Configuration copies duplicate the value containers and preserve injected
50
+ tracer/logger identities. Nested scopes, exception restoration and reset keep
51
+ the previous behavior. A read resolves the current container without caching.
52
+
53
+ There is no change notification, polling, version counter, cache, live resource
54
+ resizing or new thread-local configuration behavior. This does not add a
55
+ guarantee of atomic reconfiguration across several independent reads.
56
+
57
+ ## Regression boundaries
58
+
59
+ Public behavior tests run unchanged on unit20 and unit21. They cover late Tool
60
+ limits for sync/cooperative/offloaded/deferred operations, transformation order
61
+ and repetition, physical completion, reset, nested scopes and tracer identity.
62
+ Tracing checks cover both recording policies, redaction, errors and open spans;
63
+ Context checks cover constructor timing and explicit injection.
64
+
65
+ Separate ownership tests inject domain values without the application facade
66
+ or neutral settings. Isolated loading verifies provider laziness and prevents
67
+ loading a concrete backend or Runtime. RBS assigns the internal declarations to
68
+ their actual owners. AST gates extend the application-configuration prohibition
69
+ to Tool, Tracing and Context, reject domain fields in neutral RuntimeSettings,
70
+ and reject direct or literal-reflective reads through its old accessors.
71
+
72
+ These are targeted regression guards. They do not prove arbitrary dynamic Ruby
73
+ dependencies. Full suite, integration, existing privacy tests, examples offline
74
+ verification and Ruby/RBS architecture analysis remain package validation gates.
75
+ The complete source/tree and validation results are recorded in the package.
76
+
77
+ Unit19/20 Engine lifecycle and passive metrics behavior remain unchanged.
78
+ F01 durable Workflow children remain separate feature work. There is no stored
79
+ data migration, public operation change or source change to examples.
@@ -0,0 +1,74 @@
1
+ # r8 unit22: MCP connection lifecycle
2
+
3
+ This change is based on applied unit21, commit
4
+ `4525e71ca808acac9eb0302a59c32f00478a7782` (tree
5
+ `957baf18c23ce5659c11454f3a89e893c07b2138`). It corrects two concrete MCP
6
+ lifecycle defects and removes an unnecessary application-composition reference.
7
+ It is not a new Contract or an Execution/Engine refactor.
8
+
9
+ ## Ownership
10
+
11
+ | Owner | Responsibility |
12
+ | --- | --- |
13
+ | MCP Tool implementation | Translate SDK cancellation and results, own the client/transport, delimit one SDK call's notification lifetime |
14
+ | Existing Execution ResultSubscriptions | Register and remove explicit-cancellation callbacks |
15
+ | Existing Execution/Engine | Admit and execute cleanup work, reject submissions after shutdown, drain accepted work |
16
+ | Neutral RuntimeSettings | Supply the currently configured common logger |
17
+
18
+ The production change is confined to `lib/phronomy/tools/mcp.rb`. Execution,
19
+ Engine, Tool Contract, runtime composition, public signatures and storage
20
+ formats are unchanged.
21
+
22
+ ## Cancellation bridge lifetime
23
+
24
+ Previously each SDK call registered a callback directly on its supplied
25
+ CancellationToken and retained it until that token was cancelled or collected.
26
+ Completed and failed calls therefore accumulated callbacks when a caller reused
27
+ a token. A later cancellation also touched obsolete MCP cancellation handles.
28
+
29
+ Each call now owns an existing ResultSubscriptions collection, registers its
30
+ bridge with explicit_cancellation, and closes the collection in ensure. This
31
+ also covers SDK errors, malformed responses and cleanup failures. Other
32
+ subscribers on the same token are preserved.
33
+
34
+ The lifetime is the concrete SDK invocation, not its caller-facing TaskResult.
35
+ If OffloadPool settles a timeout while SDK work is still running, a subsequent
36
+ explicit cancellation must still reach that work. No timer, deadline promotion,
37
+ polling thread or TaskResult completion callback is introduced by the bridge.
38
+
39
+ ResultSubscriptions.close does not revoke a callback already taken by a
40
+ concurrent cancel!. Such a callback can finish after the SDK call returns. It
41
+ only captures that call's MCP cancellation handle, whose cancellation is
42
+ idempotent; it does not look up the next client or cancel a replacement call.
43
+ This preserves the existing Execution notification semantics.
44
+
45
+ ## Cleanup rejection at Runtime shutdown
46
+
47
+ After SDK cancellation the MCP instance detaches the old client before it can
48
+ be reused. Normally its transport is closed on the named Runtime cleanup pool.
49
+ Previously the synchronous fallback handled queue saturation and a stopped
50
+ pool, but not RuntimeShutdownError raised before pool acquisition. In that
51
+ case close was skipped and the shutdown error replaced the cancellation result.
52
+
53
+ MCP now applies its existing synchronous close fallback to RuntimeShutdownError
54
+ too. It does not reopen Runtime, create another worker, retry the Tool call or
55
+ relax Engine admission. Accepted cleanup remains owned and drained by Runtime.
56
+ MCP attempts to close a rejected transport and preserves the existing best-effort
57
+ close behavior if the SDK's close itself raises.
58
+
59
+ ## Logging and validation
60
+
61
+ MCP warning output reads RuntimeSettings.current.logger once per warning and
62
+ retains the existing stderr fallback. It no longer reaches the application
63
+ Configuration facade just to obtain this common value. Logger choice is still
64
+ made by application configuration; no new setting or provider is introduced.
65
+
66
+ Focused regressions cover repeated success, SDK/response failures, explicit and
67
+ already-delivered cancellation, timeout before physical completion, cancellation
68
+ racing completion, accepted cleanup, stopped Runtime, rejected submission,
69
+ failing close and both logger paths. Concurrency tests use barriers and an
70
+ injected monotonic clock rather than timing-dependent sleeps.
71
+
72
+ These are lifecycle corrections, not merely file moves. They require no data
73
+ migration or examples source change. Deferred features, including durable
74
+ Workflow children, remain outside this change.
@@ -0,0 +1,81 @@
1
+ # r8 unit23: concrete consumer composition
2
+
3
+ This change is based on applied unit22, commit
4
+ `17cf02eb1ec0ec534b3dd8e1e64c75e13c961cfc` (tree
5
+ `dc591b3d8dfb1edace4f98e68f5e505a6c457f58`). It normalizes two concrete
6
+ composition paths identified as NC02 and NC08 in the target diagrams.
7
+ These were responsibility improvements, not demonstrated runtime failures.
8
+
9
+ ## Agent Tool
10
+
11
+ The synchronous implementation previously called the application convenience
12
+ API `Agent.run_once`, which selected an ephemeral store through
13
+ `PersistenceComposition.agent`. Its asynchronous implementation already obtained
14
+ the same default through the boot-supplied `Agent::DefaultPersistence` factory.
15
+
16
+ Both paths now obtain a fresh store from that existing factory. The synchronous
17
+ path uses public Agent creation and invocation, preserving the explicit
18
+ `context: nil`, `knowledge: []`, and `on_event: nil` creation arguments that
19
+ `run_once` supplied. It forwards the same invocation options and converts the
20
+ output to a String as before. The asynchronous implementation is unchanged.
21
+
22
+ Each call still creates its own Agent and store, even when an application-level
23
+ Agent store is configured. No Agent or store is cached. Tool definitions and
24
+ instances do not acquire persistence. Cancellation propagation, asynchronous
25
+ config token priority, Tool validation, result transforms and recovery errors
26
+ retain their existing behavior.
27
+
28
+ `Agent.run_once` remains the public application convenience API. It continues to
29
+ own explicit composition; only the concrete Tool stops depending on that facade.
30
+ Calling a public composition API is not inherently invalid. Here the narrower
31
+ existing factory lets both Tool paths follow the same ownership boundary.
32
+
33
+ ## LlmJudge
34
+
35
+ The scorer owns prompt construction, the public LLM Request, score parsing and
36
+ clamping, and its warning/raise policy. It no longer selects the configured
37
+ adapter or constructs `LLMAdapter::AsyncClient` inside `score`.
38
+
39
+ `runtime_composition/evaluation_defaults.rb` supplies a single factory during
40
+ normal application loading. The factory selects the currently configured
41
+ adapter and constructs the client. Installation creates no Configuration,
42
+ client or Runtime. It uses a private, one-time binding in the existing scorer
43
+ class, not a new Contract, module registry or application extension API.
44
+
45
+ Each score invokes the factory after prompt and Request preparation, at the
46
+ same point as the previous client construction. The adapter is therefore read
47
+ again after configuration updates, reset and scoped restoration. Neither the
48
+ adapter nor the client is cached by the scorer. The factory does not move client
49
+ construction onto a worker; the existing AsyncClient still offloads the whole
50
+ backend operation. No polling, notification, retry or scheduling mechanism is
51
+ introduced.
52
+
53
+ The constructor signature is unchanged. Subclasses inherit the same default
54
+ binding. Client construction/admission/provider failures remain within the
55
+ existing `raise_on_error` policy. Normal and eager loading remain resource-free
56
+ and do not load RSpec. The scorer can also be tested with an explicitly bound
57
+ client and its public Request dependency without loading composition or Execution.
58
+
59
+ ## Boundaries and validation
60
+
61
+ | Owner | Responsibility |
62
+ | --- | --- |
63
+ | Concrete Agent Tool | Per-call Agent creation, invocation, cancellation forwarding and output conversion |
64
+ | Existing Agent default factory | Obtain a fresh store from the supplied boot binding |
65
+ | LlmJudge | Prompt, Request, score interpretation and scoring failure policy |
66
+ | Runtime composition | Select the configured LLM adapter and build its AsyncClient |
67
+ | Existing Execution and Engine | Submission, result completion, waiting and resource ownership |
68
+
69
+ Production changes are limited to the two consumers, the new composition file
70
+ and its explicit loader wiring. Contract source, Engine, Execution, persistence
71
+ formats, RBS and public API snapshots are unchanged. Examples need no source
72
+ change. The target diagrams remain at the applied unit22 baseline until this
73
+ candidate is applied; their two concrete composition items are addressed here.
74
+
75
+ Focused tests cover fresh construction and forwarding, default binding isolation,
76
+ score-time configuration changes, scoped restoration/reset, request/client order,
77
+ worker execution, failure behavior, inheritance and resource-free boot.
78
+ The targeted AST gate prevents either consumer from reintroducing these
79
+ composition dependencies; application composition itself remains permitted to
80
+ construct the client and public convenience API. Static graphs do not certify
81
+ all dynamically injected implementations or external providers.