phronomy 0.25.0 → 0.27.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (323) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +71 -0
  3. data/CONTRIBUTING.md +4 -4
  4. data/README.md +14 -7
  5. data/VERIFY.sh +27 -27
  6. data/benchmark/bench_agent_invoke.rb +26 -22
  7. data/benchmark/bench_context_assembler.rb +4 -5
  8. data/benchmark/bench_regression.rb +1 -1
  9. data/docs/architecture/agent-chat-and-state-ownership.md +147 -0
  10. data/docs/architecture/agent-configuration-and-tool-binding.md +139 -0
  11. data/docs/architecture/agent-context.md +5 -3
  12. data/docs/architecture/agent-transition-ownership.md +89 -0
  13. data/docs/architecture/before-llm-input.md +6 -0
  14. data/docs/architecture/context-management.md +30 -0
  15. data/docs/architecture/context-preparation-steps.md +90 -0
  16. data/docs/architecture/entry-action-and-team-wording.md +72 -0
  17. data/docs/architecture/execution-metadata-and-values.md +80 -0
  18. data/docs/architecture/generator-verifier-ownership.md +111 -0
  19. data/docs/architecture/multi-agent-handoff.md +8 -2
  20. data/docs/architecture/persistence-refactoring-plan.md +50 -0
  21. data/docs/architecture/persistence.md +29 -6
  22. data/docs/architecture/refactoring-closure.md +334 -0
  23. data/docs/architecture/remaining-refactoring-plan.md +374 -0
  24. data/docs/architecture/rubyllm-2-token-ownership.md +82 -0
  25. data/docs/architecture/tool-schema-recording-gap.md +50 -0
  26. data/docs/architecture/tracing.md +4 -4
  27. data/docs/architecture/workflow-terminal-ownership-design.md +104 -0
  28. data/docs/architecture.md +209 -0
  29. data/docs/async-composition.md +205 -0
  30. data/docs/decisions/010-cooperative-first-concurrency.md +23 -23
  31. data/docs/decisions/014-unified-persistence-durable-state.md +11 -0
  32. data/docs/decisions/024-event-loop-single-writer-agent-runtime.md +5 -1
  33. data/docs/decisions/025-process-local-agent-ownership-and-runtime-admission.md +13 -3
  34. data/docs/decisions/026-workflow-runtime-admission-and-durable-terminal-barrier.md +5 -1
  35. data/docs/decisions/030-agent-handoff-domain-and-durable-responsibility.md +5 -0
  36. data/docs/decisions/031-durable-multi-agent-coordination.md +5 -0
  37. data/docs/decisions/032-storage-backend-composition.md +80 -0
  38. data/docs/decisions/033-domain-persistence-ownership.md +79 -0
  39. data/docs/decisions/034-handoff-runner-coordination-ownership.md +76 -0
  40. data/docs/decisions/035-tool-executor-capability-ownership.md +68 -0
  41. data/docs/decisions/036-context-contract-ownership.md +86 -0
  42. data/docs/decisions/037-common-definition-ownership.md +62 -0
  43. data/docs/decisions/038-responsibility-based-source-layout.md +131 -0
  44. data/docs/decisions/039-runtime-configuration-lifecycle-ownership.md +74 -0
  45. data/docs/decisions/040-configuration-default-composition.md +94 -0
  46. data/docs/decisions/041-feature-owned-identity-registries.md +100 -0
  47. data/docs/decisions/042-feature-owned-execution-state.md +106 -0
  48. data/docs/decisions/043-storage-execution-constraint-notifications.md +75 -0
  49. data/docs/decisions/044-agent-default-and-one-shot-composition.md +106 -0
  50. data/docs/decisions/045-worker-input-restriction-ownership.md +100 -0
  51. data/docs/decisions/046-agent-responsibility-layout-and-shared-records.md +110 -0
  52. data/docs/decisions/047-recovered-execution-continuation-contract.md +116 -0
  53. data/docs/decisions/048-dispatch-preparation-worker-ownership.md +120 -0
  54. data/docs/decisions/049-initial-preparation-worker-ownership.md +111 -0
  55. data/docs/decisions/050-approval-resume-snapshot-and-commit-ownership.md +98 -0
  56. data/docs/decisions/051-execution-outcome-worker-ownership.md +151 -0
  57. data/docs/decisions/052-tool-invocation-restoration-ownership.md +92 -0
  58. data/docs/decisions/053-shared-state-coordination-ownership.md +71 -0
  59. data/docs/decisions/054-workflow-terminal-save-single-owner.md +76 -0
  60. data/docs/decisions/055-terminal-observer-failure-settlement.md +60 -0
  61. data/docs/decisions/056-workflow-terminal-policy-ownership.md +87 -0
  62. data/docs/decisions/057-storage-transaction-boundaries.md +73 -0
  63. data/docs/decisions/058-neutral-storage-primitives.md +78 -0
  64. data/docs/decisions/README.md +35 -6
  65. data/docs/design/durable-semantic-coordination/IMPLEMENTATION_DESIGN_V2.md +6 -0
  66. data/docs/design/durable-semantic-coordination/IMPLEMENTATION_REPORT.md +6 -0
  67. data/docs/features.md +21 -12
  68. data/docs/getting-started.md +10 -10
  69. data/docs/migrations/0.15.md +5 -0
  70. data/docs/migrations/durable-semantic-coordination-v2.md +7 -1
  71. data/docs/migrations/handoff-runner-multi-agent.md +35 -0
  72. data/docs/migrations/neutral-storage-spi.md +43 -0
  73. data/docs/migrations/parallel-tool-chat-removal.md +49 -0
  74. data/docs/migrations/shared-state-multi-agent.md +44 -0
  75. data/docs/migrations/storage-backend-composition.md +117 -0
  76. data/docs/migrations/storage-transaction-boundaries.md +74 -0
  77. data/docs/persistence-backends.md +162 -204
  78. data/docs/runtime-and-concurrency.md +205 -60
  79. data/lib/phronomy/agent/api/agent.rb +17 -0
  80. data/lib/phronomy/agent/async_event_api.rb +2 -2
  81. data/lib/phronomy/agent/base.rb +55 -251
  82. data/lib/phronomy/{agent.rb → agent/composition/run_once.rb} +4 -13
  83. data/lib/phronomy/agent/context/capability/base.rb +67 -26
  84. data/lib/phronomy/agent/context/capability/tool_executor.rb +62 -0
  85. data/lib/phronomy/agent/{context_assembler.rb → context_assembly/context_assembler.rb} +143 -88
  86. data/lib/phronomy/agent/{context_importer.rb → context_assembly/context_importer.rb} +2 -2
  87. data/lib/phronomy/agent/{ruby_llm_materializer.rb → context_assembly/ruby_llm_materializer.rb} +4 -7
  88. data/lib/phronomy/agent/context_assembly/runtime_chat_builder.rb +36 -0
  89. data/lib/phronomy/agent/context_assembly/saved_context_reader.rb +53 -0
  90. data/lib/phronomy/agent/context_assembly/state_writer.rb +165 -0
  91. data/lib/phronomy/agent/context_assembly/token_budget_resolver.rb +22 -0
  92. data/lib/phronomy/agent/{context_plan.rb → context_contract/context_plan.rb} +1 -1
  93. data/lib/phronomy/agent/{context_policy_input.rb → context_contract/context_policy_input.rb} +6 -6
  94. data/lib/phronomy/agent/{llm_input_build_context.rb → context_contract/llm_input_build_context.rb} +1 -1
  95. data/lib/phronomy/agent/{llm_input_manifest.rb → context_contract/llm_input_manifest.rb} +20 -20
  96. data/lib/phronomy/agent/{llm_input_patch.rb → context_contract/llm_input_patch.rb} +2 -2
  97. data/lib/phronomy/agent/{agent_execution.rb → execution/agent_execution.rb} +8 -4
  98. data/lib/phronomy/agent/{agent_invocation.rb → execution/agent_invocation.rb} +8 -13
  99. data/lib/phronomy/agent/{agent_invocation_session_builder.rb → execution/agent_invocation_session_builder.rb} +20 -96
  100. data/lib/phronomy/agent/execution/approval_resume_commit.rb +108 -0
  101. data/lib/phronomy/agent/execution/dispatch_preparation.rb +305 -0
  102. data/lib/phronomy/agent/{exact_execution.rb → execution/exact_execution.rb} +12 -13
  103. data/lib/phronomy/agent/{execution_cancellation.rb → execution/execution_cancellation.rb} +2 -3
  104. data/lib/phronomy/agent/execution/execution_coordinator.rb +1925 -0
  105. data/lib/phronomy/agent/execution/execution_failure.rb +30 -0
  106. data/lib/phronomy/agent/execution/execution_metadata.rb +53 -0
  107. data/lib/phronomy/agent/execution/execution_outcome_committer.rb +344 -0
  108. data/lib/phronomy/agent/execution/execution_registry.rb +459 -0
  109. data/lib/phronomy/agent/execution/execution_session_runner.rb +118 -0
  110. data/lib/phronomy/agent/execution/initial_preparation.rb +421 -0
  111. data/lib/phronomy/agent/execution/invocation_transitions.rb +86 -0
  112. data/lib/phronomy/agent/{phase_machine_builder.rb → execution/phase_machine_builder.rb} +22 -73
  113. data/lib/phronomy/agent/{provider_call_outcome.rb → execution/provider_call_outcome.rb} +9 -9
  114. data/lib/phronomy/agent/execution/runtime_record_encoder.rb +210 -0
  115. data/lib/phronomy/agent/{handoff_context.rb → handoff/handoff_context.rb} +2 -2
  116. data/lib/phronomy/agent/handoff/handoff_execution_coordinator.rb +15 -0
  117. data/lib/phronomy/agent/handoff/handoff_outcome_committer.rb +131 -0
  118. data/lib/phronomy/agent/{handoff_state.rb → handoff/handoff_state.rb} +1 -1
  119. data/lib/phronomy/agent/{journal_projection.rb → journal/journal_projection.rb} +4 -0
  120. data/lib/phronomy/agent/{journal_record.rb → journal/journal_record.rb} +3 -3
  121. data/lib/phronomy/agent/{llm_call_record.rb → journal/llm_call_record.rb} +2 -2
  122. data/lib/phronomy/agent/{agent_root.rb → lifecycle/agent_root.rb} +6 -2
  123. data/lib/phronomy/agent/lifecycle/default_persistence.rb +29 -0
  124. data/lib/phronomy/{engine/runtime/agent_ownership_registry.rb → agent/lifecycle/ownership_registry.rb} +24 -10
  125. data/lib/phronomy/{agent_already_exists_error.rb → agent/lifecycle_contract/agent_already_exists_error.rb} +2 -0
  126. data/lib/phronomy/{agent_busy_error.rb → agent/lifecycle_contract/agent_busy_error.rb} +2 -0
  127. data/lib/phronomy/{agent_purged_error.rb → agent/lifecycle_contract/agent_purged_error.rb} +2 -0
  128. data/lib/phronomy/agent/lifecycle_contract/handoff_error.rb +7 -0
  129. data/lib/phronomy/{stream_callback_error.rb → agent/lifecycle_contract/stream_callback_error.rb} +2 -0
  130. data/lib/phronomy/agent/persistence/agent_repository.rb +61 -0
  131. data/lib/phronomy/agent/persistence/codec.rb +358 -0
  132. data/lib/phronomy/agent/persistence/execution_repository.rb +108 -0
  133. data/lib/phronomy/agent/persistence/handoff_state_repository.rb +58 -0
  134. data/lib/phronomy/agent/persistence/journal_repository.rb +54 -0
  135. data/lib/phronomy/agent/persistence/queries.rb +61 -0
  136. data/lib/phronomy/agent/persistence/storage_schema.rb +24 -0
  137. data/lib/phronomy/agent/persistence/watermark.rb +27 -0
  138. data/lib/phronomy/agent/recovery/invocation_restorer.rb +132 -0
  139. data/lib/phronomy/agent/{recovery_coordinator → recovery/recovery_coordinator}/continuation.rb +21 -45
  140. data/lib/phronomy/agent/{recovery_coordinator → recovery/recovery_coordinator}/installation.rb +36 -41
  141. data/lib/phronomy/agent/{recovery_coordinator → recovery/recovery_coordinator}/resolution.rb +37 -40
  142. data/lib/phronomy/agent/{recovery_coordinator.rb → recovery/recovery_coordinator.rb} +9 -13
  143. data/lib/phronomy/agent/recovery/recovery_support.rb +227 -0
  144. data/lib/phronomy/agent/selection/candidate.rb +1 -1
  145. data/lib/phronomy/agent/{approval_evaluation_request.rb → tool_execution/approval_evaluation_request.rb} +1 -12
  146. data/lib/phronomy/agent/{tool_approval_request.rb → tool_execution/tool_approval_request.rb} +1 -10
  147. data/lib/phronomy/agent/tool_execution/tool_binding.rb +90 -0
  148. data/lib/phronomy/agent/{tool_call_intercepted.rb → tool_execution/tool_call_intercepted.rb} +2 -2
  149. data/lib/phronomy/agent/{tool_definition_set.rb → tool_execution/tool_definition_set.rb} +9 -4
  150. data/lib/phronomy/agent/{tool_invocation.rb → tool_execution/tool_invocation.rb} +69 -34
  151. data/lib/phronomy/agent/{tool_invocation_session_builder.rb → tool_execution/tool_invocation_session_builder.rb} +2 -2
  152. data/lib/phronomy/common/configuration_error.rb +7 -0
  153. data/lib/phronomy/common/error.rb +5 -0
  154. data/lib/phronomy/{agent → common/values}/immutable.rb +9 -1
  155. data/lib/phronomy/common/values/serializable.rb +32 -0
  156. data/lib/phronomy/{configuration.rb → configuration/configuration.rb} +14 -5
  157. data/lib/phronomy/configuration/global_configuration.rb +26 -0
  158. data/lib/phronomy/content_store/storage_schema.rb +11 -0
  159. data/lib/phronomy/content_store/stored_contents.rb +43 -0
  160. data/lib/phronomy/engine/backpressure_error.rb +7 -0
  161. data/lib/phronomy/{blocking.rb → engine/blocking.rb} +15 -8
  162. data/lib/phronomy/engine/cancellation_error.rb +7 -0
  163. data/lib/phronomy/engine/concurrency/cancellation_token.rb +4 -0
  164. data/lib/phronomy/engine/concurrency/offload_pool.rb +29 -16
  165. data/lib/phronomy/engine/concurrency/operation_binding.rb +43 -0
  166. data/lib/phronomy/engine/concurrency/physical_completion_task.rb +4 -62
  167. data/lib/phronomy/engine/concurrency/result_collector.rb +99 -0
  168. data/lib/phronomy/engine/concurrency/result_composition.rb +145 -0
  169. data/lib/phronomy/engine/concurrency/subscriptions.rb +68 -0
  170. data/lib/phronomy/engine/concurrency/worker_input_restricted.rb +14 -0
  171. data/lib/phronomy/engine/event_loop.rb +160 -626
  172. data/lib/phronomy/engine/event_loop_reentrancy_error.rb +8 -0
  173. data/lib/phronomy/engine/execution.rb +229 -0
  174. data/lib/phronomy/engine/execution_cancellation_error.rb +14 -0
  175. data/lib/phronomy/engine/execution_receiver.rb +65 -0
  176. data/lib/phronomy/engine/execution_timeout_error.rb +14 -0
  177. data/lib/phronomy/engine/fsm_protocol.rb +14 -0
  178. data/lib/phronomy/engine/fsm_session.rb +38 -31
  179. data/lib/phronomy/{invalid_async_entry_action_error.rb → engine/invalid_async_entry_action_error.rb} +3 -1
  180. data/lib/phronomy/{invalid_async_transition_action_error.rb → engine/invalid_async_transition_action_error.rb} +3 -1
  181. data/lib/phronomy/{invalid_async_workflow_action_error.rb → engine/invalid_async_workflow_action_error.rb} +3 -1
  182. data/lib/phronomy/{invocation_context.rb → engine/invocation_context.rb} +13 -1
  183. data/lib/phronomy/engine/pool_shutdown_error.rb +7 -0
  184. data/lib/phronomy/engine/recursion_limit_error.rb +7 -0
  185. data/lib/phronomy/engine/runtime/timer_queue.rb +11 -0
  186. data/lib/phronomy/engine/runtime.rb +80 -84
  187. data/lib/phronomy/engine/runtime_shutdown_error.rb +7 -0
  188. data/lib/phronomy/engine/runtime_shutdown_reentrancy_error.rb +7 -0
  189. data/lib/phronomy/engine/scheduler_reentrancy_error.rb +9 -0
  190. data/lib/phronomy/engine/{task.rb → task_result.rb} +101 -42
  191. data/lib/phronomy/engine/timeout_error.rb +7 -0
  192. data/lib/phronomy/filter/contract/filter_block_error.rb +14 -0
  193. data/lib/phronomy/generation/generator_verifier/agent_result_receiver.rb +89 -0
  194. data/lib/phronomy/generation/generator_verifier/pipeline_state.rb +57 -0
  195. data/lib/phronomy/generation/generator_verifier/workflow_builder.rb +112 -0
  196. data/lib/phronomy/generation/generator_verifier.rb +118 -0
  197. data/lib/phronomy/generation/low_confidence_error.rb +14 -0
  198. data/lib/phronomy/llm_adapter/base.rb +2 -2
  199. data/lib/phronomy/llm_context_window/token_budget.rb +6 -7
  200. data/lib/phronomy/llm_contract/authentication_error.rb +7 -0
  201. data/lib/phronomy/{context_budget_exceeded_error.rb → llm_contract/context_budget_exceeded_error.rb} +2 -0
  202. data/lib/phronomy/llm_contract/context_length_error.rb +7 -0
  203. data/lib/phronomy/llm_contract/rate_limit_error.rb +7 -0
  204. data/lib/phronomy/{token_usage.rb → llm_contract/token_usage.rb} +2 -2
  205. data/lib/phronomy/llm_contract/transport_error.rb +7 -0
  206. data/lib/phronomy/multi_agent/admission_registry.rb +22 -2
  207. data/lib/phronomy/multi_agent/durable_subagent_coordinator.rb +8 -8
  208. data/lib/phronomy/{agent → multi_agent}/handoff_runner.rb +18 -17
  209. data/lib/phronomy/multi_agent/orchestrator.rb +36 -68
  210. data/lib/phronomy/multi_agent/persistence/codec.rb +55 -0
  211. data/lib/phronomy/multi_agent/persistence/queries.rb +30 -0
  212. data/lib/phronomy/multi_agent/persistence/team_execution_repository.rb +108 -0
  213. data/lib/phronomy/multi_agent/persistence/team_repository.rb +61 -0
  214. data/lib/phronomy/{agent → multi_agent}/shared_state.rb +56 -39
  215. data/lib/phronomy/multi_agent/storage_contract/team_storage_schema.rb +15 -0
  216. data/lib/phronomy/multi_agent/team_coordinator.rb +21 -18
  217. data/lib/phronomy/multi_agent/team_execution.rb +1 -1
  218. data/lib/phronomy/{engine/runtime → multi_agent}/team_ownership_registry.rb +14 -4
  219. data/lib/phronomy/multi_agent/team_root.rb +1 -1
  220. data/lib/phronomy/output_parser/contract/parse_error.rb +7 -0
  221. data/lib/phronomy/persistence/api/persistence.rb +140 -0
  222. data/lib/phronomy/persistence/migration/initial_format_migration.rb +19 -19
  223. data/lib/phronomy/persistence_composition/repositories.rb +77 -0
  224. data/lib/phronomy/persistence_composition/storage_schema.rb +24 -0
  225. data/lib/phronomy/{execution_rehydration_required_error.rb → recovery/execution_rehydration_required_error.rb} +2 -0
  226. data/lib/phronomy/{recovery.rb → recovery/recovery.rb} +1 -1
  227. data/lib/phronomy/runtime_composition/agent_defaults.rb +7 -0
  228. data/lib/phronomy/runtime_composition/configuration_defaults.rb +9 -0
  229. data/lib/phronomy/runtime_composition/global_runtime.rb +19 -0
  230. data/lib/phronomy/storage/backend.rb +101 -0
  231. data/lib/phronomy/storage/backends/in_memory.rb +157 -0
  232. data/lib/phronomy/storage/blob_conflict_error.rb +10 -0
  233. data/lib/phronomy/storage/blobs.rb +31 -0
  234. data/lib/phronomy/storage/condition.rb +25 -0
  235. data/lib/phronomy/storage/condition_failed_error.rb +16 -0
  236. data/lib/phronomy/storage/conflict_error.rb +9 -0
  237. data/lib/phronomy/{persistence → storage}/durable_record.rb +12 -12
  238. data/lib/phronomy/storage/entry.rb +33 -0
  239. data/lib/phronomy/storage/guard_ref.rb +13 -0
  240. data/lib/phronomy/storage/not_found_error.rb +9 -0
  241. data/lib/phronomy/storage/record_codec.rb +177 -0
  242. data/lib/phronomy/storage/records.rb +61 -0
  243. data/lib/phronomy/storage/resource.rb +126 -0
  244. data/lib/phronomy/storage/scope.rb +25 -0
  245. data/lib/phronomy/storage/serialization_error.rb +9 -0
  246. data/lib/phronomy/storage/streams.rb +44 -0
  247. data/lib/phronomy/storage/transaction_error.rb +10 -0
  248. data/lib/phronomy/storage/unique_constraint_error.rb +17 -0
  249. data/lib/phronomy/storage/unsupported_backend_error.rb +9 -0
  250. data/lib/phronomy/storage/validation.rb +53 -0
  251. data/lib/phronomy/storage/view.rb +131 -0
  252. data/lib/phronomy/testing/eval/scorer/llm_judge.rb +5 -3
  253. data/lib/phronomy/testing/fake_clock.rb +13 -9
  254. data/lib/phronomy/testing/persistence_contract/a_content_store.rb +1 -1
  255. data/lib/phronomy/testing/persistence_contract/a_journal_repository.rb +4 -4
  256. data/lib/phronomy/testing/persistence_contract/a_persistence_backend.rb +10 -7
  257. data/lib/phronomy/testing/persistence_contract/a_workflow_state_repository.rb +2 -2
  258. data/lib/phronomy/testing/persistence_contract/an_agent_repository.rb +6 -6
  259. data/lib/phronomy/testing/persistence_contract/an_execution_repository.rb +6 -6
  260. data/lib/phronomy/testing/persistence_contract/coordination_repositories.rb +8 -8
  261. data/lib/phronomy/testing/persistence_contract/neutral_storage_primitives.rb +263 -0
  262. data/lib/phronomy/testing/persistence_contract/storage_transaction_boundaries.rb +123 -0
  263. data/lib/phronomy/testing/persistence_contract.rb +4 -0
  264. data/lib/phronomy/tool/contract/tool_error.rb +7 -0
  265. data/lib/phronomy/tools/agent.rb +6 -6
  266. data/lib/phronomy/vector_store/async_backend.rb +5 -5
  267. data/lib/phronomy/vector_store/embeddings/base.rb +2 -2
  268. data/lib/phronomy/version.rb +1 -1
  269. data/lib/phronomy/{workflow.rb → workflow/execution/workflow.rb} +10 -8
  270. data/lib/phronomy/{workflow_context.rb → workflow/execution/workflow_context.rb} +4 -0
  271. data/lib/phronomy/workflow/execution/workflow_context_ownership_error.rb +7 -0
  272. data/lib/phronomy/workflow/execution/workflow_execution_registry.rb +188 -0
  273. data/lib/phronomy/{workflow_runner.rb → workflow/execution/workflow_runner.rb} +126 -75
  274. data/lib/phronomy/workflow/execution/workflow_terminal_policy.rb +40 -0
  275. data/lib/phronomy/workflow/persistence/codec.rb +153 -0
  276. data/lib/phronomy/workflow/persistence/state_repository.rb +57 -0
  277. data/lib/phronomy/workflow/phase_machine_builder.rb +8 -8
  278. data/lib/phronomy/workflow/storage_contract/workflow_storage_schema.rb +9 -0
  279. data/lib/phronomy.rb +52 -94
  280. data/scripts/api_snapshot.rb +4 -2
  281. data/scripts/storage_spi_snapshot.rb +36 -0
  282. data/sig/phronomy/agent.rbs +4 -5
  283. data/sig/phronomy/execution_receiver.rbs +34 -0
  284. data/sig/phronomy/extensions.rbs +5 -5
  285. data/sig/phronomy/handoff.rbs +4 -2
  286. data/sig/phronomy/multi_agent.rbs +19 -3
  287. data/sig/phronomy/persistence.rbs +7 -91
  288. data/sig/phronomy/runtime.rbs +34 -7
  289. data/sig/phronomy/storage.rbs +174 -0
  290. data/sig/phronomy/tool.rbs +11 -2
  291. data/sig/phronomy/workflow.rbs +1 -1
  292. metadata +236 -99
  293. data/lib/phronomy/agent/execution_coordinator.rb +0 -3138
  294. data/lib/phronomy/agent/handoff_execution_coordinator.rb +0 -143
  295. data/lib/phronomy/agent/recovery_support.rb +0 -504
  296. data/lib/phronomy/agent/token_budget_resolver.rb +0 -70
  297. data/lib/phronomy/agent/tool_executor.rb +0 -55
  298. data/lib/phronomy/generator_verifier.rb +0 -369
  299. data/lib/phronomy/invalid_context_budget_configuration_error.rb +0 -8
  300. data/lib/phronomy/multi_agent/fan_out_invocation.rb +0 -137
  301. data/lib/phronomy/multi_agent/fan_out_session_builder.rb +0 -118
  302. data/lib/phronomy/multi_agent/parallel_tool_chat.rb +0 -116
  303. data/lib/phronomy/persistence/durable_codec.rb +0 -706
  304. data/lib/phronomy/persistence/in_memory.rb +0 -690
  305. data/lib/phronomy/persistence/repository_facades.rb +0 -535
  306. data/lib/phronomy/persistence.rb +0 -276
  307. data/lib/phronomy/ruby_llm_patches.rb +0 -24
  308. data/lib/phronomy/workflow_recovery.rb +0 -123
  309. /data/lib/phronomy/agent/{context_candidate_resolver.rb → context_assembly/context_candidate_resolver.rb} +0 -0
  310. /data/lib/phronomy/agent/{context_policy_input_builder.rb → context_assembly/context_policy_input_builder.rb} +0 -0
  311. /data/lib/phronomy/agent/{context_plan_validator.rb → context_contract/context_plan_validator.rb} +0 -0
  312. /data/lib/phronomy/agent/{context_policy.rb → context_contract/context_policy.rb} +0 -0
  313. /data/lib/phronomy/agent/{llm_operation_result.rb → execution/llm_operation_result.rb} +0 -0
  314. /data/lib/phronomy/agent/{handoff.rb → handoff/handoff.rb} +0 -0
  315. /data/lib/phronomy/agent/{handoff_capability_factory.rb → handoff/handoff_capability_factory.rb} +0 -0
  316. /data/lib/phronomy/agent/{handoff_policy.rb → handoff/handoff_policy.rb} +0 -0
  317. /data/lib/phronomy/agent/{handoff_projection.rb → handoff/handoff_projection.rb} +0 -0
  318. /data/lib/phronomy/agent/{handoff_request.rb → handoff/handoff_request.rb} +0 -0
  319. /data/lib/phronomy/{canonical_json.rb → common/canonical_json.rb} +0 -0
  320. /data/lib/phronomy/{diagnostics.rb → engine/diagnostics.rb} +0 -0
  321. /data/lib/phronomy/{event.rb → engine/event.rb} +0 -0
  322. /data/lib/phronomy/{metrics.rb → engine/metrics.rb} +0 -0
  323. /data/lib/phronomy/{runnable.rb → engine/runnable.rb} +0 -0
