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,104 @@
1
+ # Workflow terminal ownership: design and validation
2
+
3
+ Implementation baseline: core `01cd2f57549f6d1e60825254f4520d0f123e651c`
4
+ (Refactor 32 applied) and examples `2f8b467f1268dd21de4c02b1c90c8bdd211d1feb`,
5
+ 2026-09-23. W2a and W2b are applied and verified; W2b is core
6
+ `fcd434c45ad98e5c93953cbce1ffef3c12246894` (Refactor 33). The adopted private contract is
7
+ [ADR-056](../decisions/056-workflow-terminal-policy-ownership.md).
8
+
9
+ ## Role and consumers
10
+
11
+ FSMSession drives one live state machine on EventLoop. WorkflowRunner assembles
12
+ Workflow transitions, stream observation and any durable terminal save.
13
+ InvocationActions and EngineSessionBuilder uses the same engine for input, LLM and Tool
14
+ progression; ToolInvocationSessionBuilder uses it for authorization, approval
15
+ and Tool execution. Therefore the session stays in Engine.
16
+
17
+ The former leak was narrower: Engine recognized the Workflow persistence event
18
+ and interpreted its save outcomes. WorkflowTerminalPolicy now owns that rule.
19
+
20
+ ## Ownership and concrete boundary
21
+
22
+ | Owner | Responsibility |
23
+ |---|---|
24
+ | FSMSession | Identity/sink, transitions, live context, pending terminal kind/notification flag, event acceptance and final notification/event ordering. |
25
+ | WorkflowTerminalPolicy | Start the injected save callback; recognize the Workflow result event; map its outcome to a generic terminal decision. |
26
+ | Phronomy::TerminalDecision | Immutable `action` and `error` value shared by a domain policy and the session. No live session authority. |
27
+ | WorkflowRunner | Construct a policy for durable execution; retain snapshot capture, one save, F1 readback and caller completion. |
28
+ | WorkflowExecutionRegistry | Admission, owner tokens, session routing binding and recovery-required ownership. |
29
+ | EventLoop | Event routing, management events, retirement, source completion and shutdown. |
30
+
31
+ Runner builds a policy only when both repository and persist are enabled.
32
+ Agent, Tool and ephemeral Workflow need no dummy policy or delayed completion.
33
+ The policy retains only its persistence callback, with no lifecycle flags.
34
+
35
+ The three private operations are `start(terminal_type:, context:, event_sink:)`,
36
+ `handles?(event)` and `decision_for(event)`. Start does not return completion
37
+ permission. The decision value maps Workflow success to `complete`, known
38
+ failure to `fail`, and unresolved uncertainty to `retire`. Failure preserves the
39
+ original exception or the existing missing-error fallback. Invalid outcomes
40
+ remain errors. Engine no longer branches on Workflow's event or outcome values.
41
+
42
+ FSMSession alone tracks `running`, `awaiting_terminal`, and its final lifecycle
43
+ state. Matching early events are discarded before invoking decision_for;
44
+ ordinary events cannot advance while awaiting; events after done are ignored.
45
+ The retirement action reuses the existing recovery-required management route.
46
+
47
+ ## Preserved durable ordering
48
+
49
+ 1. Session reaches a logical wait/completion boundary and captures metadata.
50
+ 2. Session marks itself awaiting a decision before invoking the policy.
51
+ 3. Runner marks admission persisting_terminal and captures an immutable command.
52
+ 4. Offload saves once and reconciles an uncertain result when possible.
53
+ 5. The bound EventSink returns the result to that session on EventLoop.
54
+ 6. The policy interprets the result only while the session accepts it.
55
+ 7. A complete decision permits the deferred observer, then the terminal event.
56
+ 8. EventLoop retires the session; Runner releases admission before settling the caller.
57
+
58
+ An observer exception still uses Refactor 32's ordinary error path, with the
59
+ already confirmed snapshot retained. No observer retry or extra save is added.
60
+
61
+ Unresolved uncertainty instead retires the session and retains recovery-required
62
+ admission without falsely settling the caller. Normal shutdown clears that
63
+ ownership and ends the dispatcher, while the caller remains pending; unexpected
64
+ dispatcher failure retains its separate existing waiter-cleanup behavior. This
65
+ change does not promise that normal shutdown resolves an unknown commit.
66
+
67
+ ## Alternatives and compatibility
68
+
69
+ Moving the full session would introduce Workflow dependencies into Agent/Tool.
70
+ Renaming event strings in Engine would leave semantic ownership unchanged.
71
+ Subclass/prepend overrides would recreate the hidden execution path removed by
72
+ W1. Saving after retirement or settling on a worker would break the barrier.
73
+ The injected policy keeps each rule at its existing execution authority.
74
+
75
+ The internal constructor changes from terminal_barrier to terminal_policy;
76
+ there is no compatibility alias or new public plugin API. Without a policy,
77
+ Engine does not reserve a Workflow-specific event name. Production Workflow
78
+ emits the result event only when it has injected its durable policy.
79
+ Public signatures, Workflow command/result identities, data records and Storage
80
+ SPI stay unchanged. One policy class and one decision value type are added;
81
+ this is responsibility separation, not a total-line-count reduction.
82
+
83
+ ## Acceptance evidence
84
+
85
+ | Scenario | Test boundary |
86
+ |---|---|
87
+ | Immediate completion/halt and Agent/Tool | Existing Workflow/Agent/Tool suites and generic no-policy completion. |
88
+ | Delayed save and halted stream | Real Runtime admission tests prove no early result/notification. |
89
+ | Portable failures and F1 post/pre/conflict/unreadable | Existing save tests plus real Runtime pre-state and uncertainty tests. |
90
+ | Unknown result and normal shutdown | Admission retained until shutdown, session unbound, caller remains pending. |
91
+ | Early/ordinary/duplicate decisions | Non-Workflow policy/session contract and Workflow policy wiring tests. |
92
+ | Late sink and new incarnation | Real Runtime rejects an old sink for the same logical Workflow ID. |
93
+ | Terminal observer failure | Refactor 32's four public stream regressions. |
94
+ | Submission rejection and delivery rejection | Existing error path releases admission; rejected delivery logs without retry. |
95
+ | Invalid outcomes and missing error | Workflow policy through the real Runner/session assembly. |
96
+ | Load, types, API, gem and source boundary | Full validation and private ownership regression assertions. |
97
+
98
+ The pre-state, uncertainty/shutdown, stale-sink and rejected-delivery scenarios
99
+ also pass on the Refactor 32 baseline; they characterize preserved behavior.
100
+ New protocol tests establish the extracted ownership contract. Refactor 33
101
+ application verification completed W2b. Storage S1/S2 followed and passed on
102
+ Refactor 35; see the [closure review](refactoring-closure.md) for S3 and the
103
+ current applied/candidate boundary. The earlier Refactor 32 baseline remains
104
+ historical evidence for preserved behavior.
data/docs/architecture.md CHANGED
@@ -23,6 +23,13 @@ reviewed explicitly rather than resolved by recency.
23
23
 
