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,60 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Phronomy
4
+ module Storage
5
+ # Asynchronous execution of a synchronous raw storage backend.
6
+ #
7
+ # A transaction opens, runs and closes on one worker. Return values rather
8
+ # than transaction views: a bound view is closed when the block finishes.
9
+ # Timeout includes queue wait. Timeout/cancellation settles TaskResult but
10
+ # does not interrupt running I/O or guarantee rollback of a started write.
11
+ # Construction starts no Runtime; the default pool is resolved per operation.
12
+ # An explicitly injected pool remains owned by its caller.
13
+ #
14
+ # @api public
15
+ class AsyncClient
16
+ # @param backend [Storage::Backend] synchronous raw SPI 2 backend
17
+ # @param pool [Concurrency::OffloadPool, nil] optional execution pool
18
+ # @api public
19
+ def initialize(backend:, pool: nil)
20
+ Backend.validate_capabilities!(backend)
21
+ @backend = backend
22
+ @pool = pool
23
+ end
24
+
25
+ # Executes the entire transaction on one worker without waiting for queue
26
+ # capacity. Explicit nested backend transactions retain savepoint semantics.
27
+ #
28
+ # @param cancellation_token [Concurrency::CancellationToken, nil]
29
+ # @param timeout [Numeric, nil] operation-wide submit timeout
30
+ # @yieldparam view [Storage::View] view valid only within this transaction
31
+ # @return [Phronomy::TaskResult] the pool's original completion handle
32
+ # @api public
33
+ def transaction_async(cancellation_token: nil, timeout: nil, &operation)
34
+ raise ArgumentError, "transaction_async requires a block" unless operation
35
+
36
+ Phronomy::Execution.submit(pool: default_pool, timeout: timeout, cancellation_token: cancellation_token, on_full: :raise) do
37
+ @backend.transaction(&operation)
38
+ end
39
+ end
40
+
41
+ # Submit an existing domain-owned synchronous storage unit unchanged.
42
+ # It may already open transactions or perform reads/reconciliation. Do not
43
+ # add a transaction, timeout or cancellation condition around that unit.
44
+ # The owner supplies its current runtime's pool and applies the result.
45
+ #
46
+ # @api private
47
+ def self.submit(pool:, &operation)
48
+ raise ArgumentError, "storage submit requires a block" unless operation
49
+
50
+ Phronomy::Execution.submit(pool: pool, on_full: :raise, &operation)
51
+ end
52
+
53
+ private
54
+
55
+ def default_pool
56
+ @pool
57
+ end
58
+ end
59
+ end
60
+ end
@@ -30,8 +30,9 @@ module Phronomy
30
30
  def self.validate_capabilities!(backend)
31
31
  capabilities = backend.respond_to?(:capabilities) ? backend.capabilities : {}
32
32
  missing = REQUIRED_CAPABILITIES.reject { |key, value| capabilities.is_a?(Hash) && capabilities[key] == value }
33
- unless missing.empty? && backend.respond_to?(:view) && backend.respond_to?(:transaction)
34
- raise UnsupportedBackendError, "Persistence requires Storage SPI 2: #{missing.keys.join(", ")}"
33
+ missing_methods = %i[view transaction transaction_open?].reject { |name| backend.respond_to?(name) }
34
+ unless missing.empty? && missing_methods.empty?
35
+ raise UnsupportedBackendError, "Persistence requires Storage SPI 2: #{(missing.keys + missing_methods).join(", ")}"
35
36
  end
36
37
  end
37
38
 
@@ -40,6 +41,11 @@ module Phronomy
40
41
  REQUIRED_CAPABILITIES.transform_values { |value| (value == true) ? false : value }.freeze
41
42
  end
42
43
 
44
+ # Whether this synchronous context is already inside a backend transaction.
45
+ # Lets higher-level scopes reject claiming ownership of somebody else's commit.
46
+ # @api public
47
+ def transaction_open? = !current_view.nil?
48
+
43
49
  # All declared resources participate in one atomic transaction domain.
44
50
  # Record and stream revisions provide compare-and-swap conflict detection.
45
51
  # This does not
