phronomy 0.27.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 (475) hide show
  1. checksums.yaml +4 -4
  2. data/.mutant.yml +9 -9
  3. data/CHANGELOG.md +52 -0
  4. data/CONTRIBUTING.md +8 -8
  5. data/README.md +9 -3
  6. data/benchmark/bench_agent_invoke.rb +25 -50
  7. data/benchmark/bench_context_assembler.rb +14 -11
  8. data/benchmark/bench_regression.rb +1 -1
  9. data/benchmark/bench_tool_schema.rb +1 -1
  10. data/docs/architecture/agent-chat-and-state-ownership.md +7 -1
  11. data/docs/architecture/agent-transition-ownership.md +13 -89
  12. data/docs/architecture/backend-groups.md +152 -0
  13. data/docs/architecture/before-llm-input.md +3 -3
  14. data/docs/architecture/context-management.md +1 -1
  15. data/docs/architecture/execution-abstraction-review.md +88 -0
  16. data/docs/architecture/execution-boundaries.md +28 -0
  17. data/docs/architecture/execution-metadata-and-values.md +6 -0
  18. data/docs/architecture/multi-agent-handoff.md +6 -5
  19. data/docs/architecture/persistence.md +27 -9
  20. data/docs/architecture/r8-unit1.md +104 -0
  21. data/docs/architecture/r8-unit10.md +72 -0
  22. data/docs/architecture/r8-unit11.md +71 -0
  23. data/docs/architecture/r8-unit12.md +67 -0
  24. data/docs/architecture/r8-unit13.md +61 -0
  25. data/docs/architecture/r8-unit14.md +72 -0
  26. data/docs/architecture/r8-unit15.md +65 -0
  27. data/docs/architecture/r8-unit16.md +54 -0
  28. data/docs/architecture/r8-unit17.md +73 -0
  29. data/docs/architecture/r8-unit18.md +92 -0
  30. data/docs/architecture/r8-unit19.md +61 -0
  31. data/docs/architecture/r8-unit2.md +55 -0
  32. data/docs/architecture/r8-unit20.md +51 -0
  33. data/docs/architecture/r8-unit21.md +79 -0
  34. data/docs/architecture/r8-unit22.md +74 -0
  35. data/docs/architecture/r8-unit23.md +81 -0
  36. data/docs/architecture/r8-unit3.md +130 -0
  37. data/docs/architecture/r8-unit4.md +79 -0
  38. data/docs/architecture/r8-unit5.md +115 -0
  39. data/docs/architecture/r8-unit6.md +71 -0
  40. data/docs/architecture/r8-unit7.md +70 -0
  41. data/docs/architecture/r8-unit8.md +78 -0
  42. data/docs/architecture/r8-unit9.md +73 -0
  43. data/docs/architecture/refactoring-closure.md +10 -1
  44. data/docs/architecture/remaining-refactoring-plan.md +16 -0
  45. data/docs/architecture/storage-execution-boundaries.md +54 -0
  46. data/docs/architecture/tool-schema-recording-gap.md +6 -0
  47. data/docs/architecture/tracing.md +1 -1
  48. data/docs/architecture/workflow-terminal-ownership-design.md +2 -2
  49. data/docs/architecture.md +24 -11
  50. data/docs/decisions/015-tool-public-facade-and-rbs-boundary.md +3 -3
  51. data/docs/decisions/027-llm-adapter-provider-boundary.md +2 -0
  52. data/docs/decisions/030-agent-handoff-domain-and-durable-responsibility.md +2 -0
  53. data/docs/decisions/031-durable-multi-agent-coordination.md +2 -0
  54. data/docs/decisions/032-storage-backend-composition.md +5 -0
  55. data/docs/decisions/034-handoff-runner-coordination-ownership.md +2 -0
  56. data/docs/decisions/035-tool-executor-capability-ownership.md +1 -1
  57. data/docs/decisions/038-responsibility-based-source-layout.md +14 -0
  58. data/docs/decisions/039-runtime-configuration-lifecycle-ownership.md +8 -0
  59. data/docs/decisions/040-configuration-default-composition.md +12 -1
  60. data/docs/decisions/045-worker-input-restriction-ownership.md +4 -0
  61. data/docs/decisions/051-execution-outcome-worker-ownership.md +2 -0
  62. data/docs/decisions/056-workflow-terminal-policy-ownership.md +1 -1
  63. data/docs/decisions/058-neutral-storage-primitives.md +5 -0
  64. data/docs/decisions/059-backend-contracts-and-async-clients.md +74 -0
  65. data/docs/decisions/060-runtime-settings-and-application-configuration.md +86 -0
  66. data/docs/decisions/061-persistence-failure-contracts.md +89 -0
  67. data/docs/decisions/062-content-store-service.md +52 -0
  68. data/docs/decisions/063-execution-contracts-and-services.md +88 -0
  69. data/docs/decisions/064-agent-execution-and-multi-agent-responsibility.md +36 -0
  70. data/docs/decisions/065-vector-and-embeddings-common-operations.md +38 -0
  71. data/docs/decisions/066-llm-and-tool-operation-contracts.md +20 -0
  72. data/docs/decisions/067-agent-progress-and-engine-connection.md +29 -0
  73. data/docs/decisions/068-agent-tool-child-progress-and-tool-operation.md +36 -0
  74. data/docs/decisions/README.md +18 -1
  75. data/docs/execution-boundaries-preview.md +45 -0
  76. data/docs/features.md +8 -3
  77. data/docs/getting-started.md +9 -6
  78. data/docs/migrations/0.22.md +2 -2
  79. data/docs/migrations/durable-semantic-coordination-v2.md +2 -0
  80. data/docs/migrations/handoff-runner-multi-agent.md +2 -0
  81. data/docs/migrations/persistence-failure-contracts.md +67 -0
  82. data/docs/migrations/r8-unit10.md +36 -0
  83. data/docs/migrations/r8-unit11.md +33 -0
  84. data/docs/migrations/r8-unit12.md +31 -0
  85. data/docs/migrations/r8-unit13.md +36 -0
  86. data/docs/migrations/r8-unit14.md +31 -0
  87. data/docs/migrations/r8-unit15.md +31 -0
  88. data/docs/migrations/r8-unit16.md +26 -0
  89. data/docs/migrations/r8-unit17.md +28 -0
  90. data/docs/migrations/r8-unit18.md +29 -0
  91. data/docs/migrations/r8-unit19.md +28 -0
  92. data/docs/migrations/r8-unit20.md +24 -0
  93. data/docs/migrations/r8-unit21.md +28 -0
  94. data/docs/migrations/r8-unit22.md +29 -0
  95. data/docs/migrations/r8-unit23.md +20 -0
  96. data/docs/migrations/r8-unit4.md +67 -0
  97. data/docs/migrations/r8-unit5.md +75 -0
  98. data/docs/migrations/r8-unit6.md +109 -0
  99. data/docs/migrations/r8-unit7.md +31 -0
  100. data/docs/migrations/r8-unit8.md +33 -0
  101. data/docs/migrations/r8-unit9.md +28 -0
  102. data/docs/migrations/storage-async-client.md +103 -0
  103. data/docs/migrations/vector-async-clients.md +110 -0
  104. data/docs/persistence-backends.md +38 -21
  105. data/docs/runtime-and-concurrency.md +26 -1
  106. data/lib/phronomy/agent/admission.rb +78 -0
  107. data/lib/phronomy/agent/{lifecycle_contract/agent_already_exists_error.rb → agent_already_exists_error.rb} +1 -1
  108. data/lib/phronomy/agent/{lifecycle_contract/agent_busy_error.rb → agent_busy_error.rb} +1 -1
  109. data/lib/phronomy/agent/{lifecycle_contract/agent_purged_error.rb → agent_purged_error.rb} +1 -1
  110. data/lib/phronomy/{recovery → agent/api}/execution_rehydration_required_error.rb +1 -1
  111. data/lib/phronomy/agent/async_event_api.rb +37 -32
  112. data/lib/phronomy/agent/base.rb +74 -72
  113. data/lib/phronomy/agent/before_llm_input.rb +64 -0
  114. data/lib/phronomy/agent/composition/run_once.rb +1 -1
  115. data/lib/phronomy/agent/{context_assembly/context_candidate_resolver.rb → context_candidate_resolver.rb} +2 -2
  116. data/lib/phronomy/agent/{context_assembly/context_assembler.rb → context_preparation.rb} +35 -221
  117. data/lib/phronomy/agent/control_request.rb +21 -0
  118. data/lib/phronomy/agent/execution/agent_execution.rb +1 -1
  119. data/lib/phronomy/agent/execution/agent_invocation.rb +27 -53
  120. data/lib/phronomy/agent/execution/approval_resume_commit.rb +1 -1
  121. data/lib/phronomy/agent/execution/dispatch_preparation.rb +17 -127
  122. data/lib/phronomy/agent/execution/exact_execution.rb +44 -23
  123. data/lib/phronomy/agent/execution/execution_cancellation.rb +8 -4
  124. data/lib/phronomy/agent/execution/execution_coordinator.rb +214 -395
  125. data/lib/phronomy/agent/execution/execution_metadata.rb +1 -0
  126. data/lib/phronomy/agent/execution/execution_outcome_committer.rb +70 -126
  127. data/lib/phronomy/agent/execution/execution_registry.rb +6 -2
  128. data/lib/phronomy/agent/execution/execution_session_runner.rb +22 -27
  129. data/lib/phronomy/agent/execution/initial_preparation.rb +18 -116
  130. data/lib/phronomy/agent/execution/{agent_invocation_session_builder.rb → invocation_actions.rb} +54 -194
  131. data/lib/phronomy/agent/execution/invocation_transitions.rb +39 -1
  132. data/lib/phronomy/agent/execution/runtime_record_encoder.rb +7 -7
  133. data/lib/phronomy/agent/execution_change.rb +161 -0
  134. data/lib/phronomy/agent/execution_environment.rb +36 -0
  135. data/lib/phronomy/agent/execution_extension_state.rb +21 -0
  136. data/lib/phronomy/agent/execution_observation.rb +35 -0
  137. data/lib/phronomy/agent/filterable.rb +182 -0
  138. data/lib/phronomy/agent/handoff/{handoff_context.rb → transfer_context.rb} +4 -4
  139. data/lib/phronomy/agent/handoff/{handoff_projection.rb → transfer_projection.rb} +14 -33
  140. data/lib/phronomy/{llm_contract/transport_error.rb → agent/handoff_error.rb} +1 -1
  141. data/lib/phronomy/agent/journal/journal_projection.rb +1 -1
  142. data/lib/phronomy/agent/knowledge_item.rb +13 -0
  143. data/lib/phronomy/agent/lifecycle/agent_root.rb +1 -1
  144. data/lib/phronomy/agent/lifecycle/ownership_registry.rb +18 -23
  145. data/lib/phronomy/agent/persistence/agent_repository.rb +29 -21
  146. data/lib/phronomy/agent/persistence/cancellation_repository.rb +51 -0
  147. data/lib/phronomy/agent/persistence/codec.rb +1 -21
  148. data/lib/phronomy/agent/persistence/execution_repository.rb +57 -41
  149. data/lib/phronomy/agent/persistence/journal_repository.rb +27 -18
  150. data/lib/phronomy/agent/persistence/records.rb +33 -0
  151. data/lib/phronomy/agent/persistence/retention_repository.rb +70 -0
  152. data/lib/phronomy/agent/persistence/storage_schema.rb +7 -2
  153. data/lib/phronomy/agent/persistence/watermark.rb +13 -11
  154. data/lib/phronomy/agent/recovery/invocation_restorer.rb +13 -21
  155. data/lib/phronomy/agent/recovery/recovery_coordinator/continuation.rb +10 -9
  156. data/lib/phronomy/agent/recovery/recovery_coordinator/installation.rb +27 -27
  157. data/lib/phronomy/agent/recovery/recovery_coordinator/resolution.rb +19 -21
  158. data/lib/phronomy/agent/recovery/recovery_coordinator.rb +23 -16
  159. data/lib/phronomy/agent/recovery/recovery_rules.rb +119 -0
  160. data/lib/phronomy/agent/recovery/recovery_support.rb +8 -11
  161. data/lib/phronomy/agent/reserved_execution.rb +16 -0
  162. data/lib/phronomy/agent/retention.rb +17 -0
  163. data/lib/phronomy/agent/runtime_binding/engine_environment.rb +60 -0
  164. data/lib/phronomy/agent/runtime_binding/engine_session_builder.rb +34 -0
  165. data/lib/phronomy/agent/runtime_binding/phase_machine_builder.rb +64 -0
  166. data/lib/phronomy/agent/runtime_binding/tool_session_builder.rb +34 -0
  167. data/lib/phronomy/agent/{context_assembly/ruby_llm_materializer.rb → runtime_input.rb} +18 -35
  168. data/lib/phronomy/agent/{context_assembly/saved_context_reader.rb → saved_context_reader.rb} +6 -4
  169. data/lib/phronomy/agent/settings.rb +47 -0
  170. data/lib/phronomy/agent/{context_assembly/state_writer.rb → state_writer.rb} +4 -3
  171. data/lib/phronomy/agent/store.rb +253 -0
  172. data/lib/phronomy/agent/{lifecycle_contract/stream_callback_error.rb → stream_callback_error.rb} +1 -1
  173. data/lib/phronomy/agent/tool_execution/tool_binding.rb +4 -64
  174. data/lib/phronomy/agent/tool_execution/tool_invocation.rb +50 -219
  175. data/lib/phronomy/agent/tool_execution/tool_invocation_actions.rb +107 -0
  176. data/lib/phronomy/agent/tool_execution/tool_invocation_transitions.rb +70 -0
  177. data/lib/phronomy/configuration/runtime_settings.rb +49 -0
  178. data/lib/phronomy/content_store/storage_schema.rb +1 -0
  179. data/lib/phronomy/content_store/stored_contents.rb +2 -1
  180. data/lib/phronomy/context/assembly.rb +202 -0
  181. data/lib/phronomy/{llm_contract/context_budget_exceeded_error.rb → context/budget_exceeded_error.rb} +3 -1
  182. data/lib/phronomy/context/candidate.rb +51 -0
  183. data/lib/phronomy/context/constraint.rb +47 -0
  184. data/lib/phronomy/{agent/context_contract → context}/context_plan.rb +1 -1
  185. data/lib/phronomy/{agent/context_contract → context}/context_plan_validator.rb +3 -3
  186. data/lib/phronomy/{agent/context_contract → context}/context_policy.rb +1 -1
  187. data/lib/phronomy/{agent/context_contract → context}/context_policy_input.rb +1 -1
  188. data/lib/phronomy/{agent/context_assembly → context}/context_policy_input_builder.rb +1 -1
  189. data/lib/phronomy/context/default_policy.rb +140 -0
  190. data/lib/phronomy/context/final_budget_validator.rb +33 -0
  191. data/lib/phronomy/{agent/context_contract → context}/llm_input_build_context.rb +1 -1
  192. data/lib/phronomy/{agent/context_contract → context}/llm_input_manifest.rb +19 -19
  193. data/lib/phronomy/{agent/context_contract → context}/llm_input_patch.rb +1 -1
  194. data/lib/phronomy/context/manifest_error.rb +10 -0
  195. data/lib/phronomy/context/prompt_template.rb +98 -0
  196. data/lib/phronomy/{vector_store → documents}/loader/base.rb +1 -1
  197. data/lib/phronomy/{vector_store → documents}/loader/csv_loader.rb +2 -2
  198. data/lib/phronomy/{vector_store → documents}/loader/markdown_loader.rb +3 -3
  199. data/lib/phronomy/{vector_store → documents}/loader/plain_text_loader.rb +2 -2
  200. data/lib/phronomy/{vector_store → documents}/splitter/base.rb +1 -1
  201. data/lib/phronomy/{vector_store → documents}/splitter/fixed_size_splitter.rb +2 -2
  202. data/lib/phronomy/{vector_store → documents}/splitter/recursive_splitter.rb +2 -2
  203. data/lib/phronomy/embeddings/async/async_client.rb +44 -0
  204. data/lib/phronomy/embeddings/backends/ruby_llm_embeddings.rb +48 -0
  205. data/lib/phronomy/embeddings/base.rb +43 -0
  206. data/lib/phronomy/embeddings/invalid_result_error.rb +11 -0
  207. data/lib/phronomy/embeddings/transport_error.rb +11 -0
  208. data/lib/phronomy/engine/concurrency/offload_pool.rb +36 -21
  209. data/lib/phronomy/engine/concurrency/pool_registry.rb +47 -12
  210. data/lib/phronomy/engine/diagnostics.rb +1 -1
  211. data/lib/phronomy/engine/event_loop.rb +7 -7
  212. data/lib/phronomy/engine/execution_binding.rb +23 -0
  213. data/lib/phronomy/engine/execution_receiver_binding.rb +43 -0
  214. data/lib/phronomy/engine/fsm_protocol.rb +1 -6
  215. data/lib/phronomy/engine/fsm_session.rb +3 -3
  216. data/lib/phronomy/engine/metrics.rb +16 -14
  217. data/lib/phronomy/engine/runtime/timer_queue.rb +1 -1
  218. data/lib/phronomy/engine/runtime.rb +25 -12
  219. data/lib/phronomy/engine/terminal_decision.rb +7 -0
  220. data/lib/phronomy/execution/async_operation.rb +41 -0
  221. data/lib/phronomy/{engine → execution}/blocking.rb +2 -2
  222. data/lib/phronomy/{engine → execution}/concurrency/cancellation_token.rb +1 -1
  223. data/lib/phronomy/{engine → execution}/concurrency/deadline.rb +0 -17
  224. data/lib/phronomy/{engine → execution}/concurrency/physical_completion_task.rb +1 -1
  225. data/lib/phronomy/{engine → execution}/concurrency/result_collector.rb +1 -1
  226. data/lib/phronomy/{engine → execution}/concurrency/result_composition.rb +33 -12
  227. data/lib/phronomy/{engine/concurrency/subscriptions.rb → execution/concurrency/result_subscriptions.rb} +14 -18
  228. data/lib/phronomy/execution/concurrency/subscriptions.rb +25 -0
  229. data/lib/phronomy/{engine → execution}/execution.rb +61 -27
  230. data/lib/phronomy/execution/execution_receiver.rb +78 -0
  231. data/lib/phronomy/execution/execution_scope_state.rb +35 -0
  232. data/lib/phronomy/{engine → execution}/invocation_context.rb +0 -15
  233. data/lib/phronomy/execution/invocation_controls.rb +73 -0
  234. data/lib/phronomy/execution/runnable.rb +24 -0
  235. data/lib/phronomy/{engine → execution}/task_result.rb +3 -3
  236. data/lib/phronomy/execution/wait_policy.rb +24 -0
  237. data/lib/phronomy/filter/{contract/filter_block_error.rb → filter_block_error.rb} +1 -1
  238. data/lib/phronomy/generation/generator_verifier/agent_operation.rb +65 -0
  239. data/lib/phronomy/generation/generator_verifier/default_parser.rb +27 -0
  240. data/lib/phronomy/generation/generator_verifier/workflow_builder.rb +2 -2
  241. data/lib/phronomy/generation/generator_verifier.rb +7 -7
  242. data/lib/phronomy/llm_adapter/async/async_client.rb +47 -0
  243. data/lib/phronomy/{llm_contract → llm_adapter}/authentication_error.rb +3 -1
  244. data/lib/phronomy/llm_adapter/backends/ruby_llm.rb +183 -0
  245. data/lib/phronomy/llm_adapter/base.rb +49 -68
  246. data/lib/phronomy/{llm_contract → llm_adapter}/context_length_error.rb +3 -1
  247. data/lib/phronomy/llm_adapter/invalid_result_error.rb +10 -0
  248. data/lib/phronomy/llm_adapter/message.rb +62 -0
  249. data/lib/phronomy/{llm_contract → llm_adapter}/rate_limit_error.rb +3 -1
  250. data/lib/phronomy/llm_adapter/request.rb +79 -0
  251. data/lib/phronomy/llm_adapter/response.rb +36 -0
  252. data/lib/phronomy/llm_adapter/stream_chunk.rb +18 -0
  253. data/lib/phronomy/llm_adapter/token_usage.rb +64 -0
  254. data/lib/phronomy/llm_adapter/transport_error.rb +9 -0
  255. data/lib/phronomy/llm_adapter.rb +3 -16
  256. data/lib/phronomy/multi_agent/admission_registry.rb +1 -8
  257. data/lib/phronomy/multi_agent/durable_subagent_coordinator.rb +108 -84
  258. data/lib/phronomy/multi_agent/execution_environment.rb +29 -0
  259. data/lib/phronomy/{agent/handoff → multi_agent}/handoff.rb +2 -2
  260. data/lib/phronomy/{agent/handoff → multi_agent}/handoff_capability_factory.rb +21 -2
  261. data/lib/phronomy/multi_agent/handoff_participant.rb +79 -0
  262. data/lib/phronomy/{agent/handoff → multi_agent}/handoff_policy.rb +1 -1
  263. data/lib/phronomy/multi_agent/handoff_runner.rb +77 -100
  264. data/lib/phronomy/{agent/handoff → multi_agent}/handoff_state.rb +1 -1
  265. data/lib/phronomy/multi_agent/orchestrator.rb +61 -75
  266. data/lib/phronomy/multi_agent/persistence/codec.rb +20 -0
  267. data/lib/phronomy/multi_agent/persistence/handoff_state_repository.rb +77 -0
  268. data/lib/phronomy/multi_agent/persistence/records.rb +27 -0
  269. data/lib/phronomy/multi_agent/persistence/storage_schema.rb +21 -0
  270. data/lib/phronomy/multi_agent/persistence/team_execution_repository.rb +58 -42
  271. data/lib/phronomy/multi_agent/persistence/team_repository.rb +29 -21
  272. data/lib/phronomy/multi_agent/reserved_child_admission.rb +88 -0
  273. data/lib/phronomy/multi_agent/runtime_binding/engine_environment.rb +35 -0
  274. data/lib/phronomy/multi_agent/shared_state.rb +2 -2
  275. data/lib/phronomy/multi_agent/store.rb +156 -0
  276. data/lib/phronomy/multi_agent/team_coordinator.rb +83 -74
  277. data/lib/phronomy/multi_agent/team_ownership_registry.rb +2 -12
  278. data/lib/phronomy/output_parser/parse_error.rb +7 -0
  279. data/lib/phronomy/persistence/content_repository.rb +26 -0
  280. data/lib/phronomy/persistence/errors.rb +16 -0
  281. data/lib/phronomy/persistence/migration/initial_format_migration.rb +2 -2
  282. data/lib/phronomy/persistence/persistence.rb +23 -0
  283. data/lib/phronomy/persistence/save_outcome.rb +24 -0
  284. data/lib/phronomy/persistence/snapshot_comparison.rb +81 -0
  285. data/lib/phronomy/persistence/storage_boundary.rb +32 -0
  286. data/lib/phronomy/persistence/transaction.rb +86 -0
  287. data/lib/phronomy/persistence_composition/storage_schema.rb +9 -4
  288. data/lib/phronomy/persistence_composition/stores.rb +34 -0
  289. data/lib/phronomy/persistence_composition/unit4_migration.rb +276 -0
  290. data/lib/phronomy/runtime_composition/agent_defaults.rb +5 -1
  291. data/lib/phronomy/runtime_composition/configuration.rb +146 -0
  292. data/lib/phronomy/runtime_composition/evaluation_defaults.rb +7 -0
  293. data/lib/phronomy/runtime_composition/execution_defaults.rb +5 -0
  294. data/lib/phronomy/runtime_composition/generation_defaults.rb +6 -0
  295. data/lib/phronomy/runtime_composition/global_configuration.rb +38 -0
  296. data/lib/phronomy/runtime_composition/multi_agent_defaults.rb +9 -0
  297. data/lib/phronomy/runtime_composition/workflow_defaults.rb +4 -0
  298. data/lib/phronomy/storage/async/async_client.rb +60 -0
  299. data/lib/phronomy/storage/backend.rb +8 -2
  300. data/lib/phronomy/testing/eval/metrics.rb +1 -1
  301. data/lib/phronomy/testing/eval/scorer/llm_judge.rb +19 -3
  302. data/lib/phronomy/testing/persistence_contract/a_content_store.rb +2 -2
  303. data/lib/phronomy/testing/persistence_contract/a_journal_repository.rb +6 -6
  304. data/lib/phronomy/testing/persistence_contract/a_persistence_backend.rb +55 -52
  305. data/lib/phronomy/testing/persistence_contract/a_workflow_state_repository.rb +3 -3
  306. data/lib/phronomy/testing/persistence_contract/an_agent_repository.rb +7 -7
  307. data/lib/phronomy/testing/persistence_contract/an_execution_repository.rb +11 -11
  308. data/lib/phronomy/testing/persistence_contract/coordination_repositories.rb +57 -51
  309. data/lib/phronomy/testing/persistence_contract/neutral_storage_primitives.rb +1 -1
  310. data/lib/phronomy/testing/persistence_contract/storage_transaction_boundaries.rb +23 -22
  311. data/lib/phronomy/tool/authorization.rb +77 -0
  312. data/lib/phronomy/tool/base.rb +549 -9
  313. data/lib/phronomy/tool/call_request.rb +40 -0
  314. data/lib/phronomy/{agent/tool_execution/tool_definition_set.rb → tool/definition_set.rb} +7 -8
  315. data/lib/phronomy/tool/operation.rb +88 -0
  316. data/lib/phronomy/tool/schema.rb +214 -0
  317. data/lib/phronomy/tool/settings.rb +31 -0
  318. data/lib/phronomy/tool/tool_error.rb +7 -0
  319. data/lib/phronomy/tool/tool_executor.rb +58 -0
  320. data/lib/phronomy/tools/agent.rb +22 -90
  321. data/lib/phronomy/tools/mcp.rb +21 -14
  322. data/lib/phronomy/tools/vector_search.rb +4 -4
  323. data/lib/phronomy/tracing/automatic.rb +11 -6
  324. data/lib/phronomy/tracing/base.rb +1 -1
  325. data/lib/phronomy/tracing/observation.rb +37 -0
  326. data/lib/phronomy/tracing/settings.rb +36 -0
  327. data/lib/phronomy/vector_store/{async_backend.rb → async/async_client.rb} +35 -29
  328. data/lib/phronomy/vector_store/{in_memory.rb → backends/in_memory.rb} +12 -10
  329. data/lib/phronomy/vector_store/{pgvector.rb → backends/pgvector.rb} +44 -16
  330. data/lib/phronomy/vector_store/{redis_search.rb → backends/redis_search.rb} +74 -37
  331. data/lib/phronomy/vector_store/base.rb +118 -49
  332. data/lib/phronomy/vector_store/invalid_result_error.rb +12 -0
  333. data/lib/phronomy/vector_store.rb +2 -17
  334. data/lib/phronomy/version.rb +1 -1
  335. data/lib/phronomy/workflow/completion.rb +11 -0
  336. data/lib/phronomy/workflow/execution/workflow.rb +7 -7
  337. data/lib/phronomy/workflow/execution/workflow_action_rules.rb +67 -0
  338. data/lib/phronomy/workflow/execution/workflow_context.rb +2 -2
  339. data/lib/phronomy/workflow/execution/workflow_execution_environment.rb +27 -0
  340. data/lib/phronomy/workflow/execution/workflow_execution_registry.rb +3 -5
  341. data/lib/phronomy/workflow/execution/workflow_runner.rb +58 -79
  342. data/lib/phronomy/workflow/execution/workflow_settings.rb +28 -0
  343. data/lib/phronomy/workflow/persistence/state_repository.rb +28 -22
  344. data/lib/phronomy/workflow/persistence/storage_schema.rb +13 -0
  345. data/lib/phronomy/workflow/runtime_binding/workflow_engine_environment.rb +38 -0
  346. data/lib/phronomy/workflow/runtime_binding/workflow_phase_machine_builder.rb +156 -0
  347. data/lib/phronomy/workflow/{execution → runtime_binding}/workflow_terminal_policy.rb +4 -4
  348. data/lib/phronomy.rb +57 -16
  349. data/scripts/api_snapshot.rb +35 -15
  350. data/sig/_private/phronomy/agent/settings.rbs +19 -0
  351. data/sig/_private/phronomy/configuration/runtime_settings.rbs +20 -0
  352. data/sig/_private/phronomy/llm_adapter/async/async_client.rbs +10 -0
  353. data/sig/_private/phronomy/multi_agent/store.rbs +8 -0
  354. data/sig/_private/phronomy/persistence/storage_boundary.rbs +7 -0
  355. data/sig/_private/phronomy/tool/settings.rbs +13 -0
  356. data/sig/_private/phronomy/tracing/settings.rbs +15 -0
  357. data/sig/_private/phronomy/workflow/execution/workflow_settings.rbs +13 -0
  358. data/sig/phronomy/agent/admission.rbs +19 -0
  359. data/sig/phronomy/agent/execution_contract.rbs +132 -0
  360. data/sig/phronomy/agent/execution_environment.rbs +20 -0
  361. data/sig/phronomy/agent/store.rbs +73 -0
  362. data/sig/phronomy/agent.rbs +14 -138
  363. data/sig/phronomy/common.rbs +7 -0
  364. data/sig/phronomy/content_store/contracts.rbs +13 -0
  365. data/sig/phronomy/context.rbs +152 -0
  366. data/sig/phronomy/embeddings/async/async_client.rbs +9 -0
  367. data/sig/phronomy/embeddings/base.rbs +17 -0
  368. data/sig/phronomy/engine/concurrency/timer_bindings.rbs +22 -0
  369. data/sig/phronomy/engine/control_bindings.rbs +11 -0
  370. data/sig/phronomy/engine/control_protocols.rbs +23 -0
  371. data/sig/phronomy/engine/execution_binding.rbs +6 -0
  372. data/sig/phronomy/engine/execution_receiver.rbs +15 -0
  373. data/sig/phronomy/engine/observability.rbs +13 -0
  374. data/sig/phronomy/execution/async_operation.rbs +7 -0
  375. data/sig/phronomy/execution/blocking.rbs +5 -0
  376. data/sig/phronomy/execution/concurrency/cancellation_token.rbs +13 -0
  377. data/sig/phronomy/execution/concurrency/deadline.rbs +10 -0
  378. data/sig/phronomy/execution/concurrency/result_composition.rbs +7 -0
  379. data/sig/phronomy/execution/control_protocols.rbs +18 -0
  380. data/sig/phronomy/execution/errors.rbs +7 -0
  381. data/sig/phronomy/execution/execution.rbs +41 -0
  382. data/sig/phronomy/execution/execution_receiver.rbs +40 -0
  383. data/sig/phronomy/execution/execution_scope_state.rbs +9 -0
  384. data/sig/phronomy/execution/invocation_context.rbs +18 -0
  385. data/sig/phronomy/execution/invocation_controls.rbs +13 -0
  386. data/sig/phronomy/execution/task_result.rbs +29 -0
  387. data/sig/phronomy/extensions.rbs +0 -21
  388. data/sig/phronomy/handoff.rbs +10 -4
  389. data/sig/phronomy/llm_adapter/backends/ruby_llm.rbs +6 -0
  390. data/sig/phronomy/llm_adapter/base.rbs +14 -0
  391. data/sig/phronomy/llm_adapter/usage.rbs +14 -0
  392. data/sig/phronomy/llm_adapter/values.rbs +43 -0
  393. data/sig/phronomy/llm_context_window.rbs +10 -0
  394. data/sig/phronomy/multi_agent/reserved_child_admission.rbs +8 -0
  395. data/sig/phronomy/multi_agent/store.rbs +54 -0
  396. data/sig/phronomy/multi_agent.rbs +6 -3
  397. data/sig/phronomy/persistence/errors.rbs +18 -0
  398. data/sig/phronomy/persistence/migration.rbs +13 -0
  399. data/sig/phronomy/persistence/transaction.rbs +19 -0
  400. data/sig/phronomy/persistence.rbs +1 -99
  401. data/sig/phronomy/persistence_composition.rbs +19 -0
  402. data/sig/phronomy/runtime_composition/configuration.rbs +36 -0
  403. data/sig/phronomy/storage/async/async_client.rbs +8 -0
  404. data/sig/phronomy/storage/backends/in_memory.rbs +9 -0
  405. data/sig/phronomy/{storage.rbs → storage/contracts.rbs} +2 -16
  406. data/sig/phronomy/tool.rbs +48 -4
  407. data/sig/phronomy/tracing/observation.rbs +7 -0
  408. data/sig/phronomy/vector_store/async/async_client.rbs +13 -0
  409. data/sig/phronomy/vector_store/base.rbs +23 -0
  410. data/sig/phronomy/workflow/execution/workflow_execution_environment.rbs +14 -0
  411. data/sig/phronomy/workflow/runtime_binding/workflow_terminal_policy.rbs +7 -0
  412. data/sig/phronomy/workflow/store.rbs +8 -0
  413. data/sig/phronomy/workflow.rbs +1 -1
  414. data/sig/phronomy.rbs +0 -49
  415. metadata +318 -117
  416. data/lib/phronomy/agent/concerns/before_llm_input.rb +0 -66
  417. data/lib/phronomy/agent/concerns/error_translation.rb +0 -45
  418. data/lib/phronomy/agent/concerns/filterable.rb +0 -184
  419. data/lib/phronomy/agent/context/capability/base.rb +0 -548
  420. data/lib/phronomy/agent/context/capability/tool_executor.rb +0 -62
  421. data/lib/phronomy/agent/context/instruction/prompt_template.rb +0 -102
  422. data/lib/phronomy/agent/context_assembly/runtime_chat_builder.rb +0 -36
  423. data/lib/phronomy/agent/context_assembly/token_budget_resolver.rb +0 -22
  424. data/lib/phronomy/agent/context_parts/validators/final_budget_validator.rb +0 -37
  425. data/lib/phronomy/agent/context_policies/default.rb +0 -142
  426. data/lib/phronomy/agent/execution/phase_machine_builder.rb +0 -101
  427. data/lib/phronomy/agent/execution/provider_call_outcome.rb +0 -106
  428. data/lib/phronomy/agent/handoff/handoff_execution_coordinator.rb +0 -15
  429. data/lib/phronomy/agent/handoff/handoff_outcome_committer.rb +0 -131
  430. data/lib/phronomy/agent/handoff/handoff_request.rb +0 -45
  431. data/lib/phronomy/agent/lifecycle_contract/handoff_error.rb +0 -7
  432. data/lib/phronomy/agent/persistence/handoff_state_repository.rb +0 -58
  433. data/lib/phronomy/agent/persistence/queries.rb +0 -61
  434. data/lib/phronomy/agent/selection/candidate.rb +0 -53
  435. data/lib/phronomy/agent/selection/constraint.rb +0 -49
  436. data/lib/phronomy/agent/tool_execution/tool_call_intercepted.rb +0 -29
  437. data/lib/phronomy/agent/tool_execution/tool_invocation_session_builder.rb +0 -276
  438. data/lib/phronomy/configuration/configuration.rb +0 -68
  439. data/lib/phronomy/configuration/global_configuration.rb +0 -26
  440. data/lib/phronomy/engine/concurrency/cancellation_scope.rb +0 -124
  441. data/lib/phronomy/engine/concurrency/operation_binding.rb +0 -43
  442. data/lib/phronomy/engine/execution_receiver.rb +0 -65
  443. data/lib/phronomy/engine/runnable.rb +0 -54
  444. data/lib/phronomy/llm_adapter/ruby_llm.rb +0 -47
  445. data/lib/phronomy/llm_contract/token_usage.rb +0 -85
  446. data/lib/phronomy/multi_agent/persistence/queries.rb +0 -30
  447. data/lib/phronomy/multi_agent/storage_contract/team_storage_schema.rb +0 -15
  448. data/lib/phronomy/output_parser/contract/parse_error.rb +0 -7
  449. data/lib/phronomy/persistence/api/persistence.rb +0 -140
  450. data/lib/phronomy/persistence_composition/repositories.rb +0 -77
  451. data/lib/phronomy/recovery/recovery.rb +0 -186
  452. data/lib/phronomy/tool/contract/tool_error.rb +0 -7
  453. data/lib/phronomy/vector_store/embeddings/base.rb +0 -44
  454. data/lib/phronomy/vector_store/embeddings/ruby_llm_embeddings.rb +0 -47
  455. data/lib/phronomy/workflow/phase_machine_builder.rb +0 -205
  456. data/lib/phronomy/workflow/storage_contract/workflow_storage_schema.rb +0 -9
  457. data/sig/phronomy/execution_receiver.rbs +0 -34
  458. data/sig/phronomy/llm_adapter.rbs +0 -11
  459. data/sig/phronomy/runtime.rbs +0 -76
  460. /data/lib/phronomy/agent/{context_assembly/context_importer.rb → context_importer.rb} +0 -0
  461. /data/lib/phronomy/{engine → execution}/backpressure_error.rb +0 -0
  462. /data/lib/phronomy/{engine → execution}/cancellation_error.rb +0 -0
  463. /data/lib/phronomy/{engine → execution}/concurrency/worker_input_restricted.rb +0 -0
  464. /data/lib/phronomy/{engine → execution}/event_loop_reentrancy_error.rb +0 -0
  465. /data/lib/phronomy/{engine → execution}/execution_cancellation_error.rb +0 -0
  466. /data/lib/phronomy/{engine → execution}/execution_timeout_error.rb +0 -0
  467. /data/lib/phronomy/{engine → execution}/invalid_async_entry_action_error.rb +0 -0
  468. /data/lib/phronomy/{engine → execution}/invalid_async_transition_action_error.rb +0 -0
  469. /data/lib/phronomy/{engine → execution}/invalid_async_workflow_action_error.rb +0 -0
  470. /data/lib/phronomy/{engine → execution}/pool_shutdown_error.rb +0 -0
  471. /data/lib/phronomy/{engine → execution}/recursion_limit_error.rb +0 -0
  472. /data/lib/phronomy/{engine → execution}/runtime_shutdown_error.rb +0 -0
  473. /data/lib/phronomy/{engine → execution}/runtime_shutdown_reentrancy_error.rb +0 -0
  474. /data/lib/phronomy/{engine → execution}/scheduler_reentrancy_error.rb +0 -0
  475. /data/lib/phronomy/{engine → execution}/timeout_error.rb +0 -0