@@ -0,0 +1,139 @@
1
+ # Agent configuration and Tool binding (R09, first slice)
2
+
3
+ ## Role and boundary
4
+
5
+ Agent::Base is the public declaration and lifecycle facade. Before tools are
6
+ advertised to an LLM or installed in a runtime chat, its prepare_tool_class hook
7
+ selects the Agent's alias and result filters for the original Tool class.
8
+ ToolDefinitionSet and runtime projection installation use that same hook.
9
+ MultiAgent::Orchestrator overrides it, calls super, then adds subagent context.
10
+
11
+ Previously the hook also generated both decorator subclasses and bridged custom
12
+ asynchronous results, including cancellation and physical completion. Refactor 42
13
+ extracts that mechanism into Agent::ToolBinding in agent/tool_execution. Base
14
+ retains the selection hook and its invocation keyword for Orchestrator cooperation.
15
+ ToolBinding takes an explicit Tool class, alias and filter list; it holds no Agent
16
+ reference and does not call private Agent methods back through send.
17
+
18
+ | Owner | Responsibility |
19
+ |---|---|
20
+ | Base / Filterable | Select the original class's alias and ordered class, instance and scoped filters. |
21
+ | ToolBinding | Construct alias/result-filter decorators, preserve effective Tool names, and bridge custom async results. |
22
+ | Capability::Base / ToolExecutor | Default Tool call protocol and physical execution. |
23
+ | ToolInvocation | Validation, authorization, execution supervision and state restoration. |
24
+ | Orchestrator | Capture subagent parent/config/knowledge context after Base preparation. |
25
+
26
+ There is one new internal class and one production file. ToolBinding is marked
27
+ @api private, like other Agent implementation collaborators; it is not a new
28
+ supported application API. No loader change, mixin, alias or public signature
29
+ change is introduced. Definitions, approval, durable schemas and stored Tool
30
+ state are unchanged.
31
+
32
+ ## Preparation and reading order
33
+
34
+ Base first returns non-Class values unchanged. For classes it constructs the
35
+ alias binding, then resolves filters, then prepares the filtered class. This
36
+ order preserves subclass creation before filter selection. With neither alias
37
+ nor filters the exact original class is returned. With an alias and no filters,
38
+ the alias subclass is returned without instantiating a Tool.
39
+
40
+ ToolBinding#prepare reads the effective name and the call_async method owner,
41
+ then defines the synchronous decorator and, only when needed, the custom async
42
+ decorator. filter_async_result registers physical and logical completion in that
43
+ order. propagate_failure and complete_filtered_result separate terminal outcomes.
44
+ The methods express one level below their operation names rather than leaving
45
+ the whole callback protocol inside Base.
46
+
47
+ The original Tool class remains the scoped-filter key even when an alias creates
48
+ a subclass. Each preparation captures a newly collected filter list; it does not
49
+ cache generated classes or deep-copy filter objects. Later registrations affect
50
+ later preparations. The synchronous call passes the original args/keyword values
51
+ to super and applies class, instance and scoped filters in that order, with the
52
+ effective name and original args. Filter exceptions propagate without ToolError
53
+ wrapping by this decorator.
54
+
55
+ ## Asynchronous contract retained
56
+
57
+ - If call_async is owned by Capability::Base, leave it inherited: its ordinary
58
+ execution path reaches the decorated call. A second async filter wrapper would
59
+ apply the same filters twice.
60
+ - Any other method owner, including an inherited custom implementation, receives
61
+ the custom async decorator. It forwards args/kwargs to super and wraps the
62
+ returned operation in PhysicalCompletionTask. It does not wait for completion.
63
+ - Preserve logical completed/failed/cancelled status, values and error identity.
64
+ Failure skips filters. A filter StandardError fails the derived result with
65
+ that same exception. A synchronous startup exception still escapes call_async.
66
+ - With on_physical_complete support, forward that signal independently of the
67
+ logical result. Logical cancellation/failure must not fabricate physical
68
+ completion while the source is still working. Physical completion can precede
69
+ the logical callback or already be true when the listener is registered.
70
+ - Without that signal, mark physical completion before settling the derived
71
+ result, including filter failure. Listener registration remains physical first,
72
+ logical second, so already-settled operations are handled by existing callbacks.
73
+ - Cancelling the derived result does not cancel the source. A later successful
74
+ source completion can still execute result filters, while its derived status
75
+ remains cancelled. This is existing behavior, not a new cancellation guarantee.
76
+
77
+ No retry, additional cancellation propagation, thread/pool policy or physical
78
+ completion guarantee is added. The source signal still describes source work,
79
+ not a new synchronization boundary around the filter callback itself.
80
+
81
+ ## Agent declaration inheritance as currently implemented
82
+
83
+ Do not infer one uniform inheritance rule from the word "configuration". The
84
+ following describes current compatibility behavior; Refactor 42 does not change
85
+ the DSL methods. Parent reads are live lookups, not snapshots taken at subclass
86
+ creation.
87
+
88
+ | Declaration / getter | Child without an own value | Own value / special behavior |
89
+ |---|---|---|
90
+ | model | Global configuration.default_model; does not read parent's model | Truthy setter, nil/false are reads. Global changes remain visible until an own value is set. |
91
+ | instructions | Parent instructions, including the same Proc or template object | Text or block replaces the own value. nil without a block is a read, not a clear. |
92
+ | provider | Parent provider | Truthy setter; nil/false read. |
93
+ | tools | Parent tools array by reference | A Hash replaces the own class list. An empty Hash is an explicit empty list. nil reads. |
94
+ | tool_aliases | Parent aliases merged with own aliases | Alias values are stringified; nil entries are omitted. A child nil alias or empty tools list does not erase inherited aliases. |
95
+ | context_policy | Parent policy object, ultimately ContextPolicies::Default.instance | Exactly one ContextPolicy object replaces it. nil is invalid, not reset. |
96
+ | temperature | nil; does not inherit | Truthy setter; zero is accepted; nil/false read. |
97
+ | max_iterations | 10; does not inherit | Truthy setter; zero is accepted. |
98
+ | cache_instructions | nil; does not inherit | nil reads, false is an explicit value. |
99
+ | max_output_tokens | nil; does not inherit | nil reads; positive Integer conversion. context_window moved to the RubyLLM registry in Refactor 45. |
100
+ | agent_definition | Raises until that class declares identity/revision | Each subclass requires its own definition; this is not inherited model configuration. |
101
+ | input/output/tool_result_filter registries | Empty class registry; do not inherit | Registrations append on that class. Instance filters are separate. |
102
+ | before_llm_input / _before_llm_input | nil class callback; does not inherit | Instance and global hook behavior remains separate. |
103
+
104
+ The generic Agent rule does not override specialised subclass DSL such as
105
+ Orchestrator's subagent registry. Tool/Capability declaration inheritance is also
106
+ a different contract, already covered by its configuration-inheritance tests.
107
+
108
+ The existing test description that said "normal class configuration still
109
+ inherits" referred only to instructions and was too broad. It now names the
110
+ actual checked rule. No new policy is inferred from that earlier wording.
111
+
112
+ For compatibility, retain these rules in this source refactor. Uniform parent
113
+ fallback, alias removal and copying inherited mutable values would be separate
114
+ behavior changes requiring an explicit migration decision. They can change
115
+ model/provider combinations, budgets, Tool names and application callbacks.
116
+
117
+ ## Verification and remaining R09 work
118
+
119
+ Thirty-five new contract examples run against both the unchanged Refactor 41 and
120
+ the candidate. They exercise selection/alias order, names, filter ordering,
121
+ forwarded object identity, default/custom async behavior, logical/physical
122
+ completion, cancellation and DSL inheritance. Existing Tool definition, approval,
123
+ Orchestrator and full integration suites cover the cooperation paths.
124
+ The release, API/SPI, RBS, style, isolated gem and examples gates are recorded in
125
+ the distribution. Candidate remote CI, live PostgreSQL, live LLM and performance
126
+ are not measured by this change.
127
+
128
+ Refactor 42 is applied and independently verified at core 4a57a3c2. This
129
+ completes the Tool binding and declaration-contract slice. Refactor 43 addresses
130
+ the original Chat construction and explicit state-mutation scope; see the
131
+ [Chat/state design](agent-chat-and-state-ownership.md). It preserves the Base
132
+ hooks and operation/publication order rather than changing DSL semantics.
133
+
134
+ Refactor 43 application was verified at core 5c4c0392; R09 is closed.
135
+ R10 is implemented in Refactor 44, pending application verification.
136
+ The published SVG is applied43-01. See the [naming boundary](entry-action-and-team-wording.md)
137
+ and the separate [open Tool schema finding](tool-schema-recording-gap.md).
138
+
139
+ Refactor 45 changes the token declarations as described in [the migration](rubyllm-2-token-ownership.md). Other Agent inheritance rules above remain unchanged. Tool schema/provider configuration follows the RubyLLM 2 inherited configuration contract.
@@ -84,8 +84,10 @@ See [Context Management](context-management.md) and
84
84
  ## 3. Live mutable ownership