@@ -19,7 +19,7 @@ module Phronomy
19
19
  end
20
20
 
21
21
  def total_usage
22
- @results.map(&:usage).compact.reduce(Phronomy::TokenUsage.zero, :+)
22
+ @results.map(&:usage).compact.reduce(Phronomy::LLMAdapter::TokenUsage.zero, :+)
23
23
  end
24
24
 
25
25
  def average_latency_ms
@@ -5,6 +5,19 @@ module Phronomy
5
5
  module Eval
6
6
  module Scorer
7
7
  class LlmJudge < Base
8
+ CLIENT_FACTORIES = {}
9
+ private_constant :CLIENT_FACTORIES
10
+
11
+ # One-time boot binding, not an application extension registry. The
12
+ # factory runs for each score, after its Request has been prepared.
13
+ # @api private
14
+ def self.install_client_factory(factory)
15
+ raise ArgumentError, "factory must respond to call" unless factory.respond_to?(:call)
16
+
17
+ CLIENT_FACTORIES.replace(client: factory).freeze
18
+ nil
19
+ end
20
+
8
21
  DEFAULT_PROMPT = <<~PROMPT
9
22
  You are an impartial judge evaluating the quality of an AI assistant response.
10
23
  Rate the response on a scale from 0.0 (completely wrong or unhelpful) to 1.0 (perfect).
@@ -32,9 +45,12 @@ module Phronomy
32
45
  expected: expected.to_s,
33
46
  actual: actual.to_s
34
47
  )
35
- response = Phronomy::Runtime.instance.offload.submit do
36
- RubyLLM.chat(model: @model, provider: @provider, assume_model_exists: @assume_model_exists).ask(prompt)
37
- end.wait_result
48
+ request = Phronomy::LLMAdapter::Request.new(
49
+ model_config: {"model" => @model, "provider" => @provider&.to_s,
50
+ "assume_model_exists" => @assume_model_exists}.compact,
51
+ message: prompt
52
+ )
53
+ response = CLIENT_FACTORIES.fetch(:client).call.complete_async(request).wait_result
38
54
  response.content.to_s.strip.scan(/-?\d+\.?\d*/).first.to_f.clamp(0.0, 1.0)
39
55
  rescue => error
40
56
  raise if @raise_on_error
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  RSpec.shared_examples "a persistence content store" do
4
- let(:content_store) { persistence.contents }
4
+ let(:content_store) { stores.agent.contents }
5
5
 
6
6
  it "returns the same content_id for the same bytes" do
7
7
  first = content_store.put("same".b, canonicalization_version: 1)
@@ -21,7 +21,7 @@ RSpec.shared_examples "a persistence content store" do
21
21
  it "raises NotFoundError for a missing content_id" do
22
22
  expect do
23
23
  content_store.fetch("sha256:#{"0" * 64}")
24
- end.to raise_error(Phronomy::Storage::NotFoundError)
24
+ end.to raise_error(Phronomy::Persistence::NotFoundError)
25
25
  end
26
26
 
27
27
  it "isolates durable bytes from mutation of fetched values" do
@@ -3,7 +3,7 @@
3
3
  require "securerandom"
4
4
 
5
5
  RSpec.shared_examples "a Journal repository" do
6
- let(:journal_repository) { persistence.journals }
6
+ let(:journal_repository) { stores.agent.journals }
7
7
  let(:journal_agent_root) do
8
8
  Phronomy::Agent::AgentRoot.create(
9
9
  agent_id: "journal-agent-#{SecureRandom.uuid}",
@@ -25,7 +25,7 @@ RSpec.shared_examples "a Journal repository" do
25
25
  end
26
26
 
27
27
  before do
28
- persistence.agents.create(journal_agent_root)
28
+ stores.agent.agents.create(journal_agent_root)
29
29
  end
30
30
 
31
31
  it "appends records at the expected position and assigns durable sequences" do
@@ -51,7 +51,7 @@ RSpec.shared_examples "a Journal repository" do
51
51
  expected_position: 1,
52
52
  records: [record]
53
53
  )
