phronomy 0.27.0 → 0.29.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.mutant.yml +9 -9
- data/CHANGELOG.md +52 -0
- data/CONTRIBUTING.md +8 -8
- data/README.md +28 -7
- data/benchmark/bench_agent_invoke.rb +25 -50
- data/benchmark/bench_context_assembler.rb +14 -11
- data/benchmark/bench_regression.rb +1 -1
- data/benchmark/bench_tool_schema.rb +1 -1
- data/docs/application-recipes.md +229 -0
- data/docs/architecture/agent-chat-and-state-ownership.md +7 -1
- data/docs/architecture/agent-transition-ownership.md +13 -89
- data/docs/architecture/backend-groups.md +152 -0
- data/docs/architecture/before-llm-input.md +3 -3
- data/docs/architecture/context-management.md +1 -1
- data/docs/architecture/dx05-agent-scope.md +119 -0
- data/docs/architecture/dx05-workflow-task-state.md +134 -0
- data/docs/architecture/error-api-review.md +245 -0
- data/docs/architecture/execution-abstraction-review.md +88 -0
- data/docs/architecture/execution-boundaries.md +28 -0
- data/docs/architecture/execution-metadata-and-values.md +6 -0
- data/docs/architecture/multi-agent-handoff.md +6 -5
- data/docs/architecture/persistence.md +27 -9
- data/docs/architecture/r8-unit1.md +104 -0
- data/docs/architecture/r8-unit10.md +72 -0
- data/docs/architecture/r8-unit11.md +71 -0
- data/docs/architecture/r8-unit12.md +67 -0
- data/docs/architecture/r8-unit13.md +61 -0
- data/docs/architecture/r8-unit14.md +72 -0
- data/docs/architecture/r8-unit15.md +65 -0
- data/docs/architecture/r8-unit16.md +54 -0
- data/docs/architecture/r8-unit17.md +73 -0
- data/docs/architecture/r8-unit18.md +92 -0
- data/docs/architecture/r8-unit19.md +61 -0
- data/docs/architecture/r8-unit2.md +55 -0
- data/docs/architecture/r8-unit20.md +51 -0
- data/docs/architecture/r8-unit21.md +79 -0
- data/docs/architecture/r8-unit22.md +74 -0
- data/docs/architecture/r8-unit23.md +81 -0
- data/docs/architecture/r8-unit3.md +130 -0
- data/docs/architecture/r8-unit4.md +79 -0
- data/docs/architecture/r8-unit5.md +115 -0
- data/docs/architecture/r8-unit6.md +71 -0
- data/docs/architecture/r8-unit7.md +70 -0
- data/docs/architecture/r8-unit8.md +78 -0
- data/docs/architecture/r8-unit9.md +73 -0
- data/docs/architecture/refactoring-closure.md +10 -1
- data/docs/architecture/remaining-refactoring-plan.md +16 -0
- data/docs/architecture/storage-execution-boundaries.md +54 -0
- data/docs/architecture/tool-schema-recording-gap.md +6 -0
- data/docs/architecture/tracing.md +1 -1
- data/docs/architecture/workflow-terminal-ownership-design.md +2 -2
- data/docs/architecture.md +24 -11
- data/docs/decisions/015-tool-public-facade-and-rbs-boundary.md +3 -3
- data/docs/decisions/027-llm-adapter-provider-boundary.md +2 -0
- data/docs/decisions/030-agent-handoff-domain-and-durable-responsibility.md +2 -0
- data/docs/decisions/031-durable-multi-agent-coordination.md +2 -0
- data/docs/decisions/032-storage-backend-composition.md +5 -0
- data/docs/decisions/034-handoff-runner-coordination-ownership.md +2 -0
- data/docs/decisions/035-tool-executor-capability-ownership.md +1 -1
- data/docs/decisions/038-responsibility-based-source-layout.md +14 -0
- data/docs/decisions/039-runtime-configuration-lifecycle-ownership.md +8 -0
- data/docs/decisions/040-configuration-default-composition.md +12 -1
- data/docs/decisions/045-worker-input-restriction-ownership.md +4 -0
- data/docs/decisions/051-execution-outcome-worker-ownership.md +2 -0
- data/docs/decisions/056-workflow-terminal-policy-ownership.md +1 -1
- data/docs/decisions/058-neutral-storage-primitives.md +5 -0
- data/docs/decisions/059-backend-contracts-and-async-clients.md +74 -0
- data/docs/decisions/060-runtime-settings-and-application-configuration.md +86 -0
- data/docs/decisions/061-persistence-failure-contracts.md +89 -0
- data/docs/decisions/062-content-store-service.md +52 -0
- data/docs/decisions/063-execution-contracts-and-services.md +88 -0
- data/docs/decisions/064-agent-execution-and-multi-agent-responsibility.md +36 -0
- data/docs/decisions/065-vector-and-embeddings-common-operations.md +38 -0
- data/docs/decisions/066-llm-and-tool-operation-contracts.md +20 -0
- data/docs/decisions/067-agent-progress-and-engine-connection.md +29 -0
- data/docs/decisions/068-agent-tool-child-progress-and-tool-operation.md +36 -0
- data/docs/decisions/README.md +18 -1
- data/docs/execution-boundaries-preview.md +45 -0
- data/docs/failure-reason-codes.md +45 -0
- data/docs/features.md +12 -4
- data/docs/getting-started.md +52 -48
- data/docs/migrations/0.22.md +2 -2
- data/docs/migrations/durable-semantic-coordination-v2.md +2 -0
- data/docs/migrations/handoff-runner-multi-agent.md +2 -0
- data/docs/migrations/persistence-failure-contracts.md +67 -0
- data/docs/migrations/r8-unit10.md +36 -0
- data/docs/migrations/r8-unit11.md +33 -0
- data/docs/migrations/r8-unit12.md +31 -0
- data/docs/migrations/r8-unit13.md +36 -0
- data/docs/migrations/r8-unit14.md +31 -0
- data/docs/migrations/r8-unit15.md +31 -0
- data/docs/migrations/r8-unit16.md +26 -0
- data/docs/migrations/r8-unit17.md +28 -0
- data/docs/migrations/r8-unit18.md +29 -0
- data/docs/migrations/r8-unit19.md +28 -0
- data/docs/migrations/r8-unit20.md +24 -0
- data/docs/migrations/r8-unit21.md +28 -0
- data/docs/migrations/r8-unit22.md +29 -0
- data/docs/migrations/r8-unit23.md +20 -0
- data/docs/migrations/r8-unit4.md +67 -0
- data/docs/migrations/r8-unit5.md +75 -0
- data/docs/migrations/r8-unit6.md +109 -0
- data/docs/migrations/r8-unit7.md +31 -0
- data/docs/migrations/r8-unit8.md +33 -0
- data/docs/migrations/r8-unit9.md +28 -0
- data/docs/migrations/storage-async-client.md +103 -0
- data/docs/migrations/vector-async-clients.md +110 -0
- data/docs/ordered-event-delivery.md +54 -0
- data/docs/persistence-backends.md +38 -21
- data/docs/runtime-and-concurrency.md +26 -1
- data/docs/workflow-completion.md +92 -0
- data/gemfiles/http_minimum.gemfile +5 -0
- data/lib/phronomy/agent/admission.rb +78 -0
- data/lib/phronomy/agent/{lifecycle_contract/agent_already_exists_error.rb → agent_already_exists_error.rb} +1 -1
- data/lib/phronomy/agent/{lifecycle_contract/agent_busy_error.rb → agent_busy_error.rb} +1 -1
- data/lib/phronomy/agent/agent_not_found_error.rb +16 -0
- data/lib/phronomy/agent/{lifecycle_contract/agent_purged_error.rb → agent_purged_error.rb} +1 -1
- data/lib/phronomy/agent/agent_unloaded_error.rb +14 -0
- data/lib/phronomy/agent/api/agent.rb +13 -0
- data/lib/phronomy/{recovery → agent/api}/execution_rehydration_required_error.rb +1 -1
- data/lib/phronomy/agent/async_event_api.rb +132 -103
- data/lib/phronomy/agent/base.rb +146 -113
- data/lib/phronomy/agent/before_llm_input.rb +70 -0
- data/lib/phronomy/agent/composition/run_once.rb +1 -1
- data/lib/phronomy/agent/{context_assembly/context_candidate_resolver.rb → context_candidate_resolver.rb} +2 -2
- data/lib/phronomy/agent/{context_assembly/context_assembler.rb → context_preparation.rb} +35 -221
- data/lib/phronomy/agent/control_request.rb +21 -0
- data/lib/phronomy/agent/execution/agent_execution.rb +1 -1
- data/lib/phronomy/agent/execution/agent_invocation.rb +27 -53
- data/lib/phronomy/agent/execution/approval_resume_commit.rb +1 -1
- data/lib/phronomy/agent/execution/dispatch_preparation.rb +17 -127
- data/lib/phronomy/agent/execution/exact_execution.rb +55 -32
- data/lib/phronomy/agent/execution/execution_cancellation.rb +8 -4
- data/lib/phronomy/agent/execution/execution_coordinator.rb +229 -407
- data/lib/phronomy/agent/execution/execution_metadata.rb +1 -0
- data/lib/phronomy/agent/execution/execution_outcome_committer.rb +71 -127
- data/lib/phronomy/agent/execution/execution_registry.rb +6 -2
- data/lib/phronomy/agent/execution/execution_session_runner.rb +22 -27
- data/lib/phronomy/agent/execution/initial_preparation.rb +19 -120
- data/lib/phronomy/agent/execution/{agent_invocation_session_builder.rb → invocation_actions.rb} +54 -194
- data/lib/phronomy/agent/execution/invocation_transitions.rb +39 -1
- data/lib/phronomy/agent/execution/runtime_record_encoder.rb +8 -11
- data/lib/phronomy/agent/execution_change.rb +161 -0
- data/lib/phronomy/agent/execution_environment.rb +36 -0
- data/lib/phronomy/agent/execution_extension_state.rb +21 -0
- data/lib/phronomy/agent/execution_observation.rb +35 -0
- data/lib/phronomy/agent/filterable.rb +188 -0
- data/lib/phronomy/agent/handoff/{handoff_context.rb → transfer_context.rb} +4 -4
- data/lib/phronomy/agent/handoff/{handoff_projection.rb → transfer_projection.rb} +14 -33
- data/lib/phronomy/{llm_contract/transport_error.rb → agent/handoff_error.rb} +1 -1
- data/lib/phronomy/agent/journal/journal_projection.rb +1 -1
- data/lib/phronomy/agent/knowledge_item.rb +13 -0
- data/lib/phronomy/agent/lifecycle/agent_root.rb +1 -1
- data/lib/phronomy/agent/lifecycle/lifetime_api.rb +76 -0
- data/lib/phronomy/agent/lifecycle/operation_lease.rb +33 -0
- data/lib/phronomy/agent/lifecycle/operation_result.rb +53 -0
- data/lib/phronomy/agent/lifecycle/ownership_registry.rb +117 -31
- data/lib/phronomy/agent/lifecycle/scope.rb +198 -0
- data/lib/phronomy/agent/lifecycle/scope_cleanup_error.rb +19 -0
- data/lib/phronomy/agent/lifecycle/unload_transition.rb +78 -0
- data/lib/phronomy/agent/persistence/agent_repository.rb +29 -21
- data/lib/phronomy/agent/persistence/cancellation_repository.rb +51 -0
- data/lib/phronomy/agent/persistence/codec.rb +1 -21
- data/lib/phronomy/agent/persistence/execution_repository.rb +57 -41
- data/lib/phronomy/agent/persistence/journal_repository.rb +27 -18
- data/lib/phronomy/agent/persistence/records.rb +33 -0
- data/lib/phronomy/agent/persistence/retention_repository.rb +70 -0
- data/lib/phronomy/agent/persistence/storage_schema.rb +7 -2
- data/lib/phronomy/agent/persistence/watermark.rb +13 -11
- data/lib/phronomy/agent/recovery/invocation_restorer.rb +13 -21
- data/lib/phronomy/agent/recovery/recovery_coordinator/continuation.rb +13 -12
- data/lib/phronomy/agent/recovery/recovery_coordinator/installation.rb +34 -34
- data/lib/phronomy/agent/recovery/recovery_coordinator/resolution.rb +33 -39
- data/lib/phronomy/agent/recovery/recovery_coordinator.rb +28 -25
- data/lib/phronomy/agent/recovery/recovery_rules.rb +119 -0
- data/lib/phronomy/agent/recovery/recovery_support.rb +10 -19
- data/lib/phronomy/agent/reserved_execution.rb +16 -0
- data/lib/phronomy/agent/retention.rb +17 -0
- data/lib/phronomy/agent/runtime_binding/engine_environment.rb +60 -0
- data/lib/phronomy/agent/runtime_binding/engine_session_builder.rb +34 -0
- data/lib/phronomy/agent/runtime_binding/phase_machine_builder.rb +64 -0
- data/lib/phronomy/agent/runtime_binding/tool_session_builder.rb +34 -0
- data/lib/phronomy/agent/{context_assembly/ruby_llm_materializer.rb → runtime_input.rb} +18 -35
- data/lib/phronomy/agent/{context_assembly/saved_context_reader.rb → saved_context_reader.rb} +6 -4
- data/lib/phronomy/agent/settings.rb +47 -0
- data/lib/phronomy/agent/{context_assembly/state_writer.rb → state_writer.rb} +4 -3
- data/lib/phronomy/agent/store.rb +253 -0
- data/lib/phronomy/agent/{lifecycle_contract/stream_callback_error.rb → stream_callback_error.rb} +3 -3
- data/lib/phronomy/agent/tool_execution/tool_binding.rb +4 -64
- data/lib/phronomy/agent/tool_execution/tool_invocation.rb +50 -219
- data/lib/phronomy/agent/tool_execution/tool_invocation_actions.rb +107 -0
- data/lib/phronomy/agent/tool_execution/tool_invocation_transitions.rb +70 -0
- data/lib/phronomy/common/error.rb +65 -1
- data/lib/phronomy/configuration/runtime_settings.rb +49 -0
- data/lib/phronomy/content_store/base.rb +7 -2
- data/lib/phronomy/content_store/storage_schema.rb +1 -0
- data/lib/phronomy/content_store/stored_contents.rb +2 -1
- data/lib/phronomy/context/assembly.rb +195 -0
- data/lib/phronomy/{llm_contract/context_budget_exceeded_error.rb → context/budget_exceeded_error.rb} +3 -1
- data/lib/phronomy/context/candidate.rb +51 -0
- data/lib/phronomy/context/constraint.rb +47 -0
- data/lib/phronomy/{agent/context_contract → context}/context_plan.rb +1 -1
- data/lib/phronomy/{agent/context_contract → context}/context_plan_validator.rb +3 -3
- data/lib/phronomy/{agent/context_contract → context}/context_policy.rb +1 -1
- data/lib/phronomy/{agent/context_contract → context}/context_policy_input.rb +1 -1
- data/lib/phronomy/{agent/context_assembly → context}/context_policy_input_builder.rb +1 -1
- data/lib/phronomy/context/default_policy.rb +140 -0
- data/lib/phronomy/context/final_budget_validator.rb +33 -0
- data/lib/phronomy/{agent/context_contract → context}/llm_input_build_context.rb +1 -1
- data/lib/phronomy/{agent/context_contract → context}/llm_input_manifest.rb +19 -19
- data/lib/phronomy/{agent/context_contract → context}/llm_input_patch.rb +1 -1
- data/lib/phronomy/context/manifest_error.rb +10 -0
- data/lib/phronomy/context/prompt_template.rb +98 -0
- data/lib/phronomy/{vector_store → documents}/loader/base.rb +1 -1
- data/lib/phronomy/{vector_store → documents}/loader/csv_loader.rb +2 -2
- data/lib/phronomy/{vector_store → documents}/loader/markdown_loader.rb +3 -3
- data/lib/phronomy/{vector_store → documents}/loader/plain_text_loader.rb +2 -2
- data/lib/phronomy/{vector_store → documents}/splitter/base.rb +1 -1
- data/lib/phronomy/{vector_store → documents}/splitter/fixed_size_splitter.rb +2 -2
- data/lib/phronomy/{vector_store → documents}/splitter/recursive_splitter.rb +2 -2
- data/lib/phronomy/embeddings/async/async_client.rb +44 -0
- data/lib/phronomy/embeddings/authentication_error.rb +11 -0
- data/lib/phronomy/embeddings/backends/ruby_llm_embeddings.rb +52 -0
- data/lib/phronomy/embeddings/base.rb +43 -0
- data/lib/phronomy/embeddings/invalid_result_error.rb +11 -0
- data/lib/phronomy/embeddings/rate_limit_error.rb +11 -0
- data/lib/phronomy/embeddings/transport_error.rb +11 -0
- data/lib/phronomy/engine/concurrency/offload_pool.rb +36 -21
- data/lib/phronomy/engine/concurrency/pool_registry.rb +47 -12
- data/lib/phronomy/engine/diagnostics.rb +1 -1
- data/lib/phronomy/engine/event_loop.rb +7 -7
- data/lib/phronomy/engine/execution_binding.rb +23 -0
- data/lib/phronomy/engine/execution_receiver_binding.rb +43 -0
- data/lib/phronomy/engine/fsm_protocol.rb +1 -6
- data/lib/phronomy/engine/fsm_session.rb +3 -3
- data/lib/phronomy/engine/metrics.rb +16 -14
- data/lib/phronomy/engine/runtime/timer_queue.rb +1 -1
- data/lib/phronomy/engine/runtime.rb +25 -12
- data/lib/phronomy/engine/terminal_decision.rb +7 -0
- data/lib/phronomy/execution/async_operation.rb +41 -0
- data/lib/phronomy/{engine → execution}/blocking.rb +2 -2
- data/lib/phronomy/{engine → execution}/concurrency/cancellation_token.rb +1 -1
- data/lib/phronomy/{engine → execution}/concurrency/deadline.rb +0 -17
- data/lib/phronomy/{engine → execution}/concurrency/physical_completion_task.rb +1 -1
- data/lib/phronomy/{engine → execution}/concurrency/result_collector.rb +1 -1
- data/lib/phronomy/{engine → execution}/concurrency/result_composition.rb +33 -12
- data/lib/phronomy/{engine/concurrency/subscriptions.rb → execution/concurrency/result_subscriptions.rb} +14 -18
- data/lib/phronomy/execution/concurrency/subscriptions.rb +25 -0
- data/lib/phronomy/{engine → execution}/execution.rb +61 -27
- data/lib/phronomy/{engine → execution}/execution_cancellation_error.rb +2 -2
- data/lib/phronomy/execution/execution_receiver.rb +78 -0
- data/lib/phronomy/execution/execution_scope_state.rb +35 -0
- data/lib/phronomy/{engine → execution}/execution_timeout_error.rb +2 -2
- data/lib/phronomy/{engine → execution}/invocation_context.rb +0 -15
- data/lib/phronomy/execution/invocation_controls.rb +73 -0
- data/lib/phronomy/execution/runnable.rb +24 -0
- data/lib/phronomy/{engine → execution}/task_result.rb +9 -4
- data/lib/phronomy/execution/wait_policy.rb +24 -0
- data/lib/phronomy/filter/{contract/filter_block_error.rb → filter_block_error.rb} +3 -3
- data/lib/phronomy/generation/generator_verifier/agent_operation.rb +65 -0
- data/lib/phronomy/generation/generator_verifier/default_parser.rb +27 -0
- data/lib/phronomy/generation/generator_verifier/workflow_builder.rb +2 -2
- data/lib/phronomy/generation/generator_verifier.rb +7 -7
- data/lib/phronomy/generation/low_confidence_error.rb +2 -2
- data/lib/phronomy/integrations/ordered_event_delivery.rb +208 -0
- data/lib/phronomy/llm_adapter/async/async_client.rb +47 -0
- data/lib/phronomy/{llm_contract → llm_adapter}/authentication_error.rb +3 -1
- data/lib/phronomy/llm_adapter/backends/ruby_llm.rb +183 -0
- data/lib/phronomy/llm_adapter/base.rb +49 -68
- data/lib/phronomy/{llm_contract → llm_adapter}/context_length_error.rb +3 -1
- data/lib/phronomy/llm_adapter/invalid_result_error.rb +10 -0
- data/lib/phronomy/llm_adapter/message.rb +62 -0
- data/lib/phronomy/{llm_contract → llm_adapter}/rate_limit_error.rb +3 -1
- data/lib/phronomy/llm_adapter/request.rb +79 -0
- data/lib/phronomy/llm_adapter/response.rb +36 -0
- data/lib/phronomy/llm_adapter/stream_chunk.rb +18 -0
- data/lib/phronomy/llm_adapter/token_usage.rb +64 -0
- data/lib/phronomy/llm_adapter/transport_error.rb +9 -0
- data/lib/phronomy/llm_adapter.rb +3 -16
- data/lib/phronomy/multi_agent/admission_registry.rb +1 -8
- data/lib/phronomy/multi_agent/durable_subagent_coordinator.rb +108 -84
- data/lib/phronomy/multi_agent/execution_environment.rb +29 -0
- data/lib/phronomy/{agent/handoff → multi_agent}/handoff.rb +2 -2
- data/lib/phronomy/{agent/handoff → multi_agent}/handoff_capability_factory.rb +21 -2
- data/lib/phronomy/multi_agent/handoff_participant.rb +79 -0
- data/lib/phronomy/{agent/handoff → multi_agent}/handoff_policy.rb +1 -1
- data/lib/phronomy/multi_agent/handoff_runner.rb +77 -100
- data/lib/phronomy/{agent/handoff → multi_agent}/handoff_state.rb +1 -1
- data/lib/phronomy/multi_agent/orchestrator.rb +61 -75
- data/lib/phronomy/multi_agent/persistence/codec.rb +20 -0
- data/lib/phronomy/multi_agent/persistence/handoff_state_repository.rb +77 -0
- data/lib/phronomy/multi_agent/persistence/records.rb +27 -0
- data/lib/phronomy/multi_agent/persistence/storage_schema.rb +21 -0
- data/lib/phronomy/multi_agent/persistence/team_execution_repository.rb +60 -44
- data/lib/phronomy/multi_agent/persistence/team_repository.rb +29 -21
- data/lib/phronomy/multi_agent/reserved_child_admission.rb +88 -0
- data/lib/phronomy/multi_agent/runtime_binding/engine_environment.rb +35 -0
- data/lib/phronomy/multi_agent/shared_state.rb +2 -2
- data/lib/phronomy/multi_agent/store.rb +156 -0
- data/lib/phronomy/multi_agent/team_busy_error.rb +18 -0
- data/lib/phronomy/multi_agent/team_coordinator.rb +99 -77
- data/lib/phronomy/multi_agent/team_not_found_error.rb +18 -0
- data/lib/phronomy/multi_agent/team_ownership_registry.rb +2 -12
- data/lib/phronomy/output_parser/parse_error.rb +7 -0
- data/lib/phronomy/persistence/content_repository.rb +26 -0
- data/lib/phronomy/persistence/errors.rb +16 -0
- data/lib/phronomy/persistence/migration/initial_format_migration.rb +2 -2
- data/lib/phronomy/persistence/persistence.rb +23 -0
- data/lib/phronomy/persistence/save_outcome.rb +24 -0
- data/lib/phronomy/persistence/snapshot_comparison.rb +81 -0
- data/lib/phronomy/persistence/storage_boundary.rb +32 -0
- data/lib/phronomy/persistence/transaction.rb +86 -0
- data/lib/phronomy/persistence_composition/storage_schema.rb +9 -4
- data/lib/phronomy/persistence_composition/stores.rb +34 -0
- data/lib/phronomy/persistence_composition/unit4_migration.rb +276 -0
- data/lib/phronomy/runtime_composition/agent_defaults.rb +5 -1
- data/lib/phronomy/runtime_composition/configuration.rb +146 -0
- data/lib/phronomy/runtime_composition/evaluation_defaults.rb +7 -0
- data/lib/phronomy/runtime_composition/execution_defaults.rb +5 -0
- data/lib/phronomy/runtime_composition/generation_defaults.rb +6 -0
- data/lib/phronomy/runtime_composition/global_configuration.rb +38 -0
- data/lib/phronomy/runtime_composition/multi_agent_defaults.rb +9 -0
- data/lib/phronomy/runtime_composition/workflow_defaults.rb +4 -0
- data/lib/phronomy/storage/async/async_client.rb +60 -0
- data/lib/phronomy/storage/backend.rb +8 -2
- data/lib/phronomy/storage/condition_failed_error.rb +2 -2
- data/lib/phronomy/storage/unique_constraint_error.rb +2 -2
- data/lib/phronomy/testing/eval/metrics.rb +1 -1
- data/lib/phronomy/testing/eval/scorer/llm_judge.rb +19 -3
- data/lib/phronomy/testing/persistence_contract/a_content_store.rb +2 -2
- data/lib/phronomy/testing/persistence_contract/a_journal_repository.rb +6 -6
- data/lib/phronomy/testing/persistence_contract/a_persistence_backend.rb +55 -52
- data/lib/phronomy/testing/persistence_contract/a_workflow_state_repository.rb +3 -3
- data/lib/phronomy/testing/persistence_contract/an_agent_repository.rb +7 -7
- data/lib/phronomy/testing/persistence_contract/an_execution_repository.rb +11 -11
- data/lib/phronomy/testing/persistence_contract/coordination_repositories.rb +57 -51
- data/lib/phronomy/testing/persistence_contract/neutral_storage_primitives.rb +1 -1
- data/lib/phronomy/testing/persistence_contract/storage_transaction_boundaries.rb +23 -22
- data/lib/phronomy/tool/authorization.rb +77 -0
- data/lib/phronomy/tool/base.rb +551 -9
- data/lib/phronomy/tool/call_request.rb +40 -0
- data/lib/phronomy/{agent/tool_execution/tool_definition_set.rb → tool/definition_set.rb} +7 -8
- data/lib/phronomy/tool/operation.rb +88 -0
- data/lib/phronomy/tool/schema.rb +214 -0
- data/lib/phronomy/tool/settings.rb +31 -0
- data/lib/phronomy/tool/tool_error.rb +7 -0
- data/lib/phronomy/tool/tool_executor.rb +58 -0
- data/lib/phronomy/tools/agent.rb +22 -90
- data/lib/phronomy/tools/mcp.rb +21 -14
- data/lib/phronomy/tools/vector_search.rb +4 -4
- data/lib/phronomy/tracing/automatic.rb +11 -6
- data/lib/phronomy/tracing/base.rb +36 -7
- data/lib/phronomy/tracing/observation.rb +37 -0
- data/lib/phronomy/tracing/open_telemetry_tracer.rb +4 -29
- data/lib/phronomy/tracing/settings.rb +36 -0
- data/lib/phronomy/vector_store/{async_backend.rb → async/async_client.rb} +35 -29
- data/lib/phronomy/vector_store/{in_memory.rb → backends/in_memory.rb} +12 -10
- data/lib/phronomy/vector_store/{pgvector.rb → backends/pgvector.rb} +44 -16
- data/lib/phronomy/vector_store/{redis_search.rb → backends/redis_search.rb} +74 -37
- data/lib/phronomy/vector_store/base.rb +118 -49
- data/lib/phronomy/vector_store/invalid_result_error.rb +12 -0
- data/lib/phronomy/vector_store.rb +2 -17
- data/lib/phronomy/version.rb +1 -1
- data/lib/phronomy/workflow/completion.rb +11 -0
- data/lib/phronomy/workflow/execution/workflow.rb +37 -9
- data/lib/phronomy/workflow/execution/workflow_action_rules.rb +67 -0
- data/lib/phronomy/workflow/execution/workflow_context.rb +2 -2
- data/lib/phronomy/workflow/execution/workflow_execution_environment.rb +28 -0
- data/lib/phronomy/workflow/execution/workflow_execution_registry.rb +77 -8
- data/lib/phronomy/workflow/execution/workflow_runner.rb +105 -92
- data/lib/phronomy/workflow/execution/workflow_settings.rb +28 -0
- data/lib/phronomy/workflow/execution/workflow_task_execution.rb +153 -0
- data/lib/phronomy/workflow/execution/workflow_task_reception.rb +72 -0
- data/lib/phronomy/workflow/execution/workflow_task_resume_error.rb +14 -0
- data/lib/phronomy/workflow/persistence/state_repository.rb +28 -22
- data/lib/phronomy/workflow/persistence/storage_schema.rb +13 -0
- data/lib/phronomy/workflow/runtime_binding/workflow_engine_environment.rb +61 -0
- data/lib/phronomy/workflow/runtime_binding/workflow_phase_machine_builder.rb +158 -0
- data/lib/phronomy/workflow/runtime_binding/workflow_task_session.rb +76 -0
- data/lib/phronomy/workflow/{execution → runtime_binding}/workflow_terminal_policy.rb +4 -4
- data/lib/phronomy.rb +63 -16
- data/scripts/api_snapshot.rb +47 -15
- data/scripts/check_readme_ruby.rb +24 -29
- data/scripts/check_readme_runnable.rb +92 -81
- data/sig/_private/phronomy/agent/settings.rbs +19 -0
- data/sig/_private/phronomy/configuration/runtime_settings.rbs +20 -0
- data/sig/_private/phronomy/llm_adapter/async/async_client.rbs +10 -0
- data/sig/_private/phronomy/multi_agent/store.rbs +8 -0
- data/sig/_private/phronomy/persistence/storage_boundary.rbs +7 -0
- data/sig/_private/phronomy/tool/settings.rbs +13 -0
- data/sig/_private/phronomy/tracing/settings.rbs +15 -0
- data/sig/_private/phronomy/workflow/execution/workflow_settings.rbs +13 -0
- data/sig/phronomy/agent/admission.rbs +19 -0
- data/sig/phronomy/agent/agent_not_found_error.rbs +6 -0
- data/sig/phronomy/agent/agent_unloaded_error.rbs +6 -0
- data/sig/phronomy/agent/execution_contract.rbs +132 -0
- data/sig/phronomy/agent/execution_environment.rbs +20 -0
- data/sig/phronomy/agent/store.rbs +73 -0
- data/sig/phronomy/agent/stream_callback_error.rbs +8 -0
- data/sig/phronomy/agent.rbs +29 -135
- data/sig/phronomy/common.rbs +7 -0
- data/sig/phronomy/content_store/contracts.rbs +13 -0
- data/sig/phronomy/context.rbs +152 -0
- data/sig/phronomy/embeddings/async/async_client.rbs +9 -0
- data/sig/phronomy/embeddings/base.rbs +23 -0
- data/sig/phronomy/engine/concurrency/timer_bindings.rbs +22 -0
- data/sig/phronomy/engine/control_bindings.rbs +11 -0
- data/sig/phronomy/engine/control_protocols.rbs +23 -0
- data/sig/phronomy/engine/execution_binding.rbs +6 -0
- data/sig/phronomy/engine/execution_receiver.rbs +15 -0
- data/sig/phronomy/engine/observability.rbs +13 -0
- data/sig/phronomy/execution/async_operation.rbs +7 -0
- data/sig/phronomy/execution/blocking.rbs +5 -0
- data/sig/phronomy/execution/concurrency/cancellation_token.rbs +13 -0
- data/sig/phronomy/execution/concurrency/deadline.rbs +10 -0
- data/sig/phronomy/execution/concurrency/result_composition.rbs +7 -0
- data/sig/phronomy/execution/control_protocols.rbs +18 -0
- data/sig/phronomy/execution/errors.rbs +7 -0
- data/sig/phronomy/execution/execution.rbs +41 -0
- data/sig/phronomy/execution/execution_receiver.rbs +40 -0
- data/sig/phronomy/execution/execution_scope_state.rbs +9 -0
- data/sig/phronomy/execution/invocation_context.rbs +18 -0
- data/sig/phronomy/execution/invocation_controls.rbs +13 -0
- data/sig/phronomy/execution/task_result.rbs +29 -0
- data/sig/phronomy/extensions.rbs +1 -21
- data/sig/phronomy/filter/filter_block_error.rbs +6 -0
- data/sig/phronomy/generation/low_confidence_error.rbs +6 -0
- data/sig/phronomy/handoff.rbs +10 -4
- data/sig/phronomy/integrations.rbs +14 -0
- data/sig/phronomy/llm_adapter/backends/ruby_llm.rbs +6 -0
- data/sig/phronomy/llm_adapter/base.rbs +14 -0
- data/sig/phronomy/llm_adapter/usage.rbs +14 -0
- data/sig/phronomy/llm_adapter/values.rbs +43 -0
- data/sig/phronomy/llm_context_window.rbs +10 -0
- data/sig/phronomy/multi_agent/reserved_child_admission.rbs +8 -0
- data/sig/phronomy/multi_agent/store.rbs +54 -0
- data/sig/phronomy/multi_agent/team_busy_error.rbs +8 -0
- data/sig/phronomy/multi_agent/team_not_found_error.rbs +8 -0
- data/sig/phronomy/multi_agent.rbs +6 -3
- data/sig/phronomy/persistence/errors.rbs +18 -0
- data/sig/phronomy/persistence/migration.rbs +13 -0
- data/sig/phronomy/persistence/transaction.rbs +19 -0
- data/sig/phronomy/persistence.rbs +1 -99
- data/sig/phronomy/persistence_composition.rbs +19 -0
- data/sig/phronomy/runtime_composition/configuration.rbs +36 -0
- data/sig/phronomy/storage/async/async_client.rbs +8 -0
- data/sig/phronomy/storage/backends/in_memory.rbs +9 -0
- data/sig/phronomy/{storage.rbs → storage/contracts.rbs} +4 -18
- data/sig/phronomy/tool.rbs +48 -4
- data/sig/phronomy/tracing/observation.rbs +7 -0
- data/sig/phronomy/vector_store/async/async_client.rbs +13 -0
- data/sig/phronomy/vector_store/base.rbs +23 -0
- data/sig/phronomy/workflow/execution/workflow_execution_environment.rbs +15 -0
- data/sig/phronomy/workflow/runtime_binding/workflow_terminal_policy.rbs +7 -0
- data/sig/phronomy/workflow/store.rbs +8 -0
- data/sig/phronomy/workflow.rbs +5 -1
- data/sig/phronomy.rbs +4 -49
- metadata +365 -117
- data/lib/phronomy/agent/concerns/before_llm_input.rb +0 -66
- data/lib/phronomy/agent/concerns/error_translation.rb +0 -45
- data/lib/phronomy/agent/concerns/filterable.rb +0 -184
- data/lib/phronomy/agent/context/capability/base.rb +0 -548
- data/lib/phronomy/agent/context/capability/tool_executor.rb +0 -62
- data/lib/phronomy/agent/context/instruction/prompt_template.rb +0 -102
- data/lib/phronomy/agent/context_assembly/runtime_chat_builder.rb +0 -36
- data/lib/phronomy/agent/context_assembly/token_budget_resolver.rb +0 -22
- data/lib/phronomy/agent/context_parts/validators/final_budget_validator.rb +0 -37
- data/lib/phronomy/agent/context_policies/default.rb +0 -142
- data/lib/phronomy/agent/execution/phase_machine_builder.rb +0 -101
- data/lib/phronomy/agent/execution/provider_call_outcome.rb +0 -106
- data/lib/phronomy/agent/handoff/handoff_execution_coordinator.rb +0 -15
- data/lib/phronomy/agent/handoff/handoff_outcome_committer.rb +0 -131
- data/lib/phronomy/agent/handoff/handoff_request.rb +0 -45
- data/lib/phronomy/agent/lifecycle_contract/handoff_error.rb +0 -7
- data/lib/phronomy/agent/persistence/handoff_state_repository.rb +0 -58
- data/lib/phronomy/agent/persistence/queries.rb +0 -61
- data/lib/phronomy/agent/selection/candidate.rb +0 -53
- data/lib/phronomy/agent/selection/constraint.rb +0 -49
- data/lib/phronomy/agent/tool_execution/tool_call_intercepted.rb +0 -29
- data/lib/phronomy/agent/tool_execution/tool_invocation_session_builder.rb +0 -276
- data/lib/phronomy/configuration/configuration.rb +0 -68
- data/lib/phronomy/configuration/global_configuration.rb +0 -26
- data/lib/phronomy/engine/concurrency/cancellation_scope.rb +0 -124
- data/lib/phronomy/engine/concurrency/operation_binding.rb +0 -43
- data/lib/phronomy/engine/execution_receiver.rb +0 -65
- data/lib/phronomy/engine/runnable.rb +0 -54
- data/lib/phronomy/llm_adapter/ruby_llm.rb +0 -47
- data/lib/phronomy/llm_contract/token_usage.rb +0 -85
- data/lib/phronomy/multi_agent/persistence/queries.rb +0 -30
- data/lib/phronomy/multi_agent/storage_contract/team_storage_schema.rb +0 -15
- data/lib/phronomy/output_parser/contract/parse_error.rb +0 -7
- data/lib/phronomy/persistence/api/persistence.rb +0 -140
- data/lib/phronomy/persistence_composition/repositories.rb +0 -77
- data/lib/phronomy/recovery/recovery.rb +0 -186
- data/lib/phronomy/tool/contract/tool_error.rb +0 -7
- data/lib/phronomy/vector_store/embeddings/base.rb +0 -44
- data/lib/phronomy/vector_store/embeddings/ruby_llm_embeddings.rb +0 -47
- data/lib/phronomy/workflow/phase_machine_builder.rb +0 -205
- data/lib/phronomy/workflow/storage_contract/workflow_storage_schema.rb +0 -9
- data/sig/phronomy/execution_receiver.rbs +0 -34
- data/sig/phronomy/llm_adapter.rbs +0 -11
- data/sig/phronomy/runtime.rbs +0 -76
- /data/lib/phronomy/agent/{context_assembly/context_importer.rb → context_importer.rb} +0 -0
- /data/lib/phronomy/{engine → execution}/backpressure_error.rb +0 -0
- /data/lib/phronomy/{engine → execution}/cancellation_error.rb +0 -0
- /data/lib/phronomy/{engine → execution}/concurrency/worker_input_restricted.rb +0 -0
- /data/lib/phronomy/{engine → execution}/event_loop_reentrancy_error.rb +0 -0
- /data/lib/phronomy/{engine → execution}/invalid_async_entry_action_error.rb +0 -0
- /data/lib/phronomy/{engine → execution}/invalid_async_transition_action_error.rb +0 -0
- /data/lib/phronomy/{engine → execution}/invalid_async_workflow_action_error.rb +0 -0
- /data/lib/phronomy/{engine → execution}/pool_shutdown_error.rb +0 -0
- /data/lib/phronomy/{engine → execution}/recursion_limit_error.rb +0 -0
- /data/lib/phronomy/{engine → execution}/runtime_shutdown_error.rb +0 -0
- /data/lib/phronomy/{engine → execution}/runtime_shutdown_reentrancy_error.rb +0 -0
- /data/lib/phronomy/{engine → execution}/scheduler_reentrancy_error.rb +0 -0
- /data/lib/phronomy/{engine → execution}/timeout_error.rb +0 -0
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
# Agent Chat and explicit state ownership (R09, second slice)
|
|
2
2
|
|
|
3
|
+
> Current boundary: r8 unit 6 supersedes the historical Chat/SDK ownership and
|
|
4
|
+
> adapter extension SPI below. Agent uses LLMAdapter values; the backend owns SDK
|
|
5
|
+
> construction/interception; Tool owns canonical schema validation. See
|
|
6
|
+
> `docs/architecture/r8-unit6.md` and `docs/migrations/r8-unit6.md`.
|
|
7
|
+
|
|
8
|
+
|
|
3
9
|
## Purpose and clients
|
|
4
10
|
|
|
5
11
|
Agent::Base is the declaration and lifecycle facade used by application Agent
|
|
@@ -62,7 +68,7 @@ hook retains application/test overrides of apply_instructions and Orchestrator's
|
|
|
62
68
|
prepare_tool_class(invocation:) cooperation. Moving it into a builder receiving
|
|
63
69
|
the entire Agent would merely introduce callbacks back into Base.
|
|
64
70
|
|
|
65
|
-
|
|
71
|
+
InvocationActions and EngineSessionBuilder and InvocationRestorer keep using the same hooks.
|
|
66
72
|
Saved config is authoritative during recovery; current class declarations do
|
|
67
73
|
not overwrite it. A failure stops installation at that operation, propagates
|
|
68
74
|
the same error and does not install later Tools/messages. No new Chat cache,
|
|
@@ -1,89 +1,13 @@
|
|
|
1
|
-
# Agent
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
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.
|
|
1
|
+
# Agent transition ownership (r8 unit 7)
|
|
2
|
+
|
|
3
|
+
InvocationTransitions owns both automatic and external transitions, including
|
|
4
|
+
ordered guard evaluation. InvocationActions owns Agent entry operations.
|
|
5
|
+
EngineSessionBuilder configures FSMSession using those definitions;
|
|
6
|
+
PhaseMachineBuilder adapts them to state_machines without defining progress rules.
|
|
7
|
+
ExecutionCoordinator and RecoveryCoordinator retain durable decisions and use
|
|
8
|
+
the Agent-owned ExecutionEnvironment port for execution connection.
|
|
9
|
+
|
|
10
|
+
See [r8 unit 7](r8-unit7.md) and [ADR-067](../decisions/067-agent-progress-and-engine-connection.md).
|
|
11
|
+
Existing event source validation, callback failure priority, short-circuiting,
|
|
12
|
+
Tool outcome priority, suspended/wait/terminal boundaries and session incarnation
|
|
13
|
+
rules are preserved. Agent's Tool child FSM is still a separate remaining task.
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
# Backend responsibilities and asynchronous execution clients
|
|
2
|
+
|
|
3
|
+
The diagram distinguishes responsibility **groups** from its display layers.
|
|
4
|
+
The earlier B1-B6 horizontal bands and topical columns are restored for
|
|
5
|
+
readability. `G14`, `G46`, `G47` and `G48` remain stable responsibility identifiers;
|
|
6
|
+
boundary permissions follow those responsibilities, not B/G numbers or positions.
|
|
7
|
+
Each source directory keeps its own module box and stable module ID. Restoring
|
|
8
|
+
the display does not undo the separation of backend contracts and execution.
|
|
9
|
+
|
|
10
|
+
The restored display puts separated Backend Contracts in B5, alongside but
|
|
11
|
+
distinct from Engine Internals and Execution Contracts. B4 holds Async Clients and separately grouped Implementations. Execution
|
|
12
|
+
operations and values now share G58; the former G59 service split is removed. Backend directories awaiting separation remain visibly mixed
|
|
13
|
+
in B4; their contracts move to B5 in their implemented phase. These are display
|
|
14
|
+
positions, not a shared architectural level or namespace.
|
|
15
|
+
|
|
16
|
+
| Group | Responsibility | Dependency rule |
|
|
17
|
+
|---|---|---|
|
|
18
|
+
| G14 Engine Internals | Runtime, workers, FSM and EventLoop | No feature-specific backend or client dependencies |
|
|
19
|
+
| G58 Execution Framework | Submission protocol, TaskResult, Execution, Blocking, controls and common rules | Only Execution and Common, including neutral settings; Engine implements the mechanism |
|
|
20
|
+
| G46 Async Clients | Execute synchronous backend operations through Execution | Use Backend and Execution contracts; no direct Engine or concrete backend selection |
|
|
21
|
+
| G47 Backend Contracts | Synchronous SPI, values, errors and shared rules | No Engine, Execution Services, Async Client or concrete implementation dependencies |
|
|
22
|
+
| G48 Backend Implementations | Implement the synchronous backend SPI | Depend on the corresponding Contracts; no Engine, Execution Services or client dependencies |
|
|
23
|
+
| G57 Content Service | Content IDs, canonical text/JSON and digest integrity over Storage | Uses neutral Storage and Common; no physical backend, Engine or domain orchestration dependencies |
|
|
24
|
+
|
|
25
|
+
Composition chooses concrete backends and supplies them to consumers. These
|
|
26
|
+
are source-ownership groups, not shared Ruby namespaces. Synchronous APIs can
|
|
27
|
+
be called directly. Diagram links represent source references; calls through
|
|
28
|
+
injected objects require separate runtime review.
|
|
29
|
+
|
|
30
|
+
## Implemented phase: P1/P2/P3/P4 (`storage`)
|
|
31
|
+
|
|
32
|
+
P3 adds public VectorStore and Embeddings AsyncClients. Their synchronous
|
|
33
|
+
contracts and implementations have no Engine dependencies. See the
|
|
34
|
+
[public receiver migration](../migrations/vector-async-clients.md).
|
|
35
|
+
|
|
36
|
+
### P2: LLM
|
|
37
|
+
|
|
38
|
+
- Install the AST analyzer, group annotations, SVG formatter and boundary gate
|
|
39
|
+
in `tools/architecture/`. The Architecture workflow checks the committed
|
|
40
|
+
phase and generates evidence for its actual checkout SHA.
|
|
41
|
+
- `LLMAdapter::Base` now defines synchronous generation plus chat construction,
|
|
42
|
+
configuration, message/tool-call values, identity and optional input budget.
|
|
43
|
+
RubyLLM-specific construction and error translation belong to its backend.
|
|
44
|
+
Adapter extensions must implement the new operations; no legacy wrapper remains.
|
|
45
|
+
- `LLMAdapter::AsyncClient` owns the internal `complete_async` and `stream_async`
|
|
46
|
+
operations in `llm_adapter/async/`. It is not a public extension API.
|
|
47
|
+
- `LLMAdapter::RubyLLM` lives in `llm_adapter/backends/` and still inherits Base.
|
|
48
|
+
Its public name, synchronous signatures and default configuration are unchanged.
|
|
49
|
+
- Zeitwerk collapses these two new directories. Neither `Phronomy::Async` nor
|
|
50
|
+
`LLMAdapter::Async` / `LLMAdapter::Backends` is introduced.
|
|
51
|
+
- Agent constructs the framework client around the configured synchronous
|
|
52
|
+
adapter. Custom adapters implement no async methods and need no pool logic.
|
|
53
|
+
|
|
54
|
+
The client preserves `on_full: :raise`, the original pool TaskResult, token
|
|
55
|
+
forwarding and per-chunk cancellation. Transport timeout/retry stays with the
|
|
56
|
+
adapter/provider. Construction starts no Runtime, and the default pool is
|
|
57
|
+
resolved again on each operation; an injected pool stays caller-owned. Only an
|
|
58
|
+
internal lightweight sink runs on the worker; application event callbacks
|
|
59
|
+
continue to run on EventLoop.
|
|
60
|
+
|
|
61
|
+
Use `require "phronomy"` and the public constants. The old implementation path
|
|
62
|
+
`phronomy/llm_adapter/ruby_llm` moves to
|
|
63
|
+
`phronomy/llm_adapter/backends/ruby_llm`; arbitrary partial-load paths are not the
|
|
64
|
+
public loading contract. No shim in the contract directory reintroduces an
|
|
65
|
+
implementation dependency. No public RBS or Stable/Beta API snapshot changes
|
|
66
|
+
are needed in this phase; both are verified unchanged.
|
|
67
|
+
|
|
68
|
+
### P3: VectorStore and Embeddings
|
|
69
|
+
|
|
70
|
+
- `VectorStore::AsyncClient` owns public add/search/remove/clear async operations;
|
|
71
|
+
`VectorStore::Embeddings::AsyncClient` owns public `embed_async`.
|
|
72
|
+
- Backends implement only synchronous methods. The old `AsyncBackend` mixin
|
|
73
|
+
and inherited async methods are removed; application callers change receiver.
|
|
74
|
+
- InMemory, Pgvector, RedisSearch and RubyLLMEmbeddings move into `backends/`
|
|
75
|
+
directories. Their public constants, synchronous signatures and bodies stay
|
|
76
|
+
unchanged. Zeitwerk explicitly collapses the new `async/` and `backends/` paths.
|
|
77
|
+
- Synchronous RBS uses structural `_CancellationSignal`; async signatures keep
|
|
78
|
+
TaskResult and the execution token. The public API snapshot records the new
|
|
79
|
+
receivers and the intentional removals from Base/InMemory.
|
|
80
|
+
- All three original backend-to-Engine edges are removed. In the measured view,
|
|
81
|
+
M28/M29 join G47 Contracts in B5. M67/M68 are clients in B4 and M71/M72 are
|
|
82
|
+
separately grouped implementations. No pending Storage clients are drawn.
|
|
83
|
+
|
|
84
|
+
### P4: Storage execution
|
|
85
|
+
|
|
86
|
+
- Public `Storage::AsyncClient#transaction_async` opens the raw backend transaction
|
|
87
|
+
on a worker and yields its scoped Storage::View. Backends stay synchronous.
|
|
88
|
+
- Private `Storage::AsyncClient.submit(pool:)` executes existing domain units
|
|
89
|
+
without adding a transaction, timeout or token. All 16 durable submission sites
|
|
90
|
+
are recorded in the [execution inventory](storage-execution-boundaries.md).
|
|
91
|
+
- M69 is an Async Client and M35 a concrete Storage backend in B4.
|
|
92
|
+
Existing `Storage::Backends` is not collapsed.
|
|
93
|
+
- See the [public API and transaction rules](../migrations/storage-async-client.md).
|
|
94
|
+
|
|
95
|
+
### ContentStore service ownership
|
|
96
|
+
|
|
97
|
+
ContentStore is a content management service using Storage, not a peer physical
|
|
98
|
+
backend. Its API, canonicalization, StoredContents implementation and owned
|
|
99
|
+
StorageSchema live in `content_store/`. Base remains shared by StoredContents
|
|
100
|
+
and the Persistence exception facade. The unnecessary `backends/` subdivision
|
|
101
|
+
and Zeitwerk collapse are removed without a forwarding file or alias.
|
|
102
|
+
|
|
103
|
+
M10 belongs to G57 Content Service in the persistence column of display band B3.
|
|
104
|
+
M73 is retired, not reused. G47/G48 contain no ContentStore modules. The real
|
|
105
|
+
M10-to-Storage dependency remains in both the drawing and the full graph.
|
|
106
|
+
The boundary gate rejects reverse Storage-to-ContentStore dependencies and any
|
|
107
|
+
service path to a physical backend, Engine, client or domain orchestration.
|
|
108
|
+
Public constants, signatures, content IDs, exceptions and transaction behavior
|
|
109
|
+
remain unchanged. See [ADR-062](../decisions/062-content-store-service.md).
|
|
110
|
+
|
|
111
|
+
## r8 unit 1 framework boundaries
|
|
112
|
+
|
|
113
|
+
G58/M76/M77 now owns the common Execution framework under `execution/`.
|
|
114
|
+
Engine owns FSM-specific values and the pool/timer/runtime binding, while
|
|
115
|
+
composition selects that binding. Tracing owns explicit observation. Context
|
|
116
|
+
and Tool now own their shared operations, not merely value/error declarations.
|
|
117
|
+
The former G59/M78 split is retired. See [r8 unit 1](r8-unit1.md) for the exact
|
|
118
|
+
implemented scope, API removals and incomplete Persistence/domain work.
|
|
119
|
+
|
|
120
|
+
The full architecture still contains existing cycles outside the checked scope.
|
|
121
|
+
The recorded graph is not an ideal final r8 diagram.
|
|
122
|
+
|
|
123
|
+
## Pending phase
|
|
124
|
+
|
|
125
|
+
P5 completes the final cross-repository/API/docs review after application.
|
|
126
|
+
All retained P2-P4 responsibilities exist in source; the unnecessary M73 split
|
|
127
|
+
is superseded by G57 service ownership. The measured SVG still comes from
|
|
128
|
+
actual Ruby analysis; the target concept is a separate explanatory artifact.
|
|
129
|
+
|
|
130
|
+
## Regenerate and review
|
|
131
|
+
|
|
132
|
+
See [tool instructions](../../tools/architecture/README.md). The normal command
|
|
133
|
+
reads `tools/architecture/phase.json`:
|
|
134
|
+
|
|
135
|
+
```sh
|
|
136
|
+
python tools/architecture/refresh_diagram.py . tmp/architecture
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
The output includes the matrix, source hashes, boundary report, module/file
|
|
140
|
+
cycles and the delta from baseline 84668606. Source/module/group changes require
|
|
141
|
+
matching annotation updates. No up/down rule or coordinate controls the gate.
|
|
142
|
+
Ruby loader, RBS, cancellation, admission, streaming and configuration tests
|
|
143
|
+
remain necessary: static analysis does not replace them.
|
|
144
|
+
|
|
145
|
+
An unpublished local candidate must use `--candidate`. Its SVG states that it
|
|
146
|
+
is unapplied and disables GitHub source links. Applied commits and CI output
|
|
147
|
+
use actual source links. CI artifacts are generated after the source commit;
|
|
148
|
+
there is no self-referential SVG commit hash or automatic commit/push.
|
|
149
|
+
|
|
150
|
+
Text panels are transparent and module outlines/group colors remain intact.
|
|
151
|
+
Arrows into M33/M41/M44 are hidden by presentation settings; their AST edges,
|
|
152
|
+
source evidence and matrix cells are preserved. Boundary rules inspect all edges.
|
|
@@ -28,10 +28,10 @@ candidates are accumulated in hook order.
|
|
|
28
28
|
|
|
29
29
|
## 3. Input and result
|
|
30
30
|
|
|
31
|
-
Hooks receive immutable `Phronomy::
|
|
31
|
+
Hooks receive immutable `Phronomy::Context::LLMInputBuildContext` metadata. They do
|
|
32
32
|
not receive a mutable Provider chat/message array.
|
|
33
33
|
|
|
34
|
-
A hook returns `Phronomy::
|
|
34
|
+
A hook returns `Phronomy::Context::LLMInputPatch` or `nil`.
|
|
35
35
|
|
|
36
36
|
These two types live in the shared `agent/context_contract/` implementation
|
|
37
37
|
directory together with the Policy input and result contracts. Zeitwerk
|
|
@@ -40,7 +40,7 @@ names. Hook registration, invocation, and result handling are unchanged; see
|
|
|
40
40
|
[ADR-036](../decisions/036-context-contract-ownership.md).
|
|
41
41
|
|
|
42
42
|
```ruby
|
|
43
|
-
Phronomy::
|
|
43
|
+
Phronomy::Context::LLMInputPatch.new(
|
|
44
44
|
model_config_patch: {temperature: 0.2},
|
|
45
45
|
segment_candidates: [
|
|
46
46
|
{
|
|
@@ -85,7 +85,7 @@ same abstraction level.
|
|
|
85
85
|
Application code supplies an ordinary reusable Ruby strategy object:
|
|
86
86
|
|
|
87
87
|
```ruby
|
|
88
|
-
class SearchContextPolicy < Phronomy::
|
|
88
|
+
class SearchContextPolicy < Phronomy::Context::ContextPolicy
|
|
89
89
|
def initialize(search:)
|
|
90
90
|
@search = search
|
|
91
91
|
end
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
# Agent scope and incarnation lifetime (DX05-E core)
|
|
2
|
+
|
|
3
|
+
An application decides how long it needs an Agent. C04 owns the mechanics for
|
|
4
|
+
acquiring that incarnation and releasing it safely. A scope does not delete saved
|
|
5
|
+
Agents, stop other Agents, close an application-owned Store, or infer whether a
|
|
6
|
+
business operation should be retried.
|
|
7
|
+
|
|
8
|
+
## Application change
|
|
9
|
+
|
|
10
|
+
Before, a long-running application could create Agents for each request, but
|
|
11
|
+
the Runtime retained their mutable incarnations until shutdown. `close!` changes
|
|
12
|
+
the durable Agent lifecycle; `purge!` deletes saved state. Neither is a substitute
|
|
13
|
+
for releasing a process-local incarnation.
|
|
14
|
+
|
|
15
|
+
```ruby
|
|
16
|
+
agent = ReviewAgent.create(persistence: store)
|
|
17
|
+
agent.invoke(text) # the Runtime still owns this incarnation afterwards
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
After, the application declares the ownership boundary once:
|
|
21
|
+
|
|
22
|
+
```ruby
|
|
23
|
+
Phronomy::Agent.open_scope do |agents|
|
|
24
|
+
agent = agents.create(ReviewAgent, persistence: store)
|
|
25
|
+
agent.invoke_async(text)
|
|
26
|
+
end
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
`open_scope` waits for a returned TaskResult and returns its resolved value (or
|
|
30
|
+
raises the original exception). A plain block value is returned unchanged.
|
|
31
|
+
It then attempts to unload every Agent it acquired. A Workflow can use
|
|
32
|
+
`agents.create_async` or `agents.load_async` from EventLoop and compose their
|
|
33
|
+
TaskResults. The outer application keeps the scope alive until the Workflow has
|
|
34
|
+
finished. A scope is not serializable Workflow context.
|
|
35
|
+
|
|
36
|
+
An existing application-owned Agent cannot be adopted by `scope.load`: that
|
|
37
|
+
would give the scope permission to release someone else's object. The attempt
|
|
38
|
+
raises `AgentBusyError`. Repeated load in the same scope returns its live instance,
|
|
39
|
+
after checking class and Store compatibility. A listener cannot be replaced on
|
|
40
|
+
an already live instance. Existing `Agent.load`/`get` lookup semantics remain;
|
|
41
|
+
obtaining a reference does not extend its owning scope's lifetime.
|
|
42
|
+
|
|
43
|
+
## Release contract
|
|
44
|
+
|
|
45
|
+
`agent.unload_async` returns `TaskResult<Boolean>` and is EventLoop-safe.
|
|
46
|
+
`agent.unload!(timeout: nil)` waits externally. Both preserve all durable state:
|
|
47
|
+
root and context revisions, journal position, contents, history, metadata and
|
|
48
|
+
lifecycle status. A closed Agent remains closed after reload.
|
|
49
|
+
|
|
50
|
+
Release requires an exact live owner, no accepted operations or execution
|
|
51
|
+
admission (including approval and recovery waits), and an idle durable execution
|
|
52
|
+
ledger with no retention references. C04 interprets only the presence of opaque
|
|
53
|
+
retention references; their owning domain decides when to remove them.
|
|
54
|
+
|
|
55
|
+
Concurrent release requests share the pending handle. A successful release
|
|
56
|
+
returns `true`; an already unloaded reference returns `false`. A wait timeout
|
|
57
|
+
does not cancel the release. Store check failure rolls back the reservation and
|
|
58
|
+
preserves the original error. Runtime shutdown closes admission and drains
|
|
59
|
+
already accepted transition completion without creating a replacement Runtime.
|
|
60
|
+
|
|
61
|
+
New operations cannot enter during release. Old Agent operations fail with
|
|
62
|
+
`AgentUnloadedError` (`code: "agent.unloaded"`, `agent_id`); asynchronous methods
|
|
63
|
+
return failed TaskResults. Immutable snapshots and `agent_id` remain usable.
|
|
64
|
+
A later load creates a new instance and can bind a new listener. The old
|
|
65
|
+
reference cannot mutate or release that new owner. Purged Agents keep their
|
|
66
|
+
existing `AgentPurgedError` semantics.
|
|
67
|
+
|
|
68
|
+
A concurrent `get` or `load` during release raises `AgentBusyError` immediately;
|
|
69
|
+
it does not wait or create a second owner. Accepted operations make unload fail
|
|
70
|
+
with Busy at its admission gate. In particular, unload inside an Agent terminal
|
|
71
|
+
listener is Busy while that listener is executing. Exit the outer application
|
|
72
|
+
scope after result delivery to release it. Existing immutable local-state reads
|
|
73
|
+
remain available while Runtime shutdown is draining an incomplete transition;
|
|
74
|
+
new execution and mutation admission stays closed.
|
|
75
|
+
|
|
76
|
+
## Failure and cancellation
|
|
77
|
+
|
|
78
|
+
Scope tracks materialization receipts before starting work and registers acquired
|
|
79
|
+
Agents before returning them. Closure stops new acquisition and waits for the
|
|
80
|
+
physical completion of accepted materialization, even when its handle was
|
|
81
|
+
cancelled. Indeterminate durable create keeps the C04 recovery reservation and
|
|
82
|
+
logs the Agent ID; it is never silently made creatable again.
|
|
83
|
+
|
|
84
|
+
Scope does not cancel or wait for unjoined child execution as an implicit
|
|
85
|
+
cleanup policy. An active Agent is retained and cleanup reports `AgentBusyError`.
|
|
86
|
+
If the main operation failed, its same exception is preserved and secondary
|
|
87
|
+
cleanup failures are logged with Agent IDs. Logger failure cannot replace it.
|
|
88
|
+
If the main operation succeeded, failed cleanup raises `Agent::ScopeCleanupError`
|
|
89
|
+
(`code: "agent.scope_cleanup_failed"`). `result` preserves the successful value;
|
|
90
|
+
`failures` is an array of `{agent_id:, error:}` with the original exceptions.
|
|
91
|
+
All acquired Agents are attempted. No automatic retry, purge, or retention
|
|
92
|
+
removal is performed.
|
|
93
|
+
|
|
94
|
+
## Responsibility and ordering
|
|
95
|
+
|
|
96
|
+
- C04 owns scope receipts, exact incarnation identity, operation admission,
|
|
97
|
+
busy/retention rules, invalidation and cleanup errors.
|
|
98
|
+
- C07 supplies the existing transaction boundary. C04's Agent Store supplies
|
|
99
|
+
`assert_idle!`, `guard_agent!` and retention reads; neither Persistence nor
|
|
100
|
+
physical Storage gains incarnation release policy.
|
|
101
|
+
- C13 supplies existing TaskResult and physical-completion contracts. It gains
|
|
102
|
+
no scope membership, Agent busy rules or unload states.
|
|
103
|
+
- Engine supplies existing worker execution, serial EventLoop delivery and
|
|
104
|
+
shutdown participation. It gains no Agent-specific states.
|
|
105
|
+
- The operation lease and release reservation share the C04 ownership mutex.
|
|
106
|
+
No Store transaction, Runtime call, application callback or blocking wait runs
|
|
107
|
+
under that mutex. Accepted runner continuations use C04 internal snapshots;
|
|
108
|
+
callbacks initiating a new public operation must acquire a new lease.
|
|
109
|
+
- Agent operation completion is distinct from cancelling its public handle.
|
|
110
|
+
C04 acknowledges release after domain terminal/listener delivery and physical
|
|
111
|
+
worker completion. A queued or physically running cancelled operation still
|
|
112
|
+
blocks release.
|
|
113
|
+
|
|
114
|
+
For notifications, finish child processing, drain notifications, then exit the
|
|
115
|
+
Agent scope. `run_once` retains its existing Store and lifetime behavior; merely
|
|
116
|
+
calling it does not opt into scope cleanup.
|
|
117
|
+
|
|
118
|
+
This is P5 (core). P6 migrates application examples and performs cross-repository
|
|
119
|
+
acceptance against the published or pinned candidate core.
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
# DX05-D: Workflow-owned asynchronous task states
|
|
2
|
+
|
|
3
|
+
Status: unreleased Beta implementation. Based on DX05-A core `c673c958c`.
|
|
4
|
+
|
|
5
|
+
## Problem and intended application boundary
|
|
6
|
+
|
|
7
|
+
A Workflow application describes which operation a stage starts, how its result
|
|
8
|
+
changes business state, and where that state goes next. Repeating callbacks,
|
|
9
|
+
completion events, error envelopes and state-entry identifiers obscures those
|
|
10
|
+
choices. Workflow already owns the live execution and state-entry lifetime, so it
|
|
11
|
+
can own this correlation without knowing how an Agent, Tool or LLM runs.
|
|
12
|
+
|
|
13
|
+
The business flow is preserved. Failure, cancellation, stale-result and delivery
|
|
14
|
+
semantics become explicit and stronger; this is not a claim that every failure
|
|
15
|
+
path of the previous manual recipe was equivalent.
|
|
16
|
+
|
|
17
|
+
## Before and after
|
|
18
|
+
|
|
19
|
+
Previously, each state manually arranged delivery (simplified successful path):
|
|
20
|
+
|
|
21
|
+
```ruby
|
|
22
|
+
workflow = nil
|
|
23
|
+
workflow = Phronomy::Workflow.define(AnswerState) do
|
|
24
|
+
initial :asking
|
|
25
|
+
state :asking
|
|
26
|
+
entry :asking, ->(state) {
|
|
27
|
+
id = state.workflow_instance_id
|
|
28
|
+
agent.invoke_async(state.question).on_complete do |value, error|
|
|
29
|
+
workflow.signal(workflow_instance_id: id, event: :answer_ready,
|
|
30
|
+
payload: {value: value, error: error})
|
|
31
|
+
end
|
|
32
|
+
state
|
|
33
|
+
}
|
|
34
|
+
transition from: :asking, on: :answer_ready, to: :__finish__,
|
|
35
|
+
action: ->(state, event) {
|
|
36
|
+
raise event.payload[:error] if event.payload[:error]
|
|
37
|
+
state.merge(answer: event.payload.fetch(:value).fetch(:output))
|
|
38
|
+
}
|
|
39
|
+
end
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
That snippet also needs rejection handling and entry-specific guards for safe
|
|
43
|
+
reentry. The application now writes only the operation and successful update:
|
|
44
|
+
|
|
45
|
+
```ruby
|
|
46
|
+
workflow = Phronomy::Workflow.define(AnswerState) do
|
|
47
|
+
initial :asking
|
|
48
|
+
task_state :asking,
|
|
49
|
+
start: ->(state) { agent.invoke_async(state.question) },
|
|
50
|
+
apply: ->(state, result) { state.merge(answer: result.fetch(:output)) }
|
|
51
|
+
transition from: :asking, to: :__finish__
|
|
52
|
+
end
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
`start` receives an isolated context snapshot, including current phase and
|
|
56
|
+
Workflow identity. It must return a `Phronomy::TaskResult` promptly. It must not
|
|
57
|
+
perform blocking I/O or wait for another Task. Use `Blocking.call_async` for real
|
|
58
|
+
blocking work. `apply` receives the current context and successful value, runs
|
|
59
|
+
briefly on EventLoop, and returns the same context type or nil. Normal transition
|
|
60
|
+
guards run after `apply`. Nil means no context replacement, not failure.
|
|
61
|
+
|
|
62
|
+
A task state may have ordinary entry/exit actions and external transitions.
|
|
63
|
+
Leaving it abandons observation of its source. Declaring the same state as both
|
|
64
|
+
`state`/`wait_state` and `task_state` is rejected. Ordinary entry/transition actions
|
|
65
|
+
still cannot return a TaskResult. Business signals keep their existing API.
|
|
66
|
+
|
|
67
|
+
## Contract ownership
|
|
68
|
+
|
|
69
|
+
| Owner | Responsibility |
|
|
70
|
+
|---|---|
|
|
71
|
+
| C02 Workflow | Task-state definition; live execution and state-entry reception; once-only consumption; success application, failure/cancellation classification; stale-result and queued-progression rejection; restart policy |
|
|
72
|
+
| C13 Execution | Thread-safe TaskResult notification and cancellation subscription mechanisms |
|
|
73
|
+
| I07 Workflow runtime binding | Connect C02 decisions to the existing FSM, owner EventLoop and owner Runtime timer/shutdown services |
|
|
74
|
+
| Engine | Generic event/session delivery and lifecycle; no task-state or Agent policy is added |
|
|
75
|
+
| C04 Agent and application | Agent execution, business transformation/fallback, child cancellation policy and producer lifetime |
|
|
76
|
+
|
|
77
|
+
C02 uses its execution-environment port and receives an injected session
|
|
78
|
+
connection. It does not select Runtime or depend on I07. `WorkflowTaskSession`
|
|
79
|
+
in I07 adapts the generic FSMSession. Engine source is unchanged.
|
|
80
|
+
|
|
81
|
+
A revocable C02 reception is created before `start`. Source callbacks retain only
|
|
82
|
+
that reception. Closing it drops source and registry references. Completion is
|
|
83
|
+
sent to the originating registry under an opaque execution owner token, never
|
|
84
|
+
rerouted by a durable Workflow ID. Receiver-side validation checks the current
|
|
85
|
+
entry and consumes once. Exits, reentry, cancellation and terminal decisions
|
|
86
|
+
revoke it. Queued automatic progression also carries an entry-specific key:
|
|
87
|
+
an external transition between result application and automatic dispatch cannot
|
|
88
|
+
advance a later entry. These private messages are not public business signals.
|
|
89
|
+
|
|
90
|
+
## Outcomes and lifetime
|
|
91
|
+
|
|
92
|
+
| Condition | Caller-visible result |
|
|
93
|
+
|---|---|
|
|
94
|
+
| Start throws, source fails, or apply throws | Workflow fails with the same error object |
|
|
95
|
+
| Source status is `cancelled` | Workflow TaskResult is cancelled with the source error |
|
|
96
|
+
| Source status is `failed` with a CancellationError | Remains failed; class alone does not imply cancellation |
|
|
97
|
+
| Explicit parent token cancellation/deadline | Cancel Workflow observation; do not implicitly cancel the source |
|
|
98
|
+
| Old or duplicated source notification | Ignore; no application or retry |
|
|
99
|
+
| Current completion delivery rejects/throws | Fail on the owner; if owner delivery is wholly unavailable, settle observation only and retain admission until shutdown cleanup |
|
|
100
|
+
| Runtime shutdown while waiting | Settle observation and revoke subscriptions; no claim that child work physically stopped |
|
|
101
|
+
| Known durable terminal result | Use existing save/readback classification and release rules |
|
|
102
|
+
| Unknown durable terminal result | Fail the observation while retaining recovery-required ownership |
|
|
103
|
+
|
|
104
|
+
Cancellation is serialized on the owning EventLoop. Once terminal persistence
|
|
105
|
+
has begun, its existing durable barrier remains authoritative; later cancellation
|
|
106
|
+
does not reverse a committed or uncertain terminal decision. A source passed to
|
|
107
|
+
the state has an independent lifetime. Applications explicitly pass cancellation
|
|
108
|
+
controls to children when desired; they own Agent release and side effects.
|
|
109
|
+
|
|
110
|
+
This API creates no thread/worker for logical waits. Actual I/O and existing
|
|
111
|
+
tracing or checkpoint work may still use the bounded pool. Expected business
|
|
112
|
+
failures may be transformed into ordinary values through TaskResult composition.
|
|
113
|
+
The API does not infer retry, fallback, durable child execution or delivery ACKs.
|
|
114
|
+
|
|
115
|
+
## Persistence and restart
|
|
116
|
+
|
|
117
|
+
Normal completion and ordinary `wait_state` halts use existing Workflow
|
|
118
|
+
checkpoints. Resuming an ordinary wait into a new task state is supported. Pending
|
|
119
|
+
TaskResults, callbacks and entry keys are process-local and are never serialized.
|
|
120
|
+
Restoring a snapshot whose phase is a task state raises
|
|
121
|
+
`Phronomy::WorkflowTaskResumeError` (C02, subclass of `Phronomy::Error`, code
|
|
122
|
+
`workflow.task_resume_unsupported`) before running its start callback. The
|
|
123
|
+
application must reconcile that operation explicitly instead of automatically
|
|
124
|
+
repeating external side effects. F01 durable child execution remains separate.
|
|
125
|
+
|
|
126
|
+
## Verification
|
|
127
|
+
|
|
128
|
+
The new task-state regression suite covers immediate and delayed results,
|
|
129
|
+
repeated entry, old success/failure/cancellation, duplicate callbacks, external
|
|
130
|
+
transition races, rejected guards, delivery failure, shutdown, source/parent
|
|
131
|
+
cancellation, owner Runtime selection, retained-reference revocation, strict
|
|
132
|
+
callback result types, normal durable halt/resume, restart rejection and unknown
|
|
133
|
+
durable outcomes. Existing Workflow, TaskResult, API and executable-documentation
|
|
134
|
+
tests remain active. Examples 01/03/04/07/14/20/25/26 use the new API.
|