85
85
 
86
86
  Within one Runtime/process, one mutable live Agent instance owns one `agent_id`.
87
- Loading or creating a second mutable live instance for the same `agent_id` is
88
- rejected.
87
+ `Agent::OwnershipRegistry` reserves that identity before materialization;
88
+ Runtime strongly retains the registry through the generic shutdown contract.
89
+ Repeated load returns the same live instance, while duplicate create is rejected.
90
+ See [ADR-041](../decisions/041-feature-owned-identity-registries.md).
89
91
 
90
92
  During active execution, EventLoop is the single writer of Phronomy-managed live
91
93
  Agent execution state. Blocking Persistence work and other synchronous work that
@@ -133,7 +135,7 @@ reconcilable
133
135
  resolution_required
134
136
  ```
135
137
 
136
- Recovery does not restore the old Ruby object graph or old Task callbacks. It
138
+ Recovery does not restore the old Ruby object graph or old TaskResult callbacks. It
137
139
  reconstructs current logical state from durable evidence and continues only
138
140
  when authority and outcome certainty permit it.
139
141
 
@@ -0,0 +1,89 @@
1
+ # Agent invocation transition ownership
2
+
3
+ ## Role and scope
4
+
5
+ An Agent invocation moves between preparation, Provider calls, Tool processing,
6
+ approval suspension and completion. Three collaborators need the same policy:
7
+ AgentInvocation consumes external payloads; PhaseMachineBuilder creates the
8
+ executable state machine; AgentInvocationSessionBuilder configures FSMSession's
9
+ advance, wait and terminal boundaries. Independently maintained event lists and
10
+ transition copies could disagree about what the current phase can accept.
11
+
12
+ Refactor 39 gives that shared policy one private owner, InvocationTransitions in
13
+ agent/execution. This is Agent data in the existing transition Hash format, not
14
+ a new cross-feature DSL or Engine extension. It is not a new execution object.
15
+
16
+ ## Ownership and reading order
17
+
18
+ | Owner | Responsibility |
19
+ |---|---|
20
+ | InvocationTransitions | Initial phase, declared/automatic/approval-wait states, Tool event vocabulary and ordered external transition definitions. |
21
+ | PhaseMachineBuilder | Translate those external definitions to state_machines; retain automatic state_completed transitions and synchronous entry-action validation. |
22
+ | AgentInvocationSessionBuilder | Assemble the invocation, event sink, entry actions and machine; pass shared state and transition metadata to FSMSession. |
23
+ | AgentInvocation | Apply payloads and expose the current guard predicates; use the shared Tool event vocabulary. |
24
+ | FSMSession | Generic advancement, event delivery and wait/terminal handling. No Agent-specific decisions. |
25
+
26
+ Read the policy table for legal external sources and guard priority, the machine
27
+ builder for execution mechanics, and the session builder for action wiring.
28
+ The EXTERNAL_EVENTS Hash, each transition array and each row are frozen so one
29
+ session cannot edit another session's policy. Guard lambdas contain no captured
30
+ invocation state; they inspect the context supplied at transition time.
31
+ Old private constants and the external_events factory are removed without aliases.
32
+
33
+ ## Preserved event and phase contract
34
+
35
+ The six Tool events are authorized, approval_required, completed, failed,
36
+ rejected and cancelled, each with the tool_ prefix. Each moves waiting_for_tools
37
+ to evaluating_tools. LLM completion from calling_llm tries these in order:
38
+
39
+ 1. callback_failed? to failed;
40
+ 2. handoff_failed? to failed;
41
+ 3. handoff_requested? to handed_off;
42
+ 4. tool_call_pending? to starting_tools;
43
+ 5. unconditional fallback to output_filtering.
44
+
45
+ Guards short-circuit. A nil context skips guarded rows and takes the fallback;
46
+ guard exceptions propagate unchanged. Each evaluation uses the latest context,
47
+ without caching a selected destination. Session applies the event payload first.
48
+
49
+ LLM failure/setup failure leads from calling_llm to failed. Tool setup failure
50
+ leads from dispatching_tools to failed, while tool_dispatch_prepared returns it
51
+ to evaluating_tools. Resume moves suspended to waiting_for_tools. Application
52
+ callback failure is accepted from the existing nine active phases only.
53
+
54
+ Automatic phases remain idle, filtering_input, building_context, starting_tools,
55
+ evaluating_tools, recording_tool_results and output_filtering. calling_llm,
56
+ waiting_for_tools and dispatching_tools wait for external events. suspended ends
57
+ a segment with halted; resume uses a fresh Session identity. The four declared
58
+ terminal phases remain handed_off, completed, blocked and failed.
59
+
60
+ FSMSession reads only the from field when determining external-event admission
61
+ and waiting. It does not execute metadata guards or choose their destinations;
62
+ state_machines does that. Known-but-undeclared and unknown events retain their
63
+ existing error behavior; context-consumed stale events retain their early exit.
64
+ The internal order of event registration now follows the shared table. Transition
65
+ order within each event, which determines behavior, is preserved. The generated
66
+ machine's private event-enumeration order is not a supported public contract.
67
+
68
+ ## Verification and limits
69
+
70
+ Independent behavioral tests run on both Refactor 38 and the candidate: all 195
71
+ external-event/source-state combinations, all sixteen LLM condition combinations
72
+ including short-circuit order, nil context and guard exceptions, fifteen Session
73
+ boundaries, context-before-guard ordering, approval suspension/resume/dispatch,
74
+ and invalid source-state handling. Existing Agent, causal durability, Handoff,
75
+ Workflow and Engine tests continue to cover their collaborating behavior.
76
+
77
+ The candidate also runs the full core/integration suites, offline examples and
78
+ real SQLite, API/SPI snapshots, RBS, style, annotations and isolated gem checks.
79
+ No SQL, stored format, entry action implementation, Tool restoration, cancellation
80
+ or Coordinator sequencing is changed. The new contract tests isolate entry actions
81
+ and do not claim live Provider coverage. Live PostgreSQL/LLM and remote CI are
82
+ not executed for this candidate. Refactor 39 was independently verified after application at core 4d57614a,
83
+ tree 654241da4b2b7f32d988602d28127bc1fa155641. All 10 files and the full tree
84
+ matched, and core/integration/examples/SQLite/API/type/gem checks passed.
85
+ The published SVG is applied39-01.
86
+
87
+ R06 is applied and complete. R07 now has a Refactor 40 candidate; R08/D08, R09
88
+ and R10 remain afterward. R09's inheritance behavior and R10's action names
89
+ are not altered by the transition-ownership work.
@@ -33,6 +33,12 @@ not receive a mutable Provider chat/message array.
33
33
 
34
34
  A hook returns `Phronomy::Agent::LLMInputPatch` or `nil`.
35
35
 
36
+ These two types live in the shared `agent/context_contract/` implementation
37
+ directory together with the Policy input and result contracts. Zeitwerk
38
+ collapses the directory, preserving their existing public `Phronomy::Agent`
39
+ names. Hook registration, invocation, and result handling are unchanged; see
40
+ [ADR-036](../decisions/036-context-contract-ownership.md).
41
+
36
42
  ```ruby