54
- end.to raise_error(Phronomy::Storage::ConflictError)
54
+ end.to raise_error(Phronomy::Persistence::ConflictError)
55
55
  end
56
56
 
57
57
  it "rejects a duplicate record_id already present in the Journal" do
@@ -76,7 +76,7 @@ RSpec.shared_examples "a Journal repository" do
76
76
  expected_position: 1,
77
77
  records: [duplicate]
78
78
  )
79
- end.to raise_error(Phronomy::Storage::ConflictError)
79
+ end.to raise_error(Phronomy::Persistence::ConflictError)
80
80
  end
81
81
 
82
82
  it "rejects duplicate record_ids within one append" do
@@ -94,7 +94,7 @@ RSpec.shared_examples "a Journal repository" do
94
94
  expected_position: 0,
95
95
  records: records
96
96
  )
97
- end.to raise_error(Phronomy::Storage::ConflictError)
97
+ end.to raise_error(Phronomy::Persistence::ConflictError)
98
98
  end
99
99
 
100
100
  it "rejects records belonging to another Agent" do
@@ -106,7 +106,7 @@ RSpec.shared_examples "a Journal repository" do
106
106
  expected_position: 0,
107
107
  records: [record]
108
108
  )
109
- end.to raise_error(Phronomy::Storage::SerializationError)
109
+ end.to raise_error(Phronomy::Persistence::SerializationError)
110
110
  end
111
111
 
112
112
  it "reads records in sequence order and supports after/limit" do
@@ -27,26 +27,25 @@ RSpec.shared_examples "a Persistence backend" do
27
27
 
28
28
  it "advertises every required capability" do
29
29
  Phronomy::Storage::Backend::REQUIRED_CAPABILITIES.each do |name, required_value|
30
- expect(persistence.backend.capabilities[name]).to eq(required_value)
30
+ expect(stores.coordinator.backend.capabilities[name]).to eq(required_value)
31
31
  end
32
32
  end
33
33
 
34
- it "yields a transaction view that exposes the complete durable SPI" do
35
- persistence.transaction do |tx|
36
- expect(tx).to respond_to(
37
- :contents,
38
- :agents,
39
- :journals,
40
- :executions,
41
- :workflow_states,
42
- :handoff_states, :teams, :team_executions,
43
- :assert_agent_watermark!
44
- )
34
+ it "binds each domain to its own record protocol in one common scope" do
35
+ stores.coordinator.atomic do |scope|
36
+ stores.agent.participate(scope) do |records|
37
+ expect(records).to respond_to(:contents, :agents, :journals, :executions, :retentions, :cancellations, :assert_agent_watermark!)
38
+ expect(records).not_to respond_to(:teams, :team_executions, :workflow_states)
39
+ end
40
+ stores.multi_agent.participate(scope) do |records|
41
+ expect(records).to respond_to(:contents, :teams, :team_executions, :handoff_states)
42
+ expect(records).not_to respond_to(:agents, :executions, :workflow_states)
43
+ end
45
44
  end
46
45
  end
47
46
 
48
47
  it "returns the transaction block result" do
49
- expect(persistence.transaction { |_tx| :contract_result }).to eq(:contract_result)
48
+ expect(stores.agent.transaction { |_tx| :contract_result }).to eq(:contract_result)
50
49
  end
51
50
 
52
51
  it "commits changes across durable repositories as one transaction" do
@@ -55,7 +54,7 @@ RSpec.shared_examples "a Persistence backend" do
55
54
  workflow_id = "workflow-#{SecureRandom.uuid}"
56
55
  content_id = nil
57
56
 
58
- persistence.transaction do |tx|
57
+ stores.agent.transaction do |tx, scope|
59
58
  content_id = tx.contents.put_text("committed")
60
59
  tx.agents.create(root)
61
60
  appended = tx.journals.append(
@@ -73,11 +72,13 @@ RSpec.shared_examples "a Persistence backend" do
73
72
  ]
74
73
  )
75
74
  tx.executions.create_active(execution)
