phronomy 0.27.0 → 0.29.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 (517) 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 +28 -7
  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/application-recipes.md +229 -0
  11. data/docs/architecture/agent-chat-and-state-ownership.md +7 -1
  12. data/docs/architecture/agent-transition-ownership.md +13 -89
  13. data/docs/architecture/backend-groups.md +152 -0
  14. data/docs/architecture/before-llm-input.md +3 -3
  15. data/docs/architecture/context-management.md +1 -1
  16. data/docs/architecture/dx05-agent-scope.md +119 -0
  17. data/docs/architecture/dx05-workflow-task-state.md +134 -0
  18. data/docs/architecture/error-api-review.md +245 -0
  19. data/docs/architecture/execution-abstraction-review.md +88 -0
  20. data/docs/architecture/execution-boundaries.md +28 -0
  21. data/docs/architecture/execution-metadata-and-values.md +6 -0
  22. data/docs/architecture/multi-agent-handoff.md +6 -5
  23. data/docs/architecture/persistence.md +27 -9
  24. data/docs/architecture/r8-unit1.md +104 -0
  25. data/docs/architecture/r8-unit10.md +72 -0
  26. data/docs/architecture/r8-unit11.md +71 -0
  27. data/docs/architecture/r8-unit12.md +67 -0
  28. data/docs/architecture/r8-unit13.md +61 -0
  29. data/docs/architecture/r8-unit14.md +72 -0
  30. data/docs/architecture/r8-unit15.md +65 -0
  31. data/docs/architecture/r8-unit16.md +54 -0
  32. data/docs/architecture/r8-unit17.md +73 -0
  33. data/docs/architecture/r8-unit18.md +92 -0
  34. data/docs/architecture/r8-unit19.md +61 -0
  35. data/docs/architecture/r8-unit2.md +55 -0
  36. data/docs/architecture/r8-unit20.md +51 -0
  37. data/docs/architecture/r8-unit21.md +79 -0
  38. data/docs/architecture/r8-unit22.md +74 -0
  39. data/docs/architecture/r8-unit23.md +81 -0
  40. data/docs/architecture/r8-unit3.md +130 -0
  41. data/docs/architecture/r8-unit4.md +79 -0
  42. data/docs/architecture/r8-unit5.md +115 -0
  43. data/docs/architecture/r8-unit6.md +71 -0
  44. data/docs/architecture/r8-unit7.md +70 -0
  45. data/docs/architecture/r8-unit8.md +78 -0
  46. data/docs/architecture/r8-unit9.md +73 -0
  47. data/docs/architecture/refactoring-closure.md +10 -1
  48. data/docs/architecture/remaining-refactoring-plan.md +16 -0
  49. data/docs/architecture/storage-execution-boundaries.md +54 -0
  50. data/docs/architecture/tool-schema-recording-gap.md +6 -0
  51. data/docs/architecture/tracing.md +1 -1
  52. data/docs/architecture/workflow-terminal-ownership-design.md +2 -2
  53. data/docs/architecture.md +24 -11
  54. data/docs/decisions/015-tool-public-facade-and-rbs-boundary.md +3 -3
  55. data/docs/decisions/027-llm-adapter-provider-boundary.md +2 -0
  56. data/docs/decisions/030-agent-handoff-domain-and-durable-responsibility.md +2 -0
  57. data/docs/decisions/031-durable-multi-agent-coordination.md +2 -0
  58. data/docs/decisions/032-storage-backend-composition.md +5 -0
  59. data/docs/decisions/034-handoff-runner-coordination-ownership.md +2 -0
  60. data/docs/decisions/035-tool-executor-capability-ownership.md +1 -1
  61. data/docs/decisions/038-responsibility-based-source-layout.md +14 -0
  62. data/docs/decisions/039-runtime-configuration-lifecycle-ownership.md +8 -0
  63. data/docs/decisions/040-configuration-default-composition.md +12 -1
  64. data/docs/decisions/045-worker-input-restriction-ownership.md +4 -0
  65. data/docs/decisions/051-execution-outcome-worker-ownership.md +2 -0
  66. data/docs/decisions/056-workflow-terminal-policy-ownership.md +1 -1
  67. data/docs/decisions/058-neutral-storage-primitives.md +5 -0
  68. data/docs/decisions/059-backend-contracts-and-async-clients.md +74 -0
  69. data/docs/decisions/060-runtime-settings-and-application-configuration.md +86 -0
  70. data/docs/decisions/061-persistence-failure-contracts.md +89 -0
  71. data/docs/decisions/062-content-store-service.md +52 -0
  72. data/docs/decisions/063-execution-contracts-and-services.md +88 -0
  73. data/docs/decisions/064-agent-execution-and-multi-agent-responsibility.md +36 -0
  74. data/docs/decisions/065-vector-and-embeddings-common-operations.md +38 -0
  75. data/docs/decisions/066-llm-and-tool-operation-contracts.md +20 -0
  76. data/docs/decisions/067-agent-progress-and-engine-connection.md +29 -0
  77. data/docs/decisions/068-agent-tool-child-progress-and-tool-operation.md +36 -0
  78. data/docs/decisions/README.md +18 -1
  79. data/docs/execution-boundaries-preview.md +45 -0
  80. data/docs/failure-reason-codes.md +45 -0
  81. data/docs/features.md +12 -4
  82. data/docs/getting-started.md +52 -48
  83. data/docs/migrations/0.22.md +2 -2
  84. data/docs/migrations/durable-semantic-coordination-v2.md +2 -0
  85. data/docs/migrations/handoff-runner-multi-agent.md +2 -0
  86. data/docs/migrations/persistence-failure-contracts.md +67 -0
  87. data/docs/migrations/r8-unit10.md +36 -0
  88. data/docs/migrations/r8-unit11.md +33 -0
  89. data/docs/migrations/r8-unit12.md +31 -0
  90. data/docs/migrations/r8-unit13.md +36 -0
  91. data/docs/migrations/r8-unit14.md +31 -0
  92. data/docs/migrations/r8-unit15.md +31 -0
  93. data/docs/migrations/r8-unit16.md +26 -0
  94. data/docs/migrations/r8-unit17.md +28 -0
  95. data/docs/migrations/r8-unit18.md +29 -0
  96. data/docs/migrations/r8-unit19.md +28 -0
  97. data/docs/migrations/r8-unit20.md +24 -0
  98. data/docs/migrations/r8-unit21.md +28 -0
  99. data/docs/migrations/r8-unit22.md +29 -0
  100. data/docs/migrations/r8-unit23.md +20 -0
  101. data/docs/migrations/r8-unit4.md +67 -0
  102. data/docs/migrations/r8-unit5.md +75 -0
  103. data/docs/migrations/r8-unit6.md +109 -0
  104. data/docs/migrations/r8-unit7.md +31 -0
  105. data/docs/migrations/r8-unit8.md +33 -0
  106. data/docs/migrations/r8-unit9.md +28 -0
  107. data/docs/migrations/storage-async-client.md +103 -0
  108. data/docs/migrations/vector-async-clients.md +110 -0
  109. data/docs/ordered-event-delivery.md +54 -0
  110. data/docs/persistence-backends.md +38 -21
  111. data/docs/runtime-and-concurrency.md +26 -1
  112. data/docs/workflow-completion.md +92 -0
  113. data/gemfiles/http_minimum.gemfile +5 -0
  114. data/lib/phronomy/agent/admission.rb +78 -0
  115. data/lib/phronomy/agent/{lifecycle_contract/agent_already_exists_error.rb → agent_already_exists_error.rb} +1 -1
  116. data/lib/phronomy/agent/{lifecycle_contract/agent_busy_error.rb → agent_busy_error.rb} +1 -1
  117. data/lib/phronomy/agent/agent_not_found_error.rb +16 -0
  118. data/lib/phronomy/agent/{lifecycle_contract/agent_purged_error.rb → agent_purged_error.rb} +1 -1
  119. data/lib/phronomy/agent/agent_unloaded_error.rb +14 -0
  120. data/lib/phronomy/agent/api/agent.rb +13 -0
  121. data/lib/phronomy/{recovery → agent/api}/execution_rehydration_required_error.rb +1 -1
  122. data/lib/phronomy/agent/async_event_api.rb +132 -103
  123. data/lib/phronomy/agent/base.rb +146 -113
  124. data/lib/phronomy/agent/before_llm_input.rb +70 -0
  125. data/lib/phronomy/agent/composition/run_once.rb +1 -1
  126. data/lib/phronomy/agent/{context_assembly/context_candidate_resolver.rb → context_candidate_resolver.rb} +2 -2
  127. data/lib/phronomy/agent/{context_assembly/context_assembler.rb → context_preparation.rb} +35 -221
  128. data/lib/phronomy/agent/control_request.rb +21 -0
  129. data/lib/phronomy/agent/execution/agent_execution.rb +1 -1
  130. data/lib/phronomy/agent/execution/agent_invocation.rb +27 -53
  131. data/lib/phronomy/agent/execution/approval_resume_commit.rb +1 -1
  132. data/lib/phronomy/agent/execution/dispatch_preparation.rb +17 -127
  133. data/lib/phronomy/agent/execution/exact_execution.rb +55 -32
  134. data/lib/phronomy/agent/execution/execution_cancellation.rb +8 -4
  135. data/lib/phronomy/agent/execution/execution_coordinator.rb +229 -407
  136. data/lib/phronomy/agent/execution/execution_metadata.rb +1 -0
  137. data/lib/phronomy/agent/execution/execution_outcome_committer.rb +71 -127
  138. data/lib/phronomy/agent/execution/execution_registry.rb +6 -2
  139. data/lib/phronomy/agent/execution/execution_session_runner.rb +22 -27
  140. data/lib/phronomy/agent/execution/initial_preparation.rb +19 -120
  141. data/lib/phronomy/agent/execution/{agent_invocation_session_builder.rb → invocation_actions.rb} +54 -194
  142. data/lib/phronomy/agent/execution/invocation_transitions.rb +39 -1
  143. data/lib/phronomy/agent/execution/runtime_record_encoder.rb +8 -11
  144. data/lib/phronomy/agent/execution_change.rb +161 -0
  145. data/lib/phronomy/agent/execution_environment.rb +36 -0
  146. data/lib/phronomy/agent/execution_extension_state.rb +21 -0
  147. data/lib/phronomy/agent/execution_observation.rb +35 -0
  148. data/lib/phronomy/agent/filterable.rb +188 -0
  149. data/lib/phronomy/agent/handoff/{handoff_context.rb → transfer_context.rb} +4 -4
  150. data/lib/phronomy/agent/handoff/{handoff_projection.rb → transfer_projection.rb} +14 -33
  151. data/lib/phronomy/{llm_contract/transport_error.rb → agent/handoff_error.rb} +1 -1
  152. data/lib/phronomy/agent/journal/journal_projection.rb +1 -1
  153. data/lib/phronomy/agent/knowledge_item.rb +13 -0
  154. data/lib/phronomy/agent/lifecycle/agent_root.rb +1 -1
  155. data/lib/phronomy/agent/lifecycle/lifetime_api.rb +76 -0
  156. data/lib/phronomy/agent/lifecycle/operation_lease.rb +33 -0
  157. data/lib/phronomy/agent/lifecycle/operation_result.rb +53 -0
  158. data/lib/phronomy/agent/lifecycle/ownership_registry.rb +117 -31
  159. data/lib/phronomy/agent/lifecycle/scope.rb +198 -0
  160. data/lib/phronomy/agent/lifecycle/scope_cleanup_error.rb +19 -0
  161. data/lib/phronomy/agent/lifecycle/unload_transition.rb +78 -0
  162. data/lib/phronomy/agent/persistence/agent_repository.rb +29 -21
  163. data/lib/phronomy/agent/persistence/cancellation_repository.rb +51 -0
  164. data/lib/phronomy/agent/persistence/codec.rb +1 -21
  165. data/lib/phronomy/agent/persistence/execution_repository.rb +57 -41
  166. data/lib/phronomy/agent/persistence/journal_repository.rb +27 -18
  167. data/lib/phronomy/agent/persistence/records.rb +33 -0
  168. data/lib/phronomy/agent/persistence/retention_repository.rb +70 -0
  169. data/lib/phronomy/agent/persistence/storage_schema.rb +7 -2
  170. data/lib/phronomy/agent/persistence/watermark.rb +13 -11
  171. data/lib/phronomy/agent/recovery/invocation_restorer.rb +13 -21
  172. data/lib/phronomy/agent/recovery/recovery_coordinator/continuation.rb +13 -12
  173. data/lib/phronomy/agent/recovery/recovery_coordinator/installation.rb +34 -34
  174. data/lib/phronomy/agent/recovery/recovery_coordinator/resolution.rb +33 -39
  175. data/lib/phronomy/agent/recovery/recovery_coordinator.rb +28 -25
  176. data/lib/phronomy/agent/recovery/recovery_rules.rb +119 -0
  177. data/lib/phronomy/agent/recovery/recovery_support.rb +10 -19
  178. data/lib/phronomy/agent/reserved_execution.rb +16 -0
  179. data/lib/phronomy/agent/retention.rb +17 -0
  180. data/lib/phronomy/agent/runtime_binding/engine_environment.rb +60 -0
  181. data/lib/phronomy/agent/runtime_binding/engine_session_builder.rb +34 -0
  182. data/lib/phronomy/agent/runtime_binding/phase_machine_builder.rb +64 -0
  183. data/lib/phronomy/agent/runtime_binding/tool_session_builder.rb +34 -0
  184. data/lib/phronomy/agent/{context_assembly/ruby_llm_materializer.rb → runtime_input.rb} +18 -35
  185. data/lib/phronomy/agent/{context_assembly/saved_context_reader.rb → saved_context_reader.rb} +6 -4
  186. data/lib/phronomy/agent/settings.rb +47 -0
  187. data/lib/phronomy/agent/{context_assembly/state_writer.rb → state_writer.rb} +4 -3
  188. data/lib/phronomy/agent/store.rb +253 -0
  189. data/lib/phronomy/agent/{lifecycle_contract/stream_callback_error.rb → stream_callback_error.rb} +3 -3
  190. data/lib/phronomy/agent/tool_execution/tool_binding.rb +4 -64
  191. data/lib/phronomy/agent/tool_execution/tool_invocation.rb +50 -219
  192. data/lib/phronomy/agent/tool_execution/tool_invocation_actions.rb +107 -0
  193. data/lib/phronomy/agent/tool_execution/tool_invocation_transitions.rb +70 -0
  194. data/lib/phronomy/common/error.rb +65 -1
  195. data/lib/phronomy/configuration/runtime_settings.rb +49 -0
  196. data/lib/phronomy/content_store/base.rb +7 -2
  197. data/lib/phronomy/content_store/storage_schema.rb +1 -0
  198. data/lib/phronomy/content_store/stored_contents.rb +2 -1
  199. data/lib/phronomy/context/assembly.rb +195 -0
  200. data/lib/phronomy/{llm_contract/context_budget_exceeded_error.rb → context/budget_exceeded_error.rb} +3 -1
  201. data/lib/phronomy/context/candidate.rb +51 -0
  202. data/lib/phronomy/context/constraint.rb +47 -0
  203. data/lib/phronomy/{agent/context_contract → context}/context_plan.rb +1 -1
  204. data/lib/phronomy/{agent/context_contract → context}/context_plan_validator.rb +3 -3
  205. data/lib/phronomy/{agent/context_contract → context}/context_policy.rb +1 -1
  206. data/lib/phronomy/{agent/context_contract → context}/context_policy_input.rb +1 -1
  207. data/lib/phronomy/{agent/context_assembly → context}/context_policy_input_builder.rb +1 -1
  208. data/lib/phronomy/context/default_policy.rb +140 -0
  209. data/lib/phronomy/context/final_budget_validator.rb +33 -0
  210. data/lib/phronomy/{agent/context_contract → context}/llm_input_build_context.rb +1 -1
  211. data/lib/phronomy/{agent/context_contract → context}/llm_input_manifest.rb +19 -19
  212. data/lib/phronomy/{agent/context_contract → context}/llm_input_patch.rb +1 -1
  213. data/lib/phronomy/context/manifest_error.rb +10 -0
  214. data/lib/phronomy/context/prompt_template.rb +98 -0
  215. data/lib/phronomy/{vector_store → documents}/loader/base.rb +1 -1
  216. data/lib/phronomy/{vector_store → documents}/loader/csv_loader.rb +2 -2
  217. data/lib/phronomy/{vector_store → documents}/loader/markdown_loader.rb +3 -3
  218. data/lib/phronomy/{vector_store → documents}/loader/plain_text_loader.rb +2 -2
  219. data/lib/phronomy/{vector_store → documents}/splitter/base.rb +1 -1
  220. data/lib/phronomy/{vector_store → documents}/splitter/fixed_size_splitter.rb +2 -2
  221. data/lib/phronomy/{vector_store → documents}/splitter/recursive_splitter.rb +2 -2
  222. data/lib/phronomy/embeddings/async/async_client.rb +44 -0
  223. data/lib/phronomy/embeddings/authentication_error.rb +11 -0
  224. data/lib/phronomy/embeddings/backends/ruby_llm_embeddings.rb +52 -0
  225. data/lib/phronomy/embeddings/base.rb +43 -0
  226. data/lib/phronomy/embeddings/invalid_result_error.rb +11 -0
  227. data/lib/phronomy/embeddings/rate_limit_error.rb +11 -0
  228. data/lib/phronomy/embeddings/transport_error.rb +11 -0
  229. data/lib/phronomy/engine/concurrency/offload_pool.rb +36 -21
  230. data/lib/phronomy/engine/concurrency/pool_registry.rb +47 -12
  231. data/lib/phronomy/engine/diagnostics.rb +1 -1
  232. data/lib/phronomy/engine/event_loop.rb +7 -7
  233. data/lib/phronomy/engine/execution_binding.rb +23 -0
  234. data/lib/phronomy/engine/execution_receiver_binding.rb +43 -0
  235. data/lib/phronomy/engine/fsm_protocol.rb +1 -6
  236. data/lib/phronomy/engine/fsm_session.rb +3 -3
  237. data/lib/phronomy/engine/metrics.rb +16 -14
  238. data/lib/phronomy/engine/runtime/timer_queue.rb +1 -1
  239. data/lib/phronomy/engine/runtime.rb +25 -12
  240. data/lib/phronomy/engine/terminal_decision.rb +7 -0
  241. data/lib/phronomy/execution/async_operation.rb +41 -0
  242. data/lib/phronomy/{engine → execution}/blocking.rb +2 -2
  243. data/lib/phronomy/{engine → execution}/concurrency/cancellation_token.rb +1 -1
  244. data/lib/phronomy/{engine → execution}/concurrency/deadline.rb +0 -17
  245. data/lib/phronomy/{engine → execution}/concurrency/physical_completion_task.rb +1 -1
  246. data/lib/phronomy/{engine → execution}/concurrency/result_collector.rb +1 -1
  247. data/lib/phronomy/{engine → execution}/concurrency/result_composition.rb +33 -12
  248. data/lib/phronomy/{engine/concurrency/subscriptions.rb → execution/concurrency/result_subscriptions.rb} +14 -18
  249. data/lib/phronomy/execution/concurrency/subscriptions.rb +25 -0
  250. data/lib/phronomy/{engine → execution}/execution.rb +61 -27
  251. data/lib/phronomy/{engine → execution}/execution_cancellation_error.rb +2 -2
  252. data/lib/phronomy/execution/execution_receiver.rb +78 -0
  253. data/lib/phronomy/execution/execution_scope_state.rb +35 -0
  254. data/lib/phronomy/{engine → execution}/execution_timeout_error.rb +2 -2
  255. data/lib/phronomy/{engine → execution}/invocation_context.rb +0 -15
  256. data/lib/phronomy/execution/invocation_controls.rb +73 -0
  257. data/lib/phronomy/execution/runnable.rb +24 -0
  258. data/lib/phronomy/{engine → execution}/task_result.rb +9 -4
  259. data/lib/phronomy/execution/wait_policy.rb +24 -0
  260. data/lib/phronomy/filter/{contract/filter_block_error.rb → filter_block_error.rb} +3 -3
  261. data/lib/phronomy/generation/generator_verifier/agent_operation.rb +65 -0
  262. data/lib/phronomy/generation/generator_verifier/default_parser.rb +27 -0
  263. data/lib/phronomy/generation/generator_verifier/workflow_builder.rb +2 -2
  264. data/lib/phronomy/generation/generator_verifier.rb +7 -7
  265. data/lib/phronomy/generation/low_confidence_error.rb +2 -2
  266. data/lib/phronomy/integrations/ordered_event_delivery.rb +208 -0
  267. data/lib/phronomy/llm_adapter/async/async_client.rb +47 -0
  268. data/lib/phronomy/{llm_contract → llm_adapter}/authentication_error.rb +3 -1
  269. data/lib/phronomy/llm_adapter/backends/ruby_llm.rb +183 -0
  270. data/lib/phronomy/llm_adapter/base.rb +49 -68
  271. data/lib/phronomy/{llm_contract → llm_adapter}/context_length_error.rb +3 -1
  272. data/lib/phronomy/llm_adapter/invalid_result_error.rb +10 -0
  273. data/lib/phronomy/llm_adapter/message.rb +62 -0
  274. data/lib/phronomy/{llm_contract → llm_adapter}/rate_limit_error.rb +3 -1
  275. data/lib/phronomy/llm_adapter/request.rb +79 -0
  276. data/lib/phronomy/llm_adapter/response.rb +36 -0
  277. data/lib/phronomy/llm_adapter/stream_chunk.rb +18 -0
  278. data/lib/phronomy/llm_adapter/token_usage.rb +64 -0
  279. data/lib/phronomy/llm_adapter/transport_error.rb +9 -0
  280. data/lib/phronomy/llm_adapter.rb +3 -16
  281. data/lib/phronomy/multi_agent/admission_registry.rb +1 -8
  282. data/lib/phronomy/multi_agent/durable_subagent_coordinator.rb +108 -84
  283. data/lib/phronomy/multi_agent/execution_environment.rb +29 -0
  284. data/lib/phronomy/{agent/handoff → multi_agent}/handoff.rb +2 -2
  285. data/lib/phronomy/{agent/handoff → multi_agent}/handoff_capability_factory.rb +21 -2
  286. data/lib/phronomy/multi_agent/handoff_participant.rb +79 -0
  287. data/lib/phronomy/{agent/handoff → multi_agent}/handoff_policy.rb +1 -1
  288. data/lib/phronomy/multi_agent/handoff_runner.rb +77 -100
  289. data/lib/phronomy/{agent/handoff → multi_agent}/handoff_state.rb +1 -1
  290. data/lib/phronomy/multi_agent/orchestrator.rb +61 -75
  291. data/lib/phronomy/multi_agent/persistence/codec.rb +20 -0
  292. data/lib/phronomy/multi_agent/persistence/handoff_state_repository.rb +77 -0
  293. data/lib/phronomy/multi_agent/persistence/records.rb +27 -0
  294. data/lib/phronomy/multi_agent/persistence/storage_schema.rb +21 -0
  295. data/lib/phronomy/multi_agent/persistence/team_execution_repository.rb +60 -44
  296. data/lib/phronomy/multi_agent/persistence/team_repository.rb +29 -21
  297. data/lib/phronomy/multi_agent/reserved_child_admission.rb +88 -0
  298. data/lib/phronomy/multi_agent/runtime_binding/engine_environment.rb +35 -0
  299. data/lib/phronomy/multi_agent/shared_state.rb +2 -2
  300. data/lib/phronomy/multi_agent/store.rb +156 -0
  301. data/lib/phronomy/multi_agent/team_busy_error.rb +18 -0
  302. data/lib/phronomy/multi_agent/team_coordinator.rb +99 -77
  303. data/lib/phronomy/multi_agent/team_not_found_error.rb +18 -0
  304. data/lib/phronomy/multi_agent/team_ownership_registry.rb +2 -12
  305. data/lib/phronomy/output_parser/parse_error.rb +7 -0
  306. data/lib/phronomy/persistence/content_repository.rb +26 -0
  307. data/lib/phronomy/persistence/errors.rb +16 -0
  308. data/lib/phronomy/persistence/migration/initial_format_migration.rb +2 -2
  309. data/lib/phronomy/persistence/persistence.rb +23 -0
  310. data/lib/phronomy/persistence/save_outcome.rb +24 -0
  311. data/lib/phronomy/persistence/snapshot_comparison.rb +81 -0
  312. data/lib/phronomy/persistence/storage_boundary.rb +32 -0
  313. data/lib/phronomy/persistence/transaction.rb +86 -0
  314. data/lib/phronomy/persistence_composition/storage_schema.rb +9 -4
  315. data/lib/phronomy/persistence_composition/stores.rb +34 -0
  316. data/lib/phronomy/persistence_composition/unit4_migration.rb +276 -0
  317. data/lib/phronomy/runtime_composition/agent_defaults.rb +5 -1
  318. data/lib/phronomy/runtime_composition/configuration.rb +146 -0
  319. data/lib/phronomy/runtime_composition/evaluation_defaults.rb +7 -0
  320. data/lib/phronomy/runtime_composition/execution_defaults.rb +5 -0
  321. data/lib/phronomy/runtime_composition/generation_defaults.rb +6 -0
  322. data/lib/phronomy/runtime_composition/global_configuration.rb +38 -0
  323. data/lib/phronomy/runtime_composition/multi_agent_defaults.rb +9 -0
  324. data/lib/phronomy/runtime_composition/workflow_defaults.rb +4 -0
  325. data/lib/phronomy/storage/async/async_client.rb +60 -0
  326. data/lib/phronomy/storage/backend.rb +8 -2
  327. data/lib/phronomy/storage/condition_failed_error.rb +2 -2
  328. data/lib/phronomy/storage/unique_constraint_error.rb +2 -2
  329. data/lib/phronomy/testing/eval/metrics.rb +1 -1
  330. data/lib/phronomy/testing/eval/scorer/llm_judge.rb +19 -3
  331. data/lib/phronomy/testing/persistence_contract/a_content_store.rb +2 -2
  332. data/lib/phronomy/testing/persistence_contract/a_journal_repository.rb +6 -6
  333. data/lib/phronomy/testing/persistence_contract/a_persistence_backend.rb +55 -52
  334. data/lib/phronomy/testing/persistence_contract/a_workflow_state_repository.rb +3 -3
  335. data/lib/phronomy/testing/persistence_contract/an_agent_repository.rb +7 -7
  336. data/lib/phronomy/testing/persistence_contract/an_execution_repository.rb +11 -11
  337. data/lib/phronomy/testing/persistence_contract/coordination_repositories.rb +57 -51
  338. data/lib/phronomy/testing/persistence_contract/neutral_storage_primitives.rb +1 -1
  339. data/lib/phronomy/testing/persistence_contract/storage_transaction_boundaries.rb +23 -22
  340. data/lib/phronomy/tool/authorization.rb +77 -0
  341. data/lib/phronomy/tool/base.rb +551 -9
  342. data/lib/phronomy/tool/call_request.rb +40 -0
  343. data/lib/phronomy/{agent/tool_execution/tool_definition_set.rb → tool/definition_set.rb} +7 -8
  344. data/lib/phronomy/tool/operation.rb +88 -0
  345. data/lib/phronomy/tool/schema.rb +214 -0
  346. data/lib/phronomy/tool/settings.rb +31 -0
  347. data/lib/phronomy/tool/tool_error.rb +7 -0
  348. data/lib/phronomy/tool/tool_executor.rb +58 -0
  349. data/lib/phronomy/tools/agent.rb +22 -90
  350. data/lib/phronomy/tools/mcp.rb +21 -14
  351. data/lib/phronomy/tools/vector_search.rb +4 -4
  352. data/lib/phronomy/tracing/automatic.rb +11 -6
  353. data/lib/phronomy/tracing/base.rb +36 -7
  354. data/lib/phronomy/tracing/observation.rb +37 -0
  355. data/lib/phronomy/tracing/open_telemetry_tracer.rb +4 -29
  356. data/lib/phronomy/tracing/settings.rb +36 -0
  357. data/lib/phronomy/vector_store/{async_backend.rb → async/async_client.rb} +35 -29
  358. data/lib/phronomy/vector_store/{in_memory.rb → backends/in_memory.rb} +12 -10
  359. data/lib/phronomy/vector_store/{pgvector.rb → backends/pgvector.rb} +44 -16
  360. data/lib/phronomy/vector_store/{redis_search.rb → backends/redis_search.rb} +74 -37
  361. data/lib/phronomy/vector_store/base.rb +118 -49
  362. data/lib/phronomy/vector_store/invalid_result_error.rb +12 -0
  363. data/lib/phronomy/vector_store.rb +2 -17
  364. data/lib/phronomy/version.rb +1 -1
  365. data/lib/phronomy/workflow/completion.rb +11 -0
  366. data/lib/phronomy/workflow/execution/workflow.rb +37 -9
  367. data/lib/phronomy/workflow/execution/workflow_action_rules.rb +67 -0
  368. data/lib/phronomy/workflow/execution/workflow_context.rb +2 -2
  369. data/lib/phronomy/workflow/execution/workflow_execution_environment.rb +28 -0
  370. data/lib/phronomy/workflow/execution/workflow_execution_registry.rb +77 -8
  371. data/lib/phronomy/workflow/execution/workflow_runner.rb +105 -92
  372. data/lib/phronomy/workflow/execution/workflow_settings.rb +28 -0
  373. data/lib/phronomy/workflow/execution/workflow_task_execution.rb +153 -0
  374. data/lib/phronomy/workflow/execution/workflow_task_reception.rb +72 -0
  375. data/lib/phronomy/workflow/execution/workflow_task_resume_error.rb +14 -0
  376. data/lib/phronomy/workflow/persistence/state_repository.rb +28 -22
  377. data/lib/phronomy/workflow/persistence/storage_schema.rb +13 -0
  378. data/lib/phronomy/workflow/runtime_binding/workflow_engine_environment.rb +61 -0
  379. data/lib/phronomy/workflow/runtime_binding/workflow_phase_machine_builder.rb +158 -0
  380. data/lib/phronomy/workflow/runtime_binding/workflow_task_session.rb +76 -0
  381. data/lib/phronomy/workflow/{execution → runtime_binding}/workflow_terminal_policy.rb +4 -4
  382. data/lib/phronomy.rb +63 -16
  383. data/scripts/api_snapshot.rb +47 -15
  384. data/scripts/check_readme_ruby.rb +24 -29
  385. data/scripts/check_readme_runnable.rb +92 -81
  386. data/sig/_private/phronomy/agent/settings.rbs +19 -0
  387. data/sig/_private/phronomy/configuration/runtime_settings.rbs +20 -0
  388. data/sig/_private/phronomy/llm_adapter/async/async_client.rbs +10 -0
  389. data/sig/_private/phronomy/multi_agent/store.rbs +8 -0
  390. data/sig/_private/phronomy/persistence/storage_boundary.rbs +7 -0
  391. data/sig/_private/phronomy/tool/settings.rbs +13 -0
  392. data/sig/_private/phronomy/tracing/settings.rbs +15 -0
  393. data/sig/_private/phronomy/workflow/execution/workflow_settings.rbs +13 -0
  394. data/sig/phronomy/agent/admission.rbs +19 -0
  395. data/sig/phronomy/agent/agent_not_found_error.rbs +6 -0
  396. data/sig/phronomy/agent/agent_unloaded_error.rbs +6 -0
  397. data/sig/phronomy/agent/execution_contract.rbs +132 -0
  398. data/sig/phronomy/agent/execution_environment.rbs +20 -0
  399. data/sig/phronomy/agent/store.rbs +73 -0
  400. data/sig/phronomy/agent/stream_callback_error.rbs +8 -0
  401. data/sig/phronomy/agent.rbs +29 -135
  402. data/sig/phronomy/common.rbs +7 -0
  403. data/sig/phronomy/content_store/contracts.rbs +13 -0
  404. data/sig/phronomy/context.rbs +152 -0
  405. data/sig/phronomy/embeddings/async/async_client.rbs +9 -0
  406. data/sig/phronomy/embeddings/base.rbs +23 -0
  407. data/sig/phronomy/engine/concurrency/timer_bindings.rbs +22 -0
  408. data/sig/phronomy/engine/control_bindings.rbs +11 -0
  409. data/sig/phronomy/engine/control_protocols.rbs +23 -0
  410. data/sig/phronomy/engine/execution_binding.rbs +6 -0
  411. data/sig/phronomy/engine/execution_receiver.rbs +15 -0
  412. data/sig/phronomy/engine/observability.rbs +13 -0
  413. data/sig/phronomy/execution/async_operation.rbs +7 -0
  414. data/sig/phronomy/execution/blocking.rbs +5 -0
  415. data/sig/phronomy/execution/concurrency/cancellation_token.rbs +13 -0
  416. data/sig/phronomy/execution/concurrency/deadline.rbs +10 -0
  417. data/sig/phronomy/execution/concurrency/result_composition.rbs +7 -0
  418. data/sig/phronomy/execution/control_protocols.rbs +18 -0
  419. data/sig/phronomy/execution/errors.rbs +7 -0
  420. data/sig/phronomy/execution/execution.rbs +41 -0
  421. data/sig/phronomy/execution/execution_receiver.rbs +40 -0
  422. data/sig/phronomy/execution/execution_scope_state.rbs +9 -0
  423. data/sig/phronomy/execution/invocation_context.rbs +18 -0
  424. data/sig/phronomy/execution/invocation_controls.rbs +13 -0
  425. data/sig/phronomy/execution/task_result.rbs +29 -0
  426. data/sig/phronomy/extensions.rbs +1 -21
  427. data/sig/phronomy/filter/filter_block_error.rbs +6 -0
  428. data/sig/phronomy/generation/low_confidence_error.rbs +6 -0
  429. data/sig/phronomy/handoff.rbs +10 -4
  430. data/sig/phronomy/integrations.rbs +14 -0
  431. data/sig/phronomy/llm_adapter/backends/ruby_llm.rbs +6 -0
  432. data/sig/phronomy/llm_adapter/base.rbs +14 -0
  433. data/sig/phronomy/llm_adapter/usage.rbs +14 -0
  434. data/sig/phronomy/llm_adapter/values.rbs +43 -0
  435. data/sig/phronomy/llm_context_window.rbs +10 -0
  436. data/sig/phronomy/multi_agent/reserved_child_admission.rbs +8 -0
  437. data/sig/phronomy/multi_agent/store.rbs +54 -0
  438. data/sig/phronomy/multi_agent/team_busy_error.rbs +8 -0
  439. data/sig/phronomy/multi_agent/team_not_found_error.rbs +8 -0
  440. data/sig/phronomy/multi_agent.rbs +6 -3
  441. data/sig/phronomy/persistence/errors.rbs +18 -0
  442. data/sig/phronomy/persistence/migration.rbs +13 -0
  443. data/sig/phronomy/persistence/transaction.rbs +19 -0
  444. data/sig/phronomy/persistence.rbs +1 -99
  445. data/sig/phronomy/persistence_composition.rbs +19 -0
  446. data/sig/phronomy/runtime_composition/configuration.rbs +36 -0
  447. data/sig/phronomy/storage/async/async_client.rbs +8 -0
  448. data/sig/phronomy/storage/backends/in_memory.rbs +9 -0
  449. data/sig/phronomy/{storage.rbs → storage/contracts.rbs} +4 -18
  450. data/sig/phronomy/tool.rbs +48 -4
  451. data/sig/phronomy/tracing/observation.rbs +7 -0
  452. data/sig/phronomy/vector_store/async/async_client.rbs +13 -0
  453. data/sig/phronomy/vector_store/base.rbs +23 -0
  454. data/sig/phronomy/workflow/execution/workflow_execution_environment.rbs +15 -0
  455. data/sig/phronomy/workflow/runtime_binding/workflow_terminal_policy.rbs +7 -0
  456. data/sig/phronomy/workflow/store.rbs +8 -0
  457. data/sig/phronomy/workflow.rbs +5 -1
  458. data/sig/phronomy.rbs +4 -49
  459. metadata +365 -117
  460. data/lib/phronomy/agent/concerns/before_llm_input.rb +0 -66
  461. data/lib/phronomy/agent/concerns/error_translation.rb +0 -45
  462. data/lib/phronomy/agent/concerns/filterable.rb +0 -184
  463. data/lib/phronomy/agent/context/capability/base.rb +0 -548
  464. data/lib/phronomy/agent/context/capability/tool_executor.rb +0 -62
  465. data/lib/phronomy/agent/context/instruction/prompt_template.rb +0 -102
  466. data/lib/phronomy/agent/context_assembly/runtime_chat_builder.rb +0 -36
  467. data/lib/phronomy/agent/context_assembly/token_budget_resolver.rb +0 -22
  468. data/lib/phronomy/agent/context_parts/validators/final_budget_validator.rb +0 -37
  469. data/lib/phronomy/agent/context_policies/default.rb +0 -142
  470. data/lib/phronomy/agent/execution/phase_machine_builder.rb +0 -101
  471. data/lib/phronomy/agent/execution/provider_call_outcome.rb +0 -106
  472. data/lib/phronomy/agent/handoff/handoff_execution_coordinator.rb +0 -15
  473. data/lib/phronomy/agent/handoff/handoff_outcome_committer.rb +0 -131
  474. data/lib/phronomy/agent/handoff/handoff_request.rb +0 -45
  475. data/lib/phronomy/agent/lifecycle_contract/handoff_error.rb +0 -7
  476. data/lib/phronomy/agent/persistence/handoff_state_repository.rb +0 -58
  477. data/lib/phronomy/agent/persistence/queries.rb +0 -61
  478. data/lib/phronomy/agent/selection/candidate.rb +0 -53
  479. data/lib/phronomy/agent/selection/constraint.rb +0 -49
  480. data/lib/phronomy/agent/tool_execution/tool_call_intercepted.rb +0 -29
  481. data/lib/phronomy/agent/tool_execution/tool_invocation_session_builder.rb +0 -276
  482. data/lib/phronomy/configuration/configuration.rb +0 -68
  483. data/lib/phronomy/configuration/global_configuration.rb +0 -26
  484. data/lib/phronomy/engine/concurrency/cancellation_scope.rb +0 -124
  485. data/lib/phronomy/engine/concurrency/operation_binding.rb +0 -43
  486. data/lib/phronomy/engine/execution_receiver.rb +0 -65
  487. data/lib/phronomy/engine/runnable.rb +0 -54
  488. data/lib/phronomy/llm_adapter/ruby_llm.rb +0 -47
  489. data/lib/phronomy/llm_contract/token_usage.rb +0 -85
  490. data/lib/phronomy/multi_agent/persistence/queries.rb +0 -30
  491. data/lib/phronomy/multi_agent/storage_contract/team_storage_schema.rb +0 -15
  492. data/lib/phronomy/output_parser/contract/parse_error.rb +0 -7
  493. data/lib/phronomy/persistence/api/persistence.rb +0 -140
  494. data/lib/phronomy/persistence_composition/repositories.rb +0 -77
  495. data/lib/phronomy/recovery/recovery.rb +0 -186
  496. data/lib/phronomy/tool/contract/tool_error.rb +0 -7
  497. data/lib/phronomy/vector_store/embeddings/base.rb +0 -44
  498. data/lib/phronomy/vector_store/embeddings/ruby_llm_embeddings.rb +0 -47
  499. data/lib/phronomy/workflow/phase_machine_builder.rb +0 -205
  500. data/lib/phronomy/workflow/storage_contract/workflow_storage_schema.rb +0 -9
  501. data/sig/phronomy/execution_receiver.rbs +0 -34
  502. data/sig/phronomy/llm_adapter.rbs +0 -11
  503. data/sig/phronomy/runtime.rbs +0 -76
  504. /data/lib/phronomy/agent/{context_assembly/context_importer.rb → context_importer.rb} +0 -0
  505. /data/lib/phronomy/{engine → execution}/backpressure_error.rb +0 -0
  506. /data/lib/phronomy/{engine → execution}/cancellation_error.rb +0 -0
  507. /data/lib/phronomy/{engine → execution}/concurrency/worker_input_restricted.rb +0 -0
  508. /data/lib/phronomy/{engine → execution}/event_loop_reentrancy_error.rb +0 -0
  509. /data/lib/phronomy/{engine → execution}/invalid_async_entry_action_error.rb +0 -0
  510. /data/lib/phronomy/{engine → execution}/invalid_async_transition_action_error.rb +0 -0
  511. /data/lib/phronomy/{engine → execution}/invalid_async_workflow_action_error.rb +0 -0
  512. /data/lib/phronomy/{engine → execution}/pool_shutdown_error.rb +0 -0
  513. /data/lib/phronomy/{engine → execution}/recursion_limit_error.rb +0 -0
  514. /data/lib/phronomy/{engine → execution}/runtime_shutdown_error.rb +0 -0
  515. /data/lib/phronomy/{engine → execution}/runtime_shutdown_reentrancy_error.rb +0 -0
  516. /data/lib/phronomy/{engine → execution}/scheduler_reentrancy_error.rb +0 -0
  517. /data/lib/phronomy/{engine → execution}/timeout_error.rb +0 -0
