phronomy 0.26.0 → 0.28.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (557) hide show
  1. checksums.yaml +4 -4
  2. data/.mutant.yml +9 -9
  3. data/CHANGELOG.md +92 -0
  4. data/CONTRIBUTING.md +8 -8
  5. data/README.md +13 -3
  6. data/VERIFY.sh +27 -27
  7. data/benchmark/bench_agent_invoke.rb +26 -47
  8. data/benchmark/bench_context_assembler.rb +17 -15
  9. data/benchmark/bench_regression.rb +1 -1
  10. data/benchmark/bench_tool_schema.rb +1 -1
  11. data/docs/architecture/agent-chat-and-state-ownership.md +153 -0
  12. data/docs/architecture/agent-configuration-and-tool-binding.md +139 -0
  13. data/docs/architecture/agent-context.md +4 -2
  14. data/docs/architecture/agent-transition-ownership.md +13 -0
  15. data/docs/architecture/backend-groups.md +152 -0
  16. data/docs/architecture/before-llm-input.md +9 -3
  17. data/docs/architecture/context-management.md +31 -1
  18. data/docs/architecture/context-preparation-steps.md +90 -0
  19. data/docs/architecture/entry-action-and-team-wording.md +72 -0
  20. data/docs/architecture/execution-abstraction-review.md +88 -0
  21. data/docs/architecture/execution-boundaries.md +28 -0
  22. data/docs/architecture/execution-metadata-and-values.md +86 -0
  23. data/docs/architecture/generator-verifier-ownership.md +111 -0
  24. data/docs/architecture/multi-agent-handoff.md +11 -4
  25. data/docs/architecture/persistence-refactoring-plan.md +50 -0
  26. data/docs/architecture/persistence.md +45 -4
  27. data/docs/architecture/r8-unit1.md +104 -0
  28. data/docs/architecture/r8-unit10.md +72 -0
  29. data/docs/architecture/r8-unit11.md +71 -0
  30. data/docs/architecture/r8-unit12.md +67 -0
  31. data/docs/architecture/r8-unit13.md +61 -0
  32. data/docs/architecture/r8-unit14.md +72 -0
  33. data/docs/architecture/r8-unit15.md +65 -0
  34. data/docs/architecture/r8-unit16.md +54 -0
  35. data/docs/architecture/r8-unit17.md +73 -0
  36. data/docs/architecture/r8-unit18.md +92 -0
  37. data/docs/architecture/r8-unit19.md +61 -0
  38. data/docs/architecture/r8-unit2.md +55 -0
  39. data/docs/architecture/r8-unit20.md +51 -0
  40. data/docs/architecture/r8-unit21.md +79 -0
  41. data/docs/architecture/r8-unit22.md +74 -0
  42. data/docs/architecture/r8-unit23.md +81 -0
  43. data/docs/architecture/r8-unit3.md +130 -0
  44. data/docs/architecture/r8-unit4.md +79 -0
  45. data/docs/architecture/r8-unit5.md +115 -0
  46. data/docs/architecture/r8-unit6.md +71 -0
  47. data/docs/architecture/r8-unit7.md +70 -0
  48. data/docs/architecture/r8-unit8.md +78 -0
  49. data/docs/architecture/r8-unit9.md +73 -0
  50. data/docs/architecture/refactoring-closure.md +343 -0
  51. data/docs/architecture/remaining-refactoring-plan.md +390 -0
  52. data/docs/architecture/rubyllm-2-token-ownership.md +82 -0
  53. data/docs/architecture/storage-execution-boundaries.md +54 -0
  54. data/docs/architecture/tool-schema-recording-gap.md +56 -0
  55. data/docs/architecture/tracing.md +2 -2
  56. data/docs/architecture/workflow-terminal-ownership-design.md +104 -0
  57. data/docs/architecture.md +222 -0
  58. data/docs/decisions/014-unified-persistence-durable-state.md +11 -0
  59. data/docs/decisions/015-tool-public-facade-and-rbs-boundary.md +3 -3
  60. data/docs/decisions/024-event-loop-single-writer-agent-runtime.md +5 -1
  61. data/docs/decisions/025-process-local-agent-ownership-and-runtime-admission.md +13 -3
  62. data/docs/decisions/026-workflow-runtime-admission-and-durable-terminal-barrier.md +5 -1
  63. data/docs/decisions/027-llm-adapter-provider-boundary.md +2 -0
  64. data/docs/decisions/030-agent-handoff-domain-and-durable-responsibility.md +7 -0
  65. data/docs/decisions/031-durable-multi-agent-coordination.md +7 -0
  66. data/docs/decisions/032-storage-backend-composition.md +85 -0
  67. data/docs/decisions/033-domain-persistence-ownership.md +79 -0
  68. data/docs/decisions/034-handoff-runner-coordination-ownership.md +78 -0
  69. data/docs/decisions/035-tool-executor-capability-ownership.md +68 -0
  70. data/docs/decisions/036-context-contract-ownership.md +86 -0
  71. data/docs/decisions/037-common-definition-ownership.md +62 -0
  72. data/docs/decisions/038-responsibility-based-source-layout.md +145 -0
  73. data/docs/decisions/039-runtime-configuration-lifecycle-ownership.md +82 -0
  74. data/docs/decisions/040-configuration-default-composition.md +105 -0
  75. data/docs/decisions/041-feature-owned-identity-registries.md +100 -0
  76. data/docs/decisions/042-feature-owned-execution-state.md +106 -0
  77. data/docs/decisions/043-storage-execution-constraint-notifications.md +75 -0
  78. data/docs/decisions/044-agent-default-and-one-shot-composition.md +106 -0
  79. data/docs/decisions/045-worker-input-restriction-ownership.md +104 -0
  80. data/docs/decisions/046-agent-responsibility-layout-and-shared-records.md +110 -0
  81. data/docs/decisions/047-recovered-execution-continuation-contract.md +116 -0
  82. data/docs/decisions/048-dispatch-preparation-worker-ownership.md +120 -0
  83. data/docs/decisions/049-initial-preparation-worker-ownership.md +111 -0
  84. data/docs/decisions/050-approval-resume-snapshot-and-commit-ownership.md +98 -0
  85. data/docs/decisions/051-execution-outcome-worker-ownership.md +153 -0
  86. data/docs/decisions/052-tool-invocation-restoration-ownership.md +92 -0
  87. data/docs/decisions/053-shared-state-coordination-ownership.md +71 -0
  88. data/docs/decisions/054-workflow-terminal-save-single-owner.md +76 -0
  89. data/docs/decisions/055-terminal-observer-failure-settlement.md +60 -0
  90. data/docs/decisions/056-workflow-terminal-policy-ownership.md +87 -0
  91. data/docs/decisions/057-storage-transaction-boundaries.md +73 -0
  92. data/docs/decisions/058-neutral-storage-primitives.md +83 -0
  93. data/docs/decisions/059-backend-contracts-and-async-clients.md +74 -0
  94. data/docs/decisions/060-runtime-settings-and-application-configuration.md +86 -0
  95. data/docs/decisions/061-persistence-failure-contracts.md +89 -0
  96. data/docs/decisions/062-content-store-service.md +52 -0
  97. data/docs/decisions/063-execution-contracts-and-services.md +88 -0
  98. data/docs/decisions/064-agent-execution-and-multi-agent-responsibility.md +36 -0
  99. data/docs/decisions/065-vector-and-embeddings-common-operations.md +38 -0
  100. data/docs/decisions/066-llm-and-tool-operation-contracts.md +20 -0
  101. data/docs/decisions/067-agent-progress-and-engine-connection.md +29 -0
  102. data/docs/decisions/068-agent-tool-child-progress-and-tool-operation.md +36 -0
  103. data/docs/decisions/README.md +52 -6
  104. data/docs/design/durable-semantic-coordination/IMPLEMENTATION_DESIGN_V2.md +6 -0
  105. data/docs/design/durable-semantic-coordination/IMPLEMENTATION_REPORT.md +6 -0
  106. data/docs/execution-boundaries-preview.md +45 -0
  107. data/docs/features.md +16 -5
  108. data/docs/getting-started.md +11 -8
  109. data/docs/migrations/0.15.md +5 -0
  110. data/docs/migrations/0.22.md +2 -2
  111. data/docs/migrations/durable-semantic-coordination-v2.md +8 -0
  112. data/docs/migrations/handoff-runner-multi-agent.md +37 -0
  113. data/docs/migrations/neutral-storage-spi.md +43 -0
  114. data/docs/migrations/parallel-tool-chat-removal.md +49 -0
  115. data/docs/migrations/persistence-failure-contracts.md +67 -0
  116. data/docs/migrations/r8-unit10.md +36 -0
  117. data/docs/migrations/r8-unit11.md +33 -0
  118. data/docs/migrations/r8-unit12.md +31 -0
  119. data/docs/migrations/r8-unit13.md +36 -0
  120. data/docs/migrations/r8-unit14.md +31 -0
  121. data/docs/migrations/r8-unit15.md +31 -0
  122. data/docs/migrations/r8-unit16.md +26 -0
  123. data/docs/migrations/r8-unit17.md +28 -0
  124. data/docs/migrations/r8-unit18.md +29 -0
  125. data/docs/migrations/r8-unit19.md +28 -0
  126. data/docs/migrations/r8-unit20.md +24 -0
  127. data/docs/migrations/r8-unit21.md +28 -0
  128. data/docs/migrations/r8-unit22.md +29 -0
  129. data/docs/migrations/r8-unit23.md +20 -0
  130. data/docs/migrations/r8-unit4.md +67 -0
  131. data/docs/migrations/r8-unit5.md +75 -0
  132. data/docs/migrations/r8-unit6.md +109 -0
  133. data/docs/migrations/r8-unit7.md +31 -0
  134. data/docs/migrations/r8-unit8.md +33 -0
  135. data/docs/migrations/r8-unit9.md +28 -0
  136. data/docs/migrations/shared-state-multi-agent.md +44 -0
  137. data/docs/migrations/storage-async-client.md +103 -0
  138. data/docs/migrations/storage-backend-composition.md +117 -0
  139. data/docs/migrations/storage-transaction-boundaries.md +74 -0
  140. data/docs/migrations/vector-async-clients.md +110 -0
  141. data/docs/persistence-backends.md +190 -215
  142. data/docs/runtime-and-concurrency.md +142 -32
  143. data/lib/phronomy/agent/admission.rb +78 -0
  144. data/lib/phronomy/{agent_already_exists_error.rb → agent/agent_already_exists_error.rb} +2 -0
  145. data/lib/phronomy/{agent_busy_error.rb → agent/agent_busy_error.rb} +2 -0
  146. data/lib/phronomy/{agent_purged_error.rb → agent/agent_purged_error.rb} +2 -0
  147. data/lib/phronomy/agent/api/agent.rb +17 -0
  148. data/lib/phronomy/{execution_rehydration_required_error.rb → agent/api/execution_rehydration_required_error.rb} +2 -0
  149. data/lib/phronomy/agent/async_event_api.rb +38 -33
  150. data/lib/phronomy/agent/base.rb +106 -294
  151. data/lib/phronomy/agent/before_llm_input.rb +64 -0
  152. data/lib/phronomy/{agent.rb → agent/composition/run_once.rb} +4 -13
  153. data/lib/phronomy/agent/context_candidate_resolver.rb +2 -2
  154. data/lib/phronomy/agent/context_importer.rb +2 -2
  155. data/lib/phronomy/agent/{context_assembler.rb → context_preparation.rb} +157 -288
  156. data/lib/phronomy/agent/control_request.rb +21 -0
  157. data/lib/phronomy/agent/{agent_execution.rb → execution/agent_execution.rb} +8 -4
  158. data/lib/phronomy/agent/{agent_invocation.rb → execution/agent_invocation.rb} +32 -63
  159. data/lib/phronomy/agent/execution/approval_resume_commit.rb +108 -0
  160. data/lib/phronomy/agent/execution/dispatch_preparation.rb +195 -0
  161. data/lib/phronomy/agent/{exact_execution.rb → execution/exact_execution.rb} +43 -23
  162. data/lib/phronomy/agent/{execution_cancellation.rb → execution/execution_cancellation.rb} +8 -5
  163. data/lib/phronomy/agent/execution/execution_coordinator.rb +1744 -0
  164. data/lib/phronomy/agent/execution/execution_failure.rb +30 -0
  165. data/lib/phronomy/agent/execution/execution_metadata.rb +54 -0
  166. data/lib/phronomy/agent/execution/execution_outcome_committer.rb +288 -0
  167. data/lib/phronomy/agent/execution/execution_registry.rb +463 -0
  168. data/lib/phronomy/agent/execution/execution_session_runner.rb +113 -0
  169. data/lib/phronomy/agent/execution/initial_preparation.rb +323 -0
  170. data/lib/phronomy/agent/execution/invocation_actions.rb +368 -0
  171. data/lib/phronomy/agent/execution/invocation_transitions.rb +124 -0
  172. data/lib/phronomy/agent/execution/runtime_record_encoder.rb +210 -0
  173. data/lib/phronomy/agent/execution_change.rb +161 -0
  174. data/lib/phronomy/agent/execution_environment.rb +36 -0
  175. data/lib/phronomy/agent/execution_extension_state.rb +21 -0
  176. data/lib/phronomy/agent/execution_observation.rb +35 -0
  177. data/lib/phronomy/agent/filterable.rb +182 -0
  178. data/lib/phronomy/agent/{handoff_context.rb → handoff/transfer_context.rb} +6 -6
  179. data/lib/phronomy/agent/{handoff_projection.rb → handoff/transfer_projection.rb} +14 -33
  180. data/lib/phronomy/agent/handoff_error.rb +7 -0
  181. data/lib/phronomy/agent/{journal_projection.rb → journal/journal_projection.rb} +4 -0
  182. data/lib/phronomy/agent/{journal_record.rb → journal/journal_record.rb} +3 -3
  183. data/lib/phronomy/agent/{llm_call_record.rb → journal/llm_call_record.rb} +2 -2
  184. data/lib/phronomy/agent/knowledge_item.rb +13 -0
  185. data/lib/phronomy/agent/{agent_root.rb → lifecycle/agent_root.rb} +6 -2
  186. data/lib/phronomy/agent/lifecycle/default_persistence.rb +29 -0
  187. data/lib/phronomy/{engine/runtime/agent_ownership_registry.rb → agent/lifecycle/ownership_registry.rb} +24 -15
  188. data/lib/phronomy/agent/persistence/agent_repository.rb +69 -0
  189. data/lib/phronomy/agent/persistence/cancellation_repository.rb +51 -0
  190. data/lib/phronomy/agent/persistence/codec.rb +338 -0
  191. data/lib/phronomy/agent/persistence/execution_repository.rb +124 -0
  192. data/lib/phronomy/agent/persistence/journal_repository.rb +63 -0
  193. data/lib/phronomy/agent/persistence/records.rb +33 -0
  194. data/lib/phronomy/agent/persistence/retention_repository.rb +70 -0
  195. data/lib/phronomy/agent/persistence/storage_schema.rb +29 -0
  196. data/lib/phronomy/agent/persistence/watermark.rb +29 -0
  197. data/lib/phronomy/agent/recovery/invocation_restorer.rb +124 -0
  198. data/lib/phronomy/agent/{recovery_coordinator → recovery/recovery_coordinator}/continuation.rb +28 -51
  199. data/lib/phronomy/agent/{recovery_coordinator → recovery/recovery_coordinator}/installation.rb +50 -55
  200. data/lib/phronomy/agent/{recovery_coordinator → recovery/recovery_coordinator}/resolution.rb +38 -43
  201. data/lib/phronomy/agent/{recovery_coordinator.rb → recovery/recovery_coordinator.rb} +26 -23
  202. data/lib/phronomy/agent/recovery/recovery_rules.rb +119 -0
  203. data/lib/phronomy/agent/recovery/recovery_support.rb +224 -0
  204. data/lib/phronomy/agent/reserved_execution.rb +16 -0
  205. data/lib/phronomy/agent/retention.rb +17 -0
  206. data/lib/phronomy/agent/runtime_binding/engine_environment.rb +60 -0
  207. data/lib/phronomy/agent/runtime_binding/engine_session_builder.rb +34 -0
  208. data/lib/phronomy/agent/runtime_binding/phase_machine_builder.rb +64 -0
  209. data/lib/phronomy/agent/runtime_binding/tool_session_builder.rb +34 -0
  210. data/lib/phronomy/agent/{ruby_llm_materializer.rb → runtime_input.rb} +19 -39
  211. data/lib/phronomy/agent/saved_context_reader.rb +55 -0
  212. data/lib/phronomy/agent/settings.rb +47 -0
  213. data/lib/phronomy/agent/state_writer.rb +166 -0
  214. data/lib/phronomy/agent/store.rb +253 -0
  215. data/lib/phronomy/{stream_callback_error.rb → agent/stream_callback_error.rb} +2 -0
  216. data/lib/phronomy/agent/{approval_evaluation_request.rb → tool_execution/approval_evaluation_request.rb} +1 -12
  217. data/lib/phronomy/agent/{tool_approval_request.rb → tool_execution/tool_approval_request.rb} +1 -10
  218. data/lib/phronomy/agent/tool_execution/tool_binding.rb +30 -0
  219. data/lib/phronomy/agent/{tool_invocation.rb → tool_execution/tool_invocation.rb} +114 -248
  220. data/lib/phronomy/agent/tool_execution/tool_invocation_actions.rb +107 -0
  221. data/lib/phronomy/agent/tool_execution/tool_invocation_transitions.rb +70 -0
  222. data/lib/phronomy/common/configuration_error.rb +7 -0
  223. data/lib/phronomy/common/error.rb +5 -0
  224. data/lib/phronomy/{agent → common/values}/immutable.rb +9 -1
  225. data/lib/phronomy/common/values/serializable.rb +32 -0
  226. data/lib/phronomy/configuration/runtime_settings.rb +49 -0
  227. data/lib/phronomy/content_store/storage_schema.rb +12 -0
  228. data/lib/phronomy/content_store/stored_contents.rb +44 -0
  229. data/lib/phronomy/context/assembly.rb +202 -0
  230. data/lib/phronomy/{context_budget_exceeded_error.rb → context/budget_exceeded_error.rb} +5 -1
  231. data/lib/phronomy/context/candidate.rb +51 -0
  232. data/lib/phronomy/context/constraint.rb +47 -0
  233. data/lib/phronomy/{agent → context}/context_plan.rb +2 -2
  234. data/lib/phronomy/{agent → context}/context_plan_validator.rb +3 -3
  235. data/lib/phronomy/{agent → context}/context_policy.rb +1 -1
  236. data/lib/phronomy/{agent → context}/context_policy_input.rb +7 -7
  237. data/lib/phronomy/{agent → context}/context_policy_input_builder.rb +1 -1
  238. data/lib/phronomy/context/default_policy.rb +140 -0
  239. data/lib/phronomy/context/final_budget_validator.rb +33 -0
  240. data/lib/phronomy/{agent → context}/llm_input_build_context.rb +2 -2
  241. data/lib/phronomy/{agent → context}/llm_input_manifest.rb +21 -21
  242. data/lib/phronomy/{agent → context}/llm_input_patch.rb +3 -3
  243. data/lib/phronomy/context/manifest_error.rb +10 -0
  244. data/lib/phronomy/context/prompt_template.rb +98 -0
  245. data/lib/phronomy/{vector_store → documents}/loader/base.rb +1 -1
  246. data/lib/phronomy/{vector_store → documents}/loader/csv_loader.rb +2 -2
  247. data/lib/phronomy/{vector_store → documents}/loader/markdown_loader.rb +3 -3
  248. data/lib/phronomy/{vector_store → documents}/loader/plain_text_loader.rb +2 -2
  249. data/lib/phronomy/{vector_store → documents}/splitter/base.rb +1 -1
  250. data/lib/phronomy/{vector_store → documents}/splitter/fixed_size_splitter.rb +2 -2
  251. data/lib/phronomy/{vector_store → documents}/splitter/recursive_splitter.rb +2 -2
  252. data/lib/phronomy/embeddings/async/async_client.rb +44 -0
  253. data/lib/phronomy/embeddings/backends/ruby_llm_embeddings.rb +48 -0
  254. data/lib/phronomy/embeddings/base.rb +43 -0
  255. data/lib/phronomy/embeddings/invalid_result_error.rb +11 -0
  256. data/lib/phronomy/embeddings/transport_error.rb +11 -0
  257. data/lib/phronomy/engine/concurrency/offload_pool.rb +39 -20
  258. data/lib/phronomy/engine/concurrency/pool_registry.rb +47 -12
  259. data/lib/phronomy/{diagnostics.rb → engine/diagnostics.rb} +1 -1
  260. data/lib/phronomy/engine/event_loop.rb +164 -630
  261. data/lib/phronomy/engine/execution_binding.rb +23 -0
  262. data/lib/phronomy/engine/execution_receiver_binding.rb +43 -0
  263. data/lib/phronomy/engine/fsm_protocol.rb +9 -0
  264. data/lib/phronomy/engine/fsm_session.rb +37 -30
  265. data/lib/phronomy/engine/metrics.rb +28 -0
  266. data/lib/phronomy/engine/runtime/timer_queue.rb +1 -1
  267. data/lib/phronomy/engine/runtime.rb +104 -95
  268. data/lib/phronomy/engine/terminal_decision.rb +7 -0
  269. data/lib/phronomy/execution/async_operation.rb +41 -0
  270. data/lib/phronomy/execution/backpressure_error.rb +7 -0
  271. data/lib/phronomy/{blocking.rb → execution/blocking.rb} +2 -2
  272. data/lib/phronomy/execution/cancellation_error.rb +7 -0
  273. data/lib/phronomy/{engine → execution}/concurrency/cancellation_token.rb +5 -1
  274. data/lib/phronomy/{engine → execution}/concurrency/deadline.rb +0 -17
  275. data/lib/phronomy/{engine → execution}/concurrency/physical_completion_task.rb +1 -1
  276. data/lib/phronomy/{engine → execution}/concurrency/result_collector.rb +1 -1
  277. data/lib/phronomy/{engine → execution}/concurrency/result_composition.rb +33 -12
  278. data/lib/phronomy/{engine/concurrency/subscriptions.rb → execution/concurrency/result_subscriptions.rb} +14 -18
  279. data/lib/phronomy/execution/concurrency/subscriptions.rb +25 -0
  280. data/lib/phronomy/execution/concurrency/worker_input_restricted.rb +14 -0
  281. data/lib/phronomy/execution/event_loop_reentrancy_error.rb +8 -0
  282. data/lib/phronomy/{execution.rb → execution/execution.rb} +57 -30
  283. data/lib/phronomy/{execution_cancellation_error.rb → execution/execution_cancellation_error.rb} +2 -0
  284. data/lib/phronomy/execution/execution_receiver.rb +78 -0
  285. data/lib/phronomy/execution/execution_scope_state.rb +35 -0
  286. data/lib/phronomy/{execution_timeout_error.rb → execution/execution_timeout_error.rb} +2 -0
  287. data/lib/phronomy/{invalid_async_entry_action_error.rb → execution/invalid_async_entry_action_error.rb} +2 -0
  288. data/lib/phronomy/{invalid_async_transition_action_error.rb → execution/invalid_async_transition_action_error.rb} +2 -0
  289. data/lib/phronomy/{invalid_async_workflow_action_error.rb → execution/invalid_async_workflow_action_error.rb} +2 -0
  290. data/lib/phronomy/{invocation_context.rb → execution/invocation_context.rb} +0 -15
  291. data/lib/phronomy/execution/invocation_controls.rb +73 -0
  292. data/lib/phronomy/execution/pool_shutdown_error.rb +7 -0
  293. data/lib/phronomy/execution/recursion_limit_error.rb +7 -0
  294. data/lib/phronomy/execution/runnable.rb +24 -0
  295. data/lib/phronomy/execution/runtime_shutdown_error.rb +7 -0
  296. data/lib/phronomy/execution/runtime_shutdown_reentrancy_error.rb +7 -0
  297. data/lib/phronomy/execution/scheduler_reentrancy_error.rb +9 -0
  298. data/lib/phronomy/{engine → execution}/task_result.rb +7 -3
  299. data/lib/phronomy/execution/timeout_error.rb +7 -0
  300. data/lib/phronomy/execution/wait_policy.rb +24 -0
  301. data/lib/phronomy/filter/filter_block_error.rb +14 -0
  302. data/lib/phronomy/generation/generator_verifier/agent_operation.rb +65 -0
  303. data/lib/phronomy/generation/generator_verifier/agent_result_receiver.rb +89 -0
  304. data/lib/phronomy/generation/generator_verifier/default_parser.rb +27 -0
  305. data/lib/phronomy/generation/generator_verifier/pipeline_state.rb +57 -0
  306. data/lib/phronomy/generation/generator_verifier/workflow_builder.rb +112 -0
  307. data/lib/phronomy/generation/generator_verifier.rb +118 -0
  308. data/lib/phronomy/generation/low_confidence_error.rb +14 -0
  309. data/lib/phronomy/llm_adapter/async/async_client.rb +47 -0
  310. data/lib/phronomy/llm_adapter/authentication_error.rb +9 -0
  311. data/lib/phronomy/llm_adapter/backends/ruby_llm.rb +183 -0
  312. data/lib/phronomy/llm_adapter/base.rb +49 -68
  313. data/lib/phronomy/llm_adapter/context_length_error.rb +9 -0
  314. data/lib/phronomy/llm_adapter/invalid_result_error.rb +10 -0
  315. data/lib/phronomy/llm_adapter/message.rb +62 -0
  316. data/lib/phronomy/llm_adapter/rate_limit_error.rb +9 -0
  317. data/lib/phronomy/llm_adapter/request.rb +79 -0
  318. data/lib/phronomy/llm_adapter/response.rb +36 -0
  319. data/lib/phronomy/llm_adapter/stream_chunk.rb +18 -0
  320. data/lib/phronomy/llm_adapter/token_usage.rb +64 -0
  321. data/lib/phronomy/llm_adapter/transport_error.rb +9 -0
  322. data/lib/phronomy/llm_adapter.rb +3 -16
  323. data/lib/phronomy/llm_context_window/token_budget.rb +6 -7
  324. data/lib/phronomy/multi_agent/admission_registry.rb +15 -2
  325. data/lib/phronomy/multi_agent/durable_subagent_coordinator.rb +108 -84
  326. data/lib/phronomy/multi_agent/execution_environment.rb +29 -0
  327. data/lib/phronomy/{agent → multi_agent}/handoff.rb +2 -2
  328. data/lib/phronomy/{agent → multi_agent}/handoff_capability_factory.rb +21 -2
  329. data/lib/phronomy/multi_agent/handoff_participant.rb +79 -0
  330. data/lib/phronomy/{agent → multi_agent}/handoff_policy.rb +1 -1
  331. data/lib/phronomy/multi_agent/handoff_runner.rb +156 -0
  332. data/lib/phronomy/{agent → multi_agent}/handoff_state.rb +2 -2
  333. data/lib/phronomy/multi_agent/orchestrator.rb +61 -75
  334. data/lib/phronomy/multi_agent/persistence/codec.rb +75 -0
  335. data/lib/phronomy/multi_agent/persistence/handoff_state_repository.rb +77 -0
  336. data/lib/phronomy/multi_agent/persistence/records.rb +27 -0
  337. data/lib/phronomy/multi_agent/persistence/storage_schema.rb +21 -0
  338. data/lib/phronomy/multi_agent/persistence/team_execution_repository.rb +124 -0
  339. data/lib/phronomy/multi_agent/persistence/team_repository.rb +69 -0
  340. data/lib/phronomy/multi_agent/reserved_child_admission.rb +88 -0
  341. data/lib/phronomy/multi_agent/runtime_binding/engine_environment.rb +35 -0
  342. data/lib/phronomy/{agent → multi_agent}/shared_state.rb +56 -39
  343. data/lib/phronomy/multi_agent/store.rb +156 -0
  344. data/lib/phronomy/multi_agent/team_coordinator.rb +87 -75
  345. data/lib/phronomy/multi_agent/team_execution.rb +1 -1
  346. data/lib/phronomy/{engine/runtime → multi_agent}/team_ownership_registry.rb +5 -5
  347. data/lib/phronomy/multi_agent/team_root.rb +1 -1
  348. data/lib/phronomy/output_parser/parse_error.rb +7 -0
  349. data/lib/phronomy/persistence/content_repository.rb +26 -0
  350. data/lib/phronomy/persistence/errors.rb +16 -0
  351. data/lib/phronomy/persistence/migration/initial_format_migration.rb +21 -21
  352. data/lib/phronomy/persistence/persistence.rb +23 -0
  353. data/lib/phronomy/persistence/save_outcome.rb +24 -0
  354. data/lib/phronomy/persistence/snapshot_comparison.rb +81 -0
  355. data/lib/phronomy/persistence/storage_boundary.rb +32 -0
  356. data/lib/phronomy/persistence/transaction.rb +86 -0
  357. data/lib/phronomy/persistence_composition/storage_schema.rb +29 -0
  358. data/lib/phronomy/persistence_composition/stores.rb +34 -0
  359. data/lib/phronomy/persistence_composition/unit4_migration.rb +276 -0
  360. data/lib/phronomy/runtime_composition/agent_defaults.rb +11 -0
  361. data/lib/phronomy/runtime_composition/configuration.rb +146 -0
  362. data/lib/phronomy/runtime_composition/configuration_defaults.rb +9 -0
  363. data/lib/phronomy/runtime_composition/evaluation_defaults.rb +7 -0
  364. data/lib/phronomy/runtime_composition/execution_defaults.rb +5 -0
  365. data/lib/phronomy/runtime_composition/generation_defaults.rb +6 -0
  366. data/lib/phronomy/runtime_composition/global_configuration.rb +38 -0
  367. data/lib/phronomy/runtime_composition/global_runtime.rb +19 -0
  368. data/lib/phronomy/runtime_composition/multi_agent_defaults.rb +9 -0
  369. data/lib/phronomy/runtime_composition/workflow_defaults.rb +4 -0
  370. data/lib/phronomy/storage/async/async_client.rb +60 -0
  371. data/lib/phronomy/storage/backend.rb +107 -0
  372. data/lib/phronomy/storage/backends/in_memory.rb +157 -0
  373. data/lib/phronomy/storage/blob_conflict_error.rb +10 -0
  374. data/lib/phronomy/storage/blobs.rb +31 -0
  375. data/lib/phronomy/storage/condition.rb +25 -0
  376. data/lib/phronomy/storage/condition_failed_error.rb +16 -0
  377. data/lib/phronomy/storage/conflict_error.rb +9 -0
  378. data/lib/phronomy/{persistence → storage}/durable_record.rb +12 -12
  379. data/lib/phronomy/storage/entry.rb +33 -0
  380. data/lib/phronomy/storage/guard_ref.rb +13 -0
  381. data/lib/phronomy/storage/not_found_error.rb +9 -0
  382. data/lib/phronomy/storage/record_codec.rb +177 -0
  383. data/lib/phronomy/storage/records.rb +61 -0
  384. data/lib/phronomy/storage/resource.rb +126 -0
  385. data/lib/phronomy/storage/scope.rb +25 -0
  386. data/lib/phronomy/storage/serialization_error.rb +9 -0
  387. data/lib/phronomy/storage/streams.rb +44 -0
  388. data/lib/phronomy/storage/transaction_error.rb +10 -0
  389. data/lib/phronomy/storage/unique_constraint_error.rb +17 -0
  390. data/lib/phronomy/storage/unsupported_backend_error.rb +9 -0
  391. data/lib/phronomy/storage/validation.rb +53 -0
  392. data/lib/phronomy/storage/view.rb +131 -0
  393. data/lib/phronomy/testing/eval/metrics.rb +1 -1
  394. data/lib/phronomy/testing/eval/scorer/llm_judge.rb +19 -3
  395. data/lib/phronomy/testing/persistence_contract/a_content_store.rb +1 -1
  396. data/lib/phronomy/testing/persistence_contract/a_journal_repository.rb +2 -2
  397. data/lib/phronomy/testing/persistence_contract/a_persistence_backend.rb +54 -48
  398. data/lib/phronomy/testing/persistence_contract/a_workflow_state_repository.rb +1 -1
  399. data/lib/phronomy/testing/persistence_contract/an_agent_repository.rb +1 -1
  400. data/lib/phronomy/testing/persistence_contract/an_execution_repository.rb +5 -5
  401. data/lib/phronomy/testing/persistence_contract/coordination_repositories.rb +52 -46
  402. data/lib/phronomy/testing/persistence_contract/neutral_storage_primitives.rb +263 -0
  403. data/lib/phronomy/testing/persistence_contract/storage_transaction_boundaries.rb +124 -0
  404. data/lib/phronomy/testing/persistence_contract.rb +4 -0
  405. data/lib/phronomy/tool/authorization.rb +77 -0
  406. data/lib/phronomy/tool/base.rb +549 -9
  407. data/lib/phronomy/tool/call_request.rb +40 -0
  408. data/lib/phronomy/{agent/tool_definition_set.rb → tool/definition_set.rb} +16 -12
  409. data/lib/phronomy/tool/operation.rb +88 -0
  410. data/lib/phronomy/tool/schema.rb +214 -0
  411. data/lib/phronomy/tool/settings.rb +31 -0
  412. data/lib/phronomy/tool/tool_error.rb +7 -0
  413. data/lib/phronomy/{agent → tool}/tool_executor.rb +10 -7
  414. data/lib/phronomy/tools/agent.rb +22 -90
  415. data/lib/phronomy/tools/mcp.rb +21 -14
  416. data/lib/phronomy/tools/vector_search.rb +4 -4
  417. data/lib/phronomy/tracing/automatic.rb +11 -6
  418. data/lib/phronomy/tracing/base.rb +1 -1
  419. data/lib/phronomy/tracing/observation.rb +37 -0
  420. data/lib/phronomy/tracing/settings.rb +36 -0
  421. data/lib/phronomy/vector_store/{async_backend.rb → async/async_client.rb} +35 -29
  422. data/lib/phronomy/vector_store/{in_memory.rb → backends/in_memory.rb} +12 -10
  423. data/lib/phronomy/vector_store/{pgvector.rb → backends/pgvector.rb} +44 -16
  424. data/lib/phronomy/vector_store/{redis_search.rb → backends/redis_search.rb} +74 -37
  425. data/lib/phronomy/vector_store/base.rb +118 -49
  426. data/lib/phronomy/vector_store/invalid_result_error.rb +12 -0
  427. data/lib/phronomy/vector_store.rb +2 -17
  428. data/lib/phronomy/version.rb +1 -1
  429. data/lib/phronomy/workflow/completion.rb +11 -0
  430. data/lib/phronomy/{workflow.rb → workflow/execution/workflow.rb} +10 -8
  431. data/lib/phronomy/workflow/execution/workflow_action_rules.rb +67 -0
  432. data/lib/phronomy/{workflow_context.rb → workflow/execution/workflow_context.rb} +5 -1
  433. data/lib/phronomy/workflow/execution/workflow_context_ownership_error.rb +7 -0
  434. data/lib/phronomy/workflow/execution/workflow_execution_environment.rb +27 -0
  435. data/lib/phronomy/workflow/execution/workflow_execution_registry.rb +186 -0
  436. data/lib/phronomy/{workflow_runner.rb → workflow/execution/workflow_runner.rb} +145 -115
  437. data/lib/phronomy/workflow/execution/workflow_settings.rb +28 -0
  438. data/lib/phronomy/workflow/persistence/codec.rb +153 -0
  439. data/lib/phronomy/workflow/persistence/state_repository.rb +63 -0
  440. data/lib/phronomy/workflow/persistence/storage_schema.rb +13 -0
  441. data/lib/phronomy/workflow/runtime_binding/workflow_engine_environment.rb +38 -0
  442. data/lib/phronomy/workflow/runtime_binding/workflow_phase_machine_builder.rb +156 -0
  443. data/lib/phronomy/workflow/runtime_binding/workflow_terminal_policy.rb +40 -0
  444. data/lib/phronomy.rb +97 -98
  445. data/scripts/api_snapshot.rb +36 -16
  446. data/scripts/storage_spi_snapshot.rb +36 -0
  447. data/sig/_private/phronomy/agent/settings.rbs +19 -0
  448. data/sig/_private/phronomy/configuration/runtime_settings.rbs +20 -0
  449. data/sig/_private/phronomy/llm_adapter/async/async_client.rbs +10 -0
  450. data/sig/_private/phronomy/multi_agent/store.rbs +8 -0
  451. data/sig/_private/phronomy/persistence/storage_boundary.rbs +7 -0
  452. data/sig/_private/phronomy/tool/settings.rbs +13 -0
  453. data/sig/_private/phronomy/tracing/settings.rbs +15 -0
  454. data/sig/_private/phronomy/workflow/execution/workflow_settings.rbs +13 -0
  455. data/sig/phronomy/agent/admission.rbs +19 -0
  456. data/sig/phronomy/agent/execution_contract.rbs +132 -0
  457. data/sig/phronomy/agent/execution_environment.rbs +20 -0
  458. data/sig/phronomy/agent/store.rbs +73 -0
  459. data/sig/phronomy/agent.rbs +14 -139
  460. data/sig/phronomy/common.rbs +7 -0
  461. data/sig/phronomy/content_store/contracts.rbs +13 -0
  462. data/sig/phronomy/context.rbs +152 -0
  463. data/sig/phronomy/embeddings/async/async_client.rbs +9 -0
  464. data/sig/phronomy/embeddings/base.rbs +17 -0
  465. data/sig/phronomy/engine/concurrency/timer_bindings.rbs +22 -0
  466. data/sig/phronomy/engine/control_bindings.rbs +11 -0
  467. data/sig/phronomy/engine/control_protocols.rbs +23 -0
  468. data/sig/phronomy/engine/execution_binding.rbs +6 -0
  469. data/sig/phronomy/engine/execution_receiver.rbs +15 -0
  470. data/sig/phronomy/engine/observability.rbs +13 -0
  471. data/sig/phronomy/execution/async_operation.rbs +7 -0
  472. data/sig/phronomy/execution/blocking.rbs +5 -0
  473. data/sig/phronomy/execution/concurrency/cancellation_token.rbs +13 -0
  474. data/sig/phronomy/execution/concurrency/deadline.rbs +10 -0
  475. data/sig/phronomy/execution/concurrency/result_composition.rbs +7 -0
  476. data/sig/phronomy/execution/control_protocols.rbs +18 -0
  477. data/sig/phronomy/execution/errors.rbs +7 -0
  478. data/sig/phronomy/execution/execution.rbs +41 -0
  479. data/sig/phronomy/execution/execution_receiver.rbs +40 -0
  480. data/sig/phronomy/execution/execution_scope_state.rbs +9 -0
  481. data/sig/phronomy/execution/invocation_context.rbs +18 -0
  482. data/sig/phronomy/execution/invocation_controls.rbs +13 -0
  483. data/sig/phronomy/execution/task_result.rbs +29 -0
  484. data/sig/phronomy/extensions.rbs +0 -21
  485. data/sig/phronomy/handoff.rbs +12 -4
  486. data/sig/phronomy/llm_adapter/backends/ruby_llm.rbs +6 -0
  487. data/sig/phronomy/llm_adapter/base.rbs +14 -0
  488. data/sig/phronomy/llm_adapter/usage.rbs +14 -0
  489. data/sig/phronomy/llm_adapter/values.rbs +43 -0
  490. data/sig/phronomy/llm_context_window.rbs +10 -0
  491. data/sig/phronomy/multi_agent/reserved_child_admission.rbs +8 -0
  492. data/sig/phronomy/multi_agent/store.rbs +54 -0
  493. data/sig/phronomy/multi_agent.rbs +24 -3
  494. data/sig/phronomy/persistence/errors.rbs +18 -0
  495. data/sig/phronomy/persistence/migration.rbs +13 -0
  496. data/sig/phronomy/persistence/transaction.rbs +19 -0
  497. data/sig/phronomy/persistence.rbs +3 -185
  498. data/sig/phronomy/persistence_composition.rbs +19 -0
  499. data/sig/phronomy/runtime_composition/configuration.rbs +36 -0
  500. data/sig/phronomy/storage/async/async_client.rbs +8 -0
  501. data/sig/phronomy/storage/backends/in_memory.rbs +9 -0
  502. data/sig/phronomy/storage/contracts.rbs +160 -0
  503. data/sig/phronomy/tool.rbs +58 -5
  504. data/sig/phronomy/tracing/observation.rbs +7 -0
  505. data/sig/phronomy/vector_store/async/async_client.rbs +13 -0
  506. data/sig/phronomy/vector_store/base.rbs +23 -0
  507. data/sig/phronomy/workflow/execution/workflow_execution_environment.rbs +14 -0
  508. data/sig/phronomy/workflow/runtime_binding/workflow_terminal_policy.rbs +7 -0
  509. data/sig/phronomy/workflow/store.rbs +8 -0
  510. data/sig/phronomy/workflow.rbs +1 -1
  511. data/sig/phronomy.rbs +0 -49
  512. metadata +462 -130
  513. data/lib/phronomy/agent/agent_invocation_session_builder.rb +0 -584
  514. data/lib/phronomy/agent/concerns/before_llm_input.rb +0 -66
  515. data/lib/phronomy/agent/concerns/error_translation.rb +0 -45
  516. data/lib/phronomy/agent/concerns/filterable.rb +0 -184
  517. data/lib/phronomy/agent/context/capability/base.rb +0 -507
  518. data/lib/phronomy/agent/context/instruction/prompt_template.rb +0 -102
  519. data/lib/phronomy/agent/context_parts/validators/final_budget_validator.rb +0 -37
  520. data/lib/phronomy/agent/context_policies/default.rb +0 -142
  521. data/lib/phronomy/agent/execution_coordinator.rb +0 -3151
  522. data/lib/phronomy/agent/handoff_execution_coordinator.rb +0 -143
  523. data/lib/phronomy/agent/handoff_request.rb +0 -45
  524. data/lib/phronomy/agent/handoff_runner.rb +0 -178
  525. data/lib/phronomy/agent/phase_machine_builder.rb +0 -152
  526. data/lib/phronomy/agent/provider_call_outcome.rb +0 -106
  527. data/lib/phronomy/agent/recovery_support.rb +0 -504
  528. data/lib/phronomy/agent/selection/candidate.rb +0 -53
  529. data/lib/phronomy/agent/selection/constraint.rb +0 -49
  530. data/lib/phronomy/agent/token_budget_resolver.rb +0 -70
  531. data/lib/phronomy/agent/tool_call_intercepted.rb +0 -29
  532. data/lib/phronomy/agent/tool_invocation_session_builder.rb +0 -276
  533. data/lib/phronomy/configuration.rb +0 -59
  534. data/lib/phronomy/engine/concurrency/cancellation_scope.rb +0 -124
  535. data/lib/phronomy/engine/concurrency/operation_binding.rb +0 -43
  536. data/lib/phronomy/generator_verifier.rb +0 -369
  537. data/lib/phronomy/invalid_context_budget_configuration_error.rb +0 -8
  538. data/lib/phronomy/llm_adapter/ruby_llm.rb +0 -47
  539. data/lib/phronomy/metrics.rb +0 -26
  540. data/lib/phronomy/multi_agent/parallel_tool_chat.rb +0 -116
  541. data/lib/phronomy/persistence/durable_codec.rb +0 -706
  542. data/lib/phronomy/persistence/in_memory.rb +0 -690
  543. data/lib/phronomy/persistence/repository_facades.rb +0 -535
  544. data/lib/phronomy/persistence.rb +0 -276
  545. data/lib/phronomy/recovery.rb +0 -186
  546. data/lib/phronomy/ruby_llm_patches.rb +0 -24
  547. data/lib/phronomy/runnable.rb +0 -54
  548. data/lib/phronomy/token_usage.rb +0 -85
  549. data/lib/phronomy/vector_store/embeddings/base.rb +0 -44
  550. data/lib/phronomy/vector_store/embeddings/ruby_llm_embeddings.rb +0 -47
  551. data/lib/phronomy/workflow/phase_machine_builder.rb +0 -205
  552. data/lib/phronomy/workflow_recovery.rb +0 -123
  553. data/sig/phronomy/llm_adapter.rbs +0 -11
  554. data/sig/phronomy/runtime.rbs +0 -76
  555. /data/lib/phronomy/agent/{llm_operation_result.rb → execution/llm_operation_result.rb} +0 -0
  556. /data/lib/phronomy/{canonical_json.rb → common/canonical_json.rb} +0 -0
  557. /data/lib/phronomy/{event.rb → engine/event.rb} +0 -0