76
- tx.workflow_states.save(
77
- workflow_id,
78
- expected_revision: nil,
79
- snapshot: {fields: {value: "committed"}, phase: "pause"}
80
- )
75
+ scope.participate(persistence: stores.coordinator, adapter: Phronomy::Workflow::Persistence::StateRepository) do |workflow|
76
+ workflow.save(
77
+ workflow_id,
78
+ expected_revision: nil,
79
+ snapshot: {fields: {value: "committed"}, phase: "pause"}
80
+ )
81
+ end
81
82
 
82
83
  updated_root = root.with(
83
84
  agent_revision: 1,
@@ -87,12 +88,12 @@ RSpec.shared_examples "a Persistence backend" do
87
88
  tx.agents.save(root.agent_id, expected_revision: 0, root: updated_root)
88
89
  end
89
90
 
90
- expect(persistence.contents.exist?(content_id)).to be(true)
91
- expect(persistence.agents.load(root.agent_id).agent_revision).to eq(1)
92
- expect(persistence.journals.head(root.agent_id)).to eq(1)
93
- expect(persistence.executions.load(execution.execution_id).execution_id)
91
+ expect(stores.agent.contents.exist?(content_id)).to be(true)
92
+ expect(stores.agent.agents.load(root.agent_id).agent_revision).to eq(1)
93
+ expect(stores.agent.journals.head(root.agent_id)).to eq(1)
94
+ expect(stores.agent.executions.load(execution.execution_id).execution_id)
94
95
  .to eq(execution.execution_id)
95
- expect(persistence.workflow_states.load(workflow_id)).not_to be_nil
96
+ expect(stores.workflow.load(workflow_id)).not_to be_nil
96
97
  end
97
98
 
98
99
  it "rolls back all durable repositories when the transaction block raises" do
@@ -102,7 +103,7 @@ RSpec.shared_examples "a Persistence backend" do
102
103
  content_id = nil
103
104
 
104
105
  expect do
105
- persistence.transaction do |tx|
106
+ stores.agent.transaction do |tx, scope|
106
107
  content_id = tx.contents.put_text("temporary-#{SecureRandom.uuid}")
107
108
  tx.agents.create(root)
108
109
  tx.journals.append(
@@ -120,32 +121,34 @@ RSpec.shared_examples "a Persistence backend" do
120
121
  ]
121
122
  )
122
123
  tx.executions.create_active(execution)
123
- tx.workflow_states.save(
124
- workflow_id,
125
- expected_revision: nil,
126
- snapshot: {fields: {value: "temporary"}, phase: "pause"}
127
- )
124
+ scope.participate(persistence: stores.coordinator, adapter: Phronomy::Workflow::Persistence::StateRepository) do |workflow|
125
+ workflow.save(
126
+ workflow_id,
127
+ expected_revision: nil,
128
+ snapshot: {fields: {value: "temporary"}, phase: "pause"}
129
+ )
130
+ end
128
131
  raise "rollback-contract"
129
132
  end
130
133
  end.to raise_error("rollback-contract")
131
134
 
132
- expect(persistence.contents.exist?(content_id)).to be(false)
135
+ expect(stores.agent.contents.exist?(content_id)).to be(false)
133
136
  expect do
134
- persistence.agents.load(root.agent_id)
135
- end.to raise_error(Phronomy::Storage::NotFoundError)
136
- expect(persistence.journals.head(root.agent_id)).to eq(0)
137
+ stores.agent.agents.load(root.agent_id)
138
+ end.to raise_error(Phronomy::Persistence::NotFoundError)
139
+ expect(stores.agent.journals.head(root.agent_id)).to eq(0)
137
140
  expect do
138
- persistence.executions.load(execution.execution_id)
139
- end.to raise_error(Phronomy::Storage::NotFoundError)
140
- expect(persistence.workflow_states.load(workflow_id)).to be_nil
141
+ stores.agent.executions.load(execution.execution_id)
142
+ end.to raise_error(Phronomy::Persistence::NotFoundError)
143
+ expect(stores.workflow.load(workflow_id)).to be_nil
141
144
  end
142
145
 
143
146
  it "accepts the current Agent revision and Journal position watermark" do
144
147
  root = backend_agent_root
145
- persistence.agents.create(root)
148
+ stores.agent.agents.create(root)
146
149
 
