phronomy 0.26.0 → 0.27.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 (304) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +40 -0
  3. data/README.md +4 -0
  4. data/VERIFY.sh +27 -27
  5. data/benchmark/bench_agent_invoke.rb +26 -22
  6. data/benchmark/bench_context_assembler.rb +4 -5
  7. data/docs/architecture/agent-chat-and-state-ownership.md +147 -0
  8. data/docs/architecture/agent-configuration-and-tool-binding.md +139 -0
  9. data/docs/architecture/agent-context.md +4 -2
  10. data/docs/architecture/agent-transition-ownership.md +89 -0
  11. data/docs/architecture/before-llm-input.md +6 -0
  12. data/docs/architecture/context-management.md +30 -0
  13. data/docs/architecture/context-preparation-steps.md +90 -0
  14. data/docs/architecture/entry-action-and-team-wording.md +72 -0
  15. data/docs/architecture/execution-metadata-and-values.md +80 -0
  16. data/docs/architecture/generator-verifier-ownership.md +111 -0
  17. data/docs/architecture/multi-agent-handoff.md +8 -2
  18. data/docs/architecture/persistence-refactoring-plan.md +50 -0
  19. data/docs/architecture/persistence.md +27 -4
  20. data/docs/architecture/refactoring-closure.md +334 -0
  21. data/docs/architecture/remaining-refactoring-plan.md +374 -0
  22. data/docs/architecture/rubyllm-2-token-ownership.md +82 -0
  23. data/docs/architecture/tool-schema-recording-gap.md +50 -0
  24. data/docs/architecture/tracing.md +1 -1
  25. data/docs/architecture/workflow-terminal-ownership-design.md +104 -0
  26. data/docs/architecture.md +209 -0
  27. data/docs/decisions/014-unified-persistence-durable-state.md +11 -0
  28. data/docs/decisions/024-event-loop-single-writer-agent-runtime.md +5 -1
  29. data/docs/decisions/025-process-local-agent-ownership-and-runtime-admission.md +13 -3
  30. data/docs/decisions/026-workflow-runtime-admission-and-durable-terminal-barrier.md +5 -1
  31. data/docs/decisions/030-agent-handoff-domain-and-durable-responsibility.md +5 -0
  32. data/docs/decisions/031-durable-multi-agent-coordination.md +5 -0
  33. data/docs/decisions/032-storage-backend-composition.md +80 -0
  34. data/docs/decisions/033-domain-persistence-ownership.md +79 -0
  35. data/docs/decisions/034-handoff-runner-coordination-ownership.md +76 -0
  36. data/docs/decisions/035-tool-executor-capability-ownership.md +68 -0
  37. data/docs/decisions/036-context-contract-ownership.md +86 -0
  38. data/docs/decisions/037-common-definition-ownership.md +62 -0
  39. data/docs/decisions/038-responsibility-based-source-layout.md +131 -0
  40. data/docs/decisions/039-runtime-configuration-lifecycle-ownership.md +74 -0
  41. data/docs/decisions/040-configuration-default-composition.md +94 -0
  42. data/docs/decisions/041-feature-owned-identity-registries.md +100 -0
  43. data/docs/decisions/042-feature-owned-execution-state.md +106 -0
  44. data/docs/decisions/043-storage-execution-constraint-notifications.md +75 -0
  45. data/docs/decisions/044-agent-default-and-one-shot-composition.md +106 -0
  46. data/docs/decisions/045-worker-input-restriction-ownership.md +100 -0
  47. data/docs/decisions/046-agent-responsibility-layout-and-shared-records.md +110 -0
  48. data/docs/decisions/047-recovered-execution-continuation-contract.md +116 -0
  49. data/docs/decisions/048-dispatch-preparation-worker-ownership.md +120 -0
  50. data/docs/decisions/049-initial-preparation-worker-ownership.md +111 -0
  51. data/docs/decisions/050-approval-resume-snapshot-and-commit-ownership.md +98 -0
  52. data/docs/decisions/051-execution-outcome-worker-ownership.md +151 -0
  53. data/docs/decisions/052-tool-invocation-restoration-ownership.md +92 -0
  54. data/docs/decisions/053-shared-state-coordination-ownership.md +71 -0
  55. data/docs/decisions/054-workflow-terminal-save-single-owner.md +76 -0
  56. data/docs/decisions/055-terminal-observer-failure-settlement.md +60 -0
  57. data/docs/decisions/056-workflow-terminal-policy-ownership.md +87 -0
  58. data/docs/decisions/057-storage-transaction-boundaries.md +73 -0
  59. data/docs/decisions/058-neutral-storage-primitives.md +78 -0
  60. data/docs/decisions/README.md +35 -6
  61. data/docs/design/durable-semantic-coordination/IMPLEMENTATION_DESIGN_V2.md +6 -0
  62. data/docs/design/durable-semantic-coordination/IMPLEMENTATION_REPORT.md +6 -0
  63. data/docs/features.md +9 -3
  64. data/docs/getting-started.md +4 -4
  65. data/docs/migrations/0.15.md +5 -0
  66. data/docs/migrations/durable-semantic-coordination-v2.md +6 -0
  67. data/docs/migrations/handoff-runner-multi-agent.md +35 -0
  68. data/docs/migrations/neutral-storage-spi.md +43 -0
  69. data/docs/migrations/parallel-tool-chat-removal.md +49 -0
  70. data/docs/migrations/shared-state-multi-agent.md +44 -0
  71. data/docs/migrations/storage-backend-composition.md +117 -0
  72. data/docs/migrations/storage-transaction-boundaries.md +74 -0
  73. data/docs/persistence-backends.md +162 -204
  74. data/docs/runtime-and-concurrency.md +117 -32
  75. data/lib/phronomy/agent/api/agent.rb +17 -0
  76. data/lib/phronomy/agent/async_event_api.rb +2 -2
  77. data/lib/phronomy/agent/base.rb +51 -241
  78. data/lib/phronomy/{agent.rb → agent/composition/run_once.rb} +4 -13
  79. data/lib/phronomy/agent/context/capability/base.rb +67 -26
  80. data/lib/phronomy/agent/context/capability/tool_executor.rb +62 -0
  81. data/lib/phronomy/agent/{context_assembler.rb → context_assembly/context_assembler.rb} +143 -88
  82. data/lib/phronomy/agent/{context_importer.rb → context_assembly/context_importer.rb} +2 -2
  83. data/lib/phronomy/agent/{ruby_llm_materializer.rb → context_assembly/ruby_llm_materializer.rb} +4 -7
  84. data/lib/phronomy/agent/context_assembly/runtime_chat_builder.rb +36 -0
  85. data/lib/phronomy/agent/context_assembly/saved_context_reader.rb +53 -0
  86. data/lib/phronomy/agent/context_assembly/state_writer.rb +165 -0
  87. data/lib/phronomy/agent/context_assembly/token_budget_resolver.rb +22 -0
  88. data/lib/phronomy/agent/{context_plan.rb → context_contract/context_plan.rb} +1 -1
  89. data/lib/phronomy/agent/{context_policy_input.rb → context_contract/context_policy_input.rb} +6 -6
  90. data/lib/phronomy/agent/{llm_input_build_context.rb → context_contract/llm_input_build_context.rb} +1 -1
  91. data/lib/phronomy/agent/{llm_input_manifest.rb → context_contract/llm_input_manifest.rb} +20 -20
  92. data/lib/phronomy/agent/{llm_input_patch.rb → context_contract/llm_input_patch.rb} +2 -2
  93. data/lib/phronomy/agent/{agent_execution.rb → execution/agent_execution.rb} +8 -4
  94. data/lib/phronomy/agent/{agent_invocation.rb → execution/agent_invocation.rb} +8 -13
  95. data/lib/phronomy/agent/{agent_invocation_session_builder.rb → execution/agent_invocation_session_builder.rb} +19 -95
  96. data/lib/phronomy/agent/execution/approval_resume_commit.rb +108 -0
  97. data/lib/phronomy/agent/execution/dispatch_preparation.rb +305 -0
  98. data/lib/phronomy/agent/{exact_execution.rb → execution/exact_execution.rb} +9 -10
  99. data/lib/phronomy/agent/{execution_cancellation.rb → execution/execution_cancellation.rb} +2 -3
  100. data/lib/phronomy/agent/execution/execution_coordinator.rb +1925 -0
  101. data/lib/phronomy/agent/execution/execution_failure.rb +30 -0
  102. data/lib/phronomy/agent/execution/execution_metadata.rb +53 -0
  103. data/lib/phronomy/agent/execution/execution_outcome_committer.rb +344 -0
  104. data/lib/phronomy/agent/execution/execution_registry.rb +459 -0
  105. data/lib/phronomy/agent/execution/execution_session_runner.rb +118 -0
  106. data/lib/phronomy/agent/execution/initial_preparation.rb +421 -0
  107. data/lib/phronomy/agent/execution/invocation_transitions.rb +86 -0
  108. data/lib/phronomy/agent/{phase_machine_builder.rb → execution/phase_machine_builder.rb} +20 -71
  109. data/lib/phronomy/agent/{provider_call_outcome.rb → execution/provider_call_outcome.rb} +9 -9
  110. data/lib/phronomy/agent/execution/runtime_record_encoder.rb +210 -0
  111. data/lib/phronomy/agent/{handoff_context.rb → handoff/handoff_context.rb} +2 -2
  112. data/lib/phronomy/agent/handoff/handoff_execution_coordinator.rb +15 -0
  113. data/lib/phronomy/agent/handoff/handoff_outcome_committer.rb +131 -0
  114. data/lib/phronomy/agent/{handoff_state.rb → handoff/handoff_state.rb} +1 -1
  115. data/lib/phronomy/agent/{journal_projection.rb → journal/journal_projection.rb} +4 -0
  116. data/lib/phronomy/agent/{journal_record.rb → journal/journal_record.rb} +3 -3
  117. data/lib/phronomy/agent/{llm_call_record.rb → journal/llm_call_record.rb} +2 -2
  118. data/lib/phronomy/agent/{agent_root.rb → lifecycle/agent_root.rb} +6 -2
  119. data/lib/phronomy/agent/lifecycle/default_persistence.rb +29 -0
  120. data/lib/phronomy/{engine/runtime/agent_ownership_registry.rb → agent/lifecycle/ownership_registry.rb} +24 -10
  121. data/lib/phronomy/{agent_already_exists_error.rb → agent/lifecycle_contract/agent_already_exists_error.rb} +2 -0
  122. data/lib/phronomy/{agent_busy_error.rb → agent/lifecycle_contract/agent_busy_error.rb} +2 -0
  123. data/lib/phronomy/{agent_purged_error.rb → agent/lifecycle_contract/agent_purged_error.rb} +2 -0
  124. data/lib/phronomy/agent/lifecycle_contract/handoff_error.rb +7 -0
  125. data/lib/phronomy/{stream_callback_error.rb → agent/lifecycle_contract/stream_callback_error.rb} +2 -0
  126. data/lib/phronomy/agent/persistence/agent_repository.rb +61 -0
  127. data/lib/phronomy/agent/persistence/codec.rb +358 -0
  128. data/lib/phronomy/agent/persistence/execution_repository.rb +108 -0
  129. data/lib/phronomy/agent/persistence/handoff_state_repository.rb +58 -0
  130. data/lib/phronomy/agent/persistence/journal_repository.rb +54 -0
  131. data/lib/phronomy/agent/persistence/queries.rb +61 -0
  132. data/lib/phronomy/agent/persistence/storage_schema.rb +24 -0
  133. data/lib/phronomy/agent/persistence/watermark.rb +27 -0
  134. data/lib/phronomy/agent/recovery/invocation_restorer.rb +132 -0
  135. data/lib/phronomy/agent/{recovery_coordinator → recovery/recovery_coordinator}/continuation.rb +21 -45
  136. data/lib/phronomy/agent/{recovery_coordinator → recovery/recovery_coordinator}/installation.rb +32 -37
  137. data/lib/phronomy/agent/{recovery_coordinator → recovery/recovery_coordinator}/resolution.rb +37 -40
  138. data/lib/phronomy/agent/{recovery_coordinator.rb → recovery/recovery_coordinator.rb} +6 -10
  139. data/lib/phronomy/agent/recovery/recovery_support.rb +227 -0
  140. data/lib/phronomy/agent/selection/candidate.rb +1 -1
  141. data/lib/phronomy/agent/{approval_evaluation_request.rb → tool_execution/approval_evaluation_request.rb} +1 -12
  142. data/lib/phronomy/agent/{tool_approval_request.rb → tool_execution/tool_approval_request.rb} +1 -10
  143. data/lib/phronomy/agent/tool_execution/tool_binding.rb +90 -0
  144. data/lib/phronomy/agent/{tool_call_intercepted.rb → tool_execution/tool_call_intercepted.rb} +2 -2
  145. data/lib/phronomy/agent/{tool_definition_set.rb → tool_execution/tool_definition_set.rb} +9 -4
  146. data/lib/phronomy/agent/{tool_invocation.rb → tool_execution/tool_invocation.rb} +69 -34
  147. data/lib/phronomy/common/configuration_error.rb +7 -0
  148. data/lib/phronomy/common/error.rb +5 -0
  149. data/lib/phronomy/{agent → common/values}/immutable.rb +9 -1
  150. data/lib/phronomy/common/values/serializable.rb +32 -0
  151. data/lib/phronomy/{configuration.rb → configuration/configuration.rb} +14 -5
  152. data/lib/phronomy/configuration/global_configuration.rb +26 -0
  153. data/lib/phronomy/content_store/storage_schema.rb +11 -0
  154. data/lib/phronomy/content_store/stored_contents.rb +43 -0
  155. data/lib/phronomy/engine/backpressure_error.rb +7 -0
  156. data/lib/phronomy/{blocking.rb → engine/blocking.rb} +1 -1
  157. data/lib/phronomy/engine/cancellation_error.rb +7 -0
  158. data/lib/phronomy/engine/concurrency/cancellation_token.rb +4 -0
  159. data/lib/phronomy/engine/concurrency/offload_pool.rb +4 -0
  160. data/lib/phronomy/engine/concurrency/operation_binding.rb +1 -1
  161. data/lib/phronomy/engine/concurrency/worker_input_restricted.rb +14 -0
  162. data/lib/phronomy/engine/event_loop.rb +158 -624
  163. data/lib/phronomy/engine/event_loop_reentrancy_error.rb +8 -0
  164. data/lib/phronomy/{execution.rb → engine/execution.rb} +0 -7
  165. data/lib/phronomy/{execution_cancellation_error.rb → engine/execution_cancellation_error.rb} +2 -0
  166. data/lib/phronomy/engine/execution_receiver.rb +65 -0
  167. data/lib/phronomy/{execution_timeout_error.rb → engine/execution_timeout_error.rb} +2 -0
  168. data/lib/phronomy/engine/fsm_protocol.rb +14 -0
  169. data/lib/phronomy/engine/fsm_session.rb +35 -28
  170. data/lib/phronomy/{invalid_async_entry_action_error.rb → engine/invalid_async_entry_action_error.rb} +2 -0
  171. data/lib/phronomy/{invalid_async_transition_action_error.rb → engine/invalid_async_transition_action_error.rb} +2 -0
  172. data/lib/phronomy/{invalid_async_workflow_action_error.rb → engine/invalid_async_workflow_action_error.rb} +2 -0
  173. data/lib/phronomy/engine/pool_shutdown_error.rb +7 -0
  174. data/lib/phronomy/engine/recursion_limit_error.rb +7 -0
  175. data/lib/phronomy/engine/runtime.rb +80 -84
  176. data/lib/phronomy/engine/runtime_shutdown_error.rb +7 -0
  177. data/lib/phronomy/engine/runtime_shutdown_reentrancy_error.rb +7 -0
  178. data/lib/phronomy/engine/scheduler_reentrancy_error.rb +9 -0
  179. data/lib/phronomy/engine/task_result.rb +4 -0
  180. data/lib/phronomy/engine/timeout_error.rb +7 -0
  181. data/lib/phronomy/filter/contract/filter_block_error.rb +14 -0
  182. data/lib/phronomy/generation/generator_verifier/agent_result_receiver.rb +89 -0
  183. data/lib/phronomy/generation/generator_verifier/pipeline_state.rb +57 -0
  184. data/lib/phronomy/generation/generator_verifier/workflow_builder.rb +112 -0
  185. data/lib/phronomy/generation/generator_verifier.rb +118 -0
  186. data/lib/phronomy/generation/low_confidence_error.rb +14 -0
  187. data/lib/phronomy/llm_context_window/token_budget.rb +6 -7
  188. data/lib/phronomy/llm_contract/authentication_error.rb +7 -0
  189. data/lib/phronomy/{context_budget_exceeded_error.rb → llm_contract/context_budget_exceeded_error.rb} +2 -0
  190. data/lib/phronomy/llm_contract/context_length_error.rb +7 -0
  191. data/lib/phronomy/llm_contract/rate_limit_error.rb +7 -0
  192. data/lib/phronomy/{token_usage.rb → llm_contract/token_usage.rb} +2 -2
  193. data/lib/phronomy/llm_contract/transport_error.rb +7 -0
  194. data/lib/phronomy/multi_agent/admission_registry.rb +22 -2
  195. data/lib/phronomy/multi_agent/durable_subagent_coordinator.rb +5 -5
  196. data/lib/phronomy/{agent → multi_agent}/handoff_runner.rb +18 -17
  197. data/lib/phronomy/multi_agent/orchestrator.rb +2 -2
  198. data/lib/phronomy/multi_agent/persistence/codec.rb +55 -0
  199. data/lib/phronomy/multi_agent/persistence/queries.rb +30 -0
  200. data/lib/phronomy/multi_agent/persistence/team_execution_repository.rb +108 -0
  201. data/lib/phronomy/multi_agent/persistence/team_repository.rb +61 -0
  202. data/lib/phronomy/{agent → multi_agent}/shared_state.rb +56 -39
  203. data/lib/phronomy/multi_agent/storage_contract/team_storage_schema.rb +15 -0
  204. data/lib/phronomy/multi_agent/team_coordinator.rb +21 -18
  205. data/lib/phronomy/multi_agent/team_execution.rb +1 -1
  206. data/lib/phronomy/{engine/runtime → multi_agent}/team_ownership_registry.rb +14 -4
  207. data/lib/phronomy/multi_agent/team_root.rb +1 -1
  208. data/lib/phronomy/output_parser/contract/parse_error.rb +7 -0
  209. data/lib/phronomy/persistence/api/persistence.rb +140 -0
  210. data/lib/phronomy/persistence/migration/initial_format_migration.rb +19 -19
  211. data/lib/phronomy/persistence_composition/repositories.rb +77 -0
  212. data/lib/phronomy/persistence_composition/storage_schema.rb +24 -0
  213. data/lib/phronomy/{execution_rehydration_required_error.rb → recovery/execution_rehydration_required_error.rb} +2 -0
  214. data/lib/phronomy/{recovery.rb → recovery/recovery.rb} +1 -1
  215. data/lib/phronomy/runtime_composition/agent_defaults.rb +7 -0
  216. data/lib/phronomy/runtime_composition/configuration_defaults.rb +9 -0
  217. data/lib/phronomy/runtime_composition/global_runtime.rb +19 -0
  218. data/lib/phronomy/storage/backend.rb +101 -0
  219. data/lib/phronomy/storage/backends/in_memory.rb +157 -0
  220. data/lib/phronomy/storage/blob_conflict_error.rb +10 -0
  221. data/lib/phronomy/storage/blobs.rb +31 -0
  222. data/lib/phronomy/storage/condition.rb +25 -0
  223. data/lib/phronomy/storage/condition_failed_error.rb +16 -0
  224. data/lib/phronomy/storage/conflict_error.rb +9 -0
  225. data/lib/phronomy/{persistence → storage}/durable_record.rb +12 -12
  226. data/lib/phronomy/storage/entry.rb +33 -0
  227. data/lib/phronomy/storage/guard_ref.rb +13 -0
  228. data/lib/phronomy/storage/not_found_error.rb +9 -0
  229. data/lib/phronomy/storage/record_codec.rb +177 -0
  230. data/lib/phronomy/storage/records.rb +61 -0
  231. data/lib/phronomy/storage/resource.rb +126 -0
  232. data/lib/phronomy/storage/scope.rb +25 -0
  233. data/lib/phronomy/storage/serialization_error.rb +9 -0
  234. data/lib/phronomy/storage/streams.rb +44 -0
  235. data/lib/phronomy/storage/transaction_error.rb +10 -0
  236. data/lib/phronomy/storage/unique_constraint_error.rb +17 -0
  237. data/lib/phronomy/storage/unsupported_backend_error.rb +9 -0
  238. data/lib/phronomy/storage/validation.rb +53 -0
  239. data/lib/phronomy/storage/view.rb +131 -0
  240. data/lib/phronomy/testing/persistence_contract/a_content_store.rb +1 -1
  241. data/lib/phronomy/testing/persistence_contract/a_journal_repository.rb +4 -4
  242. data/lib/phronomy/testing/persistence_contract/a_persistence_backend.rb +10 -7
  243. data/lib/phronomy/testing/persistence_contract/a_workflow_state_repository.rb +2 -2
  244. data/lib/phronomy/testing/persistence_contract/an_agent_repository.rb +6 -6
  245. data/lib/phronomy/testing/persistence_contract/an_execution_repository.rb +6 -6
  246. data/lib/phronomy/testing/persistence_contract/coordination_repositories.rb +8 -8
  247. data/lib/phronomy/testing/persistence_contract/neutral_storage_primitives.rb +263 -0
  248. data/lib/phronomy/testing/persistence_contract/storage_transaction_boundaries.rb +123 -0
  249. data/lib/phronomy/testing/persistence_contract.rb +4 -0
  250. data/lib/phronomy/tool/contract/tool_error.rb +7 -0
  251. data/lib/phronomy/tools/agent.rb +1 -1
  252. data/lib/phronomy/version.rb +1 -1
  253. data/lib/phronomy/{workflow.rb → workflow/execution/workflow.rb} +8 -6
  254. data/lib/phronomy/{workflow_context.rb → workflow/execution/workflow_context.rb} +4 -0
  255. data/lib/phronomy/workflow/execution/workflow_context_ownership_error.rb +7 -0
  256. data/lib/phronomy/workflow/execution/workflow_execution_registry.rb +188 -0
  257. data/lib/phronomy/{workflow_runner.rb → workflow/execution/workflow_runner.rb} +122 -71
  258. data/lib/phronomy/workflow/execution/workflow_terminal_policy.rb +40 -0
  259. data/lib/phronomy/workflow/persistence/codec.rb +153 -0
  260. data/lib/phronomy/workflow/persistence/state_repository.rb +57 -0
  261. data/lib/phronomy/workflow/phase_machine_builder.rb +2 -2
  262. data/lib/phronomy/workflow/storage_contract/workflow_storage_schema.rb +9 -0
  263. data/lib/phronomy.rb +52 -94
  264. data/scripts/api_snapshot.rb +1 -1
  265. data/scripts/storage_spi_snapshot.rb +36 -0
  266. data/sig/phronomy/agent.rbs +0 -1
  267. data/sig/phronomy/execution_receiver.rbs +34 -0
  268. data/sig/phronomy/handoff.rbs +4 -2
  269. data/sig/phronomy/multi_agent.rbs +18 -0
  270. data/sig/phronomy/persistence.rbs +7 -91
  271. data/sig/phronomy/storage.rbs +174 -0
  272. data/sig/phronomy/tool.rbs +10 -1
  273. metadata +230 -99
  274. data/lib/phronomy/agent/execution_coordinator.rb +0 -3151
  275. data/lib/phronomy/agent/handoff_execution_coordinator.rb +0 -143
  276. data/lib/phronomy/agent/recovery_support.rb +0 -504
  277. data/lib/phronomy/agent/token_budget_resolver.rb +0 -70
  278. data/lib/phronomy/agent/tool_executor.rb +0 -55
  279. data/lib/phronomy/generator_verifier.rb +0 -369
  280. data/lib/phronomy/invalid_context_budget_configuration_error.rb +0 -8
  281. data/lib/phronomy/multi_agent/parallel_tool_chat.rb +0 -116
  282. data/lib/phronomy/persistence/durable_codec.rb +0 -706
  283. data/lib/phronomy/persistence/in_memory.rb +0 -690
  284. data/lib/phronomy/persistence/repository_facades.rb +0 -535
  285. data/lib/phronomy/persistence.rb +0 -276
  286. data/lib/phronomy/ruby_llm_patches.rb +0 -24
  287. data/lib/phronomy/workflow_recovery.rb +0 -123
  288. /data/lib/phronomy/agent/{context_candidate_resolver.rb → context_assembly/context_candidate_resolver.rb} +0 -0
  289. /data/lib/phronomy/agent/{context_policy_input_builder.rb → context_assembly/context_policy_input_builder.rb} +0 -0
  290. /data/lib/phronomy/agent/{context_plan_validator.rb → context_contract/context_plan_validator.rb} +0 -0
  291. /data/lib/phronomy/agent/{context_policy.rb → context_contract/context_policy.rb} +0 -0
  292. /data/lib/phronomy/agent/{llm_operation_result.rb → execution/llm_operation_result.rb} +0 -0
  293. /data/lib/phronomy/agent/{handoff.rb → handoff/handoff.rb} +0 -0
  294. /data/lib/phronomy/agent/{handoff_capability_factory.rb → handoff/handoff_capability_factory.rb} +0 -0
  295. /data/lib/phronomy/agent/{handoff_policy.rb → handoff/handoff_policy.rb} +0 -0
  296. /data/lib/phronomy/agent/{handoff_projection.rb → handoff/handoff_projection.rb} +0 -0
  297. /data/lib/phronomy/agent/{handoff_request.rb → handoff/handoff_request.rb} +0 -0
  298. /data/lib/phronomy/agent/{tool_invocation_session_builder.rb → tool_execution/tool_invocation_session_builder.rb} +0 -0
  299. /data/lib/phronomy/{canonical_json.rb → common/canonical_json.rb} +0 -0
  300. /data/lib/phronomy/{diagnostics.rb → engine/diagnostics.rb} +0 -0
  301. /data/lib/phronomy/{event.rb → engine/event.rb} +0 -0
  302. /data/lib/phronomy/{invocation_context.rb → engine/invocation_context.rb} +0 -0
  303. /data/lib/phronomy/{metrics.rb → engine/metrics.rb} +0 -0
  304. /data/lib/phronomy/{runnable.rb → engine/runnable.rb} +0 -0