@@ -0,0 +1,130 @@
1
+ # r8 unit 3: Persistence ownership and Team/Agent operations
2
+
3
+ This is a candidate based on core `a82974a7fd2360a13af71831a0c3ddc75942fae3`
4
+ and examples `70b7244c9f6542062849869a7106c5a627868a80`. It implements P01 and
5
+ removes concrete adapter selection from the unit 2 admission framework. P04 is
6
+ partially implemented for Team authorization and scheduling. It is not completion
7
+ of the full contract architecture.
8
+
9
+ ## Ownership and public application construction
10
+
11
+ ```ruby
12
+ stores = Phronomy::PersistenceComposition.in_memory
13
+ # Or: PersistenceComposition.build(backend: configured_storage_backend)
14
+
15
+ Phronomy.configure do |config|
16
+ config.agent_store = stores.agent
17
+ config.team_store = stores.team
18
+ config.workflow_store = stores.workflow
19
+ end
20
+
21
+ agent = MyAgent.create(persistence: stores.agent)
22
+ team = MyTeam.create(persistence: stores.team)
23
+ workflow = Phronomy::Workflow.define(MyContext, persistence: stores.workflow) do
24
+ # Workflow definition
25
+ end
26
+
27
+ agent_result = stores.agent.result(agent_execution_id)
28
+ team_result = stores.team.result(team_execution_id)
29
+ ```
30
+
31
+ For an isolated Agent, `PersistenceComposition.agent(backend: optional_backend)`
32
+ constructs only the Agent/content components. Ordinary Agent defaults use this
33
+ factory. A composition result is a construction bundle, not a query or execution
34
+ service; pass only the relevant component to each consumer.
35
+
36
+ | Owner | Operation / responsibility |
37
+ |---|---|
38
+ | `Persistence` | `atomic`, scope validity, participation and outer commit |
39
+ | `Agent::Store` | Agent result/list/presence/authorization operations, injected Agent record protocol |
40
+ | `MultiAgent::Store` | Team result/list operations, injected Team record protocol and Agent public operations |
41
+ | Workflow checkpoint port | `load`, `save`, `delete` with instance ID and expected revision |
42
+ | Domain `persistence/` implementations | physical resource schema, records, codecs and guards |
43
+ | `PersistenceComposition` | selects backend and adapters, validates schemas and binds components |
44
+
45
+ The stores are roles inside the existing domain framework, not new independent
46
+ contracts. Logical acceptance and state-transition decisions remain in Admission,
47
+ TeamCoordinator, and the owning domain operations. Record accessors on stores are
48
+ internal protocols for their own domain, not cross-domain application APIs.
49
+ Common Persistence neither knows these types nor imports composition.
50
+
51
+ ## Atomic participation remains unchanged
52
+
53
+ The parent reservation is committed first. At child acceptance, the parent guard
54
+ is acquired before reading the current reservation, then Agent input/execution
55
+ and root revision are written in that same scope. The parent's domain owns its
56
+ reservation/cancellation/identity checks. Agent does not interpret parent schemas.
57
+ Only after the outer commit does Agent expose its accepted state and start work.
58
+
59
+ Domain adapters are injected at construction and receive the exact scope's view.
60
+ They never select another connection or commit independently. The coordinator
61
+ identity, same-thread lifetime, savepoint behavior, conflict classification,
62
+ rollback, and uncertain-commit behavior remain in force. LLM/Tool work and async
63
+ waiting remain outside these short transactions. Wrapping ordinary async invoke
64
+ in an application transaction is not a newly supported API.
65
+
66
+ ## Team uses Agent authorization, not execution metadata
67
+
68
+ `Agent::Store#authorized_operations(scope, agent_id:, execution_id:,
69
+ invocation_id:, name:, arguments:, names:)` validates the exact requested call
70
+ against one persisted execution snapshot in the caller's scope. It checks the
71
+ Agent owner, invocation identity, authorization state, name, arguments and
72
+ requested operation family. It returns immutable `AuthorizedOperation` values
73
+ with only `invocation_id`, `name`, and `arguments`, in Provider order.
74
+
75
+ Team applies these operations and owns its durable operation-result ledger.
76
+ A committed replay returns that ledger result without reapplying the batch.
77
+ `finalize` cannot overtake earlier authorized `enqueue_task` calls. A mismatch
78
+ raises `Persistence::StateConflictError` before Team's changes commit.
79
+ `Agent::Store#exist?` reports authoritative absence; failed reads still raise.
80
+
81
+ Team scheduling now uses its own retained assignment count. The default chooses
82
+ the worker with the fewest assignments, breaking ties in worker order. Custom
83
+ schedulers receive `WorkerState#assignment_count` instead of `transcript_size`.
84
+ The count is derived from existing assignments, including failures; there is no
85
+ extra mutable counter and no Agent journal read. This deliberately changes the
86
+ default balancing metric. It does not estimate tokens, duration or resource load.
87
+
88
+ ## Removed APIs and directories
89
+
90
+ - `Persistence.in_memory`, common `transaction`, `capabilities`, repository
91
+ accessors, result/list queries and Agent watermark facade methods are removed.
92
+ `Persistence.new(backend:)` constructs only the neutral coordinator.
93
+ - Domain result queries are `stores.agent.result` / `.runs` and
94
+ `stores.team.result` / `.runs`; Handoff observation remains on the Agent store
95
+ pending the ownership work below.
96
+ - `Configuration#persistence` is replaced by `agent_store`, `team_store`, and
97
+ `workflow_store`; explicit `persistence:` arguments accept the relevant port.
98
+ - The all-domain `PersistenceComposition::Repositories` and the fixed admission
99
+ adapter classes are deleted. There are no legacy API aliases.
100
+ - `persistence/api/` and the six-file `persistence/contract/` error subdivision
101
+ are removed. Shared failures are in `persistence/errors.rb`.
102
+ - Team/Workflow schema declarations are consolidated into their existing domain
103
+ `persistence/` directories; their separate `storage_contract/` directories and
104
+ root schema constants are removed.
105
+
106
+ Storage SPI 2 and physical SQL tables/indexes are unchanged. Existing Agent,
107
+ Handoff and Workflow record codecs are unchanged. New Team worker entries omit
108
+ `transcript_size`; older entries can still be decoded and the unused field is
109
+ ignored by scheduling. Assignment history remains the authority. This does not
110
+ add an API compatibility wrapper or change saved operation results.
111
+
112
+ ## Remaining work (explicitly not claimed complete)
113
+
114
+ 1. Subagent and Handoff still interpret Agent execution/routing records and
115
+ coordination data. Storage adapter class selection has been removed, but
116
+ renaming raw record access does not make it a proper public domain operation.
117
+ Resolve logical ownership, cancellation, responsibility transfer and restart
118
+ together before changing these paths; existing atomic transfer is preserved.
119
+ 2. Orchestrator's preparation/resume integration still accesses Agent-owned
120
+ execution and context details. Team's new operation projection is not a
121
+ general solution to those ownership questions.
122
+ 3. Domain-to-FSM connections, durable Workflow child protocols, multi-record
123
+ uncertain-commit evidence and the remaining semantic dependency review are
124
+ outside this implementation unit. Workflow FINISH translation already exists.
125
+ 4. PostgreSQL concurrency verification for this candidate requires the matching
126
+ core/examples branch or local PostgreSQL setup. Unit 2 CI evidence is not
127
+ evidence that this candidate has passed PostgreSQL.
128
+
129
+ The source SVG and full Ruby/RBS evidence report remaining dependencies. Visual
130
+ suppression of shared common-value arrows does not remove graph evidence.
@@ -0,0 +1,79 @@
1
+ # r8 unit 4: Agent execution and MultiAgent responsibility
2
+
3
+ Core baseline: `3c5fddcae31cc98f8e081feae9b955cf536e5834`.
4
+ Examples baseline: `0370d09fb1608b9596e1803275f713b1a204af26`.
5
+ The foundation mapping dated 2026-09-30 and its target/concept diagrams remain the
6
+ refactoring goal. This change implements the C01/C04 boundary; it does not claim
7
+ that the whole existing implementation already matches the target DAG.
8
+
9
+ | Responsibility | Owner and current entry point |
10
+ |---|---|
11
+ | Exact execution identity, admission and observation | Agent `ReservedExecution`, `start_reserved_async`, `resume_async`, `cancel_async`, `Store#observe_execution` |
12
+ | Finalized input, groups and provenance | Agent `ControlRequest`, `TransferContext`, `TransferProjection` with Context assembly |
13
+ | Selection policy, Source/Target mapping and routing | MultiAgent `HandoffPolicy`, capability binding, `HandoffRunner`, `HandoffParticipant` |
14
+ | Static subagent slot, definition, input, inherited knowledge and import progress | MultiAgent `DurableSubagentCoordinator`; immutable content snapshot |
15
+ | Execution/Root/journal mutation and publication authority | Agent `ExecutionChange` and `ExecutionOutcomeCommitter` |
16
+ | Whole-Agent retention and durable cancellation intent | Agent public operations; Agent-owned record resources |
17
+ | History removal and release of its own holds | MultiAgent `Store#forget_subagents`, `Store#forget_handoff` |
18
+ | Physical record adapters and schema | Each domain's Persistence implementation; composition assembles them |
19
+ | Offline old-format conversion | `PersistenceComposition::Unit4Migration`; examples SQL runner |
20
+
21
+ Agent interprets neither child states nor routing phases. MultiAgent uses public
22
+ Agent values and operations; it does not read AgentExecution, raw metadata,
23
+ journals, ContextImporter values or a private event-listener getter. Child results
24
+ are observed from their authoritative execution, never mirrored as mutable child
25
+ statuses in the parent snapshot. IDs for new slots are derived from canonical
26
+ parent Agent/execution/slot identity. Migration preserves existing IDs.
27
+
28
+ ## Commit participant contract
29
+
30
+ A current, synchronous participant declares a `binding` key/version and implements
31
+ `commit`, `guard_change`, and `change_evidence`. `ExecutionChange` exposes semantic
32
+ inputs only. In one outer `Persistence#atomic` scope the participant:
33
+
34
+ 1. Locks routing/Team guards where needed, then Agent roots in lexical ID order.
35
+ 2. Calls `change.prepare_in(scope)` before its own writes. This captures complete
36
+ pre-state, including cancellation intent, under those guards.
37
+ 3. Changes its own records and calls `change.commit_in(scope, state:, transfer_receipt:, pending:)` once.
38
+ 4. Returns after the outer commit. Agent publishes the captured result only then.
39
+
40
+ The change is bound to the original thread, coordinator and prepared scope. It
41
+ checks its Agent watermark and expected execution revision. A nested savepoint
42
+ cannot authorize publication. Reconciliation compares Root, execution payload,
43
+ appended journal, extension content, cancellation intent, and participant evidence
44
+ in a consistent scope. Exact post-state proves commit; exact pre-state proves no
45
+ commit; different state or failed reads require recovery. There is no write retry.
46
+ An updated record at the expected revision alone is insufficient evidence.
47
+
48
+ Subagent cancellation retains unresolved active work. Known business errors may
49
+ follow `on_error: :skip`; unknown external outcomes cannot be skipped into success.
50
+ Handoff Source transfer and Target terminal stabilization join the same Agent
51
+ change. A suspended or recovery-required Target does not stabilize routing.
52
+ Current participant key/version and Target definition must match before resuming.
53
+ Terminal results can still be read without re-creating application wiring.
54
+
55
+ ## Retention and cancellation
56
+
57
+ `agent.retentions` prevents purge independently of MultiAgent schema. C01 records
58
+ its parent/child or conversation holds when reserving/creating work. History
59
+ removal checks unfinished work, removes its references and releases only its own
60
+ owner key in the same transaction. Other holds remain authoritative.
61
+ `agent.cancellations` stores monotonic intent separately from execution revision,
62
+ so an external cancel does not invalidate an in-flight worker's captured revision.
63
+ Signal delivery follows the durable write; restored executions read that intent.
64
+
65
+ `Agent::Admission` remains the same-scope acceptance boundary. A participant never
66
+ starts a child inside a transaction or waits for its lifetime on a worker thread.
67
+ Ordinary Agent composition does not load MultiAgent routing repositories.
68
+ Standalone `dispatch_parallel` keeps its existing Runtime-scoped behavior.
69
+
70
+ ## Remaining boundaries
71
+
72
+ `MultiAgent::AdmissionRegistry` still uses Runtime shutdown coordination. Agent,
73
+ Tool and Workflow execution internals still depend on existing Engine mechanisms.
74
+ These are later r8 work, not erased by constructor injection or diagram grouping.
75
+ The measured source diagram includes those edges and cycles. PostgreSQL lock
76
+ ordering needs its actual database gate; SQLite/InMemory results do not establish
77
+ PostgreSQL behavior. The application package records executed and unexecuted gates.
78
+
79
+ See [API and saved-data migration](../migrations/r8-unit4.md).
@@ -0,0 +1,115 @@
1
+ # r8 unit 5: VectorStore and Embeddings common contracts
2
+
3
+ Core baseline: `29818f5d0577ac5287c5429d6d169ef5fd1c0225`.
4
+ Examples baseline: `c410fc88112ad5e4648ba2e51335023885d9373b`.
5
+ The contract concept and foundation target remain the design goal. This unit
6
+ implements C10/C11 common operation ownership and DP09/DP10 placement. It does
7
+ not complete the other domain Contracts or the outstanding unit 4 acceptance gates.
8
+
9
+ ## Ownership and completion conditions
10
+
11
+ Contract membership follows domain semantics, not frequency of reuse. A Contract
12
+ defines its domain's concepts, legal inputs/results, invariants, extension points
13
+ and observable failure/operation rules. Its framework executes those rules.
14
+ Code used by several callers is not automatically a Contract; a generic utility,
15
+ concrete adapter helper or composition operation can have several callers too.
16
+
17
+ | Placement decision in this unit | Domain reason |
18
+ | --- | --- |
19
+ | VectorStore id/vector/metadata inputs and ordered search results | These describe the public vector storage/retrieval operation independently of a database |
20
+ | Embeddings text/vector inputs and results | These describe text embedding independently of the provider SDK and downstream storage |
21
+ | Validation, pre-operation cancellation checkpoint and InvalidResultError | These enforce the operation's observable invariants and failure rules |
22
+ | Float-array normalization | This realizes the declared vector representation; it does not make arbitrary serialization a Contract concern |
23
+ | Redis RESP2 decoding, distance-to-similarity conversion, Pgvector row/JSON decoding | These are concrete backend adaptations and remain in the corresponding backend |
24
+ | Document loading/splitting | These are document utilities separated from VectorStore; this move does not create a new Contract |
25
+ | Async submission and timeout settlement | These remain Execution responsibilities, connected through each AsyncClient |
26
+
27
+ | Responsibility | Owner | Completion evidence |
28
+ | --- | --- | --- |
29
+ | Vector operation entry, cancellation checkpoint, input/result validation, chaining | `VectorStore::Base` | A hook-only custom backend receives validated inputs; malformed inputs perform no I/O; malformed outputs fail explicitly |
30
+ | Search/storage algorithms, physical dimension state, database encoding | `VectorStore::{InMemory,Pgvector,RedisSearch}` | Existing algorithm and adapter tests run through inherited public operations |
31
+ | Text input and finite embedding result validation | `Embeddings::Base` | A hook-only provider works without SDK, Engine or VectorStore; malformed outputs are rejected |
32
+ | Embedding provider call and SDK exception translation | `Embeddings::RubyLLMEmbeddings` | Provider exceptions retain their cause; cancellation and application failures retain their identity |
33
+ | Submission, timeout, admission and completion handle | Each feature's `AsyncClient` and Execution | Existing pool, cancellation, timeout and Runtime reset tests |
34
+ | Document input and splitting | `Documents::Loader` / `Documents::Splitter` | Existing document tests; no VectorStore or Embeddings dependency |
35
+
36
+ Common behavior lives in the existing Base classes. There is no forwarding
37
+ Contract, Base-to-client factory, compatibility alias or mandatory embedding
38
+ provider in VectorStore. Protected `perform_*` methods are the extension SPI;
39
+ applications call the inherited public operations. Ruby can override any method,
40
+ but overriding the public template is outside the documented backend SPI.
41
+
42
+ ## Defined operation behavior
43
+
44
+ `VectorStore#add` checks cancellation, a String id, Hash metadata, a vector of
45
+ finite real numbers and the backend's known dimension before entering the
46
+ storage hook. It supplies a fresh Float array and returns the store. `remove`
47
+ and `clear` also return the store. A search validates input and positive `k`
48
+ before entering its hook, including an empty Redis store. Decimal strings for
49
+ `k` remain supported; fractional values no longer truncate silently.
50
+
51
+ Search results must be an Array of at most `k` Hashes with String `:id`, finite
52
+ numeric `:score`, Hash `:metadata`, and descending score order. A count must be
53
+ a non-negative Integer. Violations raise `VectorStore::InvalidResultError`.
54
+ Backend transport failures propagate without retries. Redis count failures no
55
+ longer become a successful zero count. Backend-specific index creation, metadata
56
+ encoding and query construction remain in the backend; they are not new common
57
+ storage primitives. Existing dimension-zero InMemory vectors remain supported.
58
+
59
+ Backends must not invent successful values while decoding malformed external
60
+ responses. RedisSearch validates its RESP2 count, field pairs, document keys,
61
+ numeric distances and JSON object metadata before producing the public result.
62
+ A genuine zero-match reply is `[0]`. A missing whole reply is invalid. Redis's
63
+ documented null document contents after expiration/update are omitted; they do
64
+ not imply a corrupt response, and the total can exceed the returned page size.
65
+ Missing/null Redis metadata and a SQL NULL metadata column still mean empty
66
+ metadata. Invalid JSON text, empty JSON text, JSON scalars/arrays and invalid
67
+ scores raise `InvalidResultError`. Pgvector also rejects invalid row ids rather
68
+ than turning them into strings. JSON parse failures preserve their original cause;
69
+ transport/database exceptions propagate unchanged and no read is retried.
70
+
71
+ The response decoders stay private to each backend. Base does not know Redis
72
+ commands, RESP versions, ActiveRecord rows, JSON columns or SDK exceptions.
73
+ The existing RESP2 support boundary and known-dimension/index initialization
74
+ requirements remain; this unit does not add RESP3 support.
75
+
76
+ Protocol references: [FT.SEARCH](https://redis.io/docs/latest/commands/ft.search/)
77
+ and [FT.INFO](https://redis.io/docs/latest/commands/ft.info/), checked 2026-10-03.
78
+
79
+ `Embeddings#embed` checks cancellation and String input, invokes `perform_embed`
80
+ once, and validates a non-empty finite vector before returning Float values.
81
+ Malformed output raises `Embeddings::InvalidResultError`. The RubyLLM backend
82
+ translates `RubyLLM::Error` to `Embeddings::TransportError`, preserving `cause`.
83
+ This error does not imply that external work was or was not accepted. There is
84
+ no automatic retry and no classification of an arbitrary application exception
85
+ as a provider failure.
86
+
87
+ Cancellation is cooperative. The common checkpoint occurs before the backend
88
+ operation; a provider may inspect the same signal during its work. A successful
89
+ write is not changed into cancellation by a post-write check. Timeout and result
90
+ settlement remain Execution responsibilities; an external call may continue.
91
+
92
+ Input errors are F0 failures before X0 I/O. For a write that has crossed X0,
93
+ failure/timeout is not proof of a rollback or of a missing external effect.
94
+ This unit adds no F1 outcome reconciliation, F4 recovery, cross-process exclusion
95
+ or exactly-once external-effect guarantee. InMemory dimension inference and
96
+ backend concurrency constraints retain their documented limits.
97
+
98
+ ## Refactoring completion tracking
99
+
100
+ | Contracts | Current boundary status | Remaining work |
101
+ | --- | --- | --- |
102
+ | C10 VectorStore / C11 Embeddings | Common contract behavior implemented in unit 5 | Real Pgvector/Redis/provider service verification remains an implementation gate, reported separately |
103
+ | C05 Context / C07 Persistence / C08 ContentStore / C12 Storage / C13 Execution / C15 Tracing | Main common foundations implemented in units 1-4 | Additional domain acceptance conditions and overall dependency review are not waived |
104
+ | C09 LLM / C06 Tool | Partial | Public values/failures, SDK-neutral operation boundary, Tool SDK inheritance and execution connection |
105
+ | C04 Agent / C01 MultiAgent | Unit 4 ownership boundary implemented | FSM/Runtime/composition dependencies |
106
+ | C02 Workflow | Partial | FSM connection and durable child identity/resume/outcome reconciliation |
107
+ | C03 Generation / C16 Filter / C17 OutputParser | Existing common implementation | Finish responsibility-level conformity review; absence of certification is not evidence that all code is missing |
108
+
109
+ Next implement C09/C06 together where their SDK boundary interacts, then finish
110
+ C04/C01/C02 execution connections and durable collaboration. Inspect the existing
111
+ C03/C16/C17 implementations against explicit conditions before scheduling rewrites.
112
+
113
+ The package records commands actually executed and unexecuted backend gates.
114
+ See [migration](../migrations/r8-unit5.md) and
115
+ [ADR-065](../decisions/065-vector-and-embeddings-common-operations.md).
@@ -0,0 +1,71 @@
1
+ # r8 unit 6: C09 LLM and C06 Tool
2
+
3
+ Contract placement is determined by ownership of meaning and operations. Reuse
4
+ alone is not a reason to put code into a contract. This unit completes the scoped
5
+ LLM/Tool operation boundary; it does not complete every contract in the target.
6
+
7
+ | Owner | Meaning and operations |
8
+ | --- | --- |
9
+ | C09 LLM, `LLMAdapter` | Immutable Request, Message, Response, StreamChunk and TokenUsage; complete/stream templates; input/result/cancellation checks; public failures |
10
+ | C06 Tool, `Tool` | CallRequest, declarations, advertised schema, argument validation/coercion, authorization evaluation and execution/error rules |
11
+ | RubyLLM backend | SDK chat construction, options, message/Tool rendering, chunk/response decoding, SDK exception translation and SDK Tool interception |
12
+ | Agent | Select context, prepare executable Tools, run approval and Tool batches, consume LLM results, persist and recover execution facts |
13
+ | Execution / AsyncClient | Scheduling, cancellation signals, deadlines and worker submission; AsyncClient submits the whole LLM operation |
14
+
15
+ Tool requests are ordinary assistant Response values. They do not authorize or
16
+ execute a Tool. Only the backend knows RubyLLM's message callback and its private
17
+ interception signal. SDK Tool declarations have a rejecting execute method; an
18
+ accidental SDK auto-execution fails instead of bypassing Agent authorization.
19
+ A minimal backend needs only protected perform_complete/perform_stream hooks.
20
+ Agent does not require a Chat-like object, SDK methods or executable Tool handles
21
+ from it. Streaming returns a final Response in addition to typed chunk events.
22
+
23
+ TokenUsage and the four existing LLM failures move from the root namespace into
24
+ LLMAdapter, with no aliases. Unknown usage remains nil, distinct from zero.
25
+ ContextLengthError remains a direct Phronomy::Error; rate limiting and
26
+ authentication remain TransportError subtypes. InvalidResultError identifies
27
+ malformed results rather than a valid empty response. SDK errors retain cause;
28
+ application callback errors and cancellation retain their original identity.
29
+
30
+ `Tool::Base` no longer inherits RubyLLM::Tool. Both `param` and explicit `parameters`
31
+ (Hash/schema DSL) produce a C06 Schema. `validate_arguments` is the public, pure
32
+ preflight operation used before approval; `call` uses the same schema/rules before
33
+ execute. Legacy private type/coercion/nesting algorithms are removed. Parameters
34
+ that were advertised but not enforced by the explicit-schema path now fail before
35
+ approval or execute. See the migration document for the supported schema dialect.
36
+
37
+ SDK initialization, setters, completion and decoding run within AsyncClient's
38
+ worker operation. Cancellation is checked before and after the backend operation,
39
+ after SDK construction, and before delivering chunks. A deadline is an Execution
40
+ cancellation signal. It can settle the caller while a blocking SDK constructor is
41
+ still running; it does not forcibly stop a thread. When that constructor returns,
42
+ the cancellation checkpoint prevents starting a new provider request. Already
43
+ sent external work is not rolled back. Local input_budget uses existing model
44
+ registry metadata; live capacity discovery is not added to the contract.
45
+
46
+ Saved context materializes Phronomy Message/CallRequest values. SDK rendering
47
+ occurs later inside the backend, including structured-content JSON rendering and
48
+ opaque thought_signature metadata. Existing durable thought_signature and usage
49
+ field spellings remain readable. New Tool batch metadata stores the validated
50
+ argument snapshot alongside raw arguments so public authorization projection
51
+ compares what was approved, including coercion and intentional null. Historical
52
+ snapshots retain their explicit old decoding rule. Recovery resolution accepts a Response or its
53
+ canonical Hash, not arbitrary SDK objects. Record identities, transaction/CAS
54
+ rules, approval ownership and F0/F1/F4 classifications remain with Agent and
55
+ Persistence. No exactly-once or automatic retry guarantee is introduced.
56
+
57
+ ## Architecture evidence
58
+
59
+ M47 (`llm_contract`) is retired into M15 (`llm_adapter`); the identifier is not
60
+ reused and historical diagrams remain historical. C09 is allowed to reference
61
+ C06 Schema/CallRequest. Directory aggregation also shows C09 -> Tool -> Execution,
62
+ because Tool::Base owns an execution template in the same directory as the values.
63
+ The directory gate permits that specific route; AST checks reject direct C09
64
+ mechanism references, Tool::Base consumption and SDK/Agent/Engine leaks. The full
65
+ Ruby/RBS matrix retains the route instead of hiding it. Standalone loading and a
66
+ minimal backend execution test additionally establish that C09 values do not
67
+ load Tool::Base, Agent, Engine or the SDK.
68
+
69
+ Remaining work includes Agent/MultiAgent/Workflow FSM and Runtime connections,
70
+ Workflow durable children and cross-record outcome evidence, live provider
71
+ verification, and the broader semantic review of existing dependency triangles.
@@ -0,0 +1,70 @@
1
+ # r8 unit 7: C04 Agent progress and execution connection
2
+
3
+ Contract placement follows ownership of meaning, invariants, operations and
4
+ failures. It is not determined by reuse. This unit improves C04; it does not mark
5
+ all of C04, C06 or the overall target complete.
6
+
7
+ | Owner | Responsibility after this change |
8
+ | --- | --- |
9
+ | Agent InvocationTransitions | Phase vocabulary, ordered automatic/external transitions, guard evaluation, iteration bound |
10
+ | Agent InvocationActions | Prepared input, LLM dispatch, Tool batch orchestration and result/event interpretation |
11
+ | Agent ExecutionCoordinator / RecoveryCoordinator | Admission, durable preparation, approval, terminal outcome, recovery and causal revision checks |
12
+ | Agent ExecutionEnvironment | Private process-local connection required by the Agent framework; session construction/registration, serial owner and operation submission |
13
+ | Agent EngineEnvironment / EngineSessionBuilder / PhaseMachineBuilder | Runtime registration, EventLoop channel, FSMSession construction and state_machines adaptation |
14
+ | ExecutionReceiver | Serial-owner admission, delivery and lifecycle framework for feature-owned live state |
15
+ | Engine ExecutionReceiverBinding | Concrete EventLoop registration, locking, queued delivery and routing |
16
+
17
+ Previously AgentInvocationSessionBuilder combined Agent entry operations with
18
+ FSMSession creation. PhaseMachineBuilder held automatic progress rules, while
19
+ InvocationTransitions held only external transitions. Execution/recovery also
20
+ selected Runtime.instance repeatedly. The split now leaves both transition sets
21
+ and their priority with Agent. The Engine builder only installs those definitions
22
+ and synchronous entry callbacks into state_machines. InvocationActions retains
23
+ Agent semantics instead of moving the old class wholesale into an adapter.
24
+
25
+ An Agent captures the environment of its ownership registry at construction.
26
+ Execution and recovery reuse it; changing the composition provider does not move
27
+ a live Agent to another Runtime. Cancellation records its durable request before
28
+ posting a notification through that same environment, including after a provider
29
+ change. Detached Agent cancellation is rejected by the existing live-owner check.
30
+ The default provider is installed lazily by runtime_composition/agent_defaults.rb.
31
+ This is an internal composition port, not a new supported application plugin API.
32
+
33
+ ExecutionRegistry remains Agent-owned. Its generic serial receiver framework
34
+ moves from Engine to Execution and receives a channel. The actual EventLoop
35
+ transport stays in Engine. WorkflowExecutionRegistry uses that same channel to
36
+ preserve its existing receiver lifecycle; Workflow policy is not migrated here.
37
+ This placement follows ownership of execution admission/lifecycle, not merely
38
+ that Agent and Workflow share a base class.
39
+
40
+ Provider Call identity is passed explicitly to AgentInvocation from the already
41
+ prepared durable execution. AgentInvocation no longer queries global Runtime to
42
+ find it. FSMSession IDs remain ephemeral routing incarnation IDs. Approval and
43
+ recovery create a fresh session while preserving durable execution/LLM/Tool IDs.
44
+ No storage schema, CAS revision, parent admission, atomicity or F0/F1/F4 policy
45
+ changes. External effects are not exactly-once. Cancel/timeout do not forcibly
46
+ stop workers or undo effects; terminal persistence still waits for physical
47
+ quiescence. Stale session/revision results remain rejected on the serial owner.
48
+
49
+ ## Evidence and limits
50
+
51
+ The tests execute the transition policy in a standalone Ruby process without
52
+ Engine or state_machines, enumerate all 32 Tool outcome priority combinations,
53
+ compare the Engine adapter's behavior, and check environment retention and
54
+ cancellation routing. Existing recovery, approval, callback failure, single-writer,
55
+ stale-result and shutdown tests remain part of full/integration validation.
56
+ An AST gate rejects concrete Engine constants and state_machines loading in Agent
57
+ execution, recovery, lifecycle and ExecutionEnvironment. This is a scoped gate,
58
+ not proof that every dependency in the system is correct.
59
+
60
+ The measured graph adds M88/G62 for agent/runtime_binding; retired IDs are not
61
+ reused. Ruby and RBS references remain in the evidence, including cycles caused
62
+ by other uncompleted boundaries. Regenerate the measured diagram from the exact
63
+ candidate; do not treat it as the acyclic target design.
64
+
65
+ Still pending: Agent's Tool child FSM/session builder and its Runtime selection;
66
+ MultiAgent and Workflow FSM/Runtime connections; Workflow durable children and
67
+ cross-record outcome evidence; broader dependency-triangle review. The C06 Tool
68
+ operation/schema contract established in unit 6 remains intact, but its Agent-side
69
+ execution connection is not declared complete by this unit. LLM AsyncClient's
70
+ execution backend selection also remains the existing C09/C13 composition.
@@ -0,0 +1,78 @@
1
+ # r8 unit 8: C04 Tool child progress and C06 operation boundaries
2
+
3
+ Contract placement follows ownership of domain meaning, invariants and operations.
4
+ C04 owns the lifecycle of a Tool invocation inside an Agent. Calling a Tool does
5
+ not transfer that lifecycle to C06. This unit completes the scoped Tool child FSM
6
+ separation left by unit 7; it does not certify all of C04 or the overall target.
7
+
8
+ | Owner | Responsibility |
9
+ | --- | --- |
10
+ | Agent ToolInvocationTransitions | Child phases, ordered automatic/external transitions, legal event sources and recursion bound |
11
+ | Agent ToolInvocationActions / ToolInvocation | Validation/authorization orchestration, approval waiting, dispatch eligibility, outcome application and parent notification |
12
+ | Agent ExecutionEnvironment | The original Agent connection for authorization and default Tool submissions, operation supervision and session creation |
13
+ | Agent ToolSessionBuilder / PhaseMachineBuilder in runtime_binding | Concrete FSMSession/EventSink construction and state_machines adaptation of Agent-owned rules |
14
+ | Tool Operation | Tool execution-mode validity, standard/custom async operation dispatch, completion protocol and result adaptation |
15
+ | Tool ToolExecutor | Default cooperative/offloaded Tool operation, using the injected C13 submission protocol |
16
+ | Execution / _ExecutionSubmitter | Execution submission and completion semantics; concrete resource selection stays in the supplied connection |
17
+
18
+ ## What changed
19
+
20
+ ToolInvocationSessionBuilder previously repeated external transitions in both its
21
+ event map and state_machines DSL while also constructing sessions and executing
22
+ Agent entry operations. The new child policy owns one immutable transition set.
23
+ The concrete phase machine and FSMSession source admission read that set. The
24
+ existing parent FSM adapter accepts a policy, so no second domain-aware FSM
25
+ implementation is introduced. Entry operations remain executable Agent code.
26
+
27
+ ToolInvocation now requires its owning execution environment for authorization
28
+ and execution. It no longer selects Runtime.instance, inspects EventLoop, creates
29
+ an ExecutionRegistry connection or selects ToolExecutor. The parent Agent and
30
+ recovery already retain the environment from unit 7; the same environment now
31
+ supplies Tool child entry operations. Authorization captures immutable command
32
+ data before submission. Worker completion delivers an outcome, and serial event
33
+ delivery applies live state.
34
+
35
+ Tool::Operation.call_async is the C06 operation entry for composition-aware
36
+ callers. It selects the standard or custom Tool protocol and validates the
37
+ execution mode and completion handle. Its submitter must implement C13 submit;
38
+ it receives no Agent-specific type. The default offloaded path uses the supplied
39
+ connection, while cooperative work executes inline without a worker. Custom
40
+ call_async implementations keep their existing keyword signature and config,
41
+ return their original handle and continue to own their execution mechanism.
42
+ In particular, an override that calls super still uses the existing Base
43
+ protocol; this change does not inject hidden Runtime state into overrides.
44
+
45
+ Tool::Operation.with_result_transform owns the synchronous/custom-async Tool
46
+ decoration mechanism formerly embedded in Agent::ToolBinding. Agent still chooses
47
+ its configured filters and their meaning. Custom async mapping uses
48
+ AsyncOperation.map and preserves physical completion after logical cancellation.
49
+ As before, an override that itself calls an already decorated synchronous method
50
+ can transform twice; this unit does not rewrite arbitrary application overrides.
51
+
52
+ ## Preserved behavior and limits
53
+
54
+ Authorization completion keeps cancelled > failed > rejected > approval wait >
55
+ authorized priority. Execution completion keeps cancelled > failed > completed.
56
+ Validation keeps failure > completed schema handling > authorization. Explicit
57
+ approve/reject/dispatch/cancel events keep their legal source phases.
58
+ Start execution still precedes mark_running!, preserving dispatch eligibility.
59
+
60
+ Approval/recovery create fresh FSMSession routing IDs while retaining durable
61
+ execution, Tool call and invocation IDs. Parent sinks are session-local. This
62
+ change does not alter persistence schema, CAS revisions, approval snapshots,
63
+ causal dispatch preparation, stale-result handling, single-writer ownership or
64
+ terminal persistence after physical quiescence. Cancellation/timeout do not undo
65
+ external effects or forcibly stop workers; exactly-once effects are not promised.
66
+
67
+ The new tests cover all 48 child guard combinations, legal event sources,
68
+ standalone policy loading without Engine/state_machines, worker-result isolation,
69
+ owning-environment submission, fresh recovery routing, custom call_async and
70
+ physical-completion-aware result transformation. Existing parent transition,
71
+ approval, recovery and shutdown suites remain acceptance gates. The AST gate now
72
+ also rejects concrete Engine/FSM references and ToolExecutor selection in Agent
73
+ tool_execution. Static gates are scoped; they do not prove every dependency valid.
74
+
75
+ MultiAgent/Workflow FSM and Runtime connections, Workflow durable children,
76
+ other concrete composition choices, overall dependency review and additional
77
+ live-service/persistence acceptance tests remain. Regenerate the measured graph
78
+ from the exact candidate; target diagrams are not measured dependency evidence.
@@ -0,0 +1,73 @@
1
+ # R8 unit 9: preserve application-defined Tool result transformations
2
+
3
+ ## Ownership
4
+
5
+ The application owns which transformations run, their order and their
6
+ multiplicity. Agent's ToolBinding captures and composes its configured filters.
7
+ C06 Tool owns the operation/decorator mechanism that executes that composition.
8
+ C13 Execution owns completion adaptation, failure/cancellation propagation and
9
+ physical-completion tracking. Shared use is not the reason for C06 ownership.
10
+
11
+ There is no universal "one filter per public invocation" policy. Each configured
12
+ stage must retain its position and multiplicity. Registering the same filter
13
+ twice or nesting result decorators remains meaningful application composition.
14
+
15
+ ## Defect
16
+
17
+ In unit 7 and unit 8 a custom call_async delegating with super reached Base's
18
+ default async bridge, which invoked the decorated synchronous call. A second
19
+ decoration then transformed the custom async completion. One configured stage
20
+ therefore ran twice. If the custom implementation additionally mapped the result,
21
+ the first transformation also ran on an intermediate value rather than the
22
+ custom operation's final result.
23
+
24
+ ## Internal delegation
25
+
26
+ Operation.with_result_transform records the exact synchronous wrapper method
27
+ only when that decorator also installs an async completion wrapper. Base's
28
+ call_async obtains a bound synchronous delegate from Operation. That delegate
29
+ skips the leading framework wrappers whose async counterparts already own their
30
+ stages. ToolExecutor receives the callable explicitly and invokes it inline or
31
+ inside the submitted worker, on the original Tool instance.
32
+
33
+ Selection stops at application methods and sync-only decorator stages. Exact
34
+ method matching avoids bypassing a later application replacement, including a
35
+ singleton call override. No Thread/Fiber local flag, per-instance busy flag,
36
+ cloning, value tagging, equality check or filter-identity deduplication is used.
37
+
38
+ ## Application calls remain application calls
39
+
40
+ Only Base's standard async-to-sync bridge is internal delegation. A custom
41
+ implementation that explicitly calls the public call method invokes that
42
+ method's configured transformations. Its async completion can then have its own
43
+ transformation. The framework does not guess whether the application intended
44
+ that explicit call to be raw execution.
45
+
46
+ For example, with a bracket transform:
47
+
48
+ | Composition | Result for x |
49
+ | --- | --- |
50
+ | One stage, custom call_async delegates using super | [x] |
51
+ | Two registrations of the bracket transform | [[x]] |
52
+ | Custom maps super's raw value to custom:x, then one stage | [custom:x] |
53
+ | Custom explicitly calls the decorated public call and prefixes custom: | [custom:[x]] |
54
+
55
+ Applications wanting Base's normal execution as an implementation step should
56
+ use super. Applications can also call their configured filters explicitly; those
57
+ calls are never deduplicated. A custom override inserted between decorators is
58
+ an application boundary, not a wrapper the framework may silently bypass.
59
+
60
+ ## Preserved completion contract
61
+
62
+ Custom completions still use AsyncOperation.map. Original failures retain their
63
+ identity, source cancellation remains cancellation, and physical completion waits
64
+ for both source work and active transformations. Cancelling a mapped result still
65
+ does not implicitly cancel its source. Default cooperative/offloaded dispatch,
66
+ the owning submitter, public keyword arguments, effective names, receiver state,
67
+ and schema/authorization rules remain intact.
68
+
69
+ ## Scope
70
+
71
+ This is a core-only correction. Public signatures and stored schemas are unchanged.
72
+ It does not complete the remaining C01/C02 connections, all C04 composition,
73
+ the source dependency cycles, or the broader acceptance gates.