@@ -0,0 +1,28 @@
1
+ # r8 unit17 migration
2
+
3
+ This core-only update requires no application or stored-data migration.
4
+ Continue using Phronomy.configure and the existing per-instance/per-invocation
5
+ options. Public names, defaults, policy validation, nil semantics, and explicit
6
+ option priority remain unchanged.
7
+
8
+ Agent and Workflow read their own option values instead of application
9
+ Configuration. MultiAgent uses its optional configured Store provider. Logging
10
+ uses RuntimeSettings. Authorization pool sizing moves into the execution
11
+ connection while Agent retains approval and timeout decisions.
12
+
13
+ There is no settings-change notification or automatic in-flight update. Existing
14
+ read timing is preserved, including scoped configuration restoration and reset.
15
+ Do not capture an internal settings object as a permanent replacement for the
16
+ current accessor, or depend on Configuration's private instance variables.
17
+
18
+ Private Agent ExecutionEnvironment implementations used by internal integrations
19
+ or tests must implement submit_authorization(timeout:, cancellation_token:, &block).
20
+ The default Engine connection submits the same authorization work with the same
21
+ pool name, resource defaults, overload behavior, and owning Runtime. Ordinary
22
+ Tool implementations and application code require no changes. Tests should set
23
+ configuration through its writers rather than intercepting an old facade getter.
24
+
25
+ Apply from unit16 commit `fb551e1a1a8334b2547ecad126dd9c152c1b0f8c` in a new
26
+ `refactor/r8-unit17` worktree using the package's checked applier. Follow the
27
+ existing shutdown/drain procedure when replacing running code. Examples remain
28
+ on their unit6 sources and are verified against this core through PHRONOMY_PATH.
@@ -0,0 +1,29 @@
1
+ # R8 unit18 migration
2
+
3
+ Apply to core at unit17 commit `26792401144118f03025952aa9ec849fb16b577f`.
4
+ No examples source changes, public API updates, schema migrations or data rewrites
5
+ are required. Existing cancellation records remain valid.
6
+
7
+ Exact-execution resume with a cancelled token now records the request in the
8
+ existing Agent ledger before continuing recovery/waiting. A recording failure is
9
+ returned to the caller. Unresolved children continue to require factual resolution
10
+ and the parent remains active; cancellation receipt does not claim completion.
11
+
12
+ Cancellation metadata on the execution and MultiAgent extension is a snapshot of
13
+ its last save. If cancellation is recorded after that save, the independent Agent
14
+ ledger preserves intent until the next recovery/change reflects it. Use the
15
+ existing Agent cancellation observation instead of assuming every stored
16
+ snapshot is immediately updated.
17
+
18
+ Keep the existing stop/drain procedure when replacing running processes. This
19
+ package does not establish new compatibility guarantees for workers already
20
+ running code from another version. Reverting this source change needs no data
21
+ rollback, but reintroduces the cancellation-loss race.
22
+
23
+ ## Delivery correction package
24
+
25
+ The unit18 cancellation-delivery correction applies on top of
26
+ `a89f42e3805fb548bf9587c49e1ab226efd174db`. It removes the gap between the
27
+ recording and notification decisions in `ExactExecution` delivery. The existing
28
+ preparation/delivery recheck, cancellation ledger and error behavior remain.
29
+ There are no additional API, schema or examples changes.
@@ -0,0 +1,28 @@
1
+ # R8 unit19 migration
2
+
3
+ Apply to core at unit18 delivery-correction commit
4
+ `a6f370d34e90ca274ec45a6b69ad1db9cb003707`.
5
+ No examples source change, data migration or public invocation API change is
6
+ required. Engine-private shutdown operations and their RBS declarations change.
7
+
8
+ Runtime shutdown now reports incomplete cleanup when workers remain alive. Check
9
+ cleanup_complete? before declaring resources released. reset_runtime! continues
10
+ to reject replacement after incomplete cleanup. Do not bypass that guard or
11
+ assume a cancelled TaskResult means its synchronous worker has stopped.
12
+
13
+ The existing Runtime stop-phase deadline, computed from cancel_grace with its
14
+ existing minimum grace, now also bounds pool joins. It is shared across EventLoop
15
+ and all pools; the previous additional 30 seconds per worker no longer applies
16
+ to Runtime shutdown. timeout still controls the preceding drain phase. Choose
17
+ grace appropriate to existing work, and configure native I/O timeouts where
18
+ needed. No Thread#raise or hard worker termination is added.
19
+
20
+ Shutdown remains terminal and returns its cached result on subsequent calls,
21
+ including an incomplete result. This change does not add retry or resume of the
22
+ shutdown procedure. Pool requests racing past the closed resource registry are
23
+ rejected with PoolShutdownError; new calls rejected earlier by Runtime retain
24
+ RuntimeShutdownError.
25
+
26
+ Use the existing controlled process-replacement procedure. Reverting the source
27
+ change needs no data rollback, but restores the resource leak and false-completion
28
+ risks. Metrics.snapshot behavior is unchanged in this unit (E03 is deferred).
@@ -0,0 +1,24 @@
1
+ # R8 unit20 migration
2
+
3
+ Apply to unit19 core commit `07b78c90ef6072f66fecb04ea6891eda50493546`.
4
+ No examples source change or data migration is required.
5
+
6
+ Metrics.snapshot, Diagnostics.snapshot and Diagnostics.dump keep their arguments,
7
+ metric keys, numeric values and output format. They no longer initialize execution
8
+ resources and remain usable while the default Runtime is stopping or stopped.
9
+
10
+ Before resource initialization, the corresponding values are zero. In particular,
11
+ offload_pool_size is zero until the default pool exists. Previously a snapshot
12
+ created the pool and reported its configured capacity. Do not use monitoring as
13
+ an implicit warmup. Normal execution still initializes the resources it needs.
14
+
15
+ For an existing pool, offload_pool_size remains its configured capacity after
16
+ shutdown; use the shutdown result to assess cleanup, not this metric. Retained
17
+ counters remain readable until default Runtime reset. After reset, observations
18
+ return zero until new resources are initialized. Named pools are not aggregated,
19
+ and simultaneous consistency across independently sampled counters is not added.
20
+
21
+ Unit19 stopping deadlines, completion judgment and cached-result behavior remain
22
+ unchanged. No public invocation API or persistence format changes. Reverting this
23
+ unit needs no data rollback but restores observation-triggered initialization and
24
+ shutdown-time diagnostic errors.
@@ -0,0 +1,28 @@
1
+ # r8 unit21 migration
2
+
3
+ This core-only responsibility refactor requires no application or stored-data
4
+ migration. Continue using Phronomy.configure with tool_result_max_size, tracer
5
+ and trace_pii, and the existing per-Tool max_result_size option. Public defaults,
6
+ nil semantics, read timing, truncation and redaction behavior remain unchanged.
7
+ Application-configured filter order and repetition remain unchanged too.
8
+
9
+ Tool and Tracing now obtain their settings through their own internal value
10
+ containers. Context::Assembly obtains its default tracer from Tracing while
11
+ retaining explicit injection and constructor-time selection. Composition still
12
+ selects concrete defaults and supplies current values; no manual per-operation
13
+ injection or settings-change subscription is required.
14
+
15
+ Internal tests or unsupported integrations constructing RuntimeSettings must
16
+ stop passing tracer: to its constructor or reading tracer, trace_pii and
17
+ tool_result_max_size from it. Ordinary application code should use the unchanged
18
+ public Configuration accessors. Its private instance variables and the new
19
+ domain settings containers are not an application extension API.
20
+
21
+ Apply from unit20 commit `bda5da03da5a4da33041953cf0eebaa32de7bb81` in a new
22
+ `refactor/r8-unit21` worktree using the package's checked applier. Verify the
23
+ expected tree before and after committing. Follow the existing shutdown/drain
24
+ procedure when replacing running code. Examples remain on their unit6 sources
25
+ and are verified against this core through PHRONOMY_PATH.
26
+
27
+ No data rollback is needed. Reverting this commit restores the earlier settings
28
+ ownership; it does not remove the unit19/20 Engine corrections.
@@ -0,0 +1,29 @@
1
+ # r8 unit22 migration
2
+
3
+ No application source or stored-data migration is required. Apply this core-only
4
+ package on unit21 commit `4525e71ca808acac9eb0302a59c32f00478a7782` and restart
5
+ using the application's existing drain/shutdown procedure.
6
+
7
+ - MCP public construction, execution, close, schema, authorization and result
8
+ formatting APIs are unchanged.
9
+ - A completed MCP call no longer retains a cancellation callback on a shared
10
+ caller token. A callback already taken by concurrent cancel! may still finish.
11
+ - Logical timeout does not end the SDK invocation's cancellation bridge. The
12
+ registration is released when that invocation exits.
13
+ - If Runtime rejects transport cleanup because it has stopped, the MCP caller
14
+ performs the existing synchronous close fallback and still receives the MCP
15
+ cancellation outcome. This can include the transport's normal close latency.
16
+ - Warning logging uses the same configured logger through neutral settings,
17
+ with stderr fallback when no logger is configured.
18
+
19
+ Execution, Engine and Contract source are unchanged. There are no new threads,
20
+ configuration options, timers or notification services. The existing MCP
21
+ cleanup pool remains in use while Runtime accepts work.
22
+
23
+ Custom tests that expected cancellation to reach an already-completed MCP call
24
+ should instead cancel while the SDK call is active and verify that completed
25
+ calls release their registrations. The SDK cancellation bridge helper is
26
+ private; its new subscriptions keyword is not a public application API.
27
+
28
+ Examples retain their unit6 source. Verify them against this core checkout using
29
+ PHRONOMY_PATH and restore only verification-generated lockfiles/artifacts.
@@ -0,0 +1,20 @@
1
+ # r8 unit23 migration
2
+
3
+ This is a core-only responsibility refactor on applied unit22.
4
+
5
+ - `Tools::Agent.from_agent`, synchronous `execute`, asynchronous `call_async`
6
+ and the public `Agent.run_once` API retain their signatures and behavior.
7
+ - Agent Tool calls still create a fresh Agent and ephemeral store. Configured
8
+ application stores do not replace this per-call store.
9
+ - `Testing::Eval::Scorer::LlmJudge` retains its constructor and scoring API.
10
+ Configure `llm_adapter` through the existing application configuration API.
11
+ - LlmJudge reads the default adapter for each score, after preparing its Request.
12
+ Existing scoped configuration and reset behavior are retained.
13
+ - The client factory is an internal boot binding. Applications do not need to
14
+ register it or adopt a new factory API.
15
+ - No Contract, Execution, Engine, RBS, data schema or stored-record migration is
16
+ required. Examples require verification only, with no source changes.
17
+
18
+ Use the package README to check the exact base commit, apply complete files,
19
+ verify the resulting tree, run the validation commands and commit the result.
20
+ Normal application loading remains `require "phronomy"`.
@@ -0,0 +1,67 @@
1
+ # r8 unit 4 migration
2
+
3
+ Update core and examples together. This is a refactoring-branch breaking change;
4
+ there are no compatibility aliases or automatic old-record loaders.
5
+
6
+ | Unit 3 | Unit 4 |
7
+ |---|---|
8
+ | `Agent::Handoff`, `Agent::HandoffPolicy` | `MultiAgent::Handoff`, `MultiAgent::HandoffPolicy` |
9
+ | `stores.team`, `config.team_store` | `stores.multi_agent`, `config.multi_agent_store` |
10
+ | HandoffRunner infers an Agent store | `HandoffRunner.new(main_agent:, handoffs:, persistence: stores.multi_agent)` |
11
+ | Orchestrator receives only Agent persistence | `Orchestrator.create(persistence: stores.agent, coordination_store: stores.multi_agent)`; pass both on `load` |
12
+ | Internal ExactExecution/metadata access by coordination | Agent reserved start, resume, cancellation and observation operations |
13
+ | AgentExecution / HandoffState envelope `0.1` | Envelope `0.2`; explicit offline conversion required |
14
+ | `coordination`, `multi_agent_coordination_ref`, Handoff result fields | immutable `reservation`, versioned `execution_extension`, `transfer_receipt` |
15
+
16
+ Construct one `PersistenceComposition.build(backend:)` and use its domain stores.
17
+ Ordinary Agents continue to use `persistence: stores.agent`. For custom
18
+ participants, follow `ExecutionChange`'s RBS contract and the
19
+ [transaction sequence](../architecture/r8-unit4.md). Do not serialize participant
20
+ objects, callbacks or live Agent references.
21
+
22
+ ## Offline SQL conversion
23
+
24
+ Stop all writers before exporting, including background workers and other
25
+ processes. Keep the old database unchanged. Run commands from example 30 (SQLite)
26
+ or 31 (PostgreSQL), with `PHRONOMY_PATH` pointing to the unit 4 core. The source DB
27
+ must have the unit 3 schema. The destination must be a separate empty database.
28
+
29
+ ```sh
30
+ export SOURCE_DATABASE_URL='sqlite3:/absolute/path/old.sqlite3'
31
+ export DESTINATION_DATABASE_URL='sqlite3:/absolute/path/new.sqlite3'
32
+ bundle exec ruby ../scripts/migrate_unit4.rb export source.json --quiescent
33
+ bundle exec ruby ../scripts/migrate_unit4.rb convert source.json converted.json --quiescent
34
+ bundle exec ruby ../scripts/migrate_unit4.rb import converted.json --quiescent
35
+ bundle exec ruby ../scripts/migrate_unit4.rb verify converted.json --quiescent
36
+ ```
37
+
38
+ Use the corresponding PostgreSQL URLs with example 31. The importer creates the
39
+ new destination schema, including retention/cancellation tables, refuses populated
40
+ tables, and commits all resources together. It preserves record IDs, physical and
41
+ logical revisions, stream positions, result/error content, transfer provenance,
42
+ knowledge order and unresolved work. A content digest, reference, owner, revision
43
+ or format mismatch aborts conversion. A checksum binds the converted resource set
44
+ to its validation. Do not edit converted JSON manually.
45
+
46
+ Verification establishes a separate connection pool and compares the complete
47
+ exported destination with the converted snapshot. Before switching application
48
+ configuration, load representative Agents with their current definitions and
49
+ participant wiring, read completed results and resume only continuations whose
50
+ external outcomes are known. Unknown external operations remain unresolved; the
51
+ migration neither retries them nor declares them complete. Keep both exports and
52
+ the old DB until that operational validation is complete. Database cutover is
53
+ explicit and is never performed by the migration command.
54
+
55
+ For non-SQL backends, `Unit4Migration.convert(snapshot, quiescent: true)` is the
56
+ pure conversion boundary. Implement offline export/import of the documented
57
+ `phronomy.snapshot/1` resources using the backend's own driver. No live-code
58
+ fallback is supplied.
59
+
60
+ ## Retention lifecycle
61
+
62
+ After all results in a conversation have been consumed, call
63
+ `runner.forget_history!` (or `stores.multi_agent.forget_handoff(main_id)`) before
64
+ purging retained participants. For completed durable subagent history use
65
+ `stores.multi_agent.forget_subagents(agent_id:, execution_id:)`. Active or
66
+ unresolved work rejects history deletion. These operations release their own
67
+ holds; they do not remove another conversation's references.
@@ -0,0 +1,75 @@
1
+ # r8 unit 5 API migration
2
+
3
+ Apply core and examples together. No saved Agent, MultiAgent or Workflow record
4
+ format changes in this unit. Old constants and forwarding aliases are removed.
5
+
6
+ | Previous API | Current API |
7
+ | --- | --- |
8
+ | `Phronomy::VectorStore::Embeddings::*` | `Phronomy::Embeddings::*` |
9
+ | `Phronomy::VectorStore::Loader::*` | `Phronomy::Documents::Loader::*` |
10
+ | `Phronomy::VectorStore::Splitter::*` | `Phronomy::Documents::Splitter::*` |
11
+
12
+ VectorStore callers continue using `add`, `search`, `remove`, `clear` and `size`.
13
+ Custom backends now override protected `perform_add`, `perform_search`,
14
+ `perform_remove`, `perform_clear`, `perform_size`, and optionally
15
+ `embedding_dimension`. The common Base performs input/result validation and
16
+ returns `self` for add/remove/clear; the return value from these three hooks is
17
+ ignored. See `sig/phronomy/vector_store/base.rbs` for exact arguments. RBS models
18
+ the non-public hooks as private because it cannot express Ruby protected visibility.
19
+
20
+ Custom embedding providers implement the protected hook, not the public template:
21
+
22
+ ```ruby
23
+ class KeywordEmbeddings < Phronomy::Embeddings::Base
24
+ protected
25
+
26
+ def perform_embed(text, cancellation_token = nil)
27
+ # Common input/result validation and the initial cancellation checkpoint
28
+ # are inherited. Long-running implementations may check the signal again.
29
+ [text.scan(/refund/i).length.to_f, text.scan(/shipping/i).length.to_f]
30
+ end
31
+ end
32
+
33
+ provider = KeywordEmbeddings.new
34
+ vector = provider.embed("refund")
35
+ task = Phronomy::Embeddings::AsyncClient.new(adapter: provider).embed_async("shipping")
36
+ result = task.wait_result
37
+ ```
38
+
39
+ Embedding input must be a String, including an optional empty string; output must
40
+ be a non-empty Array of finite real numbers. Provider output is copied to a Float
41
+ array. An empty or malformed vector raises `Embeddings::InvalidResultError`.
42
+ RubyLLM provider failures now raise `Embeddings::TransportError`; inspect `cause`
43
+ for provider-specific details. Application exceptions are unchanged.
44
+
45
+ Vector ids must be Strings and metadata must be a Hash. Numeric strings, NaN,
46
+ infinity and complex components are rejected before backend I/O. Zero-dimensional
47
+ vectors still work in InMemory. `k` accepts positive Integers or decimal strings,
48
+ including `"08"`; Float truncation, hexadecimal/octal interpretation, whitespace
49
+ and arbitrary `to_int` coercions are not part of the contract. Results must satisfy
50
+ the public shape, score ordering and limit. Invalid backend results raise
51
+ `VectorStore::InvalidResultError`; they are never retried automatically.
52
+
53
+ Update custom backend tests to exercise inherited public operations. Do not
54
+ silence malformed results, return a fake zero count on transport failure, or add
55
+ an old-name alias to bypass the migration. Real Pgvector and RedisSearch deployments
56
+ must run their actual-service conformance tests before rollout.
57
+
58
+ The revised unit 5 candidate also tightens concrete backend response decoding.
59
+ RedisSearch expects RESP2; a missing whole search reply, malformed field pairs,
60
+ invalid counts or non-numeric distances now fail with `InvalidResultError` rather
61
+ than becoming an empty result, zero count or similarity 1. Document contents that
62
+ Redis explicitly reports as null during expiration/update are still omitted.
63
+ The total match count may exceed the returned page; these valid cases are tested.
64
+ RESP3 is not introduced by this update.
65
+
66
+ For Pgvector, a NULL metadata column remains `{}`, while an empty string, invalid
67
+ JSON, or JSON that is not an object now fails. An already-decoded Hash and a JSON
68
+ object remain accepted. Redis missing/null metadata likewise remains `{}`.
69
+ Pgvector rejects malformed scores and ids; integer database ids are still mapped
70
+ to String. JSON parser errors are retained as `cause`. Connection errors remain
71
+ unchanged and are not retried.
72
+
73
+ Check pre-existing metadata for invalid JSON or non-object values before rollout;
74
+ do not silently replace corrupt values with `{}` to make verification pass.
75
+ These parsing rules are implemented by the respective backend, not by Base.
@@ -0,0 +1,109 @@
1
+ # r8 unit 6 migration
2
+
3
+ Apply core and examples together on the applied unit 5 baseline. There are no
4
+ compatibility aliases. Update custom adapters and code rescuing LLM failures.
5
+
6
+ | Previous API | Current API |
7
+ | --- | --- |
8
+ | `Phronomy::TokenUsage` | `Phronomy::LLMAdapter::TokenUsage` |
9
+ | `Phronomy::TransportError` | `Phronomy::LLMAdapter::TransportError` |
10
+ | `Phronomy::RateLimitError` | `Phronomy::LLMAdapter::RateLimitError` |
11
+ | `Phronomy::AuthenticationError` | `Phronomy::LLMAdapter::AuthenticationError` |
12
+ | `Phronomy::ContextLengthError` | `Phronomy::LLMAdapter::ContextLengthError` |
13
+ | Adapter `build_chat`, `configure_chat`, `message`, `tool_call` | Backend-owned private translation; removed from the extension SPI |
14
+ | Adapter `complete(chat, message, config:)` / `stream(...)` | Inherited `complete(request, cancellation_token:)` / `stream(...)` |
15
+ | SDK-shaped recovery provider result | `LLMAdapter::Response` or `Response#to_h` |
16
+
17
+ Implement protected hooks, leaving public validation/cancellation templates intact:
18
+
19
+ ```ruby
20
+ class EchoBackend < Phronomy::LLMAdapter::Base
21
+ protected
22
+
23
+ def perform_complete(request, cancellation_token:)
24
+ Phronomy::LLMAdapter::Response.new(content: request.message || "continued")
25
+ end
26
+
27
+ def perform_stream(request, cancellation_token:)
28
+ result = perform_complete(request, cancellation_token: cancellation_token)
29
+ yield Phronomy::LLMAdapter::StreamChunk.new(content: result.content)
30
+ result
31
+ end
32
+ end
33
+ Phronomy.configure { |config| config.llm_adapter = EchoBackend.new }
34
+ ```
35
+
36
+ Request contains JSON model_config, optional system/new message, immutable
37
+ Message history and inert Tool definition Hashes. `identity` and local
38
+ `input_budget` have defaults. Backend hooks return Response; stream yields
39
+ StreamChunk values. Tool requests are `Tool::CallRequest(id:, name:, arguments:,
40
+ metadata:)` values in an ordered array, with unique nonempty IDs. They never
41
+ contain executable Tools or approval decisions. Return assistant responses only.
42
+ Response/Message content is text, structured JSON or nil. Unknown token counts
43
+ are nil; explicit zero is zero. TokenUsage no longer provides SDK `from_tokens`.
44
+
45
+ Model/provider are nonempty Strings or nil, temperature a finite number or nil,
46
+ max_output_tokens a positive Integer or nil, and instruction-cache/model-existence
47
+ flags booleans or nil. The default RubyLLM backend still owns provider-specific
48
+ options and error translation. Existing provider/application errors are not
49
+ silently swallowed or converted into success. Custom synchronous hooks must
50
+ check cancellation during their own long operations where they can cooperate.
51
+
52
+ ## Tool schemas and approval
53
+
54
+ Tool::Base owns `parameter`/`param`, `parameters`/`params`, declaration inheritance,
55
+ name/description, provider options, `validate_arguments`, `call`, and `call_async`.
56
+ It is not a RubyLLM::Tool. Incidental inherited SDK APIs such as approval_resolver,
57
+ split_result and SDK result/content classes are not part of the new Tool API.
58
+ Keep Agent approval policies on the Agent/Tool authorization contract.
59
+
60
+ `parameters` accepts an explicit object schema or Schematist DSL (the DSL retains
61
+ its syntax without loading RubyLLM). JSON Schema 2020-12 is the supported dialect,
62
+ implicit when `$schema` is absent. Root type must be object. Supported constraints
63
+ include required/extra properties, nested objects/arrays, enum/const, numbers,
64
+ strings/formats and combinators. Unknown keywords/formats, alternate dialects,
65
+ custom vocabularies, `$id`/anchors and external refs fail at declaration time.
66
+ Local `#` / `#/...` references are resolved at construction. `strict` is a provider
67
+ annotation, not a substitute for required/additionalProperties constraints.
68
+ Defaults are annotations and are not injected into arguments.
69
+
70
+ Legacy optional `param` declarations continue to accept explicit nil and now
71
+ advertise a nullable type (and nullable enum). A legacy optional nil is normalized
72
+ to omission before approval/execution, preserving Ruby keyword defaults. An
73
+ absent optional key is not injected. Explicit schemas accept null only when their own constraints allow it.
74
+
75
+ Every declaration path validates before execution. `:raise` raises ToolError;
76
+ `:return_error` returns the existing schema-error text; `:coerce` converts explicit
77
+ primitive property/item types and then validates every constraint. It does not
78
+ guess a branch or cast through references/combinators. Fractional values are not
79
+ truncated to integers. Validation snapshots input containers; it does not mutate
80
+ the caller's arguments. Top-level keys become keyword symbols. Extra keys with
81
+ no declared/inferred parameters are rejected rather than passed to execute.
82
+
83
+ Approval receives the validated/coerced snapshot. Execution reuses those values
84
+ and validates against the same published schema. `on_error` does not turn schema
85
+ errors into successful execution. Unqualified legacy array declarations now
86
+ advertise unconstrained JSON items, matching their actual validation rule; use
87
+ an explicit items schema to restrict them.
88
+
89
+ ## Stored and in-flight executions
90
+
91
+ Storage SPI and SQL schemas are unchanged. New Tool batch metadata additionally
92
+ records `validated_arguments`, separately from the unchanged raw request fields.
93
+ Agent authorization projects and compares that exact snapshot (including explicit
94
+ null in explicit schemas). Older snapshots without this field use the historical
95
+ raw-argument/optional-nil-omission rule. Existing journal message boundaries,
96
+ Tool call identities and recorded usage remain readable. Legacy top-level
97
+ thought_signature is decoded into opaque CallRequest metadata and rendered by
98
+ the backend. Old SDK usage field spellings remain accepted by SavedContextReader.
99
+ No stored records are silently rewritten and no automatic migration is run.
100
+
101
+ Saved Tool definitions are compared exactly. Removing SDK-generated annotations,
102
+ correctly advertising nested required/extra-key rules or array item rules can
103
+ change the definition even when application source is unchanged. Finish or
104
+ explicitly resolve in-flight unit 5 executions on their original version before
105
+ upgrading. Quiescent Agent history remains readable. If a saved in-flight Tool
106
+ definition differs, recovery rejects it; do not remove that comparison or modify
107
+ historical manifests to force continuation. Saved invalid model configuration
108
+ also needs resolution on the original version. No new cross-version in-flight
109
+ compatibility guarantee is made.
@@ -0,0 +1,31 @@
1
+ # Migrating to r8 unit 7
2
+
3
+ Apply after core b337fc77dae530269bc34d895365032873d544ad (r8 unit 6).
4
+ Public Agent invocation, streaming, approval, cancellation and recovery signatures
5
+ and persistence record schemas are unchanged. The current unit 6 examples need
6
+ no source changes. Run them against the candidate using PHRONOMY_PATH and the
7
+ correct BUNDLE_GEMFILE for each example directory.
8
+
9
+ There are no compatibility aliases for removed internal APIs:
10
+
11
+ | Internal use | Replacement |
12
+ | --- | --- |
13
+ | AgentInvocationSessionBuilder | AgentInvocation plus the owning ExecutionEnvironment.build_agent_session |
14
+ | AgentInvocationSessionBuilder entry/prepared actions | InvocationActions |
15
+ | ExecutionSessionRunner.new(runtime: ...) | ExecutionSessionRunner.new(environment: ...) |
16
+ | OwnershipRegistry.for/existing_for(Runtime) | Pass an ExecutionEnvironment; EngineEnvironment adapts Runtime |
17
+ | ExecutionReceiver subclasses initialize(event_loop:) | initialize(channel:), preserving super |
18
+ | AgentInvocation.begin_llm_call! implicit Runtime lookup | Explicit llm_call_id from durable prepared execution |
19
+
20
+ ExecutionEnvironment is a private framework connection, not an application
21
+ configuration feature. Do not serialize environments, channels, sessions or live
22
+ registries. The default composition is installed by requiring phronomy. State
23
+ policy loading alone does not install a runtime. Existing persisted Agent/Tool
24
+ identities, revisions, authorization snapshots and recovery classifications are
25
+ retained. This change does not add support for exchanging in-flight unit 5 or
26
+ older execution snapshots with unit 6/7 workers.
27
+
28
+ Stop/drain old processes using the existing deployment procedure before replacing
29
+ code. Deploy all internal call-site changes together. The application package
30
+ contains a strict-base dry-run/applier, expected-tree verification, review patch,
31
+ validation logs and rollback guidance. Run --verify before and after commit.
@@ -0,0 +1,33 @@
1
+ # Migrating to r8 unit 8
2
+
3
+ Apply after core a601a0654ace42640f0251b129359ca1f326e3ad (unit 7).
4
+ This is a core-only change. The unit 6 examples at
5
+ ed455c52018338f7c5a4c2948ae0d7db131aa090 require no source changes.
6
+
7
+ Public Agent invocation/stream/approval/cancellation/recovery signatures and
8
+ Tool#call_async(args, cancellation_token:, config:) are unchanged. Tool::Operation
9
+ adds an explicit C06 operation entry and result transformation API; application
10
+ Tools do not need to adopt it. The supplied submitter applies to the default
11
+ offloaded operation only. Custom async implementations retain their existing
12
+ execution mechanism and configuration.
13
+
14
+ | Internal use | Replacement |
15
+ | --- | --- |
16
+ | Agent::ToolInvocationSessionBuilder.build / build_for_resume | The owning ExecutionEnvironment.build_tool_session, with resume_event/resume_phase when needed |
17
+ | ToolInvocationSessionBuilder transition constants | Agent::ToolInvocationTransitions |
18
+ | ToolInvocationSessionBuilder entry operations | Agent::ToolInvocationActions |
19
+ | ToolInvocation.start_authorization/runtime: and start_execution/runtime: | Pass environment: explicitly; never reconstruct it from a new global Runtime |
20
+ | Tool::ToolExecutor.call_async(runtime:) | Tool::Operation.call_async(submitter:) for contract consumers; default executor takes submitter: internally |
21
+ | Agent ToolBinding's custom-async detection and mapping mechanism | Tool::Operation.with_result_transform; Agent retains filter configuration |
22
+
23
+ Removed internal names have no aliases. Deploy all internal call sites together.
24
+ Do not persist execution environments, submitters, FSM sessions or parent sinks.
25
+ Durable IDs, record schemas, revision checks and saved approval evidence are
26
+ unchanged. The change does not certify new in-flight cross-version compatibility.
27
+ Use the existing stop/drain procedure before replacing running processes.
28
+
29
+ The application ZIP contains strict-base --check/--apply/--verify commands,
30
+ complete replacement files and deletions, expected-tree verification, a review
31
+ patch, validation evidence and rollback instructions. Run --verify before and
32
+ after commit. Verify examples with PHRONOMY_PATH pointing at the candidate and
33
+ unset a stale BUNDLE_GEMFILE before entering each Bundler context.
@@ -0,0 +1,28 @@
1
+ # R8 unit 9 migration
2
+
3
+ Apply to core unit 8, commit e9f6cc16da19be82a0b7777486926ba46d070def.
4
+ Examples source remains at unit 6, ed455c52018338f7c5a4c2948ae0d7db131aa090.
5
+
6
+ No public Tool or Agent signature, stored schema, migration CLI or example source
7
+ change is required. Existing configured filter order and repeated registrations
8
+ are preserved. The correction removes only the extra transformation caused by
9
+ Base's standard async-to-sync delegation under a custom async result decorator.
10
+
11
+ A custom call_async using super now passes its raw delegated result through its
12
+ own processing before the async decorator applies the configured transform.
13
+ Code accidentally relying on the duplicate/intermediate transformation should
14
+ express the required stages explicitly in application filter configuration.
15
+
16
+ A custom call_async explicitly calling public call retains that call's filters;
17
+ the enclosing async result decorator also retains its stage. Do not substitute
18
+ call for super when the intent is to delegate to Base's normal async execution.
19
+ The framework does not suppress application-authored calls or infer their intent.
20
+
21
+ Private changes: Base uses Tool::Operation.synchronous_delegate; ToolExecutor
22
+ accepts a bound synchronous_call keyword. Applications should not use these
23
+ private bridge helpers. Custom async implementations retain their existing
24
+ execution mechanism and keyword protocol.
25
+
26
+ Use the normal process stop/drain and restart procedure. This unit does not add
27
+ cross-version in-flight compatibility or rollback of external Tool side effects.
28
+ See docs/architecture/r8-unit9.md for operation-boundary examples.
@@ -0,0 +1,103 @@
1
+ # Storage asynchronous execution and ContentStore ownership
2
+
3
+ P4 adds the public Beta `Phronomy::Storage::AsyncClient`. Synchronous storage
4
+ backends and `Persistence#transaction` keep their existing interfaces. Backend
5
+ authors implement no scheduler or async methods.
6
+
7
+ ## Public transaction API
8
+
9
+ Construct `Storage::AsyncClient.new(backend: raw_backend, pool: nil)` around a
10
+ Storage SPI 2 backend. For an existing Persistence facade, use
11
+ `persistence.backend`. The transaction block receives a **raw Storage::View**,
12
+ not the domain repositories yielded by `Persistence#transaction`.
13
+
14
+ `transaction_async(cancellation_token: nil, timeout: nil) { |view| ... }`
15
+ returns the pool's original TaskResult. The complete transaction runs on one
16
+ worker, using the backend's normal connection and scope. Do not split a
17
+ transaction across workers or wait for another TaskResult inside its block.
18
+ Explicit synchronous `backend.transaction` calls within the block retain nested
19
+ savepoint behavior.
20
+
21
+ ### Complete offline example
22
+
23
+ This requires a checkout containing P4; the previously released 0.27.0 gem does
24
+ not contain the new client. It uses only the public raw storage contract.
25
+
26
+ ```ruby runnable
27
+ require "phronomy"
28
+ require "json"
29
+
30
+ resource = Phronomy::Storage::Resource.new(id: "example.notes", kind: :records)
31
+ backend = Phronomy::Storage::Backends::InMemory.new(resources: [resource])
32
+ client = Phronomy::Storage::AsyncClient.new(backend: backend)
33
+
34
+ begin
35
+ record = Phronomy::Storage::DurableRecord.new(
36
+ record_type: "example.note", format_version: "0.1", payload: {"text" => "saved"}
37
+ )
38
+ task = client.transaction_async do |view|
39
+ rows = view.records(resource)
40
+ rows.insert(key: "note-1", revision: 1, attributes: {}, record: record)
41
+ rows.fetch("note-1").record.payload
42
+ end
43
+ puts JSON.generate(task.wait_result)
44
+ ensure
45
+ Phronomy.reset_runtime!
46
+ end
47
+ ```
48
+
49
+ The output is `{"text":"saved"}`. Return a value from the transaction. A bound
50
+ view or resource handle becomes invalid after the block finishes, even if it
51
+ was returned through TaskResult. Scope also rejects access from another thread.
52
+ Exceptions and invalid non-local block exits roll back through the existing
53
+ backend rules; no new transaction implementation is introduced.
54
+
55
+ ## Admission, cancellation and ownership
56
+
57
+ Construction starts no Runtime. Each call resolves the current default pool,
58
+ unless an explicit caller-owned `pool:` was supplied. Runtime reset does not
59
+ transfer ownership of an injected pool.
60
+
61
+ Admission uses `on_full: :raise`: a full or stopped pool raises immediately.
62
+ Queue wait counts toward `timeout`. Cancellation/timeout before worker pickup
63
+ skips the transaction. After work starts, TaskResult may settle while the
64
+ physical transaction continues and commits. A timeout or cancellation is **not
65
+ a rollback guarantee**. The client does not kill a thread, add retries, or claim
66
+ that an uncertain commit succeeded or failed. Applications needing a durable
67
+ outcome must reconcile through their domain's identities and stored state.
68
+
69
+ ## Existing Agent, Workflow and coordination operations
70
+
71
+ Internal `Storage::AsyncClient.submit(pool:)` accepts an existing synchronous
72
+ storage unit. This is private framework API, not an application extension API.
73
+ It submits exactly once and adds no transaction, token, or timeout. This lets
74
+ domain operations preserve their own transaction and reconciliation boundaries.
75
+ See the [operation inventory](../architecture/storage-execution-boundaries.md).
76
+
77
+ In particular, a Workflow runner may have only an injected repository rather
78
+ than access to its raw backend. Internal submit therefore accepts a callable
79
+ and the owner's pool; it does not require a dummy backend or a Persistence
80
+ facade. Public transaction_async requires a real SPI 2 backend.
81
+
82
+ Durable commit/readback policy, admission release, callback delivery and the
83
+ application of results to live state remain with Agent/Workflow/MultiAgent.
84
+ No cancellation condition is added to existing terminal saves. Tool execution,
85
+ authorization, tracing and application approval listeners retain their own
86
+ execution boundaries.
87
+
88
+ ## ContentStore path and diagram
89
+
90
+ P4 originally moved `ContentStore::StoredContents` into
91
+ `content_store/backends/stored_contents.rb`. [ADR-062](../decisions/062-content-store-service.md)
92
+ supersedes that split: the implementation now lives at
93
+ `content_store/stored_contents.rb`, beside its shared API and owned schema.
94
+ The obsolete backend directory and collapse entry are deleted without a shim.
95
+ Its constant, synchronous operations, digest rules and exceptions are unchanged.
96
+ Use normal `require "phronomy"`; internal file paths are not a public load API.
97
+ Zeitwerk still collapses `storage/async/`. `Storage::Backends` remains a namespace.
98
+ ContentStore receives no artificial async API.
99
+
100
+ M10 is G57 Content Service in B3, outside Backend Contracts/Implementations;
101
+ M73 is retired. M69 Storage AsyncClient stays in B4. Text panels are transparent.
102
+ Arrows targeting M33/M41/M44 are hidden by display settings; all measured
103
+ dependencies, source evidence and matrix cells remain available.