37
43
  Phronomy::Agent::LLMInputPatch.new(
38
44
  model_config_patch: {temperature: 0.2},
@@ -50,6 +50,36 @@ RubyLLMMaterializer
50
50
  The normative Journal/Manifest split is
51
51
  [ADR-012](../decisions/012-canonical-execution-log-and-context-policy.md).
52
52
 
53
+ ### Contract ownership and physical layout
54
+
55
+ The contracts shared by Agent execution, Context policies, and input hooks live
56
+ in `lib/phronomy/agent/context_contract/`:
57
+
58
+ | Files | Responsibility |
59
+ |---|---|
60
+ | `context_policy.rb`, `context_policy_input.rb` | Policy protocol, helper methods, and typed input material |
61
+ | `context_plan.rb`, `context_plan_validator.rb` | Policy result and its validity rules |
62
+ | `llm_input_manifest.rb` | Final logical input representation and its format validation |
63
+ | `llm_input_build_context.rb`, `llm_input_patch.rb` | Input metadata and returned customization for hooks |
64
+
65
+ Zeitwerk collapses this directory. The Ruby constants keep their existing
66
+ `Phronomy::Agent::*` names; there is no `ContextContract` namespace or new
67
+ registration mechanism. Applications continue to load `phronomy` and use the
68
+ documented constants. The previous individual implementation file paths are
69
+ not retained as forwarding files.
70
+
71
+ `ContextPolicies::Default` remains a concrete strategy, while
72
+ `ContextAssembler`, input builders, candidate resolution, Runtime connections,
73
+ and persistence transactions remain on the execution side. The Manifest
74
+ validates and converts record values; it does not write to a storage backend.
75
+ Its format version, keys, and validation rules are unchanged.
76
+
77
+ This ownership decision is defined by
78
+ [ADR-036](../decisions/036-context-contract-ownership.md). Physical containment
79
+ under `agent/` does not assign the contracts to the execution layer. The
80
+ concrete policies and the shared contracts can occupy distinct groups at the
81
+ same abstraction level.
82
+
53
83
  ## 2. Public Context Policy SPI
54
84
 
55
85
  Application code supplies an ordinary reusable Ruby strategy object:
@@ -0,0 +1,90 @@
1
+ # Context preparation steps
2
+
3
+ ## Role and scope
4
+
5
+ ContextAssembler prepares the immutable semantic input supplied to Application
6
+ ContextPolicy and later validates and stores its decision as an LLMInputManifest.
7
+ InitialPreparation and DispatchPreparation run preparation outside their commit
8
+ transactions, recheck durable state, then call finalize in the commit transaction.
9
+ The public boundary and those callers already have separate responsibilities.
10
+
11
+ R07 addresses a narrower readability problem inside prepare_initial and
12
+ prepare_followup: orchestration was mixed with individual item IDs, provenance
13
+ and metadata, and record filtering plus Hook/Handoff merging were duplicated.
14
+ The original proposal calls for private extraction before adding collaborators.
15
+ Refactor 40 follows that limit: one production file changes; no class is added.
16
+
17
+ ## Reading order and responsibilities
18
+
19
+ | Private operation | Responsibility |
20
+ |---|---|
21
+ | initial_instruction_items | Choose the initial Agent instruction and optional Handoff responsibility, in order. |
22
+ | agent_instruction_item | Build the required system instruction with its stable ID, estimate and Agent provenance. |
23
+ | handoff_instruction_item | Build the required user responsibility with its ID, estimate and Handoff origin. |
24
+ | retained_instruction_items | Read only retained base instructions from the previous Manifest, using the existing compatibility predicate and converter. |
25
+ | resolve_record_candidates | Filter working records by eligibility/current generation and resolve them with Journal candidates and caller-provided exclusions. |
26
+ | merge_context_candidates | Add Hook candidates, then Handoff candidates, using the existing creation, sorting and storage operations. |
27
+ | current_input_item | Build the initial required ask argument after all candidates, including ID, sequence, provenance and metadata. |
28
+
29
+ Public preparation keeps model/Tool settings, source loading and the sequence of
30
+ these operations visible. Record collection and candidate augmentation stay as
31
+ two steps: follow-up computes its next call sequence after record resolution,
32
+ exactly as before. No new options object, pipeline DSL, mutable preparation state
33
+ or cross-feature factory is introduced. Helpers remain private to the assembler.
34
+
35
+ ## Preserved contracts
36
+
37
+ - Initial instructions come from the Agent configuration plus optional Handoff
38
+ responsibility. Follow-up instructions come from the retained base Manifest.
39
+ Current Hook instructions are rebuilt; previous Hook/Policy-generated items
40
+ do not become permanent base instructions. Legacy origin handling is unchanged.
41
+ - Working records must remain context candidates in the active transcript
42
+ generation. Initial preparation excludes the current input record; follow-up
43
+ includes eligible working records without that exclusion.
44
+ - Record candidates are resolved before Hook and then Handoff augmentation. The
45
+ current-input sequence follows all candidates, including non-conversation ones.
46
+ IDs, source fields, trust metadata, estimates, required flags, ordering, frozen
47
+ values and delivery modes retain their existing values.
48
+ - Initial input content is loaded before instruction-item construction and
49
+ candidate resolution. Initial instruction callbacks and patch normalization
50
+ retain their order. Hook content writes still precede Handoff type validation;
51
+ moving that validation earlier would be a behavior change and is not included.
52
+ - Preparation is not side-effect-free: Hook/Handoff content may be stored before
53
+ Policy succeeds. This extraction neither adds rollback nor suppresses existing
54
+ exceptions. Missing-input, reserved-metadata, resolver and Policy failures keep
55
+ their ordering; collaborator exception objects propagate unchanged.
56
+ - Application Policy executes once during prepare; finalize does not invoke it.
57
+ Finalization, its validation/encoding/store helpers, assembly policy version 8,
58
+ schemas, public signatures and transaction-owning callers are unchanged.
59
+
60
+ The new helpers use the same constructor field evaluation and call ordering.
61
+ They do not cache or deduplicate reads, normalize values earlier, or move work
62
+ across the prepare/finalize boundary merely to shorten the source.
63
+
64
+ ## Verification and trade-off
65
+
66
+ Ten behavior examples cover initial item provenance/immutability, generation and
67
+ exclusion rules, content-write order, absent instructions/Handoff, follow-up
68
+ retention and current hooks, the prepare/finalize boundary and failure precedence.
69
+ The same examples pass on Refactor 39. Four independent baseline/candidate
70
+ scenario pairs compare complete Policy input, Prepared values, Manifest bytes and
71
+ content references, plus preparation-time content read/write order. The pairs
72
+ cover initial and follow-up calls with/without base instructions and Handoff.
73
+
74
+ Full core/integration suites, common examples and real SQLite, stable/beta API
75
+ and Storage SPI snapshots, RBS, style, annotations and isolated gem checks are
76
+ also run. Live PostgreSQL, live LLM, remote CI and performance are not exercised
77
+ for this candidate; prior CI is not evidence for the candidate's core.
78
+
79
+ prepare_initial is 103 -> 55 lines and prepare_followup 57 -> 47. The whole file
80
+ is 625 -> 672 lines because seven named private methods and explicit arguments
81
+ add structure. This is a readability and duplicated-procedure improvement, not a
82
+ net line-count reduction or a directory-cycle change. The methods' names give
83
+ readers a place to choose whether they need the detailed representation.
84
+
85
+ R07 was independently verified after application at core b3dfbc5a, tree
86
+ dcd9d1bf8efb1b488f9c2b3b1c4e99bdeda6096c. All six files and the full tree matched;
87
+ core/integration/examples/SQLite/API/type/gem and four paired scenarios passed.
88
+ R07 is complete. The published diagram is applied40-01. R08/D08 now has a Refactor
89
+ 41 candidate, with R09 and R10 remaining afterward. Their behavior and naming
90
+ decisions are not part of Context preparation extraction.
@@ -0,0 +1,72 @@
1
+ # Entry-action names and Team task wording (R10)
2
+
3
+ ## Scope
4
+
5
+ Refactor 44 follows applied Refactor 43, core
6
+ `5c4c039273eb2324fcc9e9943ccf40bd1ffb3abd`. It changes two private action names
7
+ and two Team-generated strings. No new production class, alias, state, event,
8
+ loader rule, persistence format or public method signature is introduced.
9
+
10
+ ## Action names describe their local work
11
+
12
+ | Existing phase | Private action | Work |
13
+ |---|---|---|
14
+ | `filtering_input` | `apply_prepared_input_action` | Read `phronomy_filtered_input` from the prepared config and install it on the invocation. |
15
+ | `building_context` | `build_runtime_chat_action` | Build a Chat with the prepared projection's settings and apply its instructions, Tools and messages. |
16
+
17
+ These replace `filtering_input_action` and `building_context_action` respectively.
18
+ Their bodies, arguments, return values, exceptions and ordering are unchanged.
19
+ Input filtering and context preparation remain with the existing preparation
20
+ owners; these actions do not repeat that work. The first action keeps its unused
21
+ Agent argument so the existing bound-action construction remains unchanged.
22
+
23
+ Phase names, transition guards, callbacks and saved resume phases remain intact.
24
+ A phase is an existing lifecycle boundary; an entry-action name describes the
25
+ operation performed at that boundary. Renaming phases would require a separate
26
+ compatibility design for observation and saved executions.
27
+
28
+ ## Team tasks and completion handles
29
+
30
+ | Surface | Before | After |
31
+ |---|---|---|
32
+ | `finalize.summary` parameter description | `TaskResult summary` | `Task generation summary` |
33
+ | Newly committed `enqueue_task` result | `TaskResult #N enqueued: ...` | `Task #N enqueued: ...` |
34
+
35
+ These are observable text changes, not solely internal renames. The description
36
+ is sent to the LLM. The enqueue response is saved in Team operation metadata and
37
+ subsequently supplied as a Tool result. The task description supplied by the
38
+ caller is not rewritten. Tool names, argument names, types, optionality, task IDs,
39
+ batch ordering, queue contents and cancellation behavior are unchanged.
40
+ `Phronomy::TaskResult` continues to mean the asynchronous completion handle.
41
+ Team integration examples now use `Task A/B/C` for business-task descriptions.
42
+
43
+ The existing operation-ID deduplication returns the stored result verbatim.
44
+ Already committed legacy `TaskResult #...` results therefore remain unchanged
45
+ on replay, including after restart. This change does not migrate old records,
46
+ rewrite Journals or reformat results during readback. Reusing an operation ID
47
+ with different arguments still fails the existing identity check.
48
+
49
+ ## Verification and limits
50
+
51
+ The package checks the existing Agent transition and Chat contracts, durable
52
+ Team execution, full core/integration suites, offline examples, real SQLite,
53
+ API/SPI, types, style, gem loading and independent application. One additional
54
+ regression verifies legacy response replay after restart, no repeated writes,
55
+ the TaskResult return type and argument-identity rejection. It also passes on
56
+ the applied baseline.
57
+
58
+ Separate processes capture a committed finalize operation before its Agent
59
+ settlement and resume it using the other version, in both directions. Stored
60
+ operations remain byte-equivalent at the value level, tasks are not duplicated,
61
+ and the expected two remaining Provider calls occur. These are stubbed Provider
62
+ checks with an InMemory snapshot; they are not live-LLM or cross-version SQL tests.
63
+
64
+ The review exposed an existing [Tool schema recording gap](tool-schema-recording-gap.md)
65
+ on RubyLLM 1.16.0. R10 does not repair it or weaken definition checks. Successful
66
+ continuation here does not prove that incompatible parameter definitions are
67
+ rejected. The generated parameter description changes, while the current saved
68
+ Tool definition omits parameter details.
69
+
70
+ R09 is applied and verified. R10 is implemented and locally verified, pending
71
+ application verification. The newly discovered schema issue remains open, so
72
+ closing the original R/D inventory must not be described as absence of defects.
@@ -0,0 +1,80 @@
1
+ # Shared execution metadata and value conversion
2
+
3
+ Refactor 38 addresses the remaining R03 and R11 responsibilities against core
4
+ `e7e6618493df03c2eb386d78a9303796e1e13cdc`. The candidate must be applied and
5
+ verified before those items are closed. Tool restoration itself was completed
6
+ earlier and its validation and state reconstruction remain unchanged.
7
+
8
+ ## Ownership
9
+
10
+ Ordinary dispatch creates durable facts before sending an external operation.
11
+ Recovery reads those same facts after an interruption. Their stored vocabulary
12
+ therefore belongs to the execution contract, not to a recovery procedure.
13
+
14
+ | Responsibility | Owner | Callers |
15
+ |---|---|---|
16
+ | Metadata keys/version, Tool batch capture and metadata merge | `Agent::ExecutionMetadata` in `agent/execution` | Initial/dispatch preparation, Coordinator, approval commit, recovery and MultiAgent |
17
+ | Stable Tool invocation identity | `Agent::ToolInvocation.semantic_id` | Ordinary Tool preparation and recovery subject construction |
18
+ | Ruby tree conversion before JSON serialization | `Values::Serializable.convert` in `common/values` | RuntimeRecordEncoder, RecoverySupport, ExecutionMetadata and dispatch preparation |
19
+ | Recovery descriptors and outcome interpretation | `Agent::RecoverySupport` | Recovery and the existing failure reconstruction path |
20
+
21
+ ExecutionMetadata is a stateless vocabulary and snapshot helper. It does not
22
+ start an invocation, increment revisions, open a transaction or perform recovery.
23
+ Its `with_values` preserves the old execution revision. ToolInvocation's
24
+ `semantic_id` computes the same prefixed SHA-256 value over the same four IDs
25
+ and NUL separators; it never constructs, authorizes or runs a Tool.
26
+
27
+ RecoverySupport's shared constants and snapshot/merge/identity operations are
28
+ removed, with all repository callers updated. No compatibility aliases are
29
+ added for these private implementation names. `ExecutionOutcomeCommitter`
30
+ still uses `RecoverySupport.error_from_failure` for actual failure reconstruction;
31
+ this change does not claim to remove every execution/recovery dependency.
32
+
33
+ ## Conversion contract
34
+
35
+ Serializable rebuilds Hash and Array containers, stringifies Hash keys and
36
+ Symbol values, retains scalar objects, and recursively processes `to_h` results.
37
+ It preserves input order and the previous last-value-wins behavior for keys
38
+ that become equal. It does not deep-copy String values, freeze results, reject
39
+ non-Hash `to_h` results, or catch exceptions raised by application conversion.
40
+
41
+ The unsupported-value error remains ArgumentError. Callers supply their
42
+ existing diagnostic prefix, including for errors inside nested values:
43
+
44
+ | Boundary | Exact prefix before `: <class>` |
45
+ |---|---|
46
+ | RuntimeRecordEncoder.json_value | `unsupported canonical runtime value` |
47
+ | RecoverySupport.canonical_copy and existing snapshot writers | `Recovery value is not canonically serializable` |
48
+
49
+ The two existing conversion entry points remain short adapters because they
50
+ own different error contracts. They no longer implement separate recursive
51
+ algorithms. Snapshot writers retain their historical diagnostic despite its
52
+ Recovery wording, to avoid a behavior change in this responsibility refactoring.
53
+
54
+ Serializable does not establish canonical JSON validity. CanonicalJSON still
55
+ owns numeric range, non-finite/negative-zero and encoding checks. Immutable.copy
56
+ still owns copying and freezing. ProviderCallOutcome.normalize still has its
57
+ different unsupported-value-to-String behavior. Domain codecs keep their key
58
+ validation and collision rules. These operations are intentionally not merged.
59
+
60
+ ## Compatibility and verification
61
+
62
+ Stored metadata keys, version 1, Tool identity bytes and serialized values are
63
+ unchanged. Transactions, revision checks, dispatch order, Tool restoration,
64
+ approval notifications and external-effect behavior remain with their existing
65
+ owners. Public API, signatures, raw Storage SPI and database schema are unchanged.
66
+
67
+ The conversion behavior tests run against both the applied baseline and the
68
+ candidate, including nested unsupported values and application exceptions.
69
+ Existing Tool batch tests follow their new owner; the stored identity fixture
70
+ guards compatibility. Recovery, causal durability, approval/resume and
71
+ MultiAgent tests exercise the changed callers. Full core/integration suites,
72
+ common examples, real SQLite, API/SPI snapshots, RBS, annotations and packaged
73
+ gem loading complete the candidate checks. Live PostgreSQL and live providers
74
+ are not part of this candidate's execution evidence.
75
+
76
+ This improves ownership and removes a duplicated recursive algorithm. The
77
+ dependency diagram's module and file cycles remain; their disappearance is not
78
+ the completion criterion. The applied SVG remains applied37-01 until the next
79
+ application verification. The other initial proposal groups are R06, R07,
80
+ R08/D08, R09 and R10; overall refactoring is not complete.