data/docs/architecture.md CHANGED
@@ -41,6 +41,215 @@ explicit compatibility decision.
41
41
  dependency minimization must not weaken accepted durability,
42
42
  ownership, security-boundary, or extension contracts.
43
43
 
44
+ ## Responsibility groups and dependency graphs
45
+
46
+ Dependency views describe a directed graph of responsibility groups, not a
47
+ tree or a single pipeline. Several distinct groups may share one horizontal
48
+ band. A band's height expresses a proposed abstraction level; it does not imply
49
+ that its groups are independent or that every valid dependency points down.
50
+
51
+ Assess each dependency by the referenced contract and its owner. Shared value
52
+ types, extension contracts, and collaboration within a component can justify
53
+ dependencies between groups. A directory containing both shared definitions and
54
+ concrete orchestration must be examined by responsibility before assigning it a
55
+ single position. Cycles and upward arrows are review evidence, not defect counts.
56
+
57
+ The FSM terminal marker illustrates this distinction. `FSMProtocol::FINISH`
58
+ owns the internal `:__end__` marker used by the session and Workflow compilers.
59
+ The public Workflow DSL continues to use `:__finish__`. The execution session
60
+ and phase compiler do not depend on `WorkflowRunner` for this shared vocabulary;
61
+ the Workflow builder still legitimately creates its runner.
62
+
63
+ Context Policy and hook contracts provide another example. The shared values,
64
+ Manifest representation, and Plan validation live in `agent/context_contract/`,
65
+ separately from concrete policies and Agent execution. Zeitwerk collapses that
66
+ directory to preserve the existing `Phronomy::Agent` constants. A Policy's
67
+ dependency on those contracts does not make it depend on Agent execution. See
68
+ [ADR-036](decisions/036-context-contract-ownership.md).
69
+
70
+ ### Common definitions
71
+
72
+ `common/` owns general definitions shared across the framework that do not
73
+ belong to a particular feature. They must not depend on concrete Agent,
74
+ Workflow, Runtime, or other feature implementations. Being used in several
75
+ places, or inheriting a common base class, does not by itself make a definition
76
+ common; feature-owned contracts remain with their owners.
77
+
78
+ This group contains `Phronomy::Error`, `Phronomy::ConfigurationError`,
79
+ `Phronomy::CanonicalJSON`, and `Phronomy::Values::Immutable`. Zeitwerk collapses
80
+ `common/`, preserving these canonical names without introducing a
81
+ `Phronomy::Common` namespace. Other exceptions belong to their feature
82
+ contracts. `configuration/` owns settings and scalar defaults. The concrete
83
+ adapter and tracer defaults are selected in `runtime_composition/`, which binds
84
+ fresh-instance factories consumed by `Configuration.new`. This keeps concrete
85
+ feature selection outside settings while preserving application behavior.
86
+ Application Runtime reset and configuration replacement are also coordinated in
87
+ `runtime_composition/`, separately from configuration access and Engine mechanics.
88
+ See [ADR-039](decisions/039-runtime-configuration-lifecycle-ownership.md) and
89
+ [ADR-040](decisions/040-configuration-default-composition.md).
90
+ See [ADR-037](decisions/037-common-definition-ownership.md) and
91
+ [ADR-038](decisions/038-responsibility-based-source-layout.md).
92
+
93
+ ### Source placement and loading
94
+
95
+ `lib/phronomy.rb` is the application loading entry point. Internal production
96
+ files must not require it. Feature implementations and contracts live in their
97
+ responsibility directories; the direct root contains only `version.rb` and the
98
+ small namespace/loading files enumerated in ADR-038.
99
+ The separately documented external backend-test entry
100
+ `phronomy/testing/persistence_contract` retains its existing opt-in loading
101
+ contract and is excluded from production automatic loading.
102
+
103
+ Engine owns Event, Execution composition and its outcome exceptions, and the
104
+ synchronous FSM callback exceptions. Recovery owns shared rehydration
105
+ requirements. Workflow implementation lives under `workflow/execution/`;
106
+ Agent namespace/event loading lives under `agent/api/`, separately from the shared
107
+ Agent lifecycle exceptions in `agent/lifecycle_contract/`. LLM values and
108
+ call-boundary exceptions live under `llm_contract/`.
109
+
110
+ Agent consumes its private fresh-Persistence factory only when neither an
111
+ explicit instance nor a configured instance is available. Concrete selection
112
+ and binding live in `runtime_composition/agent_defaults.rb`. The one-shot
113
+ `Agent.run_once` method is defined in `agent/composition/run_once.rb`, because it
114
+ explicitly composes Agent and fresh ephemeral Persistence on every call.
115
+ The application entry loads both composition files; Agent execution and
116
+ namespace loading do not delegate upward to them. See
117
+ [ADR-044](decisions/044-agent-default-and-one-shot-composition.md).
118
+
119
+ Types excluded from authorization worker inputs declare the internal,
120
+ methodless `Concurrency::WorkerInputRestricted` contract at their own
121
+ definitions. ToolInvocation checks that execution-boundary contract rather
122
+ than concrete Workflow types. The original restriction set and opaque
123
+ application-value behavior are preserved; see
124
+ [ADR-045](decisions/045-worker-input-restriction-ownership.md).
125
+
126
+ Agent implementation files are grouped into lifecycle, execution, Tool execution,
127
+ context assembly, journal, Handoff and recovery directories. These directories
128
+ are collapsed, so existing Agent constant names remain unchanged. Journal encoding,
129
+ saved context reads and live invocation restoration have separate internal owners;
130
+ transaction and EventLoop state decisions remain with their callers. See
131
+ [ADR-046](decisions/046-agent-responsibility-layout-and-shared-records.md).
132
+
133
+ Recovery hands semantic continuation commands to the execution owner through
134
+ its EventLoop delivery boundary. The owner checks current identity, revision
135
+ and session state before applying them. `Agent::ExecutionSessionRunner` shares
136
+ ordinary and recovered Agent/Tool session registration and reports completion
137
+ back to the same coordinator; operation workers now own terminal persistence
138
+ under its EventLoop result authority (ADR-051 below).
139
+ See [ADR-047](decisions/047-recovered-execution-continuation-contract.md).
140
+
141
+ InvocationRestorer decodes saved Tool snapshots, resolves the Tool Call and Tool,
142
+ and matches approval evidence. The newly constructed ToolInvocation applies its
143
+ own saved state through the internal `restore_state!` operation; Recovery no
144
+ longer writes its instance variables. State application neither evaluates approval
145
+ nor dispatches Tool execution. Existing recovery installation notifications and
146
+ continuation rules are unchanged. See
147
+ [ADR-052](decisions/052-tool-invocation-restoration-ownership.md).
148
+
149
+ `Agent::DispatchPreparation` owns Provider/Tool dispatch prerequisites and their
150
+ operation-specific readback. ExecutionCoordinator captures and submits inputs,
151
+ then validates/applies results on EventLoop before dispatch. The worker's Provider
152
+ entry separates record encoding, application ContextPolicy, prerequisite commit
153
+ and post-commit materialization without changing transaction/rescue boundaries.
154
+ Its input/result types are worker-owned; existing Coordinator constant paths are
155
+ internal aliases, with changed canonical Ruby names. See
156
+ [ADR-048](decisions/048-dispatch-preparation-worker-ownership.md).
157
+
158
+ `Agent::InitialPreparation` owns initial durable admission, Context preparation,
159
+ preparation failure persistence and replay from saved preparing inputs. Ordinary
160
+ start and recovery share the admitted-preparation steps; Runtime admission,
161
+ result validation, live-state apply and session delivery remain on EventLoop.
162
+ The known failure base advances only after a successful commit response.
163
+ `Agent::ExecutionFailure` shares the existing pure failure classification with
164
+ terminal persistence; it does not own transactions or delivery. See
165
+ [ADR-049](decisions/049-initial-preparation-worker-ownership.md).
166
+
167
+ `Agent::ApprovalResumeCommit` persists approval decisions with operation-owned
168
+ Tool recovery snapshots. Coordinator validates the suspended owner and approval
169
+ request before copying canonical snapshot values into the immutable Command;
170
+ there is no shared snapshot lookup. The worker validates the target, stages
171
+ recovery facts and commits decision/Execution/Root together. EventLoop retains
172
+ admission, stale-result checks, live-state application and session resumption.
173
+ An uncertain commit still requires recovery; it is not retried or treated as a
174
+ confirmed resume. Internal Coordinator type aliases remain, with changed
175
+ canonical names and an added Command snapshot field. See
176
+ [ADR-050](decisions/050-approval-resume-snapshot-and-commit-ownership.md).
177
+
178
+ `Agent::ExecutionOutcomeCommitter` owns ordinary completion, failure, suspension
179
+ and child waiting; `Agent::HandoffOutcomeCommitter` adds atomic Source transfer.
180
+ The Handoff Coordinator now only selects its worker. Transaction boundaries,
181
+ operation-specific readback and Handoff selection precedence remain unchanged.
182
+ Coordinator retains quiescence, submission, stale-result validation, live-state
183
+ application, admission and Task/listener delivery. Command/view/outcome types are
184
+ worker-owned with internal Coordinator aliases and changed canonical Ruby names.
185
+ See [ADR-051](decisions/051-execution-outcome-worker-ownership.md).
186
+
187
+ The remaining execution owner expresses result handling as validation, committed
188
+ state installation, and continuation or delivery. Private methods keep these
189
+ steps in Coordinator; they introduce neither another owner nor shared per-operation
190
+ fields. The operation-specific authority checks and outer rescue boundaries stay
191
+ at the result entry points. Start/resume admission and submission flags stay in
192
+ the same methods as their cleanup decisions.
193
+
194
+ | Owner entry | Purpose-level steps |
195
+ | --- | --- |
196
+ | Initial preparation recovery result | Validate preparing owner; restart the prepared session or settle its saved failure; complete the load observer |
197
+ | Approval resume result | Validate suspended revision; install committed state and waiter; observe the task; resume the FSM |
198
+ | Terminal result | Validate revision/session; handle commit uncertainty; apply state and acknowledge the snapshot; deliver the selected outcome |
199
+
200
+ Terminal delivery releases ownership before notifying completed/failed/Handoff
201
+ observers, then settles Tasks. Suspension keeps ordinary Tasks pending. Ordinary
202
+ commit uncertainty keeps recovery admission and pending waiters; coordination
203
+ errors retain their separate release-and-fail behavior. Session registration
204
+ failure during preparation recovery still terminalizes without a live session;
205
+ trace/resume failure still uses the newly installed execution revision.
206
+ This is an internal readability refinement of ADR-024/047/051, not a change to
207
+ persistence, recovery guarantees or public interfaces.
208
+
209
+ Selected nested Zeitwerk roots retain existing top-level Phronomy constants
210
+ without changing the enclosing feature's existing nested constants. For
211
+ example, `Phronomy::WorkflowContext` and `Phronomy::WorkflowRunner` coexist with
212
+ `Phronomy::Workflow::Persistence`. Workflow remains a class and its source
213
+ file lives beside its implementation. These moves do not introduce aliases or
214
+ a new public API for requiring arbitrary internal paths.
215
+
216
+ WorkflowRunner directly owns terminal save submission and F1 snapshot readback.
217
+ The former WorkflowRecovery prepend and shadowed save implementation are removed;
218
+ the active path is independent of an installation hook. Private methods separate
219
+ submission, save/reconciliation and result delivery. FSMSession still interprets
220
+ the terminal persistence event; that ownership is a separate next step. See
221
+ [ADR-054](decisions/054-workflow-terminal-save-single-owner.md) and the
222
+ [remaining refactoring plan](architecture/remaining-refactoring-plan.md).
223
+ The Agent entry explicitly preserves Agent lifecycle extension installation.
224
+ Configuration accessors now live beside Configuration, rather than inside the
225
+ loader. Configuration constructs fresh components through internally bound
226
+ factories; composition selects their concrete types. Static source-reference
227
+ graphs do not follow these injected calls. LLMAdapter's async bridge still uses
228
+ Runtime, and other dependency cycles remain.
229
+
230
+ Agent and Team implement their identity registries in `agent/` and
231
+ `multi_agent/`. Runtime strongly retains one of each when registered, using only
232
+ its generic shutdown participant contract. Feature code reserves identities,
233
+ handles feature exceptions, and detaches owners after completed cleanup.
234
+ See [ADR-041](decisions/041-feature-owned-identity-registries.md).
235
+
236
+ Agent and Workflow also own their distinct execution registries. EventLoop
237
+ retains them through Engine's internal `ExecutionReceiver` contract, dispatches
238
+ queued messages and combines generic session/delivery counts with their idle
239
+ predicates. Normal mutation remains on the EventLoop thread; only final
240
+ invalidation after join runs on the management thread. EventLoop has no Agent
241
+ or Workflow dispatch branch. See
242
+ [ADR-042](decisions/042-feature-owned-execution-state.md).
243
+
244
+ `MultiAgent::SharedState` owns sequential peer coordination through a findings
245
+ store created for each invocation. It equips member Agents with shared-store
246
+ Tools, runs complete cycles, checks stopping conditions and aggregates findings.
247
+ It is not an individual Agent's durable state or execution coordinator. Its
248
+ Experimental public namespace moves from Agent to MultiAgent without an alias;
249
+ generated semantic definition IDs retain their previous values. See
250
+ [ADR-053](decisions/053-shared-state-coordination-ownership.md) and the
251
+ [migration guide](migrations/shared-state-multi-agent.md).
252
+
44
253
  ## Current architecture