147
150
  expect(
148
- persistence.assert_agent_watermark!(
151
+ stores.agent.assert_agent_watermark!(
149
152
  agent_id: root.agent_id,
150
153
  agent_revision: root.agent_revision,
151
154
  journal_position: root.journal_position
@@ -155,23 +158,23 @@ RSpec.shared_examples "a Persistence backend" do
155
158
 
156
159
  it "raises ConflictError when the durable Agent revision has advanced" do
157
160
  root = backend_agent_root
158
- persistence.agents.create(root)
161
+ stores.agent.agents.create(root)
159
162
  advanced = root.with(agent_revision: 1)
160
- persistence.agents.save(root.agent_id, expected_revision: 0, root: advanced)
163
+ stores.agent.agents.save(root.agent_id, expected_revision: 0, root: advanced)
161
164
 
162
165
  expect do
163
- persistence.assert_agent_watermark!(
166
+ stores.agent.assert_agent_watermark!(
164
167
  agent_id: root.agent_id,
165
168
  agent_revision: 0,
166
169
  journal_position: 0
167
170
  )
168
- end.to raise_error(Phronomy::Storage::ConflictError)
171
+ end.to raise_error(Phronomy::Persistence::ConflictError)
169
172
  end
170
173
 
171
174
  it "raises ConflictError when the durable Journal position has advanced" do
172
175
  root = backend_agent_root
173
- persistence.agents.create(root)
174
- persistence.journals.append(
176
+ stores.agent.agents.create(root)
177
+ stores.agent.journals.append(
175
178
  root.agent_id,
176
179
  expected_position: 0,
177
180
  records: [
@@ -186,23 +189,23 @@ RSpec.shared_examples "a Persistence backend" do
186
189
  )
187
190
 
188
191
  expect do
189
- persistence.assert_agent_watermark!(
192
+ stores.agent.assert_agent_watermark!(
190
193
  agent_id: root.agent_id,
191
194
  agent_revision: 0,
192
195
  journal_position: 0
193
196
  )
194
- end.to raise_error(Phronomy::Storage::ConflictError)
197
+ end.to raise_error(Phronomy::Persistence::ConflictError)
195
198
  end
196
199
 
197
200
  it "rolls back earlier writes when a watermark precondition fails" do
198
201
  root = backend_agent_root
199
- persistence.agents.create(root)
202
+ stores.agent.agents.create(root)
200
203
  advanced = root.with(agent_revision: 1)
201
- persistence.agents.save(root.agent_id, expected_revision: 0, root: advanced)
204
+ stores.agent.agents.save(root.agent_id, expected_revision: 0, root: advanced)
202
205
  temporary_content_id = nil
203
206
 
204
207
  expect do
205
- persistence.transaction do |tx|
208
+ stores.agent.transaction do |tx, scope|
206
209
  temporary_content_id = tx.contents.put_text(
207
210
  "watermark-rollback-#{SecureRandom.uuid}"
208
211
  )
@@ -212,8 +215,8 @@ RSpec.shared_examples "a Persistence backend" do
212
215
  journal_position: 0
213
216
  )
214
217
  end
215
- end.to raise_error(Phronomy::Storage::ConflictError)
218
+ end.to raise_error(Phronomy::Persistence::ConflictError)
216
219
 
217
- expect(persistence.contents.exist?(temporary_content_id)).to be(false)
220
+ expect(stores.agent.contents.exist?(temporary_content_id)).to be(false)
218
221
  end
219
222
  end
@@ -3,7 +3,7 @@
3
3
  require "securerandom"
4
4
 
5
5
  RSpec.shared_examples "a workflow state repository" do
6
- let(:repository) { persistence.workflow_states }
6
+ let(:repository) { stores.workflow }
7
7
 
8
8
  def workflow_contract_value(hash, key)
9
9
  hash.key?(key) ? hash[key] : hash[key.to_s]
@@ -54,7 +54,7 @@ RSpec.shared_examples "a workflow state repository" do
54
54
  expected_revision: nil,
55
55
  snapshot: {fields: {value: 2}, phase: "__end__"}
56
56
  )
57
- end.to raise_error(Phronomy::Storage::ConflictError)
57
+ end.to raise_error(Phronomy::Persistence::ConflictError)
58
58
  end
59
59
 
60
60
  it "returns a snapshot representation accepted by WorkflowRunner" do
@@ -111,7 +111,7 @@ RSpec.shared_examples "a workflow state repository" do
111
111
 
112
112
  expect do
113
113
  repository.delete(workflow_instance_id, expected_revision: 99)
114
- end.to raise_error(Phronomy::Storage::ConflictError)
114
+ end.to raise_error(Phronomy::Persistence::ConflictError)
115
115
 
116
116
  repository.delete(workflow_instance_id, expected_revision: 1)
117
117
  expect(repository.load(workflow_instance_id)).to be_nil
@@ -3,7 +3,7 @@
3
3
  require "securerandom"
4
4
 
5
5
  RSpec.shared_examples "an Agent repository" do
6
- let(:agent_repository) { persistence.agents }
6
+ let(:agent_repository) { stores.agent.agents }
7
7
  let(:agent_root) do
8
8
  Phronomy::Agent::AgentRoot.create(
9
9
  agent_id: "contract-agent-#{SecureRandom.uuid}",
@@ -22,13 +22,13 @@ RSpec.shared_examples "an Agent repository" do
22
22
 
23
23
  expect do
24
24
  agent_repository.create(agent_root)
25
- end.to raise_error(Phronomy::Storage::ConflictError)
25
+ end.to raise_error(Phronomy::Persistence::ConflictError)
26
26
  end
27
27
 
28
28
  it "raises NotFoundError for a missing Agent" do
29
29
  expect do
30
30
  agent_repository.load("missing-#{SecureRandom.uuid}")
31
- end.to raise_error(Phronomy::Storage::NotFoundError)
31
+ end.to raise_error(Phronomy::Persistence::NotFoundError)
32
32
  end
33
33
 
34
34
  it "saves only at the expected revision" do
@@ -54,7 +54,7 @@ RSpec.shared_examples "an Agent repository" do
54
54
 
55
55
  expect do
56
56
  agent_repository.save(agent_root.agent_id, expected_revision: 0, root: stale)
57
- end.to raise_error(Phronomy::Storage::ConflictError)
57
+ end.to raise_error(Phronomy::Persistence::ConflictError)
58
58
  end
59
59
 
60
60
  it "rejects an Agent identity mismatch" do
@@ -71,7 +71,7 @@ RSpec.shared_examples "an Agent repository" do
71
71
  expected_revision: 0,
72
72
  root: other
73
73
  )
74
- end.to raise_error(Phronomy::Storage::SerializationError)
74
+ end.to raise_error(Phronomy::Persistence::SerializationError)
75
75
  end
76
76
 
77
77
  it "requires revision to advance exactly once" do
@@ -84,7 +84,7 @@ RSpec.shared_examples "an Agent repository" do
84
84
  expected_revision: 0,
85
85
  root: skipped
86
86
  )
87
- end.to raise_error(Phronomy::Storage::ConflictError)
87
+ end.to raise_error(Phronomy::Persistence::ConflictError)
88
88
  end
89
89
 
90
90
  it "deletes idempotently" do
@@ -94,6 +94,6 @@ RSpec.shared_examples "an Agent repository" do
94
94
 
95
95
  expect do
96
96
  agent_repository.load(agent_root.agent_id)
97
- end.to raise_error(Phronomy::Storage::NotFoundError)
97
+ end.to raise_error(Phronomy::Persistence::NotFoundError)
98
98
  end
99
99
  end
@@ -3,7 +3,7 @@
3
3
  require "securerandom"
4
4
 
5
5
  RSpec.shared_examples "an Execution repository" do
6
- let(:execution_repository) { persistence.executions }
6
+ let(:execution_repository) { stores.agent.executions }
7
7
  let(:execution_agent_root) do
8
8
  Phronomy::Agent::AgentRoot.create(
9
9
  agent_id: "execution-agent-#{SecureRandom.uuid}",
@@ -27,7 +27,7 @@ RSpec.shared_examples "an Execution repository" do
27
27
  end
28
28
 
29
29
  before do
30
- persistence.agents.create(execution_agent_root)
30
+ stores.agent.agents.create(execution_agent_root)
31
31
  end
32
32
 
33
33
  it "creates and loads an active execution" do
@@ -40,7 +40,7 @@ RSpec.shared_examples "an Execution repository" do
40
40
  it "raises NotFoundError for a missing execution" do
41
41
  expect do
42
42
  execution_repository.load("missing-#{SecureRandom.uuid}")
43
- end.to raise_error(Phronomy::Storage::NotFoundError)
43
+ end.to raise_error(Phronomy::Persistence::NotFoundError)
44
44
  end
45
45
 
46
46
  it "rejects a duplicate execution_id" do
@@ -49,7 +49,7 @@ RSpec.shared_examples "an Execution repository" do
49
49
 
50
50
  expect do
51
51
  execution_repository.create_active(execution)
52
- end.to raise_error(Phronomy::Storage::ConflictError)
52
+ end.to raise_error(Phronomy::Persistence::ConflictError)
53
53
  end
54
54
 
55
55
  it "admits at most one active or suspended execution for one Agent" do
@@ -68,7 +68,7 @@ RSpec.shared_examples "an Execution repository" do
68
68
  agent_definition_id: "contract-agent",
69
69
  agent_definition_version: 1
70
70
  )
71
- persistence.agents.create(other_root)
71
+ stores.agent.agents.create(other_root)
72
72
 
73
73
  expect do
74
74
  execution_repository.create_active(build_contract_execution(execution_agent_root))
@@ -107,7 +107,7 @@ RSpec.shared_examples "an Execution repository" do
107
107
  expected_revision: 0,
108
108
  execution: updated
109
109
  )
110
- end.to raise_error(Phronomy::Storage::ConflictError)
110
+ end.to raise_error(Phronomy::Persistence::ConflictError)
111
111
  end
112
112
 
113
113
  it "rejects an execution identity mismatch" do
@@ -118,7 +118,7 @@ RSpec.shared_examples "an Execution repository" do
118
118
  agent_definition_id: "contract-agent",
119
119
  agent_definition_version: 1
120
120
  )
121
- persistence.agents.create(other_root)
121
+ stores.agent.agents.create(other_root)
122
122
  other = build_contract_execution(other_root).with(
123
123
  execution_revision: 1,
124
124
  status: :active,
@@ -131,7 +131,7 @@ RSpec.shared_examples "an Execution repository" do
131
131
  expected_revision: 0,
132
132
  execution: other
133
133
  )
134
- end.to raise_error(Phronomy::Storage::SerializationError)
134
+ end.to raise_error(Phronomy::Persistence::SerializationError)
135
135
  end
136
136
 
137
137
  it "requires execution revision to advance exactly once" do
@@ -149,7 +149,7 @@ RSpec.shared_examples "an Execution repository" do
149
149
  expected_revision: 0,
150
150
  execution: skipped
151
151
  )
152
- end.to raise_error(Phronomy::Storage::ConflictError)
152
+ end.to raise_error(Phronomy::Persistence::ConflictError)
153
153
  end
154
154
 
155
155
  it "lists active executions for one Agent" do
@@ -179,7 +179,7 @@ RSpec.shared_examples "an Execution repository" do
179
179
 
180
180
  expect do
181
181
  execution_repository.load(execution.execution_id)
182
- end.to raise_error(Phronomy::Storage::NotFoundError)
182
+ end.to raise_error(Phronomy::Persistence::NotFoundError)
183
183
  end
184
184
 
185
185
  it "deletes all executions for one Agent without deleting other Agents' executions" do
@@ -188,7 +188,7 @@ RSpec.shared_examples "an Execution repository" do
188
188
  agent_definition_id: "contract-agent",
189
189
  agent_definition_version: 1
190
190
  )
191
- persistence.agents.create(other_root)
191
+ stores.agent.agents.create(other_root)
192
192
  own = build_contract_execution(execution_agent_root)
193
193
  other = build_contract_execution(other_root)
194
194
  execution_repository.create_active(own)