@@ -0,0 +1,72 @@
1
+ # r8 unit 10: C01 MultiAgent execution connection
2
+
3
+ Contract placement follows ownership of meaning and invariants, not reuse.
4
+ AdmissionRegistry and TeamOwnershipRegistry already existed in MultiAgent.
5
+ They remain there; neither moves to Engine and no generic Registry is added.
6
+
7
+ | Owner | Responsibility |
8
+ | --- | --- |
9
+ | MultiAgent AdmissionRegistry | One synchronous coordination call per live owner; close admission and wait for admitted calls |
10
+ | MultiAgent TeamOwnershipRegistry | One live Team per ID and environment; class/store consistency, construction exclusion, shutdown cleanup |
11
+ | MultiAgent TeamCoordinator / HandoffRunner | Coordination, durable reservations, child operations, scheduling, aggregation, recovery and outcomes |
12
+ | MultiAgent ExecutionEnvironment | Private process-local connection needed by C01: registry access, owning-environment validity and submission |
13
+ | MultiAgent EngineEnvironment in runtime_binding | Runtime selection, participant registration/lookup, Runtime identity comparison and Execution submission to the captured Runtime |
14
+ | Engine Runtime | Generic participant lifecycle: close, wait under one deadline, stop resources, then finalize |
15
+ | runtime_composition/multi_agent_defaults.rb | Lazy selection of the environment and default persistence factory |
16
+
17
+ There are two registrations. Recording a Team or an active coordination call
18
+ inside a Registry is a MultiAgent operation. Registering that Registry as a
19
+ Runtime shutdown participant is an implementation connection. Previously the
20
+ Registry class methods and their callers mixed these two responsibilities.
21
+ Team/Handoff also selected Runtime directly, and Team cancellation submitted
22
+ work directly to it. The environment port separates those concrete connections.
23
+
24
+ Runtime's existing begin_draining / wait_until_idle / optional
25
+ after_runtime_shutdown protocol remains unchanged. Registry methods define
26
+ what those callbacks mean for MultiAgent. The admission registry waits for
27
+ active coordination calls; Team ownership waits for in-progress construction,
28
+ not for every retained Team to disappear. Live Team references are cleared
29
+ only after successful resource shutdown. Runtime acquires no Team/Handoff rules.
30
+ The shared callback protocol alone is not a reason to add a new logical Contract.
31
+
32
+ The default adapter shares registries by their existing class keys within each
33
+ Runtime. Concurrent adapters get the same registered instance. Lookup does not
34
+ register a participant, including after draining starts. Admission acquisition
35
+ continues to reject a stopped/failed Runtime; a retained ownership registry can
36
+ still be looked up, while its own construction gate rejects new work.
37
+
38
+ Team and Handoff capture their environment on construction. Existing objects do
39
+ not switch registry or cancellation destination when the provider changes.
40
+ The default adapter compares the captured Runtime with the current default to
41
+ preserve stale-owner rejection. Cancellation submission uses the captured
42
+ Runtime explicitly. The environment itself is neither persisted nor authority
43
+ for a durable execution. This is an internal composition extension, not a new
44
+ supported application plugin API.
45
+
46
+ Public Team/Handoff signatures, exception classes, durable IDs, record schemas,
47
+ CAS rules, parent/child atomic participation and recovery semantics are unchanged.
48
+ ReservedChildAdmission still validates domain reservations within the shared
49
+ persistence scope. It is distinct from the process-local AdmissionRegistry.
50
+ Engine lifecycle and Execution completion/cancellation rules are unchanged.
51
+
52
+ ## Evidence and remaining scope
53
+
54
+ Standalone tests use both registries without loading Engine. Connection tests
55
+ exercise Team identity and store consistency, duplicate Handoff calls, release
56
+ on failure, stale-owner rejection, original-environment cancellation, callback
57
+ cleanup and real worker submission after default Runtime replacement. Existing
58
+ shutdown tests cover concurrent registration, construction during draining,
59
+ failed EventLoop closure, deadlines and finalization. Durable coordination and
60
+ recovery suites remain acceptance gates.
61
+
62
+ The dependency model adds M89/G63 for multi_agent/runtime_binding. AST guards
63
+ reject Runtime/Engine selection and private shutdown registration/lookup inside
64
+ MultiAgent domain files. Graph guards reject direct domain-to-Engine/binding
65
+ dependencies while retaining lower-level reverse-dependency restrictions.
66
+ Measured Ruby/RBS references remain visible; these are scoped rules, not proof
67
+ that the complete dependency graph is acyclic or every Contract is complete.
68
+
69
+ Remaining work includes Workflow connections and durable child outcomes,
70
+ MultiAgent's existing global/default persistence selection, broader semantic
71
+ dependency review, and live-service/additional persistence acceptance gates.
72
+ This unit completes the proposed C01 Runtime connection split, not all C01 work.
@@ -0,0 +1,71 @@
1
+ # r8 unit 11: C04 concrete Policy and LLM connection selection
2
+
3
+ Contract placement follows ownership of meaning and invariants, not reuse.
4
+ This unit addresses review findings B01 and B02: Agent::Base selected the
5
+ concrete DefaultPolicy, and InvocationActions constructed the concrete LLM
6
+ AsyncClient. Neither choice belongs to Agent progress decisions.
7
+
8
+ | Owner | Responsibility |
9
+ | --- | --- |
10
+ | Agent::Base / C04 | Declare, validate, inherit and use a ContextPolicy |
11
+ | ContextPolicy / C05 | Context-selection operation contract |
12
+ | DefaultPolicy implementation / I01 | Existing selection strategy and token-budget allocation |
13
+ | runtime_composition/agent_defaults.rb / A01 | Install DefaultPolicy through the existing Base.context_policy DSL |
14
+ | Agent InvocationActions / C04 | Prepare the LLM request, request a client through the owning environment, track completion and deliver progress |
15
+ | Agent ExecutionEnvironment | Private connection capability to build an LLM client for the supplied adapter |
16
+ | Agent EngineEnvironment / I07 | Select AsyncClient and bind submission to the captured Runtime |
17
+ | LLM AsyncClient / I06 | Run the complete C09 operation through C13 submission; forward stream chunks and cancellation |
18
+ | LLMAdapter / C09 | Synchronous complete/stream operations and request/response rules |
19
+
20
+ Ordinary require "phronomy" installs the existing DefaultPolicy instance.
21
+ Base no longer supplies a concrete fallback; an unconfigured root raises a
22
+ ConfigurationError. No supported loading path is left unconfigured. Class
23
+ inheritance and explicit Policy overrides retain their existing semantics.
24
+ Selecting the default does not create configuration, stores or a Runtime.
25
+ This does not change DefaultPolicy's algorithm or introduce a policy registry.
26
+
27
+ InvocationActions now asks its retained environment for the LLM client.
28
+ It still reads the configured adapter at dispatch time. The Engine binding
29
+ constructs AsyncClient with itself as the existing C13 submitter protocol;
30
+ AsyncClient does not depend on the Agent environment type. No generic factory
31
+ registry, new logical Contract or public application API is introduced.
32
+
33
+ The client forwards the original TaskResult rather than replacing it. Logical
34
+ cancellation and physical worker completion remain distinct. An explicit pool
35
+ still uses Execution's existing pool-selection protocol and overrides the
36
+ injected submitter. A standalone client with no injected submitter continues
37
+ to resolve the current default Runtime at each call. Client construction
38
+ starts no Runtime resources.
39
+
40
+ For Agent calls, submission now uses the Agent's captured Runtime, matching
41
+ its sessions and other work. Replacing the default Runtime cannot redirect
42
+ only its LLM worker to a different owner. A stopped owner rejects new work
43
+ through the existing RuntimeShutdownError. Provider errors, admission failure,
44
+ chunk ordering, cancellation and completion are not translated by this change.
45
+ Public Agent/Policy signatures, manifests, durable schemas and recovery rules
46
+ are unchanged. The private AsyncClient constructor adds an optional submitter;
47
+ its private RBS uses the existing _ExecutionSubmitter interface.
48
+
49
+ ## Evidence and remaining scope
50
+
51
+ Regression tests cover ordinary lazy loading, inherited/explicit Policies,
52
+ complete and streaming Agent calls after default Runtime replacement, live
53
+ adapter selection, provider worker ownership and EventLoop callback ownership.
54
+ Connection tests cover resource-free construction and stopped-owner rejection.
55
+ Async client tests cover the narrow submitter, explicit pool precedence and
56
+ physical completion after cancellation; existing failure/backpressure tests
57
+ remain acceptance gates.
58
+
59
+ Ruby AST guards reject DefaultPolicy and AsyncClient references in Agent domain
60
+ files. The Ruby/RBS graph gate separately rejects Agent domain dependencies on
61
+ llm_adapter/async and permits the binding connection. Existing lower-level
62
+ reverse-dependency rules remain intact. These checks have the same static
63
+ analysis limitations as the existing architecture tooling; they do not prove
64
+ that all logical Contract dependencies are acyclic or complete.
65
+
66
+ B01 and B02 are addressed in this candidate. C04 is not declared globally
67
+ complete. Remaining review includes C01 Orchestrator inheritance from the
68
+ concrete Agent tool, C02 Workflow execution connections and separately scoped
69
+ durable child behavior, and Recovery's domain/persistence responsibilities.
70
+ Existing domain-level explicit/configured/default store selection is not itself
71
+ a defect: concrete default persistence factories are already in composition.
@@ -0,0 +1,67 @@
1
+ # r8 unit 12: C01 subagent operations use the C06 Tool contract
2
+
3
+ Contract placement follows ownership of meaning and invariants, not reuse.
4
+ This unit addresses B03: Orchestrator.subagent generated a subclass of the
5
+ concrete Tools::Agent implementation (I04). The generated class replaced Agent
6
+ creation and child coordination, but inherited Tool operation rules incidentally.
7
+
8
+ | Owner | Responsibility |
9
+ | --- | --- |
10
+ | MultiAgent / C01 | Define the subagent operation, child class, knowledge/context inheritance, child error policy and durable reconciliation |
11
+ | Agent / C04 | Public child invocation and recovery outcomes |
12
+ | Tool / C06 | Input schema, Tool error policy, result limits and completion-handle requirements |
13
+ | Execution / C13 | Nonblocking completion composition and physical completion propagation |
14
+ | Tools::Agent / I04 | Standalone concrete Agent Tool construction through from_agent |
15
+
16
+ Orchestrator remains an Agent::Base subclass: a coordinating Agent is a valid
17
+ C01-to-C04 relationship. Its generated subagent Tool now derives directly from
18
+ Tool::Base and explicitly declares cooperative execution and its input schema.
19
+ Generating this domain-owned operation belongs to C01; no runtime registry,
20
+ factory, new logical Contract or composition layer is needed for that operation.
21
+
22
+ Tool::Base has a private call_async_operation helper that validates inputs,
23
+ requires a completion handle, applies Tool error policy and limits successful
24
+ results. Its block supplies the domain operation. It does not create Agents,
25
+ select implementations, wait for completion or decide how many application
26
+ filters to run. Both the subagent operation and Tools::Agent use this helper.
27
+ The default Tool::Base#call_async path and synchronous-call delegation are
28
+ unchanged, including the unit 9 result-transformation behavior.
29
+
30
+ ExecutionRehydrationRequiredError remains an Agent-domain outcome. Tools::Agent
31
+ and the C01 operation retain their private pass-through hooks; C06 does not
32
+ reference this error or interpret recovery. Generic errors retain their original
33
+ backtrace when wrapped; ToolError and CancellationError remain unchanged.
34
+ Suppression logging uses C06's existing RuntimeSettings logger capability.
35
+
36
+ An ordinary asynchronous subagent call still checks cancellation before schema
37
+ validation, starts the child without occupying a waiting offload worker, maps
38
+ its output and applies Tool policy. The subagent on_error option continues to
39
+ control child failure (raise or skip); it is distinct from Tool on_error policy.
40
+
41
+ An admitted durable child follows the existing reconciliation path directly.
42
+ It is reconciled even with a cancelled parent token; unknown outcomes and
43
+ recovery requirements are not hidden. This path retains its existing validation,
44
+ result and cancellation behavior, without adding the ordinary-call truncation
45
+ or error-suppression pipeline. Agent-owned configured result transformations
46
+ still wrap either path in the configured order, including repeated filters.
47
+ Parent/child IDs, reservations, stores, persistence schemas and recovery rules
48
+ are unchanged. Logical settlement does not falsely imply physical completion.
49
+
50
+ ## Evidence and remaining scope
51
+
52
+ Non-Agent Tool tests cover asynchronous validation/coercion, errors, result
53
+ limits, cancellation and separate physical completion. Subagent tests cover
54
+ operation without Tools::Agent, ordinary and admitted-child cancellation,
55
+ recovery error identity and repeated transformations after truncation. Existing
56
+ pool-starvation, knowledge inheritance, durable coordination/restart and result
57
+ transformation tests remain acceptance gates.
58
+
59
+ The AST gate rejects concrete Tools references in C01 domain files and
60
+ Agent recovery interpretation in C06. The Ruby/RBS graph gate rejects C01
61
+ domain-to-tools implementation dependencies. Existing lower-level and Engine
62
+ binding rules remain intact. These are targeted regression checks, not proof
63
+ of all logical Contract dependencies or global acyclicity.
64
+
65
+ B03 is addressed in this candidate. C02 Workflow execution connections, its
66
+ separately scoped durable child guarantees, and broader Recovery responsibility
67
+ review remain. No completed status is asserted for all of C01/C02/C04.
@@ -0,0 +1,61 @@
1
+ # r8 unit 13: C02 Workflow rules and Engine connections
2
+
3
+ Contract placement follows ownership of meaning and invariants, not reuse.
4
+ This unit addresses B04: WorkflowRunner and its registry previously selected
5
+ Runtime, built FSMSession instances and constructed Engine event envelopes.
6
+ The phase compiler also contained Workflow callback rules alongside the
7
+ state_machines translation.
8
+
9
+ | Owner | Responsibility |
10
+ | --- | --- |
11
+ | Workflow / C02 | Topology, callback rules, segment admission, identity/owner checks, hydration, snapshots, persistence outcome classification and recovery-required retention |
12
+ | Workflow runtime binding | Compile topology into state_machines, build/register sessions, select the owning Runtime and translate classified outcomes into terminal decisions |
13
+ | Execution / C13 | Completion handles and receiver lifecycle/routing protocol |
14
+ | Engine | Serial dispatch, atomic delivery, generic FSM execution and terminal gate |
15
+ | Application | State actions, guards, external event correlation and child operation choices |
16
+
17
+ WorkflowActionRules owns synchronous entry, transition and exit callback
18
+ constraints, optional event arguments and adoption of returned WorkflowContext
19
+ values. The compiler installs these rules as machine callbacks. Initial entry
20
+ callbacks also pass through the rules before reaching the generic FSM session.
21
+ Application callback order remains exit, transition action, entry.
22
+
23
+ WorkflowExecutionEnvironment is a private C02 connection port. Composition
24
+ installs its provider; WorkflowEngineEnvironment implements it. Compiling a
25
+ Workflow captures its environment without starting an EventLoop, workers or
26
+ execution registration. Starts, durable loads, live signals, terminal saves,
27
+ completion and admission release use that same owner. Changing the default
28
+ Runtime does not silently move a compiled Workflow or its continuations to a
29
+ different owner. Recompile the Workflow after replacing/stopping that Runtime.
30
+ Scalar per-call configuration and configured repository resolution retain their
31
+ existing behavior. Tracing keeps its independent existing execution composition.
32
+
33
+ WorkflowExecutionRegistry remains in C02. workflow_instance_id, opaque owner
34
+ token and fsm_session_id remain distinct. Routing resolves the current target
35
+ under the existing lifecycle lock; ExecutionReceiverBinding constructs the
36
+ Engine event within the same atomic delivery operation. No new registry or
37
+ public extension API is introduced.
38
+
39
+ Runner continues to classify terminal persistence results as success, known
40
+ failure or outcome unknown. The binding only translates these outcomes into
41
+ complete, fail or retire instructions. A successful terminal notification still
42
+ requires confirmed persistence. An uncertain outcome still retires the session
43
+ while retaining recovery-required admission; it does not announce success or
44
+ release another owner's segment. Readback/reconciliation does not retry a save.
45
+ Admission is acquired before durable load, and rejected competitors do not load.
46
+
47
+ ## Evidence and remaining scope
48
+
49
+ Existing tests cover competing admission, immutable terminal snapshots, lost
50
+ responses, unknown outcomes, shutdown, wait/resume, live event routing and action
51
+ ordering. New tests cover standalone callback rules, resource-free compilation,
52
+ owner retention across blocked load/save and default replacement, and rejection
53
+ on a stopped owner. Ruby AST and Ruby/RBS graph checks reject C02-to-Engine or
54
+ C02-to-binding dependencies while preserving lower-layer restrictions.
55
+
56
+ The targeted C02 execution connection boundary is addressed. This is not proof
57
+ that every logical Contract is complete or that the whole source graph is
58
+ acyclic. F01 durable Workflow children still need an explicit specification for
59
+ identity, reservation, completion persistence and recovery; application actions
60
+ may still launch ordinary asynchronous work. Broader Recovery ownership review
61
+ also remains. No durable child protocol or persistence schema is added here.
@@ -0,0 +1,72 @@
1
+ # r8 unit 14: assign existing recovery rules to their owners
2
+
3
+ The former private `Phronomy::Recovery` combined Agent operation subjects and
4
+ factual resolutions with general persistence evidence comparison. Sharing a
5
+ file or using the word recovery does not make these one Contract.
6
+
7
+ | Responsibility | Owner after this change |
8
+ | --- | --- |
9
+ | LLM/Tool subject identity, resolution material, resumability classification | C04 Agent, private `Agent::RecoveryRules` |
10
+ | Revision/snapshot evidence comparison and normalization | C07 Persistence, private `Persistence::SnapshotComparison` |
11
+ | Selection of Workflow evidence and interpretation of pre/post/conflict | C02 Workflow, existing WorkflowRunner |
12
+ | Agent restoration, resolution save/readback and continuation | C04 Agent, existing RecoveryCoordinator |
13
+ | Parent/child coordination and durable reconciliation | C01 MultiAgent, unchanged |
14
+
15
+ There is no independent Recovery Contract. C14 remains retired; C17 is
16
+ OutputParser. M50/G34 are retired in the current source architecture without
17
+ reusing their identifiers. Historical phase configurations retain their history.
18
+
19
+ ## Behavioral scope
20
+
21
+ This is a relocation of existing rules and their call sites. No public API,
22
+ persisted schema, outcome value, retry, observer, admission or ownership rule is
23
+ added. Error classes/messages and validation ordering are retained. Ordinary
24
+ framework boot still loads the relocated definitions. The former private
25
+ namespace and file are removed, without a compatibility alias. The existing
26
+ public `Phronomy::ExecutionRehydrationRequiredError` moves to `agent/api` while
27
+ retaining its root namespace, superclass and lazy-loading behavior; it remains
28
+ an Agent-domain outcome, also consumed by delegation callers.
29
+
30
+ `Agent::RecoveryRules` describes external operation facts as `succeeded`,
31
+ `failed` or `not_performed`. Its `Classification` describes resumability. The
32
+ existing structural `persistence_operation` subject normalization is retained
33
+ to avoid changing accepted input or errors; it does not provide a new generic
34
+ durable operation identity or a new supported Agent resolution operation.
35
+
36
+ `Persistence::SnapshotComparison` returns `pre_state`, `post_state` or
37
+ `conflict`. It performs no I/O. Workflow supplies authoritative readback and
38
+ intended evidence, handles read errors, and decides completion, known failure
39
+ or recovery-waiting admission retention. In particular:
40
+
41
+ - An absent record with an absent expected pre revision remains pre-state.
42
+ - Without an explicit post revision, a matching normalized snapshot and a
43
+ revision different from the expected pre revision identifies post-state.
44
+ - With an explicit post revision, both revision and snapshot must match.
45
+ - Otherwise a matching pre revision identifies pre-state, even if the snapshot
46
+ differs. The explicit post comparison still precedes this check.
47
+ - Accessors precede symbol keys, which precede string keys. Nested hash keys
48
+ and symbol values normalize to strings. Read/accessor errors propagate to
49
+ the owning domain as before.
50
+
51
+ `Persistence::SaveOutcome` is unchanged. It compares domain-supplied before/after
52
+ evidence using its existing equality and reports `committed`, `not_committed`
53
+ or `unknown`. It is not substituted for snapshot comparison: their predicates
54
+ and error handling differ. Agent-specific execution metadata comparisons also
55
+ remain in Agent.
56
+
57
+ ## Verification and limits
58
+
59
+ The relocated specs retain existing cases. Additional regressions fix comparison
60
+ priority, normalization, accessor precedence, error identity, resolution error
61
+ ordering and subject immutability. The same 45 primitive examples pass against
62
+ the unit13 definitions and the relocated definitions. Existing Agent recovery
63
+ and Workflow terminal persistence tests cover their surrounding behavior.
64
+
65
+ AST and combined Ruby/RBS graph gates reject dependencies from other domains on
66
+ Agent recovery rules and domain references in generic persistence comparison.
67
+ These checks guard this boundary, not all possible semantic coupling. Root
68
+ loader wiring and dynamic injection require separate review and runtime tests.
69
+
70
+ Durable Workflow children (F01) remain deferred feature work, outside this
71
+ responsibility refactor and outside its acceptance criteria. This change does
72
+ not establish global acyclicity or completion of every Contract.
@@ -0,0 +1,65 @@
1
+ # r8 unit15: Generation contract boundaries
2
+
3
+ This responsibility refactor is based on applied unit14, commit
4
+ `97c3d76b35594bb971a60a2932410ddf22e48d3a` (tree
5
+ `c326196212a4ac369294a9ccb936619813e51250`).
6
+
7
+ ## B05: Agent operation connection
8
+
9
+ Generation previously used `send(:__invoke_async_with_event_sink, ...)` to
10
+ select Agent's private per-execution listener. It now constructs each Agent
11
+ once with its public `on_event:` option and calls public `invoke_async`.
12
+
13
+ The private Generation `AgentOperation` owns the connection, not Agent execution:
14
+
15
+ - Each returned TaskResult supplies that call's terminal result or original
16
+ failure. Terminal incarnation notifications are not interpreted a second time.
17
+ - Approval remains a listener notification while the Agent TaskResult is pending.
18
+ Generation retains its existing policy: approval suspension fails the pipeline.
19
+ - Pending submissions retain their Generation listeners in Workflow entry order.
20
+ Agent continues to own admission. A rejected overlapping call cannot replace
21
+ another call's approval listener; a queued call may be admitted after the prior
22
+ result settles. Only the corresponding settled or synchronously failed request
23
+ is removed. Result callbacks are thread-safe and never wait on the EventLoop.
24
+ - Agent instances and their conversations are reused across iterations and
25
+ pipeline invocations. No per-call Agent creation, automatic cancellation,
26
+ retry policy, durable child tracking, or new runtime registry is introduced.
27
+ - The unused private Agent event-sink method is removed. Per-invocation public
28
+ `on_event:` arguments remain unsupported.
29
+
30
+ `AgentResultReceiver` and `PipelineState` retain event interpretation, parsing,
31
+ request correlation, stale-result rejection, review feedback and trust decisions.
32
+ Their rule bodies are unchanged. `WorkflowBuilder` retains state definitions and
33
+ entry order. Its private operation port is not a new public Agent API.
34
+
35
+ The connection relies on existing public Agent guarantees: one admitted
36
+ execution per Agent, ordered incarnation notifications, and TaskResult settlement
37
+ for terminal results. Approval does not settle the TaskResult. Handoff remains
38
+ outside GeneratorVerifier completion semantics, as before.
39
+
40
+ ## B06: Default parser composition
41
+
42
+ `runtime_composition/generation_defaults.rb` selects the existing JsonParser
43
+ through a private one-time factory binding. Generation lazily creates and reuses
44
+ one default parser per pipeline only when default parsing is needed. Boot creates
45
+ no parser, Agent, Persistence or Runtime for this binding.
46
+
47
+ Generation owns `default_parse_draft` and `default_parse_review`, including the
48
+ existing ParseError fallback payloads. Existing custom parser callables take
49
+ precedence. No application configuration changes are required. OutputParser's
50
+ contract and its concrete implementations are unchanged.
51
+
52
+ ## Scope and verification
53
+
54
+ AST regression gates reject concrete parser selection and the removed private
55
+ Agent invocation in Generation. Public-only Agent doubles cover inline completion,
56
+ busy failure, queued admission, stale terminal notifications, timeout, cancellation
57
+ and approval while pending. Real Agent integration covers approval in both phases
58
+ and retained conversations. Domain event-rule tests use the private Generation
59
+ operation port; they no longer pretend a private Agent method is the public API.
60
+
61
+ Public signatures, result shape, stored schemas, generation/review decisions,
62
+ parser fallback values and default iteration limits are preserved. The internal
63
+ result-observation plumbing changes; this is not merely a physical file move.
64
+ F01 durable Workflow children remain deferred feature work. This checkpoint does
65
+ not certify all framework dependencies or all concrete Engine responsibilities.
@@ -0,0 +1,54 @@
1
+ # r8 unit16: Explicit cancellation subscription ownership
2
+
3
+ This responsibility refactor is based on applied unit15, commit
4
+ `9aebef9217383cebb7fa3ec8b2d17b5763cd3c5e` (tree
5
+ `fcc1bd3bc72ed611a7d4e9090dcf2391b6bc7471`). It addresses B07 only.
6
+
7
+ ## C13 owns registration lifetime
8
+
9
+ `Concurrency::ResultSubscriptions#explicit_cancellation` registers the existing
10
+ CancellationToken notification and owns its disposal through `close`. This is
11
+ an internal Execution operation, reusing the existing subscription collection;
12
+ it is not a new public registry or a new Tool implementation.
13
+
14
+ The existing `cancellation` operation delegates its registration bookkeeping to
15
+ this method and retains its additional `cancelled?` check. Its `Subscriptions`
16
+ subclass retains deadline scheduling. An explicit registration alone neither
17
+ checks an elapsed deadline nor schedules a timer.
18
+
19
+ CancellationToken still owns callback storage, delivery, exception isolation,
20
+ and private removal. `on_cancel` still returns the token. Public signatures,
21
+ exception types, and the callback behavior are unchanged. In particular, closing
22
+ a registration does not retract a callback already taken by concurrent `cancel!`.
23
+
24
+ ## Consumers retain their execution decisions
25
+
26
+ - C01 TeamCoordinator registers its existing cancellation callback through C13
27
+ and closes the collection in the existing `ensure` block. Team still owns the
28
+ durable cancel request, child cancellation, and terminal outcome interpretation.
29
+ - I09 OffloadPool registers its existing operation cancellation callback through
30
+ the same operation. It still owns queue/worker admission, logical settlement,
31
+ deadline promotion, abandonment, and physical completion. Timer registrations
32
+ are closed before cancellation registrations, preserving cleanup order.
33
+ - C06 Tool already passes its token to the standard offloaded submitter. Its
34
+ operation dispatch and cooperative/custom-async paths are unchanged. No
35
+ Tool-specific subscription or symmetric copy of Team logic is introduced.
36
+
37
+ An already-cancelled token may deliver during registration and close the
38
+ subscription collection before registration returns. The existing collection's
39
+ `add` behavior disposes such a late-added registration immediately. The same
40
+ mechanism covers a concurrent `close` during registration.
41
+
42
+ ## Verification and remaining scope
43
+
44
+ Behavioral checks cover explicit cancellation, expired deadlines without explicit
45
+ cancellation, inline and concurrent close, delivery already in flight, callback
46
+ failure isolation, and Team/worker cleanup after success and failure. Existing
47
+ OffloadPool timeout, cancellation, and physical-completion tests remain applicable.
48
+ The AST gate rejects private token-removal calls outside Execution, including
49
+ literal reflective calls in Engine and domain code.
50
+
51
+ B08 configuration access and F01 durable Workflow children are not implemented
52
+ here. Public API/RBS, storage schemas, default configuration, and domain rules
53
+ are retained. This change does not certify all Contract boundaries or eliminate
54
+ the aggregate implementation graph's cycles.
@@ -0,0 +1,73 @@
1
+ # r8 unit17: Domain settings consumption
2
+
3
+ This responsibility-only refactor is based on applied unit16, commit
4
+ `fb551e1a1a8334b2547ecad126dd9c152c1b0f8c` (tree
5
+ `1ddb3b0e3f4eb97c1738ad02f9035eeefa180c90`). It addresses B08.
6
+
7
+ ## Values and composition have different owners
8
+
9
+ Agent::Settings owns Agent option values and the existing stream callback error
10
+ policy validation. WorkflowSettings owns the Workflow progress limit and optional
11
+ state repository. They contain actual domain values, never the application
12
+ Configuration object. Their readers do not select a concrete adapter or backend.
13
+ Configuration remains the application-facing facade and composes these values;
14
+ its existing readers, writers, default values and zero-argument constructor remain.
15
+ The application composition boundary supplies the defaults and lazy providers.
16
+
17
+ The existing MultiAgent::Store receives a provider for the optional configured
18
+ store. It does not construct a fallback. Team still falls back to its fresh-store
19
+ factory; Orchestrator still permits no coordination store unless durable children
20
+ require one. Explicit stores and execution participants keep their priority.
21
+ A single store reader does not require a separate MultiAgent settings class.
22
+
23
+ Logger reads use the existing neutral RuntimeSettings. Agent authorization pool
24
+ size and queue capacity belong to the execution connection, which reads them
25
+ when submitting authorization work to the owning Runtime. Agent retains timeout
26
+ selection, approval evaluation, result interpretation, and operation supervision.
27
+ The private ExecutionEnvironment#submit_authorization operation separates those
28
+ resource choices from ToolInvocation. Generic Tool submission is unchanged.
29
+
30
+ ## Preserve read timing without notifications
31
+
32
+ Each existing read remains at its previous execution boundary. Providers are
33
+ bound without evaluating Configuration or starting Runtime resources. A read
34
+ resolves the current domain values; it does not subscribe, poll, cache, or push
35
+ changes. There is no observer, change event, background task, version counter,
36
+ refresh loop, or new in-flight reconfiguration guarantee.
37
+
38
+ The existing read positions and short-circuit rules remain significant:
39
+
40
+ - Agent class model fallback is read when model is requested. Explicit class
41
+ models keep precedence. Already-created Agent stores are not replaced.
42
+ - Hooks and LLM adapter operations are read at the existing input preparation,
43
+ identity check, and call sites. Hook order and validation remain Agent rules.
44
+ - Workflow limits are read when starting or resuming execution. An admitted
45
+ execution retains its limit; a changed global default does not update it.
46
+ - Explicit nil, per-invocation overrides, configured stores, and fresh fallback
47
+ stores retain their existing meanings. No new defaults are created on reads.
48
+ - Configuration copies duplicate the domain value containers while retaining
49
+ injected component identities, preserving nested scoped overrides and reset.
50
+
51
+ The new domain value types are internal, grouped by responsibility rather than
52
+ one class per setting. Public Configuration continues to offer the same settings;
53
+ applications do not need to inject every value manually. Its private instance
54
+ variables and internal containers are not an application extension API.
55
+
56
+ ## Verification and limits
57
+
58
+ Regression checks cover lazy boot and direct Configuration loading, nested scope
59
+ restoration after failure, reset, component identities, nil, class and invocation
60
+ overrides, hook read timing/order, Workflow admission-time limits, persistent
61
+ Agent stores, and the distinct Team/Orchestrator fallback behavior. Execution
62
+ connection tests verify authorization resource options and owning Runtime.
63
+ Existing failure-policy/logging tests configure values through public writers
64
+ instead of mocking the old composition getter. RBS records the new internal
65
+ boundaries without erasing domain operation types.
66
+
67
+ AST gates reject application Configuration references from Agent, Workflow, and
68
+ MultiAgent domain code, including literal reflective access. They also reject
69
+ pool sizing in domain code. These are targeted regression checks, not a proof of
70
+ all dynamic dependencies or a whole-framework completion claim.
71
+
72
+ B07 remains applied. F01 durable Workflow children and other feature work are
73
+ outside this change. There are no storage schema or public operation changes.
@@ -0,0 +1,92 @@
1
+ # R8 unit18: durable cancellation receipt
2
+
3
+ ## Problem
4
+
5
+ An Orchestrator load can return while recovery of a framework-owned child is still
6
+ in flight. If the child needs external factual resolution, Agent captures an
7
+ immutable terminal command that will retain the active parent in coordination
8
+ wait. A cancelled token supplied to `resume` after command capture previously
9
+ cancelled only the live invocation. The earlier command could then persist a
10
+ false cancellation snapshot and release the owner. Restart lost the request.
11
+
12
+ Controlled scheduling reproduced this in both unit16 and unit17, three times out
13
+ of three. The original example passed 200 natural repetitions. Without the
14
+ applicant's original failure log, equivalence to that initial failure is not
15
+ established. The controlled race is independently demonstrated.
16
+
17
+ ## Ownership
18
+
19
+ Agent owns receipt of cancellation for an exact execution, its existing durable
20
+ cancellation ledger, and persistence of the parent execution. MultiAgent still
21
+ owns the unresolved-child and pending-parent rules. Execution owns notification
22
+ registration and delivery; Engine owns runtime connections. No Agent decision is
23
+ moved into those mechanisms or into neutral Persistence/Storage.
24
+
25
+ `ExactExecution` validates identity, reservation, input and participant binding
26
+ before recording a supplied cancellation through `Store#request_cancellation`.
27
+ The write runs in its existing off-EventLoop preparation, before recovery or
28
+ waiting. If cancellation first becomes visible during EventLoop delivery,
29
+ preparation runs again before the live owner is signalled. Recording errors fail
30
+ the observer and do not proceed to recovery or notification.
31
+
32
+ `ExecutionChange#prepare_in` already reads the monotonic cancellation ledger
33
+ inside the participant transaction. `ExecutionOutcomeCommitter` now uses that
34
+ prepared fact for a pending execution's cancellation metadata. The worker's
35
+ captured command remains immutable; it does not query a live invocation or token.
36
+
37
+ ## Ordering and preserved semantics
38
+
39
+ - Before outcome commit: the transaction sees the accepted ledger entry and saves
40
+ cancellation in both Agent pending metadata and MultiAgent extension state.
41
+ - After outcome commit: the ledger retains newly accepted intent without changing
42
+ execution revision or invalidating the in-flight result. The previously saved
43
+ metadata/extension remain a snapshot; the next recovery/change incorporates the
44
+ ledger. Immediate equality between those snapshots and the ledger is not an API
45
+ guarantee. The ledger is the durable source of accepted cancellation intent.
46
+ - After owner release: receipt records intent before recovery installation.
47
+ - An absent execution is not assigned a cancellation record. A terminal result,
48
+ including one that wins against cancellation receipt, remains unchanged.
49
+ - Unknown child external outcomes still require factual resolution. No LLM replay,
50
+ forced child completion or new recovery capability is introduced.
51
+
52
+ There is no schema change, public API change, new Contract, Registry, subscription
53
+ or polling mechanism. This fixes receipt of cancellation observed by the existing
54
+ exact-execution path; it does not introduce continuous subscription to an incoming
55
+ token after observer registration.
56
+
57
+ ## Verification design
58
+
59
+ Queue gates hold the outcome worker before commit and after commit/before result
60
+ publication. Gates never block EventLoop or hold a storage transaction. Tests
61
+ assert ledger persistence, unchanged revision during receipt, pending snapshots,
62
+ restart preservation, unknown-child activity and zero LLM replay. Additional
63
+ component tests cover validation rejection, write failure, recovery ordering,
64
+ late token observation and terminal-result preservation. The pending commit test
65
+ also covers committed-response loss.
66
+
67
+ The original checkpoint fixture now performs phase inspection and snapshot copy
68
+ under one backend lock, preventing concurrent after-commit hooks from replacing a
69
+ selected checkpoint. Its initial assertion uses the durable ledger because a
70
+ request arriving after a saved waiting snapshot need not rewrite that snapshot.
71
+ Separate deterministic tests assert the snapshot on each side of the commit.
72
+
73
+ ## Unit18 delivery correction
74
+
75
+ The first unit18 version checked the incoming token twice inside delivery: once
76
+ to decide whether to record, and again to decide whether to signal. Cancellation
77
+ between those observations could skip recording but still signal the owner.
78
+ A suspended approval execution then exited without a completion reconciliation,
79
+ leaving the durable ledger empty.
80
+
81
+ Delivery now uses one cancellation observation for both decisions. After finding
82
+ and validating the current owner, an observed cancellation returns to off-loop
83
+ preparation if unrecorded, or signals the owner if already recorded. The separate
84
+ preparation and delivery observations remain intentional: scheduling between those
85
+ stages can change the token. A notification is never authorized by a different
86
+ observation from the one used to enforce its recording prerequisite.
87
+
88
+ Regression tests use the real suspended owner, registry and EventLoop. They
89
+ cancel the incoming token just before delivery or during the owner lookup, and
90
+ cover both successful recording and recording failure. They assert recording
91
+ before notification, no notification on write failure, off-loop persistence and
92
+ unchanged suspended execution contents. No polling or new subscription is added.