45
254
 
46
255
  | Area | Current document |
@@ -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.
@@ -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
@@ -4,6 +4,11 @@
4
4
 
5
5
  Accepted. V2 revision 2, 2026-09-06.
6
6
 
7
+ The HandoffRunner namespace and ownership are amended by
8
+ [034-handoff-runner-coordination-ownership](034-handoff-runner-coordination-ownership.md).
9
+ The public Runner is now `Phronomy::MultiAgent::HandoffRunner`. Other Handoff
10
+ types and the durable semantics below remain unchanged in this first step.
11
+
7
12
  User approval covers the V2 boundary and the five recovery-contract clarifications.
8
13
  Acceptance is design authority; it is not a claim of repository integration or test success.
9
14
 
@@ -4,6 +4,11 @@
4
4
 
5
5
  Accepted. V2 revision 2, 2026-09-06.
6
6
 
7
+ The HandoffRunner namespace and ownership are amended by
8
+ [034-handoff-runner-coordination-ownership](034-handoff-runner-coordination-ownership.md).
9
+ The public Runner is now `Phronomy::MultiAgent::HandoffRunner`. Other Handoff
10
+ types and the durable semantics below remain unchanged in this first step.
11
+
7
12
  User approval covers the V2 boundary and the five recovery-contract clarifications.