24
24
  ## Design principles
25
25
 
26
+ The current r8 refinement of Agent parent/Tool child progress and concrete
27
+ execution connections is described in [unit 8](architecture/r8-unit8.md), building
28
+ on [unit 7](architecture/r8-unit7.md). C04 owns Agent progress and approval/recovery;
29
+ C06 owns Tool operations; C13 supplies execution submission/completion. Concrete
30
+ FSM construction stays in Agent runtime_binding. These scoped changes do not
31
+ declare the full contract target or remaining dependency cycles complete.
32
+
26
33
  These are design heuristics for new and revised architecture. They do not
27
34
  override an Accepted ADR, an established public/extension contract, or an
28
35
  explicit compatibility decision.
@@ -41,10 +48,222 @@ explicit compatibility decision.
41
48
  dependency minimization must not weaken accepted durability,
42
49
  ownership, security-boundary, or extension contracts.
43
50
 
51
+ ## Responsibility groups and dependency graphs
52
+
53
+ Dependency views describe a directed graph of responsibility groups, not a
54
+ tree or a single pipeline. Several distinct groups may share one horizontal
55
+ band. A band's height expresses a proposed abstraction level; it does not imply
56
+ that its groups are independent or that every valid dependency points down.
57
+
58
+ Assess each dependency by the referenced contract and its owner. Shared value
59
+ types, extension contracts, and collaboration within a component can justify
60
+ dependencies between groups. A directory containing both shared definitions and
61
+ concrete orchestration must be examined by responsibility before assigning it a
62
+ single position. Cycles and upward arrows are review evidence, not defect counts.
63
+
64
+ The FSM terminal marker illustrates this distinction. `FSMProtocol::FINISH`
65
+ owns the internal `:__end__` marker used by the session and Workflow compilers.
66
+ The public Workflow DSL continues to use `:__finish__`. The execution session
67
+ and phase compiler do not depend on `WorkflowRunner` for this shared vocabulary;
68
+ the Workflow builder still legitimately creates its runner.
69
+
70
+ Context Policy and hook contracts provide another example. The shared values,
71
+ Manifest representation, and Plan validation live in `agent/context_contract/`,
72
+ separately from concrete policies and Agent execution. Zeitwerk collapses that
73
+ directory to preserve the existing `Phronomy::Agent` constants. A Policy's
74
+ dependency on those contracts does not make it depend on Agent execution. See
75
+ [ADR-036](decisions/036-context-contract-ownership.md).
76
+
77
+ ### Common definitions
78
+
79
+ `common/` owns general definitions shared across the framework that do not
80
+ belong to a particular feature. They must not depend on concrete Agent,
81
+ Workflow, Runtime, or other feature implementations. Being used in several
82
+ places, or inheriting a common base class, does not by itself make a definition
83
+ common; feature-owned contracts remain with their owners.
84
+
85
+ This group contains `Phronomy::Error`, `Phronomy::ConfigurationError`,
86
+ `Phronomy::CanonicalJSON`, and `Phronomy::Values::Immutable`. Zeitwerk collapses
87
+ `common/`, preserving these canonical names without introducing a
88
+ `Phronomy::Common` namespace. Other exceptions belong to their feature
89
+ contracts. `configuration/` owns settings and scalar defaults. The concrete
90
+ adapter and tracer defaults are selected in `runtime_composition/`, which binds
91
+ fresh-instance factories consumed by `Configuration.new`. This keeps concrete
92
+ feature selection outside settings while preserving application behavior.
93
+ Application Runtime reset and configuration replacement are also coordinated in
94
+ `runtime_composition/`, separately from configuration access and Engine mechanics.
95
+ See [ADR-039](decisions/039-runtime-configuration-lifecycle-ownership.md) and
96
+ [ADR-040](decisions/040-configuration-default-composition.md).
97
+ See [ADR-037](decisions/037-common-definition-ownership.md) and
98
+ [ADR-038](decisions/038-responsibility-based-source-layout.md).
99
+
100
+ ### Source placement and loading
101
+
102
+ `lib/phronomy.rb` is the application loading entry point. Internal production
103
+ files must not require it. Feature implementations and contracts live in their
104
+ responsibility directories; the direct root contains only `version.rb` and the
105
+ small namespace/loading files enumerated in ADR-038.
106
+ The separately documented external backend-test entry
107
+ `phronomy/testing/persistence_contract` retains its existing opt-in loading
108
+ contract and is excluded from production automatic loading.
109
+
110
+ Engine owns Event, Execution composition and its outcome exceptions, and the
111
+ synchronous FSM callback exceptions. Recovery owns shared rehydration
112
+ requirements. Workflow implementation lives under `workflow/execution/`;
113
+ Agent namespace/event loading lives under `agent/api/`, separately from the shared
114
+ Agent lifecycle exceptions in `agent/lifecycle_contract/`. LLM values and
115
+ call-boundary exceptions live under `llm_adapter/`, together with the SDK-neutral
116
+ operation contract. See [r8 unit 6](architecture/r8-unit6.md).
117
+
118
+ Agent consumes its private fresh-Persistence factory only when neither an
119
+ explicit instance nor a configured instance is available. Concrete selection
120
+ and binding live in `runtime_composition/agent_defaults.rb`. The one-shot
121
+ `Agent.run_once` method is defined in `agent/composition/run_once.rb`, because it
122
+ explicitly composes Agent and fresh ephemeral Persistence on every call.
123
+ The application entry loads both composition files; Agent execution and
124
+ namespace loading do not delegate upward to them. See
125
+ [ADR-044](decisions/044-agent-default-and-one-shot-composition.md).
126
+
127
+ Types excluded from authorization worker inputs declare the internal,
128
+ methodless `Concurrency::WorkerInputRestricted` contract at their own
129
+ definitions. ToolInvocation checks that execution-boundary contract rather
130
+ than concrete Workflow types. The original restriction set and opaque
131
+ application-value behavior are preserved; see
132
+ [ADR-045](decisions/045-worker-input-restriction-ownership.md).
133
+
134
+ Agent implementation files are grouped into lifecycle, execution, Tool execution,
135
+ context assembly, journal, Handoff and recovery directories. These directories
136
+ are collapsed, so existing Agent constant names remain unchanged. Journal encoding,
137
+ saved context reads and live invocation restoration have separate internal owners;
138
+ transaction and EventLoop state decisions remain with their callers. See
139
+ [ADR-046](decisions/046-agent-responsibility-layout-and-shared-records.md).
140
+
141
+ Recovery hands semantic continuation commands to the execution owner through
142
+ its EventLoop delivery boundary. The owner checks current identity, revision
143
+ and session state before applying them. `Agent::ExecutionSessionRunner` shares
144
+ ordinary and recovered Agent/Tool session registration and reports completion
145
+ back to the same coordinator; operation workers now own terminal persistence
146
+ under its EventLoop result authority (ADR-051 below).
147
+ See [ADR-047](decisions/047-recovered-execution-continuation-contract.md).
148
+
149
+ InvocationRestorer decodes saved Tool snapshots, resolves the Tool Call and Tool,
150
+ and matches approval evidence. The newly constructed ToolInvocation applies its
151
+ own saved state through the internal `restore_state!` operation; Recovery no
152
+ longer writes its instance variables. State application neither evaluates approval
153
+ nor dispatches Tool execution. Existing recovery installation notifications and
154
+ continuation rules are unchanged. See
155
+ [ADR-052](decisions/052-tool-invocation-restoration-ownership.md).
156
+
157
+ `Agent::DispatchPreparation` owns Provider/Tool dispatch prerequisites and their
158
+ operation-specific readback. ExecutionCoordinator captures and submits inputs,
159
+ then validates/applies results on EventLoop before dispatch. The worker's Provider
160
+ entry separates record encoding, application ContextPolicy, prerequisite commit
161
+ and post-commit materialization without changing transaction/rescue boundaries.
162
+ Its input/result types are worker-owned; existing Coordinator constant paths are
163
+ internal aliases, with changed canonical Ruby names. See
164
+ [ADR-048](decisions/048-dispatch-preparation-worker-ownership.md).
165
+
166
+ `Agent::InitialPreparation` owns initial durable admission, Context preparation,
167
+ preparation failure persistence and replay from saved preparing inputs. Ordinary
168
+ start and recovery share the admitted-preparation steps; Runtime admission,
169
+ result validation, live-state apply and session delivery remain on EventLoop.
170
+ The known failure base advances only after a successful commit response.
171
+ `Agent::ExecutionFailure` shares the existing pure failure classification with
172
+ terminal persistence; it does not own transactions or delivery. See
173
+ [ADR-049](decisions/049-initial-preparation-worker-ownership.md).
174
+
175
+ `Agent::ApprovalResumeCommit` persists approval decisions with operation-owned
176
+ Tool recovery snapshots. Coordinator validates the suspended owner and approval
177
+ request before copying canonical snapshot values into the immutable Command;
178
+ there is no shared snapshot lookup. The worker validates the target, stages
179
+ recovery facts and commits decision/Execution/Root together. EventLoop retains
180
+ admission, stale-result checks, live-state application and session resumption.
181
+ An uncertain commit still requires recovery; it is not retried or treated as a
182
+ confirmed resume. Internal Coordinator type aliases remain, with changed
183
+ canonical names and an added Command snapshot field. See
184
+ [ADR-050](decisions/050-approval-resume-snapshot-and-commit-ownership.md).
185
+
186
+ `Agent::ExecutionOutcomeCommitter` and `Agent::ExecutionChange` own Agent
187
+ completion, failure, suspension, dispatch preparation and commit proof. A limited
188
+ participant joins its own domain changes to the same scope. MultiAgent owns
189
+ subagent reservations and Handoff routing; it passes extension state and transfer
190
+ receipts, never Agent records or arbitrary update blocks. The EventLoop owner
191
+ continues to apply confirmed results and deliver callbacks. See
192
+ [r8 unit 4](architecture/r8-unit4.md).
193
+
194
+ The remaining execution owner expresses result handling as validation, committed
195
+ state installation, and continuation or delivery. Private methods keep these
196
+ steps in Coordinator; they introduce neither another owner nor shared per-operation
197
+ fields. The operation-specific authority checks and outer rescue boundaries stay
198
+ at the result entry points. Start/resume admission and submission flags stay in
199
+ the same methods as their cleanup decisions.
200
+
201
+ | Owner entry | Purpose-level steps |
202
+ | --- | --- |
203
+ | Initial preparation recovery result | Validate preparing owner; restart the prepared session or settle its saved failure; complete the load observer |
204
+ | Approval resume result | Validate suspended revision; install committed state and waiter; observe the task; resume the FSM |
205
+ | Terminal result | Validate revision/session; handle commit uncertainty; apply state and acknowledge the snapshot; deliver the selected outcome |
206
+
207
+ Terminal delivery releases ownership before notifying completed/failed/Handoff
208
+ observers, then settles Tasks. Suspension keeps ordinary Tasks pending. Ordinary
209
+ commit uncertainty keeps recovery admission and pending waiters; coordination
210
+ errors retain their separate release-and-fail behavior. Session registration
211
+ failure during preparation recovery still terminalizes without a live session;
212
+ trace/resume failure still uses the newly installed execution revision.
213
+ This is an internal readability refinement of ADR-024/047/051, not a change to
214
+ persistence, recovery guarantees or public interfaces.
215
+
216
+ Selected nested Zeitwerk roots retain existing top-level Phronomy constants
217
+ without changing the enclosing feature's existing nested constants. For
218
+ example, `Phronomy::WorkflowContext` and `Phronomy::WorkflowRunner` coexist with
219
+ `Phronomy::Workflow::Persistence`. Workflow remains a class and its source
220
+ file lives beside its implementation. These moves do not introduce aliases or
221
+ a new public API for requiring arbitrary internal paths.
222
+
223
+ WorkflowRunner directly owns terminal save submission and F1 snapshot readback.
224
+ The former WorkflowRecovery prepend and shadowed save implementation are removed;
225
+ the active path is independent of an installation hook. Private methods separate
226
+ submission, save/reconciliation and result delivery. FSMSession still interprets
227
+ the terminal persistence event; that ownership is a separate next step. See
228
+ [ADR-054](decisions/054-workflow-terminal-save-single-owner.md) and the
229
+ [remaining refactoring plan](architecture/remaining-refactoring-plan.md).
230
+ The Agent entry explicitly preserves Agent lifecycle extension installation.
231
+ Configuration accessors now live beside Configuration, rather than inside the
232
+ loader. Configuration constructs fresh components through internally bound
233
+ factories; composition selects their concrete types. Static source-reference
234
+ graphs do not follow these injected calls. LLMAdapter's private AsyncClient now
235
+ owns the Runtime dependency; its synchronous Base and RubyLLM implementation
236
+ are independent of Engine. VectorStore/Embeddings migration and other cycles
237
+ remain. See [Backend responsibilities](architecture/backend-groups.md).
238
+
239
+ Agent and Team implement their identity registries in `agent/` and
240
+ `multi_agent/`. Runtime strongly retains one of each when registered, using only
241
+ its generic shutdown participant contract. Feature code reserves identities,
242
+ handles feature exceptions, and detaches owners after completed cleanup.
243
+ See [ADR-041](decisions/041-feature-owned-identity-registries.md).
244
+
245
+ Agent and Workflow also own their distinct execution registries. EventLoop
246
+ retains them through Engine's internal `ExecutionReceiver` contract, dispatches
247
+ queued messages and combines generic session/delivery counts with their idle
248
+ predicates. Normal mutation remains on the EventLoop thread; only final
249
+ invalidation after join runs on the management thread. EventLoop has no Agent
250
+ or Workflow dispatch branch. See
251
+ [ADR-042](decisions/042-feature-owned-execution-state.md).
252
+
253
+ `MultiAgent::SharedState` owns sequential peer coordination through a findings
254
+ store created for each invocation. It equips member Agents with shared-store
255
+ Tools, runs complete cycles, checks stopping conditions and aggregates findings.
256
+ It is not an individual Agent's durable state or execution coordinator. Its
257
+ Experimental public namespace moves from Agent to MultiAgent without an alias;
258
+ generated semantic definition IDs retain their previous values. See
259
+ [ADR-053](decisions/053-shared-state-coordination-ownership.md) and the
260
+ [migration guide](migrations/shared-state-multi-agent.md).
261
+
44
262
  ## Current architecture
