phronomy 0.26.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +40 -0
- data/README.md +4 -0
- data/VERIFY.sh +27 -27
- data/benchmark/bench_agent_invoke.rb +26 -22
- data/benchmark/bench_context_assembler.rb +4 -5
- data/docs/architecture/agent-chat-and-state-ownership.md +147 -0
- data/docs/architecture/agent-configuration-and-tool-binding.md +139 -0
- data/docs/architecture/agent-context.md +4 -2
- data/docs/architecture/agent-transition-ownership.md +89 -0
- data/docs/architecture/before-llm-input.md +6 -0
- data/docs/architecture/context-management.md +30 -0
- data/docs/architecture/context-preparation-steps.md +90 -0
- data/docs/architecture/entry-action-and-team-wording.md +72 -0
- data/docs/architecture/execution-metadata-and-values.md +80 -0
- data/docs/architecture/generator-verifier-ownership.md +111 -0
- data/docs/architecture/multi-agent-handoff.md +8 -2
- data/docs/architecture/persistence-refactoring-plan.md +50 -0
- data/docs/architecture/persistence.md +27 -4
- data/docs/architecture/refactoring-closure.md +334 -0
- data/docs/architecture/remaining-refactoring-plan.md +374 -0
- data/docs/architecture/rubyllm-2-token-ownership.md +82 -0
- data/docs/architecture/tool-schema-recording-gap.md +50 -0
- data/docs/architecture/tracing.md +1 -1
- data/docs/architecture/workflow-terminal-ownership-design.md +104 -0
- data/docs/architecture.md +209 -0
- data/docs/decisions/014-unified-persistence-durable-state.md +11 -0
- data/docs/decisions/024-event-loop-single-writer-agent-runtime.md +5 -1
- data/docs/decisions/025-process-local-agent-ownership-and-runtime-admission.md +13 -3
- data/docs/decisions/026-workflow-runtime-admission-and-durable-terminal-barrier.md +5 -1
- data/docs/decisions/030-agent-handoff-domain-and-durable-responsibility.md +5 -0
- data/docs/decisions/031-durable-multi-agent-coordination.md +5 -0
- data/docs/decisions/032-storage-backend-composition.md +80 -0
- data/docs/decisions/033-domain-persistence-ownership.md +79 -0
- data/docs/decisions/034-handoff-runner-coordination-ownership.md +76 -0
- data/docs/decisions/035-tool-executor-capability-ownership.md +68 -0
- data/docs/decisions/036-context-contract-ownership.md +86 -0
- data/docs/decisions/037-common-definition-ownership.md +62 -0
- data/docs/decisions/038-responsibility-based-source-layout.md +131 -0
- data/docs/decisions/039-runtime-configuration-lifecycle-ownership.md +74 -0
- data/docs/decisions/040-configuration-default-composition.md +94 -0
- data/docs/decisions/041-feature-owned-identity-registries.md +100 -0
- data/docs/decisions/042-feature-owned-execution-state.md +106 -0
- data/docs/decisions/043-storage-execution-constraint-notifications.md +75 -0
- data/docs/decisions/044-agent-default-and-one-shot-composition.md +106 -0
- data/docs/decisions/045-worker-input-restriction-ownership.md +100 -0
- data/docs/decisions/046-agent-responsibility-layout-and-shared-records.md +110 -0
- data/docs/decisions/047-recovered-execution-continuation-contract.md +116 -0
- data/docs/decisions/048-dispatch-preparation-worker-ownership.md +120 -0
- data/docs/decisions/049-initial-preparation-worker-ownership.md +111 -0
- data/docs/decisions/050-approval-resume-snapshot-and-commit-ownership.md +98 -0
- data/docs/decisions/051-execution-outcome-worker-ownership.md +151 -0
- data/docs/decisions/052-tool-invocation-restoration-ownership.md +92 -0
- data/docs/decisions/053-shared-state-coordination-ownership.md +71 -0
- data/docs/decisions/054-workflow-terminal-save-single-owner.md +76 -0
- data/docs/decisions/055-terminal-observer-failure-settlement.md +60 -0
- data/docs/decisions/056-workflow-terminal-policy-ownership.md +87 -0
- data/docs/decisions/057-storage-transaction-boundaries.md +73 -0
- data/docs/decisions/058-neutral-storage-primitives.md +78 -0
- data/docs/decisions/README.md +35 -6
- data/docs/design/durable-semantic-coordination/IMPLEMENTATION_DESIGN_V2.md +6 -0
- data/docs/design/durable-semantic-coordination/IMPLEMENTATION_REPORT.md +6 -0
- data/docs/features.md +9 -3
- data/docs/getting-started.md +4 -4
- data/docs/migrations/0.15.md +5 -0
- data/docs/migrations/durable-semantic-coordination-v2.md +6 -0
- data/docs/migrations/handoff-runner-multi-agent.md +35 -0
- data/docs/migrations/neutral-storage-spi.md +43 -0
- data/docs/migrations/parallel-tool-chat-removal.md +49 -0
- data/docs/migrations/shared-state-multi-agent.md +44 -0
- data/docs/migrations/storage-backend-composition.md +117 -0
- data/docs/migrations/storage-transaction-boundaries.md +74 -0
- data/docs/persistence-backends.md +162 -204
- data/docs/runtime-and-concurrency.md +117 -32
- data/lib/phronomy/agent/api/agent.rb +17 -0
- data/lib/phronomy/agent/async_event_api.rb +2 -2
- data/lib/phronomy/agent/base.rb +51 -241
- data/lib/phronomy/{agent.rb → agent/composition/run_once.rb} +4 -13
- data/lib/phronomy/agent/context/capability/base.rb +67 -26
- data/lib/phronomy/agent/context/capability/tool_executor.rb +62 -0
- data/lib/phronomy/agent/{context_assembler.rb → context_assembly/context_assembler.rb} +143 -88
- data/lib/phronomy/agent/{context_importer.rb → context_assembly/context_importer.rb} +2 -2
- data/lib/phronomy/agent/{ruby_llm_materializer.rb → context_assembly/ruby_llm_materializer.rb} +4 -7
- data/lib/phronomy/agent/context_assembly/runtime_chat_builder.rb +36 -0
- data/lib/phronomy/agent/context_assembly/saved_context_reader.rb +53 -0
- data/lib/phronomy/agent/context_assembly/state_writer.rb +165 -0
- data/lib/phronomy/agent/context_assembly/token_budget_resolver.rb +22 -0
- data/lib/phronomy/agent/{context_plan.rb → context_contract/context_plan.rb} +1 -1
- data/lib/phronomy/agent/{context_policy_input.rb → context_contract/context_policy_input.rb} +6 -6
- data/lib/phronomy/agent/{llm_input_build_context.rb → context_contract/llm_input_build_context.rb} +1 -1
- data/lib/phronomy/agent/{llm_input_manifest.rb → context_contract/llm_input_manifest.rb} +20 -20
- data/lib/phronomy/agent/{llm_input_patch.rb → context_contract/llm_input_patch.rb} +2 -2
- data/lib/phronomy/agent/{agent_execution.rb → execution/agent_execution.rb} +8 -4
- data/lib/phronomy/agent/{agent_invocation.rb → execution/agent_invocation.rb} +8 -13
- data/lib/phronomy/agent/{agent_invocation_session_builder.rb → execution/agent_invocation_session_builder.rb} +19 -95
- data/lib/phronomy/agent/execution/approval_resume_commit.rb +108 -0
- data/lib/phronomy/agent/execution/dispatch_preparation.rb +305 -0
- data/lib/phronomy/agent/{exact_execution.rb → execution/exact_execution.rb} +9 -10
- data/lib/phronomy/agent/{execution_cancellation.rb → execution/execution_cancellation.rb} +2 -3
- data/lib/phronomy/agent/execution/execution_coordinator.rb +1925 -0
- data/lib/phronomy/agent/execution/execution_failure.rb +30 -0
- data/lib/phronomy/agent/execution/execution_metadata.rb +53 -0
- data/lib/phronomy/agent/execution/execution_outcome_committer.rb +344 -0
- data/lib/phronomy/agent/execution/execution_registry.rb +459 -0
- data/lib/phronomy/agent/execution/execution_session_runner.rb +118 -0
- data/lib/phronomy/agent/execution/initial_preparation.rb +421 -0
- data/lib/phronomy/agent/execution/invocation_transitions.rb +86 -0
- data/lib/phronomy/agent/{phase_machine_builder.rb → execution/phase_machine_builder.rb} +20 -71
- data/lib/phronomy/agent/{provider_call_outcome.rb → execution/provider_call_outcome.rb} +9 -9
- data/lib/phronomy/agent/execution/runtime_record_encoder.rb +210 -0
- data/lib/phronomy/agent/{handoff_context.rb → handoff/handoff_context.rb} +2 -2
- data/lib/phronomy/agent/handoff/handoff_execution_coordinator.rb +15 -0
- data/lib/phronomy/agent/handoff/handoff_outcome_committer.rb +131 -0
- data/lib/phronomy/agent/{handoff_state.rb → handoff/handoff_state.rb} +1 -1
- data/lib/phronomy/agent/{journal_projection.rb → journal/journal_projection.rb} +4 -0
- data/lib/phronomy/agent/{journal_record.rb → journal/journal_record.rb} +3 -3
- data/lib/phronomy/agent/{llm_call_record.rb → journal/llm_call_record.rb} +2 -2
- data/lib/phronomy/agent/{agent_root.rb → lifecycle/agent_root.rb} +6 -2
- data/lib/phronomy/agent/lifecycle/default_persistence.rb +29 -0
- data/lib/phronomy/{engine/runtime/agent_ownership_registry.rb → agent/lifecycle/ownership_registry.rb} +24 -10
- data/lib/phronomy/{agent_already_exists_error.rb → agent/lifecycle_contract/agent_already_exists_error.rb} +2 -0
- data/lib/phronomy/{agent_busy_error.rb → agent/lifecycle_contract/agent_busy_error.rb} +2 -0
- data/lib/phronomy/{agent_purged_error.rb → agent/lifecycle_contract/agent_purged_error.rb} +2 -0
- data/lib/phronomy/agent/lifecycle_contract/handoff_error.rb +7 -0
- data/lib/phronomy/{stream_callback_error.rb → agent/lifecycle_contract/stream_callback_error.rb} +2 -0
- data/lib/phronomy/agent/persistence/agent_repository.rb +61 -0
- data/lib/phronomy/agent/persistence/codec.rb +358 -0
- data/lib/phronomy/agent/persistence/execution_repository.rb +108 -0
- data/lib/phronomy/agent/persistence/handoff_state_repository.rb +58 -0
- data/lib/phronomy/agent/persistence/journal_repository.rb +54 -0
- data/lib/phronomy/agent/persistence/queries.rb +61 -0
- data/lib/phronomy/agent/persistence/storage_schema.rb +24 -0
- data/lib/phronomy/agent/persistence/watermark.rb +27 -0
- data/lib/phronomy/agent/recovery/invocation_restorer.rb +132 -0
- data/lib/phronomy/agent/{recovery_coordinator → recovery/recovery_coordinator}/continuation.rb +21 -45
- data/lib/phronomy/agent/{recovery_coordinator → recovery/recovery_coordinator}/installation.rb +32 -37
- data/lib/phronomy/agent/{recovery_coordinator → recovery/recovery_coordinator}/resolution.rb +37 -40
- data/lib/phronomy/agent/{recovery_coordinator.rb → recovery/recovery_coordinator.rb} +6 -10
- data/lib/phronomy/agent/recovery/recovery_support.rb +227 -0
- data/lib/phronomy/agent/selection/candidate.rb +1 -1
- data/lib/phronomy/agent/{approval_evaluation_request.rb → tool_execution/approval_evaluation_request.rb} +1 -12
- data/lib/phronomy/agent/{tool_approval_request.rb → tool_execution/tool_approval_request.rb} +1 -10
- data/lib/phronomy/agent/tool_execution/tool_binding.rb +90 -0
- data/lib/phronomy/agent/{tool_call_intercepted.rb → tool_execution/tool_call_intercepted.rb} +2 -2
- data/lib/phronomy/agent/{tool_definition_set.rb → tool_execution/tool_definition_set.rb} +9 -4
- data/lib/phronomy/agent/{tool_invocation.rb → tool_execution/tool_invocation.rb} +69 -34
- data/lib/phronomy/common/configuration_error.rb +7 -0
- data/lib/phronomy/common/error.rb +5 -0
- data/lib/phronomy/{agent → common/values}/immutable.rb +9 -1
- data/lib/phronomy/common/values/serializable.rb +32 -0
- data/lib/phronomy/{configuration.rb → configuration/configuration.rb} +14 -5
- data/lib/phronomy/configuration/global_configuration.rb +26 -0
- data/lib/phronomy/content_store/storage_schema.rb +11 -0
- data/lib/phronomy/content_store/stored_contents.rb +43 -0
- data/lib/phronomy/engine/backpressure_error.rb +7 -0
- data/lib/phronomy/{blocking.rb → engine/blocking.rb} +1 -1
- data/lib/phronomy/engine/cancellation_error.rb +7 -0
- data/lib/phronomy/engine/concurrency/cancellation_token.rb +4 -0
- data/lib/phronomy/engine/concurrency/offload_pool.rb +4 -0
- data/lib/phronomy/engine/concurrency/operation_binding.rb +1 -1
- data/lib/phronomy/engine/concurrency/worker_input_restricted.rb +14 -0
- data/lib/phronomy/engine/event_loop.rb +158 -624
- data/lib/phronomy/engine/event_loop_reentrancy_error.rb +8 -0
- data/lib/phronomy/{execution.rb → engine/execution.rb} +0 -7
- data/lib/phronomy/{execution_cancellation_error.rb → engine/execution_cancellation_error.rb} +2 -0
- data/lib/phronomy/engine/execution_receiver.rb +65 -0
- data/lib/phronomy/{execution_timeout_error.rb → engine/execution_timeout_error.rb} +2 -0
- data/lib/phronomy/engine/fsm_protocol.rb +14 -0
- data/lib/phronomy/engine/fsm_session.rb +35 -28
- data/lib/phronomy/{invalid_async_entry_action_error.rb → engine/invalid_async_entry_action_error.rb} +2 -0
- data/lib/phronomy/{invalid_async_transition_action_error.rb → engine/invalid_async_transition_action_error.rb} +2 -0
- data/lib/phronomy/{invalid_async_workflow_action_error.rb → engine/invalid_async_workflow_action_error.rb} +2 -0
- data/lib/phronomy/engine/pool_shutdown_error.rb +7 -0
- data/lib/phronomy/engine/recursion_limit_error.rb +7 -0
- data/lib/phronomy/engine/runtime.rb +80 -84
- data/lib/phronomy/engine/runtime_shutdown_error.rb +7 -0
- data/lib/phronomy/engine/runtime_shutdown_reentrancy_error.rb +7 -0
- data/lib/phronomy/engine/scheduler_reentrancy_error.rb +9 -0
- data/lib/phronomy/engine/task_result.rb +4 -0
- data/lib/phronomy/engine/timeout_error.rb +7 -0
- data/lib/phronomy/filter/contract/filter_block_error.rb +14 -0
- data/lib/phronomy/generation/generator_verifier/agent_result_receiver.rb +89 -0
- data/lib/phronomy/generation/generator_verifier/pipeline_state.rb +57 -0
- data/lib/phronomy/generation/generator_verifier/workflow_builder.rb +112 -0
- data/lib/phronomy/generation/generator_verifier.rb +118 -0
- data/lib/phronomy/generation/low_confidence_error.rb +14 -0
- data/lib/phronomy/llm_context_window/token_budget.rb +6 -7
- data/lib/phronomy/llm_contract/authentication_error.rb +7 -0
- data/lib/phronomy/{context_budget_exceeded_error.rb → llm_contract/context_budget_exceeded_error.rb} +2 -0
- data/lib/phronomy/llm_contract/context_length_error.rb +7 -0
- data/lib/phronomy/llm_contract/rate_limit_error.rb +7 -0
- data/lib/phronomy/{token_usage.rb → llm_contract/token_usage.rb} +2 -2
- data/lib/phronomy/llm_contract/transport_error.rb +7 -0
- data/lib/phronomy/multi_agent/admission_registry.rb +22 -2
- data/lib/phronomy/multi_agent/durable_subagent_coordinator.rb +5 -5
- data/lib/phronomy/{agent → multi_agent}/handoff_runner.rb +18 -17
- data/lib/phronomy/multi_agent/orchestrator.rb +2 -2
- data/lib/phronomy/multi_agent/persistence/codec.rb +55 -0
- data/lib/phronomy/multi_agent/persistence/queries.rb +30 -0
- data/lib/phronomy/multi_agent/persistence/team_execution_repository.rb +108 -0
- data/lib/phronomy/multi_agent/persistence/team_repository.rb +61 -0
- data/lib/phronomy/{agent → multi_agent}/shared_state.rb +56 -39
- data/lib/phronomy/multi_agent/storage_contract/team_storage_schema.rb +15 -0
- data/lib/phronomy/multi_agent/team_coordinator.rb +21 -18
- data/lib/phronomy/multi_agent/team_execution.rb +1 -1
- data/lib/phronomy/{engine/runtime → multi_agent}/team_ownership_registry.rb +14 -4
- data/lib/phronomy/multi_agent/team_root.rb +1 -1
- data/lib/phronomy/output_parser/contract/parse_error.rb +7 -0
- data/lib/phronomy/persistence/api/persistence.rb +140 -0
- data/lib/phronomy/persistence/migration/initial_format_migration.rb +19 -19
- data/lib/phronomy/persistence_composition/repositories.rb +77 -0
- data/lib/phronomy/persistence_composition/storage_schema.rb +24 -0
- data/lib/phronomy/{execution_rehydration_required_error.rb → recovery/execution_rehydration_required_error.rb} +2 -0
- data/lib/phronomy/{recovery.rb → recovery/recovery.rb} +1 -1
- data/lib/phronomy/runtime_composition/agent_defaults.rb +7 -0
- data/lib/phronomy/runtime_composition/configuration_defaults.rb +9 -0
- data/lib/phronomy/runtime_composition/global_runtime.rb +19 -0
- data/lib/phronomy/storage/backend.rb +101 -0
- data/lib/phronomy/storage/backends/in_memory.rb +157 -0
- data/lib/phronomy/storage/blob_conflict_error.rb +10 -0
- data/lib/phronomy/storage/blobs.rb +31 -0
- data/lib/phronomy/storage/condition.rb +25 -0
- data/lib/phronomy/storage/condition_failed_error.rb +16 -0
- data/lib/phronomy/storage/conflict_error.rb +9 -0
- data/lib/phronomy/{persistence → storage}/durable_record.rb +12 -12
- data/lib/phronomy/storage/entry.rb +33 -0
- data/lib/phronomy/storage/guard_ref.rb +13 -0
- data/lib/phronomy/storage/not_found_error.rb +9 -0
- data/lib/phronomy/storage/record_codec.rb +177 -0
- data/lib/phronomy/storage/records.rb +61 -0
- data/lib/phronomy/storage/resource.rb +126 -0
- data/lib/phronomy/storage/scope.rb +25 -0
- data/lib/phronomy/storage/serialization_error.rb +9 -0
- data/lib/phronomy/storage/streams.rb +44 -0
- data/lib/phronomy/storage/transaction_error.rb +10 -0
- data/lib/phronomy/storage/unique_constraint_error.rb +17 -0
- data/lib/phronomy/storage/unsupported_backend_error.rb +9 -0
- data/lib/phronomy/storage/validation.rb +53 -0
- data/lib/phronomy/storage/view.rb +131 -0
- data/lib/phronomy/testing/persistence_contract/a_content_store.rb +1 -1
- data/lib/phronomy/testing/persistence_contract/a_journal_repository.rb +4 -4
- data/lib/phronomy/testing/persistence_contract/a_persistence_backend.rb +10 -7
- data/lib/phronomy/testing/persistence_contract/a_workflow_state_repository.rb +2 -2
- data/lib/phronomy/testing/persistence_contract/an_agent_repository.rb +6 -6
- data/lib/phronomy/testing/persistence_contract/an_execution_repository.rb +6 -6
- data/lib/phronomy/testing/persistence_contract/coordination_repositories.rb +8 -8
- data/lib/phronomy/testing/persistence_contract/neutral_storage_primitives.rb +263 -0
- data/lib/phronomy/testing/persistence_contract/storage_transaction_boundaries.rb +123 -0
- data/lib/phronomy/testing/persistence_contract.rb +4 -0
- data/lib/phronomy/tool/contract/tool_error.rb +7 -0
- data/lib/phronomy/tools/agent.rb +1 -1
- data/lib/phronomy/version.rb +1 -1
- data/lib/phronomy/{workflow.rb → workflow/execution/workflow.rb} +8 -6
- data/lib/phronomy/{workflow_context.rb → workflow/execution/workflow_context.rb} +4 -0
- data/lib/phronomy/workflow/execution/workflow_context_ownership_error.rb +7 -0
- data/lib/phronomy/workflow/execution/workflow_execution_registry.rb +188 -0
- data/lib/phronomy/{workflow_runner.rb → workflow/execution/workflow_runner.rb} +122 -71
- data/lib/phronomy/workflow/execution/workflow_terminal_policy.rb +40 -0
- data/lib/phronomy/workflow/persistence/codec.rb +153 -0
- data/lib/phronomy/workflow/persistence/state_repository.rb +57 -0
- data/lib/phronomy/workflow/phase_machine_builder.rb +2 -2
- data/lib/phronomy/workflow/storage_contract/workflow_storage_schema.rb +9 -0
- data/lib/phronomy.rb +52 -94
- data/scripts/api_snapshot.rb +1 -1
- data/scripts/storage_spi_snapshot.rb +36 -0
- data/sig/phronomy/agent.rbs +0 -1
- data/sig/phronomy/execution_receiver.rbs +34 -0
- data/sig/phronomy/handoff.rbs +4 -2
- data/sig/phronomy/multi_agent.rbs +18 -0
- data/sig/phronomy/persistence.rbs +7 -91
- data/sig/phronomy/storage.rbs +174 -0
- data/sig/phronomy/tool.rbs +10 -1
- metadata +230 -99
- data/lib/phronomy/agent/execution_coordinator.rb +0 -3151
- data/lib/phronomy/agent/handoff_execution_coordinator.rb +0 -143
- data/lib/phronomy/agent/recovery_support.rb +0 -504
- data/lib/phronomy/agent/token_budget_resolver.rb +0 -70
- data/lib/phronomy/agent/tool_executor.rb +0 -55
- data/lib/phronomy/generator_verifier.rb +0 -369
- data/lib/phronomy/invalid_context_budget_configuration_error.rb +0 -8
- data/lib/phronomy/multi_agent/parallel_tool_chat.rb +0 -116
- data/lib/phronomy/persistence/durable_codec.rb +0 -706
- data/lib/phronomy/persistence/in_memory.rb +0 -690
- data/lib/phronomy/persistence/repository_facades.rb +0 -535
- data/lib/phronomy/persistence.rb +0 -276
- data/lib/phronomy/ruby_llm_patches.rb +0 -24
- data/lib/phronomy/workflow_recovery.rb +0 -123
- /data/lib/phronomy/agent/{context_candidate_resolver.rb → context_assembly/context_candidate_resolver.rb} +0 -0
- /data/lib/phronomy/agent/{context_policy_input_builder.rb → context_assembly/context_policy_input_builder.rb} +0 -0
- /data/lib/phronomy/agent/{context_plan_validator.rb → context_contract/context_plan_validator.rb} +0 -0
- /data/lib/phronomy/agent/{context_policy.rb → context_contract/context_policy.rb} +0 -0
- /data/lib/phronomy/agent/{llm_operation_result.rb → execution/llm_operation_result.rb} +0 -0
- /data/lib/phronomy/agent/{handoff.rb → handoff/handoff.rb} +0 -0
- /data/lib/phronomy/agent/{handoff_capability_factory.rb → handoff/handoff_capability_factory.rb} +0 -0
- /data/lib/phronomy/agent/{handoff_policy.rb → handoff/handoff_policy.rb} +0 -0
- /data/lib/phronomy/agent/{handoff_projection.rb → handoff/handoff_projection.rb} +0 -0
- /data/lib/phronomy/agent/{handoff_request.rb → handoff/handoff_request.rb} +0 -0
- /data/lib/phronomy/agent/{tool_invocation_session_builder.rb → tool_execution/tool_invocation_session_builder.rb} +0 -0
- /data/lib/phronomy/{canonical_json.rb → common/canonical_json.rb} +0 -0
- /data/lib/phronomy/{diagnostics.rb → engine/diagnostics.rb} +0 -0
- /data/lib/phronomy/{event.rb → engine/event.rb} +0 -0
- /data/lib/phronomy/{invocation_context.rb → engine/invocation_context.rb} +0 -0
- /data/lib/phronomy/{metrics.rb → engine/metrics.rb} +0 -0
- /data/lib/phronomy/{runnable.rb → engine/runnable.rb} +0 -0
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
# ADR-049: Initial Preparation Worker Ownership
|
|
2
|
+
|
|
3
|
+
**Status**: Accepted on the architecture refactoring branch
|
|
4
|
+
**Date**: 2026-09-22
|
|
5
|
+
**Refines**: [024-event-loop-single-writer-agent-runtime](024-event-loop-single-writer-agent-runtime.md),
|
|
6
|
+
[042-feature-owned-execution-state](042-feature-owned-execution-state.md),
|
|
7
|
+
[047-recovered-execution-continuation-contract](047-recovered-execution-continuation-contract.md)
|
|
8
|
+
and [048-dispatch-preparation-worker-ownership](048-dispatch-preparation-worker-ownership.md).
|
|
9
|
+
|
|
10
|
+
## Problem
|
|
11
|
+
|
|
12
|
+
ExecutionCoordinator still owned initial durable admission, application filtering,
|
|
13
|
+
Context preparation, failure persistence and replay of saved preparation inputs.
|
|
14
|
+
Its ordinary start and preparing-recovery paths shared persistence work with
|
|
15
|
+
EventLoop admission, live state and completion delivery. Simply relocating that
|
|
16
|
+
work would leave long methods mixing representation details and control steps.
|
|
17
|
+
|
|
18
|
+
## Decision
|
|
19
|
+
|
|
20
|
+
### Preparation owns persistence; the execution owner owns live control
|
|
21
|
+
|
|
22
|
+
`Agent::InitialPreparation` owns `prepare(Command)` and `recover(RecoveryCommand)`.
|
|
23
|
+
Its Command and Result retain the fields of the former Coordinator-owned types.
|
|
24
|
+
Coordinator keeps their old constant paths as aliases. Their canonical Ruby names
|
|
25
|
+
change; these are internal process-local types, not saved or public API records.
|
|
26
|
+
|
|
27
|
+
Coordinator retains replay-eligibility capture, Runtime admission, live-owner
|
|
28
|
+
checks, Offload submission, completion messages, stale-result validation, live
|
|
29
|
+
Agent/Registry updates, session registration and Task/listener settlement.
|
|
30
|
+
Preparing recovery captures the execution, root and journal records in an explicit
|
|
31
|
+
RecoveryCommand. Result tasks and load completion handles stay on EventLoop.
|
|
32
|
+
The worker does not call back into Coordinator or initiate Provider/Tool dispatch.
|
|
33
|
+
|
|
34
|
+
The worker is marked `WorkerInputRestricted` and holds existing Agent services and
|
|
35
|
+
Persistence. It keeps operation state in local variables. This does not remove all
|
|
36
|
+
Agent service references or make arbitrary application input/config values deeply
|
|
37
|
+
immutable. Approval snapshot isolation remains a later stage.
|
|
38
|
+
|
|
39
|
+
### Preserve admission outcomes and operation-specific failure boundaries
|
|
40
|
+
|
|
41
|
+
Input extraction precedes durable admission. An extraction failure returns
|
|
42
|
+
`not_established`. During admission, durable busy returns `recovery_required`;
|
|
43
|
+
the existing known-conflict/validation exception set returns `not_established`;
|
|
44
|
+
other exceptions return `outcome_unknown`. The execution owner preserves the
|
|
45
|
+
corresponding Runtime admission release or fail-closed behavior.
|
|
46
|
+
|
|
47
|
+
Durable admission still creates Execution and advances AgentRoot together, after
|
|
48
|
+
validating Team/Subagent/Handoff reservation ownership in the same transaction.
|
|
49
|
+
Splitting those ownership checks into named helpers changes no acceptance rule.
|
|
50
|
+
|
|
51
|
+
For admitted preparation the body reads as filter, stage input, prepare Context,
|
|
52
|
+
commit, and materialize. Hooks and ContextPolicy run outside the commit
|
|
53
|
+
transaction. Cancellation is checked before filtering, before assembly and after
|
|
54
|
+
Policy. The commit revalidates the Agent watermark after Policy returns.
|
|
55
|
+
|
|
56
|
+
The failure base advances from preparing Execution to active Execution only after
|
|
57
|
+
the active commit has returned successfully. A lost active-commit response leaves
|
|
58
|
+
the old revision as the failure base. If the active commit did occur, the existing
|
|
59
|
+
failure transaction conflicts and rolls back its Journal append; the worker does
|
|
60
|
+
not return an unconfirmed terminal result or add a new retry/readback policy.
|
|
61
|
+
|
|
62
|
+
A post-commit materialization error is terminalized from the known active
|
|
63
|
+
revision. Failure persistence atomically appends audit records, saves terminal
|
|
64
|
+
Execution and advances AgentRoot. A failure in that transaction, including lost
|
|
65
|
+
response, escapes to the execution owner; it is not converted into a confirmed
|
|
66
|
+
terminal Result. This initial-preparation contract intentionally differs from
|
|
67
|
+
DispatchPreparation's operation-specific uncertain-outcome reconciliation.
|
|
68
|
+
|
|
69
|
+
`Agent::ExecutionFailure` owns the existing pure error-to-status and status-to-audit
|
|
70
|
+
kind mappings. Both initial failure persistence and the remaining terminal worker
|
|
71
|
+
use it, avoiding duplicated classification rules. It owns no transaction, live
|
|
72
|
+
state or result delivery. Normal/Handoff terminal transaction behavior is unchanged.
|
|
73
|
+
|
|
74
|
+
### Recovery consumes saved inputs without admitting another execution
|
|
75
|
+
|
|
76
|
+
The worker first checks the replayable marker, reads current input and rebuilds
|
|
77
|
+
config from the saved invocation mode, coordination services and optional canonical
|
|
78
|
+
Hash durable_context. The recovered config and durable context remain frozen.
|
|
79
|
+
Read failures or invalid durable context escape before admitted preparation;
|
|
80
|
+
they do not trigger a failure commit or a speculative retry.
|
|
81
|
+
|
|
82
|
+
Ordinary start and recovery use the same admitted-preparation operation and Result.
|
|
83
|
+
Recovery keeps the same execution identity and does not call durable admission.
|
|
84
|
+
Runtime-only approval/listener state is not reconstructed. Existing Coordinator
|
|
85
|
+
validation and recovery delivery remain authoritative.
|
|
86
|
+
|
|
87
|
+
## Guarantees and verification
|
|
88
|
+
|
|
89
|
+
Using [018-durability-guarantees-and-failure-model](018-durability-guarantees-and-failure-model.md):
|
|
90
|
+
|
|
91
|
+
| Subject / property | Provider | Failure / boundary | Result |
|
|
92
|
+
| --- | --- | --- | --- |
|
|
93
|
+
| Same-process Agent starts: fail closed for uncertain/busy admission | Existing Runtime registry plus worker outcome classification | F0/F1/F4; before framework Provider/Tool X0 | YES, unchanged |
|
|
94
|
+
| Initial preparation: stale root/revision rejection | Persistence watermark/CAS and failure transaction rollback | F1/F2/F3; before framework Provider/Tool X0 | CONDITIONAL on conforming Persistence |
|
|
95
|
+
| Failure transition: Journal, Execution and Root commit together | Existing Persistence transaction | F0/F1; atomicity does not imply response certainty | CONDITIONAL on conforming backend; no new certainty guarantee |
|
|
96
|
+
| Preparing recovery: continue the same execution | Existing replay eligibility, saved inputs and owner validation | F4; application preparation may run again | CONDITIONAL on the existing replay-safe preparation contract |
|
|
97
|
+
| Arbitrary application or external effects: exactly once | No new exclusion/idempotency protocol | F1/F4 across application-defined X0 | NO new guarantee |
|
|
98
|
+
|
|
99
|
+
Behavioral tests cover transaction ordering, pre-admission extraction failure,
|
|
100
|
+
known admission failure, lost admission/active/failure commit responses,
|
|
101
|
+
post-commit materialization failure, cancellation and watermark changes after
|
|
102
|
+
Policy, blocked input and replay input restoration/validation/read failure.
|
|
103
|
+
Architecture guards include all new worker helpers and exclude control/delivery
|
|
104
|
+
dependencies. Existing normal execution, Team/Subagent/Handoff and recovery suites
|
|
105
|
+
cover the owner wiring and unchanged coordination checks.
|
|
106
|
+
|
|
107
|
+
## Remaining work
|
|
108
|
+
|
|
109
|
+
Approval snapshot isolation and approval persistence, followed by normal/Handoff
|
|
110
|
+
outcome worker extraction, remain separate stages. This stage does not finish
|
|
111
|
+
Coordinator decomposition or remove all Agent dependency cycles.
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
# ADR-050: Approval Resume Snapshot and Commit Ownership
|
|
2
|
+
|
|
3
|
+
**Status**: Accepted on the architecture refactoring branch
|
|
4
|
+
**Date**: 2026-09-22
|
|
5
|
+
**Refines**: [024-event-loop-single-writer-agent-runtime](024-event-loop-single-writer-agent-runtime.md),
|
|
6
|
+
[047-recovered-execution-continuation-contract](047-recovered-execution-continuation-contract.md)
|
|
7
|
+
and [049-initial-preparation-worker-ownership](049-initial-preparation-worker-ownership.md).
|
|
8
|
+
|
|
9
|
+
## Problem
|
|
10
|
+
|
|
11
|
+
Approval resume captured a Tool batch into a Coordinator Hash keyed by execution
|
|
12
|
+
ID before validating the current approval request. A worker later removed that
|
|
13
|
+
entry under a Mutex. Two queued requests could overwrite or consume each other's
|
|
14
|
+
snapshot even though the worker commands belonged to distinct operations.
|
|
15
|
+
The outer frozen Array also shared mutable String values with the invocation.
|
|
16
|
+
The command did not completely describe the recovery facts it would persist.
|
|
17
|
+
|
|
18
|
+
## Decision
|
|
19
|
+
|
|
20
|
+
### Validate and capture on EventLoop
|
|
21
|
+
|
|
22
|
+
ExecutionCoordinator validates the live Agent owner, suspended Execution and
|
|
23
|
+
approval request ID before capturing the invocation's canonical Tool snapshot.
|
|
24
|
+
It copies and recursively freezes that value tree with `Values::Immutable.copy`
|
|
25
|
+
and stores it directly in the operation's `tool_batch_snapshot` field. An absent
|
|
26
|
+
invocation gives nil; a present invocation with no children gives a frozen empty
|
|
27
|
+
Array. No shared approval snapshot Hash or Mutex remains in either owner.
|
|
28
|
+
|
|
29
|
+
This applies to canonical recovery facts only. Arbitrary application objects in
|
|
30
|
+
config, listener or callback state do not acquire a new deep-copy contract.
|
|
31
|
+
The general RecoverySupport snapshot builder keeps its existing contract.
|
|
32
|
+
|
|
33
|
+
Snapshot isolation was implemented and behaviorally verified before extracting
|
|
34
|
+
the persistence operation, so the concurrency fix can be reviewed independently
|
|
35
|
+
of the ownership change.
|
|
36
|
+
|
|
37
|
+
### Persist the captured decision in an operation worker
|
|
38
|
+
|
|
39
|
+
`Agent::ApprovalResumeCommit#commit` reads as validate the approval target, stage
|
|
40
|
+
the captured recovery facts, then persist the decision. Its helpers own record
|
|
41
|
+
fields, metadata representation and repository calls. It holds only the Agent ID
|
|
42
|
+
and Persistence; all operation state is local. It is `WorkerInputRestricted`.
|
|
43
|
+
|
|
44
|
+
The existing transaction still writes approval decision Content, adds the
|
|
45
|
+
approval_decided record to Execution working records, saves active/resuming
|
|
46
|
+
Execution with its expected revision and advances AgentRoot with its expected
|
|
47
|
+
revision. Staging metadata preserves the original execution revision so the
|
|
48
|
+
durable transition advances it exactly once. A nil snapshot preserves existing
|
|
49
|
+
metadata; an empty snapshot replaces the previous Tool batch.
|
|
50
|
+
|
|
51
|
+
Coordinator retains Runtime admission, Offload submission, completion messages,
|
|
52
|
+
late-result validation, live-state replacement, completion waiters, tracing and
|
|
53
|
+
SessionRunner resumption. Rejection before Offload submission restores suspended
|
|
54
|
+
admission. A commit error keeps admission recovery_required. A late result for
|
|
55
|
+
an advanced or cancelled Execution fails only the approval observer and does not
|
|
56
|
+
start a session. Existing duplicate-approval acceptance and CAS rules are unchanged.
|
|
57
|
+
|
|
58
|
+
The worker does not read back uncertain results, retry a transaction, contact
|
|
59
|
+
Provider/Tool adapters or invoke application callbacks. A lost commit response
|
|
60
|
+
escapes as an error; the owner follows the existing recovery-required path.
|
|
61
|
+
Persistence atomicity must not be presented as certainty about that response.
|
|
62
|
+
|
|
63
|
+
### Internal type compatibility
|
|
64
|
+
|
|
65
|
+
Command and Result are owned by ApprovalResumeCommit. Coordinator retains
|
|
66
|
+
`ResumeCommitCommand` and `ResumeCommitResult` as aliases to those exact classes.
|
|
67
|
+
Their canonical Ruby names change to `ApprovalResumeCommit::Command` and
|
|
68
|
+
`ApprovalResumeCommit::Result`. Command appends the required internal field
|
|
69
|
+
`tool_batch_snapshot`; Result retains its existing members. Internal positional
|
|
70
|
+
construction/reflection is consequently not unchanged. These types are neither
|
|
71
|
+
public API nor durable records. Saved schema and public approval API stay unchanged.
|
|
72
|
+
|
|
73
|
+
## Guarantees and verification
|
|
74
|
+
|
|
75
|
+
Using [ADR-018](018-durability-guarantees-and-failure-model.md):
|
|
76
|
+
|
|
77
|
+
| Subject / property | Provider | Failure / boundary | Result |
|
|
78
|
+
| --- | --- | --- | --- |
|
|
79
|
+
| Queued approval operation retains its captured facts | EventLoop validation and independent immutable Command values | F0/F2/F3; before Provider/Tool X0 | YES for canonical Tool snapshot values |
|
|
80
|
+
| Approval transition is atomic (G5), stale writes are rejected (G8) | Existing Persistence transaction and Execution/Root CAS | F2; no framework X0 in this worker | CONDITIONAL on conforming backend |
|
|
81
|
+
| Unknown approval commit is not treated as confirmed resumption | Worker error propagation and owner recovery_required admission | F1; no new worker X0 | YES; no new commit certainty or readback guarantee |
|
|
82
|
+
| Restored approval waiting continues the same execution (G4) | Existing recovery reconstruction and validated resume path | F4; later Tool work may cross X0 | CONDITIONAL on existing recovery/integration contracts |
|
|
83
|
+
| Cross-process exclusion (G7), external duplicate prevention (G9), exactly once (G10) | No new protocol supplied by this change | F1/F2/F4 across X0 | NO new guarantee |
|
|
84
|
+
|
|
85
|
+
Tests cover mutation after capture, reversed worker order, stale and invalid
|
|
86
|
+
requests, rejected submission, empty/absent batches, successive approvals,
|
|
87
|
+
approval/denial persistence, Execution and Root conflicts, transaction response
|
|
88
|
+
loss and stale results after cancellation or a newer approval. Existing recovery
|
|
89
|
+
integration tests restore approval waiting and resume both approval and denial.
|
|
90
|
+
The unit fault injections are not a hard-process-loss or real external-service test.
|
|
91
|
+
Architecture guards inspect the worker helpers for live-control dependencies.
|
|
92
|
+
|
|
93
|
+
## Remaining work
|
|
94
|
+
|
|
95
|
+
Normal terminal persistence and Handoff terminal persistence remain coupled in
|
|
96
|
+
ExecutionCoordinator and its subclass. They are the next extraction stage and
|
|
97
|
+
must be designed together. This change does not complete Coordinator decomposition
|
|
98
|
+
or eliminate Agent dependency cycles.
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
# ADR-051: Execution Outcome Worker Ownership
|
|
2
|
+
|
|
3
|
+
**Status**: Accepted on the architecture refactoring branch
|
|
4
|
+
**Date**: 2026-09-22
|
|
5
|
+
**Refines**: [024-event-loop-single-writer-agent-runtime](024-event-loop-single-writer-agent-runtime.md),
|
|
6
|
+
[030-agent-handoff-domain-and-durable-responsibility](030-agent-handoff-domain-and-durable-responsibility.md),
|
|
7
|
+
[047-recovered-execution-continuation-contract](047-recovered-execution-continuation-contract.md)
|
|
8
|
+
and [050-approval-resume-snapshot-and-commit-ownership](050-approval-resume-snapshot-and-commit-ownership.md).
|
|
9
|
+
|
|
10
|
+
## Problem
|
|
11
|
+
|
|
12
|
+
ExecutionCoordinator owned both EventLoop execution control and Offload result
|
|
13
|
+
persistence. HandoffExecutionCoordinator overrode outcome selection and depended
|
|
14
|
+
on its parent's transaction helpers. Extracting only one side would preserve
|
|
15
|
+
that hidden dependency or accidentally change Handoff precedence. Moving the
|
|
16
|
+
long bodies unchanged would also leave persistence policy mixed with individual
|
|
17
|
+
record fields.
|
|
18
|
+
|
|
19
|
+
## Decision
|
|
20
|
+
|
|
21
|
+
### Select and persist outcomes in operation workers
|
|
22
|
+
|
|
23
|
+
`Agent::ExecutionOutcomeCommitter#commit_outcome` selects completion, failure,
|
|
24
|
+
approval suspension or owned-child waiting from a captured command. It handles
|
|
25
|
+
persistence exceptions through the existing operation-specific readback rules.
|
|
26
|
+
`Agent::HandoffOutcomeCommitter` specializes that selection and atomic Source
|
|
27
|
+
transfer, sharing ordinary completion, failure and suspension persistence.
|
|
28
|
+
Handoff selection retains its separate callback/error/suspension/transfer order;
|
|
29
|
+
it does not acquire the ordinary worker's child-coordination wait branch.
|
|
30
|
+
|
|
31
|
+
HandoffExecutionCoordinator retains its class identity and inheritance, but now
|
|
32
|
+
only selects the Handoff worker. This selection is internal, not a public SPI.
|
|
33
|
+
Coordinator captures input, submits the worker, validates the returned revision
|
|
34
|
+
and session, applies live state and delivers results. Worker code never calls
|
|
35
|
+
back into Coordinator. Command state and intermediate results remain local to
|
|
36
|
+
one operation; workers hold only Agent service context and Persistence.
|
|
37
|
+
|
|
38
|
+
Agent context is still required by the existing coordination hook, error
|
|
39
|
+
translation, saved Manifest reader and transcript materializer. This is not a
|
|
40
|
+
claim that all Agent references or dependency cycles have been removed.
|
|
41
|
+
`WorkerInputRestricted` marks both worker types; it is not a recursive validator
|
|
42
|
+
of arbitrary application-owned values.
|
|
43
|
+
|
|
44
|
+
### Keep transactions visible in the purpose-level methods
|
|
45
|
+
|
|
46
|
+
`commit_completed` encodes completion records, appends Journal, saves Execution
|
|
47
|
+
and coordination, advances Root and materializes the caller-facing transcript
|
|
48
|
+
inside one transaction, then constructs the result. Record fields and repository
|
|
49
|
+
arguments belong to its helpers. Transcript materialization stays inside the
|
|
50
|
+
transaction so failure rolls back the transition.
|
|
51
|
+
|
|
52
|
+
`commit_failed_outcome` persists audit-only records and the translated failure.
|
|
53
|
+
The Context revision stays unchanged because none of those records is a Context
|
|
54
|
+
candidate. Completion and Handoff advance Context only if the appended records
|
|
55
|
+
contain a candidate. Suspension retains its records in Execution working state,
|
|
56
|
+
advances Root to suspended and does not append Journal or advance Context.
|
|
57
|
+
|
|
58
|
+
`commit_handed_off` validates Source routing and cancellation, persists projected
|
|
59
|
+
Context, transfers routing to a deterministic Target execution ID, and saves
|
|
60
|
+
Source Journal, Execution and Root in one transaction. Target definition lookup
|
|
61
|
+
uses the transaction view; the existing saved Manifest reader keeps its service
|
|
62
|
+
context. Target completion/failure stabilizes routing inside its own existing
|
|
63
|
+
terminal transaction. No Provider/Tool dispatch or application delivery moves
|
|
64
|
+
into these workers.
|
|
65
|
+
|
|
66
|
+
### Preserve the distinct readback contracts
|
|
67
|
+
|
|
68
|
+
| Operation | Existing confirmation rule after an exception | Consequence |
|
|
69
|
+
| --- | --- | --- |
|
|
70
|
+
| Ordinary/Handoff terminal | Same Agent, terminal Execution, expected revision + 1; then load saved Root, Journal and result | Reuse the persisted outcome; do not write a second terminal transition |
|
|
71
|
+
| Child-coordination wait | Complete saved Execution payload equals the intended waiting record | Return that nonterminal wait; active status alone does not establish a match |
|
|
72
|
+
| Approval suspension | It is nonterminal, so terminal readback does not confirm it | Propagate uncertain completion to the owner |
|
|
73
|
+
|
|
74
|
+
Terminal confirmation is deliberately not changed to DispatchPreparation's
|
|
75
|
+
full intended-payload comparison. Missing, active, mismatched or unreadable
|
|
76
|
+
results do not authorize another write. Readback errors retain their existing
|
|
77
|
+
propagation behavior. Recovered success retains the existing smaller result
|
|
78
|
+
shape; recovered failures use `RecoverySupport.error_from_failure`, including
|
|
79
|
+
its generic Phronomy::Error representation. This extraction does not normalize
|
|
80
|
+
those results or introduce a stronger commit-certainty protocol.
|
|
81
|
+
|
|
82
|
+
### Preserve EventLoop result authority and delivery
|
|
83
|
+
|
|
84
|
+
The owner still waits for physical work quiescence before terminal persistence.
|
|
85
|
+
A stale result changes no live state, admission or Task. Completed/failed/Handoff
|
|
86
|
+
results release ownership and deliver their existing events before settling
|
|
87
|
+
waiters. Suspension retains admission and leaves the original Task pending;
|
|
88
|
+
exact observers receive the existing approval-required failure. Child waiting
|
|
89
|
+
releases ownership and fails waiters with recovery required.
|
|
90
|
+
|
|
91
|
+
A worker error for ordinary execution retains recovery_required admission and
|
|
92
|
+
pending waiters. The existing coordination-metadata error path releases the
|
|
93
|
+
owner and fails waiters. Those branches are not merged into unconditional cleanup.
|
|
94
|
+
Live Handoff request/Manifest delivery handles remain outside the worker command.
|
|
95
|
+
|
|
96
|
+
### Internal types
|
|
97
|
+
|
|
98
|
+
ExecutionOutcomeCommitter owns `Command`, `Outcome`, `TerminalView` and
|
|
99
|
+
`HandoffTerminalView`. Coordinator retains its previous constant paths as aliases
|
|
100
|
+
to the same classes. All four member lists stay unchanged; their canonical Ruby
|
|
101
|
+
names change. TerminalDelivery and TerminalCommitReady remain owner-local.
|
|
102
|
+
These types are internal and are not serialized by class name. Public API, saved
|
|
103
|
+
schemas, Agent/Handoff Coordinator identity and caller selection remain unchanged.
|
|
104
|
+
|
|
105
|
+
## Guarantees and verification
|
|
106
|
+
|
|
107
|
+
Using [ADR-018](018-durability-guarantees-and-failure-model.md):
|
|
108
|
+
|
|
109
|
+
| Subject / property | Provider | Failure / boundary | Result |
|
|
110
|
+
| --- | --- | --- | --- |
|
|
111
|
+
| Terminal or Handoff transition atomicity (G5), stale write rejection (G8) | Existing transaction and repository CAS | F0/F2; no new framework X0 | CONDITIONAL on conforming Persistence backend |
|
|
112
|
+
| No second terminal write after uncertain response | Operation-specific worker readback and owner recovery path | F1; no new worker X0 | YES; no stronger outcome-certainty guarantee |
|
|
113
|
+
| Current execution alone may apply worker results | Existing EventLoop owner/revision/session guards | F2/F3 and delayed completion | YES within the same Runtime ownership contract |
|
|
114
|
+
| Logical continuation from saved Source/Target state (G4) | Existing Handoff recovery and exact Target identity | F4; later execution can cross X0 | CONDITIONAL on existing recovery contracts |
|
|
115
|
+
| Cross-process exclusion (G7), external duplicate prevention (G9), exactly once (G10) | No new protocol added | F1/F2/F4 across X0 | NO new guarantee |
|
|
116
|
+
|
|
117
|
+
Behavior tests exercise completion/rejection, failure categories, suspension,
|
|
118
|
+
transaction rollback, Root CAS, response loss and readback mismatches/failures,
|
|
119
|
+
child waiting, atomic Source transfer, routing conflict/cancellation and Target
|
|
120
|
+
completion/failure. Existing suites cover physical quiescence, stale results,
|
|
121
|
+
callback policy, approval recovery and durable Handoff recovery. Unit fault
|
|
122
|
+
injections do not represent real process loss or live external service failures.
|
|
123
|
+
Architecture guards now inspect the actual workers and disallow repository
|
|
124
|
+
reloads in Coordinator without the old terminal-helper exceptions.
|
|
125
|
+
|
|
126
|
+
## Owner-control review (2026-09-22)
|
|
127
|
+
|
|
128
|
+
The fifth stage keeps one execution owner and makes its remaining result paths
|
|
129
|
+
read as validation, state application and continuation/delivery. Preparation
|
|
130
|
+
recovery separates failed-outcome settlement from session restart. Approval
|
|
131
|
+
resume separates committed-state installation and tracing from FSM entry.
|
|
132
|
+
Terminal results retain visible outcome selection while private methods handle
|
|
133
|
+
the distinct waiting, suspension, completion, Handoff and failure deliveries.
|
|
134
|
+
Only the identical execution/admission release is shared across terminal paths.
|
|
135
|
+
Initial preparation snapshot construction is named explicitly; start/resume
|
|
136
|
+
admission flags, submission flags and their rescue decisions remain together.
|
|
137
|
+
|
|
138
|
+
No transaction, authority condition, failure policy, public type or class owner
|
|
139
|
+
changes. Direct Ready delivery tests run on the real EventLoop/ExecutionRegistry
|
|
140
|
+
and check stale-result isolation, state-before-notification, notification-before-
|
|
141
|
+
settlement, fallback waiters, suspension, uncertainty and recovery/resume failure
|
|
142
|
+
boundaries. These tests also pass against the preceding implementation, documenting
|
|
143
|
+
preserved behavior rather than a new contract. F0/F1/F3 are injected locally;
|
|
144
|
+
no new X0 operation or stronger F4 guarantee is claimed.
|
|
145
|
+
|
|
146
|
+
## Remaining work
|
|
147
|
+
|
|
148
|
+
The execution-owner decomposition and final readability review are implemented.
|
|
149
|
+
Tool restoration, SharedState, Storage domain responsibilities and Workflow
|
|
150
|
+
terminal ownership remain separate work items. Further owner splitting needs a
|
|
151
|
+
concrete responsibility or failure-boundary reason; file length alone is not one.
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
# ADR-052: Tool Invocation Restoration Ownership
|
|
2
|
+
|
|
3
|
+
**Status**: Accepted on the architecture refactoring branch
|
|
4
|
+
**Date**: 2026-09-22
|
|
5
|
+
**Refines**: [046-agent-responsibility-layout-and-shared-records](046-agent-responsibility-layout-and-shared-records.md)
|
|
6
|
+
and [047-recovered-execution-continuation-contract](047-recovered-execution-continuation-contract.md).
|
|
7
|
+
|
|
8
|
+
## Problem
|
|
9
|
+
|
|
10
|
+
InvocationRestorer decoded saved Tool batches and directly assigned
|
|
11
|
+
ToolInvocation's status, result, authorization decision and approval evidence.
|
|
12
|
+
Moving restoration into its own module in ADR-046 left that knowledge of another
|
|
13
|
+
object's representation intact. ADR-047 explicitly retained it as separate work.
|
|
14
|
+
A change to ToolInvocation's state representation therefore required Recovery to
|
|
15
|
+
track its instance variables as well as the saved format.
|
|
16
|
+
|
|
17
|
+
## Decision
|
|
18
|
+
|
|
19
|
+
Keep the existing classes and introduce the internal
|
|
20
|
+
`ToolInvocation#restore_state!(status:, result: nil, approval_item: nil)` operation.
|
|
21
|
+
It is Ruby-public for the Recovery caller and classified `@api private`; it is
|
|
22
|
+
not an Application extension SPI. Its input is materialized semantic state,
|
|
23
|
+
not an Execution record or a persistence repository.
|
|
24
|
+
|
|
25
|
+
InvocationRestorer retains saved snapshot key normalization, Tool Call and Tool
|
|
26
|
+
lookup, construction of ordinary or missing-Tool invocations, and matching the
|
|
27
|
+
approval item by invocation ID. It converts the saved status to a Symbol and
|
|
28
|
+
passes the saved result and matched approval item to the newly constructed
|
|
29
|
+
ToolInvocation. No ToolInvocation instance variable is assigned by Recovery.
|
|
30
|
+
The separate AgentInvocation batch-ID assignment is outside this change.
|
|
31
|
+
|
|
32
|
+
ToolInvocation owns the supported-state dispatch and approval evidence copy:
|
|
33
|
+
|
|
34
|
+
| Saved state | Existing behavior retained |
|
|
35
|
+
| --- | --- |
|
|
36
|
+
| awaiting_approval | Validate arguments unless already terminal, restore require_approval and the waiting state |
|
|
37
|
+
| authorized | Validate arguments unless already terminal, restore allow and the authorized state |
|
|
38
|
+
| completed | Restore the saved result, including nil or false, and completed state |
|
|
39
|
+
| rejected | Restore rejection and its decision |
|
|
40
|
+
| failed | Restore the existing generic Tool preflight failure |
|
|
41
|
+
| cancelled | Restore cancellation |
|
|
42
|
+
| Other state | Raise ExecutionRehydrationRequiredError before applying approval evidence |
|
|
43
|
+
|
|
44
|
+
The entry method reads as saved-state application followed by saved approval
|
|
45
|
+
evidence application. Private methods contain each operation's implementation.
|
|
46
|
+
Evidence copying preserves the existing immutable facts and reason semantics,
|
|
47
|
+
including an explicit nil facts value. A missing approval item leaves constructor
|
|
48
|
+
defaults intact. Saved display evidence is not a new policy evaluation input.
|
|
49
|
+
|
|
50
|
+
The caller supplies a newly constructed invocation before session installation.
|
|
51
|
+
This is not a general rollback or arbitrary live-state replacement interface.
|
|
52
|
+
The existing EventLoop ownership and continuation validation remain unchanged.
|
|
53
|
+
The old internal `InvocationRestorer.restore_tool_snapshot!` entry is removed;
|
|
54
|
+
no forwarding compatibility wrapper is introduced for this private helper.
|
|
55
|
+
|
|
56
|
+
## Compatibility and limits
|
|
57
|
+
|
|
58
|
+
No public API, RBS contract, saved schema, approval decision, external replay
|
|
59
|
+
eligibility, missing-Tool rule, or callback sequence changes. The existing
|
|
60
|
+
validation behavior is retained, including the handling of current Tool
|
|
61
|
+
validation errors and missing definitions; this refactor does not add a new
|
|
62
|
+
schema-migration or saved-state validation policy. It does not restore arbitrary
|
|
63
|
+
Application Tool instance variables.
|
|
64
|
+
|
|
65
|
+
Restoration itself does not run authorization policy, execute a Tool, acquire a
|
|
66
|
+
Runtime, perform persistence I/O or notify listeners. This does not suppress the
|
|
67
|
+
existing recovery installation notification of an outstanding approval request.
|
|
68
|
+
Load-time notification and later approval/rejection dispatch keep their existing
|
|
69
|
+
owners. External outcome-unknown resolution and framework operation recovery
|
|
70
|
+
remain with RecoveryCoordinator and the execution owner.
|
|
71
|
+
|
|
72
|
+
Under [018-durability-guarantees-and-failure-model](018-durability-guarantees-and-failure-model.md),
|
|
73
|
+
this change concerns operation-local reconstruction from already materialized
|
|
74
|
+
facts. Unsupported input is an F0 rejection without X0 dispatch by this operation.
|
|
75
|
+
Same logical execution resumption after F4 remains CONDITIONAL on the existing
|
|
76
|
+
confirmed saved state and operation-specific recovery contract. F1 outcome
|
|
77
|
+
resolution is unchanged. No new external-effect exactly-once guarantee follows.
|
|
78
|
+
|
|
79
|
+
## Verification
|
|
80
|
+
|
|
81
|
+
Replace tests that mock another object's instance-variable writes with real
|
|
82
|
+
ToolInvocation behavior tests. Run identical assertions against the old owner
|
|
83
|
+
boundary and the new operation. Cover all six states, unsupported states, saved
|
|
84
|
+
results, missing definitions, immutable approval evidence, and dispatch gating
|
|
85
|
+
before and after approval. Existing restart tests exercise approval and rejection
|
|
86
|
+
through actual recovery installation and session continuation. Run the ordinary
|
|
87
|
+
and integration suites, API snapshot, annotations, RBS, examples and SQLite
|
|
88
|
+
persistence checks. No test count implies a stronger F4 or X0 guarantee.
|
|
89
|
+
|
|
90
|
+
SharedState coordination ownership, Storage domain responsibilities and Workflow
|
|
91
|
+
terminal persistence remain separate work. This decision completes only the Tool
|
|
92
|
+
restoration ownership item carried forward by ADR-047.
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
# ADR-053: SharedState Coordination Ownership
|
|
2
|
+
|
|
3
|
+
## Status
|
|
4
|
+
|
|
5
|
+
Accepted on the architecture refactoring branch, 2026-09-22.
|
|
6
|
+
This resolves the deferred SharedState ownership decision in
|
|
7
|
+
[046-agent-responsibility-layout-and-shared-records](046-agent-responsibility-layout-and-shared-records.md).
|
|
8
|
+
|
|
9
|
+
## Context
|
|
10
|
+
|
|
11
|
+
SharedState creates an invocation-local findings store, equips several Agent
|
|
12
|
+
definitions with read/write Tools, invokes members in declaration order, repeats
|
|
13
|
+
cycles until a configured limit, and aggregates the findings. It is not an
|
|
14
|
+
individual Agent's state container or execution coordinator. These responsibilities
|
|
15
|
+
belong to MultiAgent, alongside the other multi-Agent coordination patterns.
|
|
16
|
+
|
|
17
|
+
Its implementation also mixes cycle orchestration with individual member calls,
|
|
18
|
+
and researcher instrumentation with the bodies of injected Tool definitions.
|
|
19
|
+
Moving a file alone would leave those abstraction levels mixed.
|
|
20
|
+
|
|
21
|
+
## Decision
|
|
22
|
+
|
|
23
|
+
1. Move the implementation to `multi_agent/shared_state.rb`, exposing the
|
|
24
|
+
Experimental `Phronomy::MultiAgent::SharedState` and its nested `KnowledgeStore`.
|
|
25
|
+
Remove `Phronomy::Agent::SharedState` without an alias on this branch, following
|
|
26
|
+
the coordination ownership precedent in
|
|
27
|
+
[034-handoff-runner-coordination-ownership](034-handoff-runner-coordination-ownership.md).
|
|
28
|
+
Update examples, RBS and the [migration guide](../migrations/shared-state-multi-agent.md)
|
|
29
|
+
together. Ordinary consumers continue to `require "phronomy"`.
|
|
30
|
+
2. Express invocation as termination validation, store creation, member
|
|
31
|
+
coordination and result aggregation. Express each cycle as ordered member
|
|
32
|
+
invocation followed by stopping decisions. Build the two injected Tool
|
|
33
|
+
definitions in named private methods. Keep these responsibilities in the same
|
|
34
|
+
class; no new execution manager or general coordination abstraction is needed.
|
|
35
|
+
3. Preserve the DSL, method parameters, prompt text, Tool descriptions/schema,
|
|
36
|
+
cooperative execution mode, original Tool aliases, result shape and exceptions.
|
|
37
|
+
Members remain sequential; findings from an earlier member are visible to the
|
|
38
|
+
next member in the same cycle. `terminate_when` still takes precedence over
|
|
39
|
+
timeout after each complete cycle, and timeout does not interrupt a member.
|
|
40
|
+
4. Preserve the generated Agent definition ID prefix
|
|
41
|
+
`Phronomy::Agent::SharedState::Instrumented/` and instrumentation version 1.
|
|
42
|
+
This string is semantic identity, not a Ruby constant lookup or old-name alias.
|
|
43
|
+
Namespace placement alone must not change the wrapped definition revision.
|
|
44
|
+
|
|
45
|
+
## Consequences and limits
|
|
46
|
+
|
|
47
|
+
This is a breaking rename of an Experimental public API, including the nested
|
|
48
|
+
store class name. The Stable/Beta API snapshot does not enumerate SharedState;
|
|
49
|
+
an unchanged snapshot does not establish complete public API compatibility.
|
|
50
|
+
|
|
51
|
+
The store is still newly created for each invocation and is not durable shared
|
|
52
|
+
Agent state. The coordinator adds no resume, cancellation, asynchronous execution,
|
|
53
|
+
transaction, F4 or X0 guarantee. `invoke` still accepts `config:` without
|
|
54
|
+
forwarding it to the member calls. Revising that behavior is a separate change.
|
|
55
|
+
|
|
56
|
+
No persistence schema or saved-record migration is introduced. Individual Agent
|
|
57
|
+
persistence keeps its existing rules; this move does not make the in-memory
|
|
58
|
+
coordination lifetime resumable. The method extraction slightly increases source
|
|
59
|
+
length and does not eliminate unrelated dependency cycles.
|
|
60
|
+
|
|
61
|
+
Storage domain responsibilities and Workflow terminal ownership remain separate
|
|
62
|
+
work items. This decision does not reopen the completed ExecutionCoordinator split.
|
|
63
|
+
|
|
64
|
+
## Verification obligations
|
|
65
|
+
|
|
66
|
+
Verify new namespace loading, absence of the old alias, repeated eager-load
|
|
67
|
+
identity and no Runtime startup during loading. Exercise existing coordination,
|
|
68
|
+
stopping, aggregation, Tool alias and definition identity tests. Check the full
|
|
69
|
+
and integration suites, offline examples, RBS, annotations, style and built gem
|
|
70
|
+
contents, including removal of the old implementation path. Record executed
|
|
71
|
+
results and untested environments separately in the delivery review.
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
# ADR-054: One Workflow Terminal Save Implementation
|
|
2
|
+
|
|
3
|
+
## Status and scope
|
|
4
|
+
|
|
5
|
+
Accepted on the architecture refactoring branch, 2026-09-22.
|
|
6
|
+
Amends only the Workflow recovery prepend requirement in
|
|
7
|
+
[038-responsibility-based-source-layout](038-responsibility-based-source-layout.md).
|
|
8
|
+
The durable barrier in
|
|
9
|
+
[026-workflow-runtime-admission-and-durable-terminal-barrier](026-workflow-runtime-admission-and-durable-terminal-barrier.md)
|
|
10
|
+
and the receiver ownership in
|
|
11
|
+
[042-feature-owned-execution-state](042-feature-owned-execution-state.md)
|
|
12
|
+
remain unchanged.
|
|
13
|
+
|
|
14
|
+
## Problem
|
|
15
|
+
|
|
16
|
+
WorkflowRunner defines terminal save submission, but WorkflowRecovery defines
|
|
17
|
+
the same method and is prepended during application loading. It never calls
|
|
18
|
+
`super`. The active implementation reconciles uncertain save outcomes against
|
|
19
|
+
durable pre/post state; the shadowed implementation does not. Reading or editing
|
|
20
|
+
the Runner alone can therefore target code that is not actually used.
|
|
21
|
+
|
|
22
|
+
## Decision
|
|
23
|
+
|
|
24
|
+
Move the currently active submission and F1 reconciliation into WorkflowRunner.
|
|
25
|
+
Delete the shadowed implementation, the private WorkflowRecovery module and its
|
|
26
|
+
explicit installation. Do not introduce a new class or compatibility alias for
|
|
27
|
+
the removed private override.
|
|
28
|
+
|
|
29
|
+
Express terminal save submission as admission marking, immutable command
|
|
30
|
+
construction, Offload submission and session-local result delivery. Named private
|
|
31
|
+
methods own saving/reconciliation and delivery separately. The existing Command
|
|
32
|
+
and Result Data classes retain their identity and members.
|
|
33
|
+
|
|
34
|
+
The worker saves once. Portable ConflictError, NotFoundError, SerializationError
|
|
35
|
+
and UnsupportedBackendError remain known failures without readback. Other save
|
|
36
|
+
errors use the existing authoritative snapshot comparison: exact post-state is
|
|
37
|
+
success, pre-state preserves the original failure, and conflict or failed
|
|
38
|
+
readback remains outcome-unknown. No automatic save retry is introduced.
|
|
39
|
+
|
|
40
|
+
The existing session sink receives `workflow_terminal_persistence_result`.
|
|
41
|
+
Offload completion errors still become outcome-unknown, and rejected sink
|
|
42
|
+
delivery retains its existing warning. Runner still marks admission and captures
|
|
43
|
+
the snapshot on EventLoop; workers only use that captured command for persistence.
|
|
44
|
+
|
|
45
|
+
## Compatibility and guarantees
|
|
46
|
+
|
|
47
|
+
This is an internal ownership/readability change. Public Workflow/Persistence
|
|
48
|
+
APIs, Backend SPI, snapshots, revisions, error messages and the session event
|
|
49
|
+
protocol are unchanged. Removing the prepend can make WorkflowRunner load lazily
|
|
50
|
+
under ordinary `require "phronomy"`; first access and eager loading must retain
|
|
51
|
+
the same recovery behavior without starting Runtime.
|
|
52
|
+
|
|
53
|
+
F1 save certainty remains CONDITIONAL on authoritative readback matching the
|
|
54
|
+
existing expected pre-state or intended post-state rules. It is not established
|
|
55
|
+
merely by receiving an exception. F0 portable failures follow the existing known
|
|
56
|
+
failure path. Runtime release, success notification and Task settlement still
|
|
57
|
+
wait for EventLoop-owned session acceptance; uncertain outcomes keep the existing
|
|
58
|
+
recovery-required behavior. F4 readability depends on the backend retaining
|
|
59
|
+
confirmed data. X0 external effects are outside this save, and this change adds
|
|
60
|
+
no execution replay, distributed ownership or exactly-once guarantee.
|
|
61
|
+
|
|
62
|
+
FSMSession still owns interpretation of the Workflow terminal persistence
|
|
63
|
+
event. Moving that policy out of Engine is a separate next step; this decision
|
|
64
|
+
does not claim that the entire Workflow terminal ownership issue is resolved.
|
|
65
|
+
Storage's fixed repository slots and Agent watermark also remain separate work.
|
|
66
|
+
|
|
67
|
+
## Verification
|
|
68
|
+
|
|
69
|
+
Characterize the effective submission path before and after the change, including
|
|
70
|
+
immutable snapshots, known errors, F1 post/pre/conflicting/unreadable outcomes,
|
|
71
|
+
single-save behavior and failed Offload completion delivery. Preserve existing
|
|
72
|
+
real-runtime tests for delayed save, stream barriers, admission release and
|
|
73
|
+
uncertain outcomes. Verify ordinary/eager loading without the override, full and
|
|
74
|
+
integration suites, API/RBS/annotations/style, offline examples and built gem
|
|
75
|
+
contents. Keep results from tests actually run distinct from unavailable live
|
|
76
|
+
Provider or database-server evidence.
|