8
13
  Acceptance is design authority; it is not a claim of repository integration or test success.
9
14
 
@@ -0,0 +1,80 @@
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
+ ## Context
13
+
14
+ The previous `Persistence` class combined raw storage contracts with domain
15
+ repository construction, codecs, and result queries. Physical backends inherited
16
+ that class, and SQL implementations called `build_transaction_view` to construct
17
+ upper domain facades. This made the common storage boundary depend on the
18
+ entities whose records it stored.
19
+
20
+ ## Decision
21
+
22
+ 1. `Storage::Backend` and `Storage::Repositories` define synchronous raw storage
23
+ and transaction-view protocols. `Storage::DurableRecord` and portable storage
24
+ errors belong to this common contract. These files do not depend on Agent,
25
+ MultiAgent, Runtime, or the domain-facing Persistence implementation.
26
+ 2. Concrete backends depend on that contract and their physical storage tools.
27
+ The in-memory implementation lives in `storage/backends/in_memory.rb` and
28
+ retains its single Monitor and single all-repository transaction snapshot.
29
+ 3. `Persistence.new(backend:)` composes the domain service over a selected backend.
30
+ The existing domain codecs and facades remain in `persistence/`. They validate
31
+ and convert records using the actual domain record definitions.
32
+ 4. The same facade builder wraps the root backend and the raw view yielded by
33
+ `backend.transaction`. Transaction conversion stays inside the backend block;
34
+ conversion failures therefore participate in its normal rollback semantics.
35
+ 5. `Persistence.in_memory` is the explicit convenience assembly. Backend selection
36
+ belongs to construction, not to the common storage contract.
37
+ 6. Replace the old Persistence subclass SPI, raw-repository constructor,
38
+ `build_transaction_view`, `Persistence::InMemory`, and old record/error owners.
39
+ No compatibility aliases or second implementation of that SPI are retained.
40
+ See the [migration guide](../migrations/storage-backend-composition.md).
41
+
42
+ Both concrete backends and domain persistence depend on the common storage
43
+ contract. These are sibling responsibility groups, not a requirement for one
44
+ strict vertical ordering of the entire system. Runtime calls to a selected
45
+ backend do not establish a source dependency on that backend's concrete class.
46
+
47
+ ## Preserved contracts
48
+
49
+ All eight repositories remain one atomic transaction domain. Their IDs,
50
+ revision/position checks, active execution constraints, record types, format
51
+ versions, and payload schemas are unchanged. ContentStore retains its separate
52
+ canonicalization API. The shared `AgentBusyError` remains the existing admission
53
+ failure contract; its standalone definition does not load Agent implementation.
54
+
55
+ Atomic durable-state transitions remain CONDITIONAL on a conforming backend for
56
+ F0 operations; commit-outcome certainty under F1 remains NO as a general promise.
57
+ F4 restart readability remains CONDITIONAL on retained confirmed durable data;
58
+ InMemory does not provide disk retention. X0 external effects remain outside the
59
+ storage transaction. This change adds no asynchronous SPI or execution ownership.
60
+
61
+ ## Consequences and validation
62
+
63
+ Custom SQL backends migrate their superclass, record/error references, and raw
64
+ transaction view construction. They keep all transaction repositories and the
65
+ watermark bound to the same connection. Applications wrap a raw backend once.
66
+
67
+ An isolated-load architecture test checks that storage can use opaque records and
68
+ admission without loading domain or execution code. Public contract tests cover
69
+ root/transaction view separation and removal of the replaced SPI. Existing
70
+ repository conformance, commit/rollback/CAS, codec, recovery, and integration tests
71
+ remain required. Codec rejection after a physical write must roll back the whole
72
+ transaction, not leave a committed partial operation.
73
+
74
+ Shared Immutable ownership has already moved to `Values::Immutable`; this change
75
+ preserves that boundary. Domain model placement and unrelated module cycles
76
+ remain separate subsequent changes. In particular, DurableCodec retains its
77
+ TeamRoot / TeamExecution references to validate and reconstruct Team records.
78
+ Those belong to domain persistence, not to the common storage contract.
79
+ Moving a type or hiding a constant reference alone is not evidence that this
80
+ storage boundary has been separated.
@@ -0,0 +1,79 @@
1
+ # 033: Own persistence rules within each domain
2
+
3
+ - Status: Amended
4
+ - Date: 2026-09-18
5
+ - Error boundary refined by: [043-storage-execution-constraint-notifications](043-storage-execution-constraint-notifications.md)
6
+ - Refines: [032-storage-backend-composition](032-storage-backend-composition.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
+ ## Context
13
+
14
+ ADR-032 separated raw storage from domain persistence, but the common-looking
15
+ `persistence/` directory still collected Agent, Team, and Workflow schemas and
16
+ repository facades. Moving that directory to an upper band in a dependency
17
+ diagram described its contents; it did not establish suitable domain ownership.
18
+ The public Persistence entry point also contained domain-specific result queries.
19
+
20
+ ## Decision
21
+
22
+ 1. `agent/persistence/` owns AgentRoot, Journal, AgentExecution, and Handoff
23
+ codecs/repositories and Agent/Handoff result queries.
24
+ 2. `multi_agent/persistence/` owns TeamRoot and TeamExecution codecs/repositories
25
+ and Team result queries. Team persistence can be used over a raw backend
26
+ without loading Agent implementation or the combined Persistence service.
27
+ 3. `workflow/persistence/` owns the Workflow record schema, normalization rules,
28
+ and state repository. Workflow symbol normalization remains specific to that
29
+ domain; other codecs do not adopt it implicitly.
30
+ 4. `Storage::RecordCodec` contains shared record-envelope and scalar validation.
31
+ Domain codecs extend it; it neither selects nor imports a domain codec.
32
+ These helpers and domain components are private implementation, not new SPI.
33
+ 5. `PersistenceComposition::Repositories` explicitly assembles the seven domain
34
+ repository wrappers and the existing ContentStore from one raw storage view.
35
+ The public `Phronomy::Persistence` service remains the compatible entry point.
36
+ It delegates queries and retains the Runtime observation-thread guard.
37
+ Each view creates and caches domain wrappers on first use, under one lock,
38
+ so Agent-only use does not load Team or Workflow implementations.
39
+ 6. Conversion remains inside `backend.transaction`. Root and transaction paths
40
+ use the same builder. Reusing the root view when the backend yields itself
41
+ retains the existing repository identity and fault-injection behavior.
42
+ 7. Delete the private combined `Persistence::DurableCodec` and
43
+ `Persistence::RepositoryFacades`; do not preserve a second owner through
44
+ compatibility aliases. Explicit historical migration keeps its public API
45
+ and calls the new domain codecs.
46
+
47
+ InMemory, SQLite, and PostgreSQL are all concrete implementations of the common
48
+ Backend contract. Domain repository wrappers are consumers of that contract;
49
+ they do not introduce a second physical transaction boundary.
50
+
51
+ ## Preserved contracts and limits
52
+
53
+ Public Persistence methods, Backend SPI, eight repository accessors, IDs,
54
+ revisions/positions, active constraints, physical SQL schemas, record types,
55
+ format versions, and payload schemas are unchanged. Existing SQL backends need
56
+ no source migration for this ownership change. The public result-reader dispatch
57
+ and observation guard remain in the public entry point.
58
+
59
+ Atomic durable-state transitions and rollback remain CONDITIONAL on a conforming
60
+ backend for F0. Commit-outcome certainty under F1 is not added. F4 restart
61
+ readability depends on retained confirmed data; InMemory is not disk retention.
62
+ X0 effects remain outside storage transactions.
63
+
64
+ The raw `Storage::Repositories` still names eight Phronomy record repositories and
65
+ an Agent watermark operation. This is an explicit intermediate state, not a claim
66
+ that the framework contract is domain-neutral. Contract generalization and naming
67
+ of the final common persistence framework are deferred to the staged plan below.
68
+
69
+ ## Validation
70
+
71
+ Existing record-schema, backend conformance, optimistic conflict, recovery,
72
+ Handoff, Team, Workflow, and public compatibility tests remain required. A
73
+ separate-process boundary test uses Team persistence without Agent, Workflow,
74
+ Runtime, or combined-Persistence loading. Another process uses the public Agent
75
+ repositories without loading Team or Workflow implementations. A failure-injection test rejects the
76
+ Team response after writes and verifies rollback across Agent, Team, and content.
77
+ Dependency analysis must not introduce a new nontrivial file cycle.
78
+
79
+ See [the staged implementation plan](../architecture/persistence-refactoring-plan.md).
@@ -0,0 +1,76 @@
1
+ # ADR-034: Handoff Runner Coordination Ownership
2
+
3
+ ## Status
4
+
5
+ Accepted for the H1 step on `refactor/architecture`, 2026-09-18.
6
+ The subsequent Handoff contract and persistence separation is deferred.
7
+
8
+ ## Scope of supersession
9
+
10
+ This amends the Runner placement/public namespace in
11
+ [030-agent-handoff-domain-and-durable-responsibility](030-agent-handoff-domain-and-durable-responsibility.md)
12
+ and the domain map in
13
+ [031-durable-multi-agent-coordination](031-durable-multi-agent-coordination.md).
14
+ All other durable Handoff semantics remain in force.
15
+
16
+ ## Context
17
+
18
+ HandoffRunner validates a graph of concrete Agents, selects the active Agent,
19
+ invokes or resumes exact executions, follows multiple transfers, and scopes
20
+ cancellation/result lookup to a specified chain. Those responsibilities span
21
+ Agents. They differ from an individual Agent's execution, Journal and Context.
22
+
23
+ Calling Handoff from an Agent does not make that whole coordination lifetime an
24
+ Agent implementation detail. Updating the Source and routing state in one
25
+ transaction also does not require them to occupy one module.
26
+
27
+ The Runner and TeamCoordinator share the Runtime-local AdmissionRegistry. Keeping
28
+ the Runner inside Agent creates an Agent-to-MultiAgent concrete dependency.
29
+ Moving only the Runner aligns ownership without generalizing the registry or
30
+ changing the existing shutdown participant contract.
31
+
32
+ ## Decision
33
+
34
+ 1. Move the public Runner implementation from `agent/handoff_runner.rb` to
35
+ `multi_agent/handoff_runner.rb` and expose
36
+ `Phronomy::MultiAgent::HandoffRunner`.
37
+ 2. Remove `Phronomy::Agent::HandoffRunner` without a compatibility alias on the
38
+ refactoring branch. Migrate API documentation, RBS, snapshot and consumers
39
+ together. See the [migration guide](../migrations/handoff-runner-multi-agent.md).
40
+ 3. Retain `Agent::Handoff`, `HandoffPolicy`, Context/Request/State and Agent
41
+ terminal/persistence integration during H1. Qualify the Runner's dependencies
42
+ explicitly. This mixed placement is an intermediate state.
43
+ 4. Keep AdmissionRegistry in MultiAgent. The admission key, exception classes,
44
+ successful-call release and Runtime shutdown participation are unchanged.
45
+ 5. Preserve method parameters/results, record formats, main-Agent anchor,
46
+ deterministic Target IDs, transaction boundaries, exact recovery and scoped
47
+ cancellation. H1 introduces no new execution or shutdown manager.
48
+
49
+ ## Consequences and limits
50
+
51
+ Agent no longer directly names a MultiAgent implementation in production source.
52
+ The Runner's existing Tracing dependency now belongs to the MultiAgent directory.
53
+ Module-edge totals and large strongly connected components need not decrease:
54
+ this step changes responsibility placement, not the underlying algorithm.
55
+
56
+ Agent still interprets Handoff/Team coordination metadata. This logical coupling
57
+ is not removed merely because a directory edge disappears.
58
+
59
+ Later work must separate Request construction, Coordinator selection, Context
60
+ conversion, transaction participation and purge/recovery constraints before
61
+ moving the remaining Handoff-specific types and persistence rules. That work must
62
+ preserve one transaction for Source termination plus responsibility transfer and
63
+ for Target termination plus routing stabilization. It must not promote transferred
64
+ Context into permanent Target Journal/Knowledge or depend on post-commit callbacks
65
+ for coordination correctness.
66
+
67
+ ## Verification obligations
68
+
69
+ The new public constant must load with Zeitwerk and match its RBS/API snapshot;
70
+ the old constant must not remain as an alias. Existing Handoff, multi-hop,
71
+ cancellation/recovery, shutdown and SQLite reconstruction scenarios must pass.
72
+ API guards must distinguish `MultiAgent::HandoffRunner` from the removed exact
73
+ constant `MultiAgent::Handoff`.
74
+
75
+ The implementation delivery records test results separately; this ADR does not
76
+ assert that unexecuted live-LLM or database-server tests passed.
@@ -0,0 +1,68 @@
1
+ # ADR-035: Default Tool Executor Ownership
2
+
3
+ ## Status
4
+
5
+ Accepted on the architecture refactoring branch as T1.
6
+
7
+ This decision assigns the default Tool execution helper to the existing
8
+ Capability implementation. The public Tool facade defined by ADR-015 remains
9
+ the same Class object with the same canonical implementation name.
10
+
11
+ ## Context
12
+
13
+ `Agent::Context::Capability::Base#call_async` delegates default asynchronous
14
+ dispatch to `Agent::ToolExecutor`. The helper selects inline cooperative work
15
+ or OffloadPool submission and returns a TaskResult. It has no responsibility
16
+ for Agent state, approval, persistence, recovery, or multi-Agent coordination.
17
+
18
+ Placing this helper directly under Agent makes the Capability directory depend
19
+ on Agent execution while Agent execution also depends on Capability. The
20
+ underlying helper is part of the Tool calling contract and its standard
21
+ implementation, so its ownership should reflect that role.
22
+
23
+ Moving only the helper to `tool/` would introduce another directory cycle:
24
+ `tool/base.rb` currently aliases `Agent::Context::Capability::Base`. Moving the
25
+ canonical Tool class and changing its runtime name would require a separate
26
+ public compatibility decision.
27
+
28
+ ## Decision
29
+
30
+ 1. Move the helper to
31
+ `Phronomy::Agent::Context::Capability::ToolExecutor`, in
32
+ `agent/context/capability/tool_executor.rb`. Classify this helper as private
33
+ API and remove the old internal constant without a compatibility alias.
34
+ 2. Use the new helper from Capability Base and Agent ToolInvocation. Preserve
35
+ the existing dispatch implementation and error messages.
36
+ 3. Keep `Tool::Base` and `Agent::Context::Capability::Base` as the same Class
37
+ object. Preserve their canonical name, DSL state, method-owner checks, and
38
+ the public `call_async(args, cancellation_token:, config:)` protocol.
39
+ 4. Keep Runtime selection, authorization and logical result ownership in Agent
40
+ ToolInvocation. Its standard path passes Runtime and `on_full: :raise` to
41
+ the private helper; custom Tool implementations receive the public protocol.
42
+ Agent-as-Tool continues through its own asynchronous Agent lifecycle.
43
+ 5. Keep the existing TaskResult and OffloadPool mechanisms in Engine. This
44
+ step adds no execution manager or application registration requirement.
45
+
46
+ ## Consequences and limits
47
+
48
+ The Capability directory now directly names its existing Engine dependencies
49
+ instead of an Agent-owned wrapper. The code-level algorithm and file-level
50
+ dependency graph are preserved when the moved file is matched to its source.
51
+ Directory placement changes do not imply that all larger dependency cycles
52
+ have been resolved.
53
+
54
+ Applications should use the public Tool authoring and invocation contracts.
55
+ Code or tests that directly reference the removed private Agent::ToolExecutor
56
+ constant need to follow its new internal name. The public Tool API and durable
57
+ formats require no migration, and the Context contract regrouping remains a
58
+ separate change.
59
+
60
+ ## Verification obligations
61
+
62
+ Verify cooperative execution, OffloadPool dispatch, cancellation propagation,
63
+ Runtime injection, custom `call_async`, and Agent-as-Tool. Keep the existing
64
+ offload-boundary observations aligned with the moved source path. The public
65
+ API snapshot, RBS and Tool class identity must remain unchanged; Zeitwerk must
66
+ load the new helper and leave the old internal constant absent.
67
+
68
+ The implementation delivery records its actual test results separately.