45
263
 
46
264
  | Area | Current document |
47
265
  |---|---|
266
+ | Backend Contracts, Implementations, Async Clients and dependency diagrams | [Backend responsibilities](architecture/backend-groups.md) |
48
267
  | Agent state, identity, ownership, and Context authority | [Agent Context](architecture/agent-context.md) |
49
268
  | Per-LLM-call Context Policy and Manifest construction | [Context Management](architecture/context-management.md) |
50
269
  | Journal-backed Knowledge and retrieval integration | [Knowledge and RAG](architecture/knowledge-and-rag.md) |
@@ -87,3 +306,6 @@ Durable multi-agent coordination is described by [ADR-029](decisions/029-semanti
87
306
  TeamExecution is a purpose-specific CAS authority delegating coordinator/workers
88
307
  to ordinary Agents, with no Team FSMSession or second Workflow engine.
89
308
  Static subagent reservation lives in the existing parent AgentExecution metadata.
309
+
310
+ Current C10/C11 common operation ownership and independent Embeddings/Documents
311
+ placement are specified in [r8 unit 5](architecture/r8-unit5.md).
@@ -278,3 +278,14 @@ ambiguous.
278
278
 
279
279
  Rejected. Cleanup from an invocation that failed to acquire admission could then
280
280
  release the real owner's reservation. Release is owner-aware by construction.
281
+
282
+ ## Storage composition refinement (2026-09-17)
283
+
284
+ [ADR-032](032-storage-backend-composition.md) refines the public storage boundary:
285
+ `Persistence` is the domain-facing composed service and `Storage::Backend` is
286
+ the raw storage extension contract. Backend inheritance from `Persistence`, the
287
+ old raw-repository constructor, and `build_transaction_view` are replaced.
288
+ Storage record/error constants move to `Storage`. The single atomic transaction
289
+ domain, durable-state/live-owner split, and failure guarantees in this decision
290
+ remain in force. Earlier API spellings in this decision are historical for this
291
+ amended scope; use the current Backend contract and migration guide.
@@ -9,7 +9,7 @@ Accepted.
9
9
  Phronomy has accumulated two related API-maintenance problems:
10
10
 
11
11
  1. Application-defined Tools are implemented by subclassing the internal-taxonomy
12
- name `Phronomy::Agent::Context::Capability::Base`, even though the product
12
+ name `Phronomy::Tool::Base`, even though the product
13
13
  concept exposed to users is simply a Tool.
14
14
  2. The gem ships almost no RBS signatures, so the distinction between
15
15
  application APIs, extension SPIs, and private implementation objects is not
@@ -42,7 +42,7 @@ Phronomy::Tool::Base
42
42
  The existing implementation class remains:
43
43
 
44
44
  ```ruby
45
- Phronomy::Agent::Context::Capability::Base
45
+ Phronomy::Tool::Base
46
46
  ```
47
47
 
48
48
  `Phronomy::Tool::Base` is an exact constant alias to that same class object. It
@@ -58,7 +58,7 @@ This preserves:
58
58
  name.
59
59
 
60
60
  Consequently, `Phronomy::Tool::Base.name` intentionally remains
61
- `"Phronomy::Agent::Context::Capability::Base"`. If a future public contract
61
+ `"Phronomy::Tool::Base"`. If a future public contract
62
62
  requires the runtime class name itself to become `Phronomy::Tool::Base`, that is
63
63
  a separate migration decision.
64
64
 
@@ -1,6 +1,10 @@
1
1
  # ADR-024: EventLoop Single-Writer Agent Runtime State
2
2
 
3
- **Status**: Accepted
3
+ **Status**: Amended
4
+ **Implementation ownership amendment**: [042-feature-owned-execution-state](042-feature-owned-execution-state.md) moves feature execution state and decisions to Agent/Workflow receivers; the EventLoop thread remains the single writer. Its registration, delivery and drain rules refine the original descriptions below.
5
+
6
+ **Worker input classification amendment**: [045-worker-input-restriction-ownership](045-worker-input-restriction-ownership.md) replaces the concrete rejection list with an execution-boundary marker declared by each owning type. The existing value/behavior restrictions and application-owned opaque-value contract remain unchanged.
7
+
4
8
  **Date**: 2026-08-24
5
9
  **Partially supersedes**: [ADR-014](014-unified-persistence-durable-state.md) for live Agent Runtime ownership and `AgentExecutionActivation`
6
10
  **Complements**: [ADR-010](010-cooperative-first-concurrency.md), [ADR-012](012-canonical-execution-log-and-context-policy.md), [ADR-018](018-durability-guarantees-and-failure-model.md), [ADR-022](022-agent-execution-parent-identity-and-runtime-routing-boundary.md), [ADR-023](023-fsm-session-incarnation-identity-and-routing.md)
@@ -1,7 +1,10 @@
1
1
  # ADR-025: Process-Local Agent Ownership and Runtime Admission
2
2
 
3
- **Status**: Accepted
3
+ **Status**: Amended
4
+ **Implementation ownership amendment**: [042-feature-owned-execution-state](042-feature-owned-execution-state.md) moves feature execution state and decisions to Agent/Workflow receivers; the EventLoop thread remains the single writer. Its registration, delivery and drain rules refine the original descriptions below.
5
+
4
6
  **Date**: 2026-08-24
7
+ **Amended by**: [041-feature-owned-identity-registries](041-feature-owned-identity-registries.md) for registry implementation ownership and its generic Runtime shutdown contract
5
8
  **Partially supersedes**: [ADR-014](014-unified-persistence-durable-state.md) for same-process Agent live-instance ownership and top-level execution admission
6
9
  **Complements**: [ADR-018](018-durability-guarantees-and-failure-model.md), [ADR-022](022-agent-execution-parent-identity-and-runtime-routing-boundary.md), [ADR-023](023-fsm-session-incarnation-identity-and-routing.md), [ADR-024](024-event-loop-single-writer-agent-runtime.md)
7
10
 
@@ -43,8 +46,8 @@ live ownership service.
43
46
 
44
47
  ### One `agent_id` has one mutable live Agent owner per Runtime
45
48
 
46
- A Runtime owns a purpose-specific Agent ownership registry keyed only by
47
- `agent_id`:
49
+ Agent owns the purpose-specific registry implementation, keyed only by
50
+ `agent_id`; Runtime strongly retains one registered instance for its lifetime:
48
51
 
49
52
  ```text
50
53
  agent_id
@@ -63,6 +66,13 @@ The registry is separate from EventLoop's `execution_id -> AgentExecutionState`
63
66
  directory. Agent lifetime and Execution lifetime are different semantic
64
67
  lifetimes and must not be represented by one registry.
65
68
 
69
+ The original implementation placed this registry under Runtime. ADR-041 moves
70
+ it to `Agent::OwnershipRegistry` and removes the feature-specific Runtime
71
+ forwarding methods. Runtime uses only the generic shutdown participant contract
72
+ to close, wait for, and finally detach registered owners. The invariant and
73
+ Runtime-scoped lifetime are unchanged; EventLoop admission is not moved by that
74
+ amendment.
75
+
66
76
  ### Public Agent construction/resolution semantics
67
77
 
68
78
  The public operations have distinct meanings:
@@ -1,6 +1,10 @@
1
1
  # ADR-026: Workflow Runtime Admission and Durable Terminal Barrier
2
2
 
3
- **Status**: Accepted
3
+ **Status**: Amended
4
+ **Implementation ownership amendment**: [042-feature-owned-execution-state](042-feature-owned-execution-state.md) moves feature execution state and decisions to Agent/Workflow receivers; the EventLoop thread remains the single writer. Its registration, delivery and drain rules refine the original descriptions below.
5
+ **Observer failure clarification**: [055-terminal-observer-failure-settlement](055-terminal-observer-failure-settlement.md) keeps terminal observer errors on the ordinary failure path without undoing an already confirmed save.
6
+ **Terminal policy ownership amendment**: [056-workflow-terminal-policy-ownership](056-workflow-terminal-policy-ownership.md) moves Workflow event/outcome interpretation to WorkflowTerminalPolicy while preserving the shared session, durable barrier and uncertainty lifecycle.
7
+
4
8
  **Date**: 2026-08-24
5
9
  **Partially supersedes**: [ADR-014](014-unified-persistence-durable-state.md) for same-process Workflow admission ownership and terminal durable-barrier ordering
6
10
  **Refines**: [ADR-023](023-fsm-session-incarnation-identity-and-routing.md) by removing the transitional Workflow FSMSession-identity reservation bridge
@@ -46,6 +46,8 @@ reconciliation must not silently promote its API stability.
46
46
  2. `Phronomy::LLMAdapter::Base#complete` and `#stream` are the public
47
47
  Provider-call extension boundary. Phronomy owns the framework-side
48
48
  asynchronous/offload wrappers around that synchronous adapter contract.
49
+ [ADR-059](059-backend-contracts-and-async-clients.md) locates those wrappers
50
+ in the private `LLMAdapter::AsyncClient`, separate from Base and RubyLLM.
49
51
  3. `Phronomy::LLMAdapter::RubyLLM` remains the default configured LLM adapter
50
52
  and RubyLLM remains Phronomy's default Provider integration.
51
53
  4. A custom LLMAdapter may replace Provider-call behavior, but the LLMAdapter
@@ -1,9 +1,16 @@
1
1
  # ADR-030: Agent Handoff Domain and Durable Responsibility
2
2
 
3
+ > r8 unit 4 supersedes the Agent/Handoff ownership and storage portions below. See [the unit 4 migration](../migrations/r8-unit4.md). Earlier statements describe their original change only.
4
+
3
5
  ## Status
4
6
 
5
7
  Accepted. V2 revision 2, 2026-09-06.
6
8
 
9
+ The HandoffRunner namespace and ownership are amended by
10
+ [034-handoff-runner-coordination-ownership](034-handoff-runner-coordination-ownership.md).
11
+ The public Runner is now `Phronomy::MultiAgent::HandoffRunner`. Other Handoff
12
+ types and the durable semantics below remain unchanged in this first step.
13
+
7
14
  User approval covers the V2 boundary and the five recovery-contract clarifications.
8
15
  Acceptance is design authority; it is not a claim of repository integration or test success.
9
16
 
@@ -1,9 +1,16 @@
1
1
  # ADR-031: Durable Multi-Agent Semantic Coordination
2
2
 
3
+ > Agent/MultiAgent ownership is amended by [ADR-064](064-agent-execution-and-multi-agent-responsibility.md).
4
+
3
5
  ## Status
4
6
 
5
7
  Accepted. V2 revision 2, 2026-09-06.
6
8
 
9
+ The HandoffRunner namespace and ownership are amended by
10
+ [034-handoff-runner-coordination-ownership](034-handoff-runner-coordination-ownership.md).
11
+ The public Runner is now `Phronomy::MultiAgent::HandoffRunner`. Other Handoff
12
+ types and the durable semantics below remain unchanged in this first step.
13
+
7
14
  User approval covers the V2 boundary and the five recovery-contract clarifications.
8
15
  Acceptance is design authority; it is not a claim of repository integration or test success.
9
16
 
@@ -0,0 +1,85 @@
1
+ # 032: Compose domain persistence over a storage backend
2
+
3
+ - Status: Accepted
4
+ - Domain ownership refined by: [033-domain-persistence-ownership](033-domain-persistence-ownership.md)
5
+ - Date: 2026-09-17
6
+ - Refines: [014-unified-persistence-durable-state](014-unified-persistence-durable-state.md)
7
+
8
+ The raw fixed-repository/error portions are amended by
9
+ [ADR-058](058-neutral-storage-primitives.md). Domain ownership and applicable
10
+ transaction/uncertainty decisions below remain in force.
11
+
12
+ Domain-facing exception ownership is further amended by
13
+ [061-persistence-failure-contracts](061-persistence-failure-contracts.md).
14
+ Raw backend exceptions remain owned by Storage; domain repository exits now
15
+ translate their known categories to independent Persistence exceptions.
16
+
17
+ ## Context
18
+
19
+ The previous `Persistence` class combined raw storage contracts with domain
20
+ repository construction, codecs, and result queries. Physical backends inherited
21
+ that class, and SQL implementations called `build_transaction_view` to construct
22
+ upper domain facades. This made the common storage boundary depend on the
23
+ entities whose records it stored.
24
+
25
+ ## Decision
26
+
27
+ 1. `Storage::Backend` and `Storage::Repositories` define synchronous raw storage
28
+ and transaction-view protocols. `Storage::DurableRecord` and portable storage
29
+ errors belong to this common contract. These files do not depend on Agent,
30
+ MultiAgent, Runtime, or the domain-facing Persistence implementation.
31
+ 2. Concrete backends depend on that contract and their physical storage tools.
32
+ The in-memory implementation lives in `storage/backends/in_memory.rb` and
33
+ retains its single Monitor and single all-repository transaction snapshot.
34
+ 3. `Persistence.new(backend:)` composes the domain service over a selected backend.
35
+ The existing domain codecs and facades remain in `persistence/`. They validate
36
+ and convert records using the actual domain record definitions.
37
+ 4. The same facade builder wraps the root backend and the raw view yielded by
38
+ `backend.transaction`. Transaction conversion stays inside the backend block;
39
+ conversion failures therefore participate in its normal rollback semantics.
40
+ 5. `Persistence.in_memory` is the explicit convenience assembly. Backend selection
41
+ belongs to construction, not to the common storage contract.
42
+ 6. Replace the old Persistence subclass SPI, raw-repository constructor,
43
+ `build_transaction_view`, `Persistence::InMemory`, and old record/error owners.
44
+ No compatibility aliases or second implementation of that SPI are retained.
45
+ See the [migration guide](../migrations/storage-backend-composition.md).
46
+
47
+ Both concrete backends and domain persistence depend on the common storage
48
+ contract. These are sibling responsibility groups, not a requirement for one
49
+ strict vertical ordering of the entire system. Runtime calls to a selected
50
+ backend do not establish a source dependency on that backend's concrete class.
51
+
52
+ ## Preserved contracts
53
+
54
+ All eight repositories remain one atomic transaction domain. Their IDs,
55
+ revision/position checks, active execution constraints, record types, format
56
+ versions, and payload schemas are unchanged. ContentStore retains its separate
57
+ canonicalization API. The shared `AgentBusyError` remains the existing admission
58
+ failure contract; its standalone definition does not load Agent implementation.
59
+
60
+ Atomic durable-state transitions remain CONDITIONAL on a conforming backend for
61
+ F0 operations; commit-outcome certainty under F1 remains NO as a general promise.
62
+ F4 restart readability remains CONDITIONAL on retained confirmed durable data;
63
+ InMemory does not provide disk retention. X0 external effects remain outside the
64
+ storage transaction. This change adds no asynchronous SPI or execution ownership.
65
+
66
+ ## Consequences and validation
67
+
68
+ Custom SQL backends migrate their superclass, record/error references, and raw
69
+ transaction view construction. They keep all transaction repositories and the
70
+ watermark bound to the same connection. Applications wrap a raw backend once.
71
+
72
+ An isolated-load architecture test checks that storage can use opaque records and
73
+ admission without loading domain or execution code. Public contract tests cover
74
+ root/transaction view separation and removal of the replaced SPI. Existing
75
+ repository conformance, commit/rollback/CAS, codec, recovery, and integration tests
76
+ remain required. Codec rejection after a physical write must roll back the whole
77
+ transaction, not leave a committed partial operation.
78
+
79
+ Shared Immutable ownership has already moved to `Values::Immutable`; this change
80
+ preserves that boundary. Domain model placement and unrelated module cycles
81
+ remain separate subsequent changes. In particular, DurableCodec retains its
82
+ TeamRoot / TeamExecution references to validate and reconstruct Team records.
83
+ Those belong to domain persistence, not to the common storage contract.
84
+ Moving a type or hiding a constant reference alone is not evidence that this
85
+ storage boundary has been separated.