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,89 @@
|
|
|
1
|
+
# Agent invocation transition ownership
|
|
2
|
+
|
|
3
|
+
## Role and scope
|
|
4
|
+
|
|
5
|
+
An Agent invocation moves between preparation, Provider calls, Tool processing,
|
|
6
|
+
approval suspension and completion. Three collaborators need the same policy:
|
|
7
|
+
AgentInvocation consumes external payloads; PhaseMachineBuilder creates the
|
|
8
|
+
executable state machine; AgentInvocationSessionBuilder configures FSMSession's
|
|
9
|
+
advance, wait and terminal boundaries. Independently maintained event lists and
|
|
10
|
+
transition copies could disagree about what the current phase can accept.
|
|
11
|
+
|
|
12
|
+
Refactor 39 gives that shared policy one private owner, InvocationTransitions in
|
|
13
|
+
agent/execution. This is Agent data in the existing transition Hash format, not
|
|
14
|
+
a new cross-feature DSL or Engine extension. It is not a new execution object.
|
|
15
|
+
|
|
16
|
+
## Ownership and reading order
|
|
17
|
+
|
|
18
|
+
| Owner | Responsibility |
|
|
19
|
+
|---|---|
|
|
20
|
+
| InvocationTransitions | Initial phase, declared/automatic/approval-wait states, Tool event vocabulary and ordered external transition definitions. |
|
|
21
|
+
| PhaseMachineBuilder | Translate those external definitions to state_machines; retain automatic state_completed transitions and synchronous entry-action validation. |
|
|
22
|
+
| AgentInvocationSessionBuilder | Assemble the invocation, event sink, entry actions and machine; pass shared state and transition metadata to FSMSession. |
|
|
23
|
+
| AgentInvocation | Apply payloads and expose the current guard predicates; use the shared Tool event vocabulary. |
|
|
24
|
+
| FSMSession | Generic advancement, event delivery and wait/terminal handling. No Agent-specific decisions. |
|
|
25
|
+
|
|
26
|
+
Read the policy table for legal external sources and guard priority, the machine
|
|
27
|
+
builder for execution mechanics, and the session builder for action wiring.
|
|
28
|
+
The EXTERNAL_EVENTS Hash, each transition array and each row are frozen so one
|
|
29
|
+
session cannot edit another session's policy. Guard lambdas contain no captured
|
|
30
|
+
invocation state; they inspect the context supplied at transition time.
|
|
31
|
+
Old private constants and the external_events factory are removed without aliases.
|
|
32
|
+
|
|
33
|
+
## Preserved event and phase contract
|
|
34
|
+
|
|
35
|
+
The six Tool events are authorized, approval_required, completed, failed,
|
|
36
|
+
rejected and cancelled, each with the tool_ prefix. Each moves waiting_for_tools
|
|
37
|
+
to evaluating_tools. LLM completion from calling_llm tries these in order:
|
|
38
|
+
|
|
39
|
+
1. callback_failed? to failed;
|
|
40
|
+
2. handoff_failed? to failed;
|
|
41
|
+
3. handoff_requested? to handed_off;
|
|
42
|
+
4. tool_call_pending? to starting_tools;
|
|
43
|
+
5. unconditional fallback to output_filtering.
|
|
44
|
+
|
|
45
|
+
Guards short-circuit. A nil context skips guarded rows and takes the fallback;
|
|
46
|
+
guard exceptions propagate unchanged. Each evaluation uses the latest context,
|
|
47
|
+
without caching a selected destination. Session applies the event payload first.
|
|
48
|
+
|
|
49
|
+
LLM failure/setup failure leads from calling_llm to failed. Tool setup failure
|
|
50
|
+
leads from dispatching_tools to failed, while tool_dispatch_prepared returns it
|
|
51
|
+
to evaluating_tools. Resume moves suspended to waiting_for_tools. Application
|
|
52
|
+
callback failure is accepted from the existing nine active phases only.
|
|
53
|
+
|
|
54
|
+
Automatic phases remain idle, filtering_input, building_context, starting_tools,
|
|
55
|
+
evaluating_tools, recording_tool_results and output_filtering. calling_llm,
|
|
56
|
+
waiting_for_tools and dispatching_tools wait for external events. suspended ends
|
|
57
|
+
a segment with halted; resume uses a fresh Session identity. The four declared
|
|
58
|
+
terminal phases remain handed_off, completed, blocked and failed.
|
|
59
|
+
|
|
60
|
+
FSMSession reads only the from field when determining external-event admission
|
|
61
|
+
and waiting. It does not execute metadata guards or choose their destinations;
|
|
62
|
+
state_machines does that. Known-but-undeclared and unknown events retain their
|
|
63
|
+
existing error behavior; context-consumed stale events retain their early exit.
|
|
64
|
+
The internal order of event registration now follows the shared table. Transition
|
|
65
|
+
order within each event, which determines behavior, is preserved. The generated
|
|
66
|
+
machine's private event-enumeration order is not a supported public contract.
|
|
67
|
+
|
|
68
|
+
## Verification and limits
|
|
69
|
+
|
|
70
|
+
Independent behavioral tests run on both Refactor 38 and the candidate: all 195
|
|
71
|
+
external-event/source-state combinations, all sixteen LLM condition combinations
|
|
72
|
+
including short-circuit order, nil context and guard exceptions, fifteen Session
|
|
73
|
+
boundaries, context-before-guard ordering, approval suspension/resume/dispatch,
|
|
74
|
+
and invalid source-state handling. Existing Agent, causal durability, Handoff,
|
|
75
|
+
Workflow and Engine tests continue to cover their collaborating behavior.
|
|
76
|
+
|
|
77
|
+
The candidate also runs the full core/integration suites, offline examples and
|
|
78
|
+
real SQLite, API/SPI snapshots, RBS, style, annotations and isolated gem checks.
|
|
79
|
+
No SQL, stored format, entry action implementation, Tool restoration, cancellation
|
|
80
|
+
or Coordinator sequencing is changed. The new contract tests isolate entry actions
|
|
81
|
+
and do not claim live Provider coverage. Live PostgreSQL/LLM and remote CI are
|
|
82
|
+
not executed for this candidate. Refactor 39 was independently verified after application at core 4d57614a,
|
|
83
|
+
tree 654241da4b2b7f32d988602d28127bc1fa155641. All 10 files and the full tree
|
|
84
|
+
matched, and core/integration/examples/SQLite/API/type/gem checks passed.
|
|
85
|
+
The published SVG is applied39-01.
|
|
86
|
+
|
|
87
|
+
R06 is applied and complete. R07 now has a Refactor 40 candidate; R08/D08, R09
|
|
88
|
+
and R10 remain afterward. R09's inheritance behavior and R10's action names
|
|
89
|
+
are not altered by the transition-ownership work.
|
|
@@ -33,6 +33,12 @@ not receive a mutable Provider chat/message array.
|
|
|
33
33
|
|
|
34
34
|
A hook returns `Phronomy::Agent::LLMInputPatch` or `nil`.
|
|
35
35
|
|
|
36
|
+
These two types live in the shared `agent/context_contract/` implementation
|
|
37
|
+
directory together with the Policy input and result contracts. Zeitwerk
|
|
38
|
+
collapses the directory, preserving their existing public `Phronomy::Agent`
|
|
39
|
+
names. Hook registration, invocation, and result handling are unchanged; see
|
|
40
|
+
[ADR-036](../decisions/036-context-contract-ownership.md).
|
|
41
|
+
|
|
36
42
|
```ruby
|
|
37
43
|
Phronomy::Agent::LLMInputPatch.new(
|
|
38
44
|
model_config_patch: {temperature: 0.2},
|
|
@@ -50,6 +50,36 @@ RubyLLMMaterializer
|
|
|
50
50
|
The normative Journal/Manifest split is
|
|
51
51
|
[ADR-012](../decisions/012-canonical-execution-log-and-context-policy.md).
|
|
52
52
|
|
|
53
|
+
### Contract ownership and physical layout
|
|
54
|
+
|
|
55
|
+
The contracts shared by Agent execution, Context policies, and input hooks live
|
|
56
|
+
in `lib/phronomy/agent/context_contract/`:
|
|
57
|
+
|
|
58
|
+
| Files | Responsibility |
|
|
59
|
+
|---|---|
|
|
60
|
+
| `context_policy.rb`, `context_policy_input.rb` | Policy protocol, helper methods, and typed input material |
|
|
61
|
+
| `context_plan.rb`, `context_plan_validator.rb` | Policy result and its validity rules |
|
|
62
|
+
| `llm_input_manifest.rb` | Final logical input representation and its format validation |
|
|
63
|
+
| `llm_input_build_context.rb`, `llm_input_patch.rb` | Input metadata and returned customization for hooks |
|
|
64
|
+
|
|
65
|
+
Zeitwerk collapses this directory. The Ruby constants keep their existing
|
|
66
|
+
`Phronomy::Agent::*` names; there is no `ContextContract` namespace or new
|
|
67
|
+
registration mechanism. Applications continue to load `phronomy` and use the
|
|
68
|
+
documented constants. The previous individual implementation file paths are
|
|
69
|
+
not retained as forwarding files.
|
|
70
|
+
|
|
71
|
+
`ContextPolicies::Default` remains a concrete strategy, while
|
|
72
|
+
`ContextAssembler`, input builders, candidate resolution, Runtime connections,
|
|
73
|
+
and persistence transactions remain on the execution side. The Manifest
|
|
74
|
+
validates and converts record values; it does not write to a storage backend.
|
|
75
|
+
Its format version, keys, and validation rules are unchanged.
|
|
76
|
+
|
|
77
|
+
This ownership decision is defined by
|
|
78
|
+
[ADR-036](../decisions/036-context-contract-ownership.md). Physical containment
|
|
79
|
+
under `agent/` does not assign the contracts to the execution layer. The
|
|
80
|
+
concrete policies and the shared contracts can occupy distinct groups at the
|
|
81
|
+
same abstraction level.
|
|
82
|
+
|
|
53
83
|
## 2. Public Context Policy SPI
|
|
54
84
|
|
|
55
85
|
Application code supplies an ordinary reusable Ruby strategy object:
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
# Context preparation steps
|
|
2
|
+
|
|
3
|
+
## Role and scope
|
|
4
|
+
|
|
5
|
+
ContextAssembler prepares the immutable semantic input supplied to Application
|
|
6
|
+
ContextPolicy and later validates and stores its decision as an LLMInputManifest.
|
|
7
|
+
InitialPreparation and DispatchPreparation run preparation outside their commit
|
|
8
|
+
transactions, recheck durable state, then call finalize in the commit transaction.
|
|
9
|
+
The public boundary and those callers already have separate responsibilities.
|
|
10
|
+
|
|
11
|
+
R07 addresses a narrower readability problem inside prepare_initial and
|
|
12
|
+
prepare_followup: orchestration was mixed with individual item IDs, provenance
|
|
13
|
+
and metadata, and record filtering plus Hook/Handoff merging were duplicated.
|
|
14
|
+
The original proposal calls for private extraction before adding collaborators.
|
|
15
|
+
Refactor 40 follows that limit: one production file changes; no class is added.
|
|
16
|
+
|
|
17
|
+
## Reading order and responsibilities
|
|
18
|
+
|
|
19
|
+
| Private operation | Responsibility |
|
|
20
|
+
|---|---|
|
|
21
|
+
| initial_instruction_items | Choose the initial Agent instruction and optional Handoff responsibility, in order. |
|
|
22
|
+
| agent_instruction_item | Build the required system instruction with its stable ID, estimate and Agent provenance. |
|
|
23
|
+
| handoff_instruction_item | Build the required user responsibility with its ID, estimate and Handoff origin. |
|
|
24
|
+
| retained_instruction_items | Read only retained base instructions from the previous Manifest, using the existing compatibility predicate and converter. |
|
|
25
|
+
| resolve_record_candidates | Filter working records by eligibility/current generation and resolve them with Journal candidates and caller-provided exclusions. |
|
|
26
|
+
| merge_context_candidates | Add Hook candidates, then Handoff candidates, using the existing creation, sorting and storage operations. |
|
|
27
|
+
| current_input_item | Build the initial required ask argument after all candidates, including ID, sequence, provenance and metadata. |
|
|
28
|
+
|
|
29
|
+
Public preparation keeps model/Tool settings, source loading and the sequence of
|
|
30
|
+
these operations visible. Record collection and candidate augmentation stay as
|
|
31
|
+
two steps: follow-up computes its next call sequence after record resolution,
|
|
32
|
+
exactly as before. No new options object, pipeline DSL, mutable preparation state
|
|
33
|
+
or cross-feature factory is introduced. Helpers remain private to the assembler.
|
|
34
|
+
|
|
35
|
+
## Preserved contracts
|
|
36
|
+
|
|
37
|
+
- Initial instructions come from the Agent configuration plus optional Handoff
|
|
38
|
+
responsibility. Follow-up instructions come from the retained base Manifest.
|
|
39
|
+
Current Hook instructions are rebuilt; previous Hook/Policy-generated items
|
|
40
|
+
do not become permanent base instructions. Legacy origin handling is unchanged.
|
|
41
|
+
- Working records must remain context candidates in the active transcript
|
|
42
|
+
generation. Initial preparation excludes the current input record; follow-up
|
|
43
|
+
includes eligible working records without that exclusion.
|
|
44
|
+
- Record candidates are resolved before Hook and then Handoff augmentation. The
|
|
45
|
+
current-input sequence follows all candidates, including non-conversation ones.
|
|
46
|
+
IDs, source fields, trust metadata, estimates, required flags, ordering, frozen
|
|
47
|
+
values and delivery modes retain their existing values.
|
|
48
|
+
- Initial input content is loaded before instruction-item construction and
|
|
49
|
+
candidate resolution. Initial instruction callbacks and patch normalization
|
|
50
|
+
retain their order. Hook content writes still precede Handoff type validation;
|
|
51
|
+
moving that validation earlier would be a behavior change and is not included.
|
|
52
|
+
- Preparation is not side-effect-free: Hook/Handoff content may be stored before
|
|
53
|
+
Policy succeeds. This extraction neither adds rollback nor suppresses existing
|
|
54
|
+
exceptions. Missing-input, reserved-metadata, resolver and Policy failures keep
|
|
55
|
+
their ordering; collaborator exception objects propagate unchanged.
|
|
56
|
+
- Application Policy executes once during prepare; finalize does not invoke it.
|
|
57
|
+
Finalization, its validation/encoding/store helpers, assembly policy version 8,
|
|
58
|
+
schemas, public signatures and transaction-owning callers are unchanged.
|
|
59
|
+
|
|
60
|
+
The new helpers use the same constructor field evaluation and call ordering.
|
|
61
|
+
They do not cache or deduplicate reads, normalize values earlier, or move work
|
|
62
|
+
across the prepare/finalize boundary merely to shorten the source.
|
|
63
|
+
|
|
64
|
+
## Verification and trade-off
|
|
65
|
+
|
|
66
|
+
Ten behavior examples cover initial item provenance/immutability, generation and
|
|
67
|
+
exclusion rules, content-write order, absent instructions/Handoff, follow-up
|
|
68
|
+
retention and current hooks, the prepare/finalize boundary and failure precedence.
|
|
69
|
+
The same examples pass on Refactor 39. Four independent baseline/candidate
|
|
70
|
+
scenario pairs compare complete Policy input, Prepared values, Manifest bytes and
|
|
71
|
+
content references, plus preparation-time content read/write order. The pairs
|
|
72
|
+
cover initial and follow-up calls with/without base instructions and Handoff.
|
|
73
|
+
|
|
74
|
+
Full core/integration suites, common examples and real SQLite, stable/beta API
|
|
75
|
+
and Storage SPI snapshots, RBS, style, annotations and isolated gem checks are
|
|
76
|
+
also run. Live PostgreSQL, live LLM, remote CI and performance are not exercised
|
|
77
|
+
for this candidate; prior CI is not evidence for the candidate's core.
|
|
78
|
+
|
|
79
|
+
prepare_initial is 103 -> 55 lines and prepare_followup 57 -> 47. The whole file
|
|
80
|
+
is 625 -> 672 lines because seven named private methods and explicit arguments
|
|
81
|
+
add structure. This is a readability and duplicated-procedure improvement, not a
|
|
82
|
+
net line-count reduction or a directory-cycle change. The methods' names give
|
|
83
|
+
readers a place to choose whether they need the detailed representation.
|
|
84
|
+
|
|
85
|
+
R07 was independently verified after application at core b3dfbc5a, tree
|
|
86
|
+
dcd9d1bf8efb1b488f9c2b3b1c4e99bdeda6096c. All six files and the full tree matched;
|
|
87
|
+
core/integration/examples/SQLite/API/type/gem and four paired scenarios passed.
|
|
88
|
+
R07 is complete. The published diagram is applied40-01. R08/D08 now has a Refactor
|
|
89
|
+
41 candidate, with R09 and R10 remaining afterward. Their behavior and naming
|
|
90
|
+
decisions are not part of Context preparation extraction.
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
# Entry-action names and Team task wording (R10)
|
|
2
|
+
|
|
3
|
+
## Scope
|
|
4
|
+
|
|
5
|
+
Refactor 44 follows applied Refactor 43, core
|
|
6
|
+
`5c4c039273eb2324fcc9e9943ccf40bd1ffb3abd`. It changes two private action names
|
|
7
|
+
and two Team-generated strings. No new production class, alias, state, event,
|
|
8
|
+
loader rule, persistence format or public method signature is introduced.
|
|
9
|
+
|
|
10
|
+
## Action names describe their local work
|
|
11
|
+
|
|
12
|
+
| Existing phase | Private action | Work |
|
|
13
|
+
|---|---|---|
|
|
14
|
+
| `filtering_input` | `apply_prepared_input_action` | Read `phronomy_filtered_input` from the prepared config and install it on the invocation. |
|
|
15
|
+
| `building_context` | `build_runtime_chat_action` | Build a Chat with the prepared projection's settings and apply its instructions, Tools and messages. |
|
|
16
|
+
|
|
17
|
+
These replace `filtering_input_action` and `building_context_action` respectively.
|
|
18
|
+
Their bodies, arguments, return values, exceptions and ordering are unchanged.
|
|
19
|
+
Input filtering and context preparation remain with the existing preparation
|
|
20
|
+
owners; these actions do not repeat that work. The first action keeps its unused
|
|
21
|
+
Agent argument so the existing bound-action construction remains unchanged.
|
|
22
|
+
|
|
23
|
+
Phase names, transition guards, callbacks and saved resume phases remain intact.
|
|
24
|
+
A phase is an existing lifecycle boundary; an entry-action name describes the
|
|
25
|
+
operation performed at that boundary. Renaming phases would require a separate
|
|
26
|
+
compatibility design for observation and saved executions.
|
|
27
|
+
|
|
28
|
+
## Team tasks and completion handles
|
|
29
|
+
|
|
30
|
+
| Surface | Before | After |
|
|
31
|
+
|---|---|---|
|
|
32
|
+
| `finalize.summary` parameter description | `TaskResult summary` | `Task generation summary` |
|
|
33
|
+
| Newly committed `enqueue_task` result | `TaskResult #N enqueued: ...` | `Task #N enqueued: ...` |
|
|
34
|
+
|
|
35
|
+
These are observable text changes, not solely internal renames. The description
|
|
36
|
+
is sent to the LLM. The enqueue response is saved in Team operation metadata and
|
|
37
|
+
subsequently supplied as a Tool result. The task description supplied by the
|
|
38
|
+
caller is not rewritten. Tool names, argument names, types, optionality, task IDs,
|
|
39
|
+
batch ordering, queue contents and cancellation behavior are unchanged.
|
|
40
|
+
`Phronomy::TaskResult` continues to mean the asynchronous completion handle.
|
|
41
|
+
Team integration examples now use `Task A/B/C` for business-task descriptions.
|
|
42
|
+
|
|
43
|
+
The existing operation-ID deduplication returns the stored result verbatim.
|
|
44
|
+
Already committed legacy `TaskResult #...` results therefore remain unchanged
|
|
45
|
+
on replay, including after restart. This change does not migrate old records,
|
|
46
|
+
rewrite Journals or reformat results during readback. Reusing an operation ID
|
|
47
|
+
with different arguments still fails the existing identity check.
|
|
48
|
+
|
|
49
|
+
## Verification and limits
|
|
50
|
+
|
|
51
|
+
The package checks the existing Agent transition and Chat contracts, durable
|
|
52
|
+
Team execution, full core/integration suites, offline examples, real SQLite,
|
|
53
|
+
API/SPI, types, style, gem loading and independent application. One additional
|
|
54
|
+
regression verifies legacy response replay after restart, no repeated writes,
|
|
55
|
+
the TaskResult return type and argument-identity rejection. It also passes on
|
|
56
|
+
the applied baseline.
|
|
57
|
+
|
|
58
|
+
Separate processes capture a committed finalize operation before its Agent
|
|
59
|
+
settlement and resume it using the other version, in both directions. Stored
|
|
60
|
+
operations remain byte-equivalent at the value level, tasks are not duplicated,
|
|
61
|
+
and the expected two remaining Provider calls occur. These are stubbed Provider
|
|
62
|
+
checks with an InMemory snapshot; they are not live-LLM or cross-version SQL tests.
|
|
63
|
+
|
|
64
|
+
The review exposed an existing [Tool schema recording gap](tool-schema-recording-gap.md)
|
|
65
|
+
on RubyLLM 1.16.0. R10 does not repair it or weaken definition checks. Successful
|
|
66
|
+
continuation here does not prove that incompatible parameter definitions are
|
|
67
|
+
rejected. The generated parameter description changes, while the current saved
|
|
68
|
+
Tool definition omits parameter details.
|
|
69
|
+
|
|
70
|
+
R09 is applied and verified. R10 is implemented and locally verified, pending
|
|
71
|
+
application verification. The newly discovered schema issue remains open, so
|
|
72
|
+
closing the original R/D inventory must not be described as absence of defects.
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
# Shared execution metadata and value conversion
|
|
2
|
+
|
|
3
|
+
Refactor 38 addresses the remaining R03 and R11 responsibilities against core
|
|
4
|
+
`e7e6618493df03c2eb386d78a9303796e1e13cdc`. The candidate must be applied and
|
|
5
|
+
verified before those items are closed. Tool restoration itself was completed
|
|
6
|
+
earlier and its validation and state reconstruction remain unchanged.
|
|
7
|
+
|
|
8
|
+
## Ownership
|
|
9
|
+
|
|
10
|
+
Ordinary dispatch creates durable facts before sending an external operation.
|
|
11
|
+
Recovery reads those same facts after an interruption. Their stored vocabulary
|
|
12
|
+
therefore belongs to the execution contract, not to a recovery procedure.
|
|
13
|
+
|
|
14
|
+
| Responsibility | Owner | Callers |
|
|
15
|
+
|---|---|---|
|
|
16
|
+
| Metadata keys/version, Tool batch capture and metadata merge | `Agent::ExecutionMetadata` in `agent/execution` | Initial/dispatch preparation, Coordinator, approval commit, recovery and MultiAgent |
|
|
17
|
+
| Stable Tool invocation identity | `Agent::ToolInvocation.semantic_id` | Ordinary Tool preparation and recovery subject construction |
|
|
18
|
+
| Ruby tree conversion before JSON serialization | `Values::Serializable.convert` in `common/values` | RuntimeRecordEncoder, RecoverySupport, ExecutionMetadata and dispatch preparation |
|
|
19
|
+
| Recovery descriptors and outcome interpretation | `Agent::RecoverySupport` | Recovery and the existing failure reconstruction path |
|
|
20
|
+
|
|
21
|
+
ExecutionMetadata is a stateless vocabulary and snapshot helper. It does not
|
|
22
|
+
start an invocation, increment revisions, open a transaction or perform recovery.
|
|
23
|
+
Its `with_values` preserves the old execution revision. ToolInvocation's
|
|
24
|
+
`semantic_id` computes the same prefixed SHA-256 value over the same four IDs
|
|
25
|
+
and NUL separators; it never constructs, authorizes or runs a Tool.
|
|
26
|
+
|
|
27
|
+
RecoverySupport's shared constants and snapshot/merge/identity operations are
|
|
28
|
+
removed, with all repository callers updated. No compatibility aliases are
|
|
29
|
+
added for these private implementation names. `ExecutionOutcomeCommitter`
|
|
30
|
+
still uses `RecoverySupport.error_from_failure` for actual failure reconstruction;
|
|
31
|
+
this change does not claim to remove every execution/recovery dependency.
|
|
32
|
+
|
|
33
|
+
## Conversion contract
|
|
34
|
+
|
|
35
|
+
Serializable rebuilds Hash and Array containers, stringifies Hash keys and
|
|
36
|
+
Symbol values, retains scalar objects, and recursively processes `to_h` results.
|
|
37
|
+
It preserves input order and the previous last-value-wins behavior for keys
|
|
38
|
+
that become equal. It does not deep-copy String values, freeze results, reject
|
|
39
|
+
non-Hash `to_h` results, or catch exceptions raised by application conversion.
|
|
40
|
+
|
|
41
|
+
The unsupported-value error remains ArgumentError. Callers supply their
|
|
42
|
+
existing diagnostic prefix, including for errors inside nested values:
|
|
43
|
+
|
|
44
|
+
| Boundary | Exact prefix before `: <class>` |
|
|
45
|
+
|---|---|
|
|
46
|
+
| RuntimeRecordEncoder.json_value | `unsupported canonical runtime value` |
|
|
47
|
+
| RecoverySupport.canonical_copy and existing snapshot writers | `Recovery value is not canonically serializable` |
|
|
48
|
+
|
|
49
|
+
The two existing conversion entry points remain short adapters because they
|
|
50
|
+
own different error contracts. They no longer implement separate recursive
|
|
51
|
+
algorithms. Snapshot writers retain their historical diagnostic despite its
|
|
52
|
+
Recovery wording, to avoid a behavior change in this responsibility refactoring.
|
|
53
|
+
|
|
54
|
+
Serializable does not establish canonical JSON validity. CanonicalJSON still
|
|
55
|
+
owns numeric range, non-finite/negative-zero and encoding checks. Immutable.copy
|
|
56
|
+
still owns copying and freezing. ProviderCallOutcome.normalize still has its
|
|
57
|
+
different unsupported-value-to-String behavior. Domain codecs keep their key
|
|
58
|
+
validation and collision rules. These operations are intentionally not merged.
|
|
59
|
+
|
|
60
|
+
## Compatibility and verification
|
|
61
|
+
|
|
62
|
+
Stored metadata keys, version 1, Tool identity bytes and serialized values are
|
|
63
|
+
unchanged. Transactions, revision checks, dispatch order, Tool restoration,
|
|
64
|
+
approval notifications and external-effect behavior remain with their existing
|
|
65
|
+
owners. Public API, signatures, raw Storage SPI and database schema are unchanged.
|
|
66
|
+
|
|
67
|
+
The conversion behavior tests run against both the applied baseline and the
|
|
68
|
+
candidate, including nested unsupported values and application exceptions.
|
|
69
|
+
Existing Tool batch tests follow their new owner; the stored identity fixture
|
|
70
|
+
guards compatibility. Recovery, causal durability, approval/resume and
|
|
71
|
+
MultiAgent tests exercise the changed callers. Full core/integration suites,
|
|
72
|
+
common examples, real SQLite, API/SPI snapshots, RBS, annotations and packaged
|
|
73
|
+
gem loading complete the candidate checks. Live PostgreSQL and live providers
|
|
74
|
+
are not part of this candidate's execution evidence.
|
|
75
|
+
|
|
76
|
+
This improves ownership and removes a duplicated recursive algorithm. The
|
|
77
|
+
dependency diagram's module and file cycles remain; their disappearance is not
|
|
78
|
+
the completion criterion. The applied SVG remains applied37-01 until the next
|
|
79
|
+
application verification. The other initial proposal groups are R06, R07,
|
|
80
|
+
R08/D08, R09 and R10; overall refactoring is not complete.
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
# GeneratorVerifier ownership and event contract
|
|
2
|
+
|
|
3
|
+
## Role and problem
|
|
4
|
+
|
|
5
|
+
GeneratorVerifier exposes the draft/review/retry pattern. An application supplies
|
|
6
|
+
two Agent classes, prompt builders, optional result parsers and convergence
|
|
7
|
+
settings. invoke runs the Workflow and returns the existing Result, optionally
|
|
8
|
+
raising LowConfidenceError. Agent completion arrives as Workflow events; Workflow
|
|
9
|
+
entry actions return context immediately rather than awaiting Agent Tasks.
|
|
10
|
+
|
|
11
|
+
R08 and D08 describe the same issue: a 199-line build_workflow mixes the graph
|
|
12
|
+
with Agent startup, response parsing/normalization and failure notification.
|
|
13
|
+
Nested PipelineState also occupies the public facade's source file. Separating
|
|
14
|
+
only the file without removing receiver-to-facade private calls would leave the
|
|
15
|
+
responsibility problem in place.
|
|
16
|
+
|
|
17
|
+
## Owners and reading order
|
|
18
|
+
|
|
19
|
+
| Owner | Responsibility |
|
|
20
|
+
|---|---|
|
|
21
|
+
| GeneratorVerifier | Public settings and Result; cached Workflow assembly, invocation, default JSON parser fallbacks and final confidence/raise policy. |
|
|
22
|
+
| GeneratorVerifier::WorkflowBuilder | Draft/review/finalize/failed graph, request IDs, prompt creation, Agent startup and convergence guard. |
|
|
23
|
+
| GeneratorVerifier::AgentResultReceiver | Separate draft/review payload conversion, common terminal-event classification and failure notification to the supplied Workflow. |
|
|
24
|
+
| GeneratorVerifier::PipelineState | Existing Workflow fields, request correlation, stale/duplicate rejection and EventLoop-owned state mutation. |
|
|
25
|
+
|
|
26
|
+
The last three constants are private. WorkflowBuilder and AgentResultReceiver
|
|
27
|
+
are new internal classes; PipelineState is the existing class moved with its
|
|
28
|
+
body and canonical name unchanged. The implementation lives in three files under
|
|
29
|
+
generation/generator_verifier. The public facade and Result keep their names and
|
|
30
|
+
locations; no loader changes or compatibility aliases are introduced.
|
|
31
|
+
|
|
32
|
+
The initial D08 sketch suggested multi_agent/generator_verifier_workflow.rb.
|
|
33
|
+
Since the prior layout work established generation as this pattern's owner,
|
|
34
|
+
the internal files now stay there instead of creating a second feature owner.
|
|
35
|
+
The new directory adds a module in directory-based analysis, not a public API.
|
|
36
|
+
|
|
37
|
+
WorkflowBuilder#build reads as a graph: named entries, then ordered transitions.
|
|
38
|
+
start_draft/start_review describe request preparation and dispatch. The receiver's
|
|
39
|
+
draft_payload and review_payload retain different meanings. Their common listener
|
|
40
|
+
has only the two internally selected phases; it is not a public configurable
|
|
41
|
+
pipeline. It shares the same terminal/error rules rather than combining response
|
|
42
|
+
formats into an options-driven generic parser.
|
|
43
|
+
|
|
44
|
+
Default parsers remain explicit callables captured by the facade. Clamp and
|
|
45
|
+
citation normalization move to their receiver owner. The old __send__ calls back
|
|
46
|
+
to facade helpers disappear. The existing private Agent event-sink entry point
|
|
47
|
+
is still called via send; changing that cooperation API is outside this scope.
|
|
48
|
+
|
|
49
|
+
## Preserved ordering and failure contract
|
|
50
|
+
|
|
51
|
+
- Each Agent is constructed once, lazily during the first successful Workflow
|
|
52
|
+
build. The cached Workflow and Agent instances are reused. Each invoke gets a
|
|
53
|
+
fresh Workflow context. No locking or new concurrency policy is introduced.
|
|
54
|
+
- Each request gets a new UUID and a merged context before prompt construction.
|
|
55
|
+
The listener captures that request ID and the context's stable Workflow ID.
|
|
56
|
+
Workflow closures see the completed Workflow assignment before any entry runs.
|
|
57
|
+
- Entry actions start asynchronous Agent work and return next_state, never a
|
|
58
|
+
TaskResult. Inline completion remains valid because signal queues a Workflow
|
|
59
|
+
event. Unknown/nonterminal Agent events are ignored.
|
|
60
|
+
- done parses output, normalizes the phase-specific payload and signals the
|
|
61
|
+
matching completed event. StandardError from parsing, normalization or success
|
|
62
|
+
notification is signalled as the corresponding failed event with the same
|
|
63
|
+
exception object. Failure-notification exceptions are not retried or wrapped.
|
|
64
|
+
- error/timeout/cancelled use the payload error or the same phase-specific
|
|
65
|
+
fallback message. approval_required remains a pipeline failure. A false return
|
|
66
|
+
from signal is returned without a retry or a new failure event.
|
|
67
|
+
- PipelineState accepts only the current request ID. It clears the accepted ID,
|
|
68
|
+
increments iteration after draft completion, appends feedback after review,
|
|
69
|
+
and consumes old/duplicate results before any transition. The receiver does
|
|
70
|
+
not mutate context or add its own deduplication; stale done payloads can still
|
|
71
|
+
be parsed before the state rejects their correlated event.
|
|
72
|
+
- Review completes when both the lower normalized score meets threshold and
|
|
73
|
+
approval is literal true, or when the iteration limit has been reached.
|
|
74
|
+
Otherwise it returns to draft and passes the last feedback to its prompt.
|
|
75
|
+
- Final Result trust remains confidence >= threshold. At the iteration limit,
|
|
76
|
+
high confidence with approved=false can therefore still produce trusted=true.
|
|
77
|
+
A nonpositive limit still executes one draft/review cycle. These are observed
|
|
78
|
+
existing semantics, not behavior fixes hidden in this extraction.
|
|
79
|
+
|
|
80
|
+
Public initialize/invoke parameters, Result fields/trusted? alias, parser
|
|
81
|
+
fallbacks, score/citation normalization, error messages and PipelineState fields
|
|
82
|
+
remain unchanged. Agent/Workflow/Engine/Storage behavior and SQL are not modified.
|
|
83
|
+
Private clamp/normalize_citations implementations relocate; private overrides are
|
|
84
|
+
not treated as additional supported public APIs.
|
|
85
|
+
|
|
86
|
+
## Verification and trade-off
|
|
87
|
+
|
|
88
|
+
Thirty-nine behavior examples pass unchanged on Refactor 40 and the candidate.
|
|
89
|
+
They cover inline completion, ignored progress, pending Task returns, both phases'
|
|
90
|
+
error/timeout/cancelled/approval failures, parser and notification failures,
|
|
91
|
+
request correlation, duplicate/old callbacks, clamping, literal approval, final
|
|
92
|
+
trust, iteration limits, caching, fresh state and config forwarding. Existing
|
|
93
|
+
delayed-callback and WebMock integration examples cover the real Workflow path.
|
|
94
|
+
|
|
95
|
+
A separate process comparison preserves public methods, parameters, constants,
|
|
96
|
+
Result shape, the private state name/field schema/defaults and Runtime inactivity.
|
|
97
|
+
Stable/Beta snapshots do not list GeneratorVerifier, so this explicit comparison
|
|
98
|
+
supplements those existing gates. Core/integration/examples/real SQLite, type,
|
|
99
|
+
style, annotations and isolated gem checks are included in distribution evidence.
|
|
100
|
+
Live PostgreSQL, live LLM, candidate CI and performance are not run for this scope.
|
|
101
|
+
|
|
102
|
+
The facade is 369 -> 118 lines. Workflow definition is 199 -> 34 lines, with a
|
|
103
|
+
12-line facade assembly method. The three internal files are 112/89/57 lines,
|
|
104
|
+
for 376 total, seven more than before. Two new classes and one moved class cost
|
|
105
|
+
additional files; they give graph, receiver and state independent reading units.
|
|
106
|
+
Directory-level dependency counts increase with that physical partition; cycle
|
|
107
|
+
membership is unchanged. This is responsibility separation, not cycle removal.
|
|
108
|
+
|
|
109
|
+
Refactor 41 is applied and independently verified at core e87eb77f, tree
|
|
110
|
+
14dc8a546a4fd96e19e0713f7480ca2efa3c331a. All nine files and the full tree match.
|
|
111
|
+
R08/D08 is closed. The published diagram is applied41-01. R09 and R10 remain.
|
|
@@ -20,7 +20,13 @@ returns control to the caller. Handoff changes the active Agent for the current
|
|
|
20
20
|
coordination lifetime.
|
|
21
21
|
|
|
22
22
|
Normative Handoff intent is
|
|
23
|
-
[ADR-030](../decisions/030-agent-handoff-domain-and-durable-responsibility.md)
|
|
23
|
+
[ADR-030](../decisions/030-agent-handoff-domain-and-durable-responsibility.md),
|
|
24
|
+
with the Runner ownership amendment in
|
|
25
|
+
[ADR-034](../decisions/034-handoff-runner-coordination-ownership.md).
|
|
26
|
+
|
|
27
|
+
The Runner owns the cross-Agent turn. Handoff edges, Policy, Context and
|
|
28
|
+
Agent terminal/persistence integration remain in Agent during this first
|
|
29
|
+
migration step. See the [Runner migration](../migrations/handoff-runner-multi-agent.md).
|
|
24
30
|
|
|
25
31
|
## 2. Public API
|
|
26
32
|
|
|
@@ -32,7 +38,7 @@ handoff = Phronomy::Agent::Handoff.new(
|
|
|
32
38
|
policy: policy
|
|
33
39
|
)
|
|
34
40
|
|
|
35
|
-
runner = Phronomy::
|
|
41
|
+
runner = Phronomy::MultiAgent::HandoffRunner.new(
|
|
36
42
|
main_agent: triage,
|
|
37
43
|
handoffs: [handoff]
|
|
38
44
|
)
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# Persistence responsibility refactoring plan
|
|
2
|
+
|
|
3
|
+
The Storage staged implementation reaches its bounded S3 cleanup in Refactor 36;
|
|
4
|
+
application verification remains. The broader initial review still has open
|
|
5
|
+
proposals recorded in the remaining responsibility plan.
|
|
6
|
+
[ADR-033](../decisions/033-domain-persistence-ownership.md) established domain
|
|
7
|
+
ownership; [ADR-058](../decisions/058-neutral-storage-primitives.md) now defines
|
|
8
|
+
the neutral Storage SPI. Historical raw contracts are not the current API.
|
|
9
|
+
See the [remaining responsibility plan](remaining-refactoring-plan.md) for the
|
|
10
|
+
applied commit pair and the [closure review](refactoring-closure.md) for the
|
|
11
|
+
final naming, placement and evidence boundary.
|
|
12
|
+
|
|
13
|
+
## Target and current ownership
|
|
14
|
+
|
|
15
|
+
Domain repositories own record meanings, codecs, revisions and business
|
|
16
|
+
constraints. Storage owns typed neutral resources, Records/Streams/Blobs,
|
|
17
|
+
conditions and transaction scopes. Concrete InMemory and SQL drivers implement
|
|
18
|
+
physical operations. Composition selects implementations and assembles domain
|
|
19
|
+
wrappers; Storage does not import concrete domain implementations.
|
|
20
|
+
|
|
21
|
+
The public `Phronomy::Persistence` facade remains the application entry point.
|
|
22
|
+
It is distinct from `Phronomy::Storage`, the backend extension contract.
|
|
23
|
+
Directories express responsibility; existing public constants need not be
|
|
24
|
+
renamed to match every directory. The dependency graph is not a tree.
|
|
25
|
+
|
|
26
|
+
## Stages
|
|
27
|
+
|
|
28
|
+
| Stage | Result |
|
|
29
|
+
|---|---|
|
|
30
|
+
| 1. Domain ownership | Refactor 09 moved schemas, repositories and queries to their domains. Later layout work placed record definitions and ownership contracts beside those features. |
|
|
31
|
+
| 2. Neutral contract | Refactors 34 and 35 unified the failure/transaction boundaries and replaced eight raw repository slots with Resources, Records/Streams/Blobs and guarded conditions. Core, InMemory, SQLite and PostgreSQL were migrated together. Applied SPI 2 passed S2c, including real PostgreSQL. |
|
|
32
|
+
| 3. Naming and placement | Refactor 36 retains the facade/SPI names, feature schemas, composition and reference-driver locations. Resource owns schema-reference normalization; generic Validation does not depend on Resource. Documentation records current status and historical boundaries. Distribution application verification remains separate. |
|
|
33
|
+
|
|
34
|
+
## Invariants and gates
|
|
35
|
+
|
|
36
|
+
All repositories and ContentStore continue to join one backend transaction.
|
|
37
|
+
Splitting classes must not split commits. Codec response validation stays inside
|
|
38
|
+
the atomic boundary. IDs, revisions, journal positions, active constraints,
|
|
39
|
+
record type/version/payload and the F0/F1/F4/X0 limits remain unchanged.
|
|
40
|
+
|
|
41
|
+
Product API and Storage SPI snapshots, RBS, existing domain/backend conformance,
|
|
42
|
+
unit/integration suites, SQL examples and isolated gem loading verify the
|
|
43
|
+
implemented boundary. Record which tests ran against which tree: Refactor 35's
|
|
44
|
+
PostgreSQL CI is evidence for Refactor 35, not a claim that unpublished
|
|
45
|
+
Refactor 36 ran remotely. Refactor 36 does not change SQL or its public protocol.
|
|
46
|
+
|
|
47
|
+
Keep the applied-source diagram until the delivered candidate is applied and
|
|
48
|
+
verified. Remaining directory cycles and runtime collaboration are recorded,
|
|
49
|
+
not described as eliminated by moving files. Future behavior, performance or
|
|
50
|
+
distributed-operation work requires its own scope and evidence.
|
|
@@ -9,8 +9,31 @@
|
|
|
9
9
|
|
|
10
10
|
## 1. Durable boundary
|
|
11
11
|
|
|
12
|
-
`Phronomy::Persistence` is the single durable-state
|
|
13
|
-
|
|
12
|
+
`Phronomy::Persistence` is the domain-facing service for the single durable-state
|
|
13
|
+
transaction domain used by Agents, Teams, and Workflows. It composes a
|
|
14
|
+
`Storage::Backend`; storage implementations do not inherit the domain service.
|
|
15
|
+
|
|
16
|
+
The `storage/` directory owns record carriers, portable errors, repository views,
|
|
17
|
+
and the Backend contract. `storage/backends/` owns physical storage implementations.
|
|
18
|
+
The `agent/persistence/`, `multi_agent/persistence/`, and `workflow/persistence/`
|
|
19
|
+
directories own their domain codecs and repositories. Agent and Team result
|
|
20
|
+
queries live with those domains. `storage/record_codec.rb` contains only shared
|
|
21
|
+
record-envelope and scalar validation; it does not select a domain schema.
|
|
22
|
+
`persistence_composition/` assembles the domain repositories over one raw view.
|
|
23
|
+
The public `Phronomy::Persistence` entry point delegates to those components and
|
|
24
|
+
retains its observation-thread guard.
|
|
25
|
+
The root and transaction paths use the same facade construction, with transaction
|
|
26
|
+
facades bound to the raw backend view for that transaction.
|
|
27
|
+
See [ADR-032](../decisions/032-storage-backend-composition.md) and
|
|
28
|
+
[ADR-033](../decisions/033-domain-persistence-ownership.md).
|
|
29
|
+
|
|
30
|
+
Shared value copying belongs to `Values::Immutable` in `values/`. Agent records,
|
|
31
|
+
Team records, Recovery classifications, and Persistence result views use this
|
|
32
|
+
internal helper without borrowing an Agent implementation. It copies and freezes
|
|
33
|
+
Hash, Array, and String trees; other values pass through unchanged. Its separate
|
|
34
|
+
canonical JSON check delegates to `CanonicalJSON`. Each domain codec and repository owns its record schema, key normalization,
|
|
35
|
+
identity, and revision validation. Moving this helper
|
|
36
|
+
does not change record formats, transaction ownership, or recovery guarantees.
|
|
14
37
|
|
|
15
38
|
| Repository | Durable authority |
|
|
16
39
|
|---|---|
|
|
@@ -70,7 +93,7 @@ Defined semantic durable transitions are atomic according to the Persistence
|
|
|
70
93
|
transaction contract and conforming backend.
|
|
71
94
|
|
|
72
95
|
Revision/watermark/CAS checks reject stale durable transitions with
|
|
73
|
-
`
|
|
96
|
+
`Storage::ConflictError` rather than silently merging/reloading competing
|
|
74
97
|
state.
|
|
75
98
|
|
|
76
99
|
Conflict detection is not competing-execution exclusion and cannot undo an
|
|
@@ -107,7 +130,7 @@ Phronomy does not claim arbitrary external exactly-once side effects.
|
|
|
107
130
|
## 7. Durable codec
|
|
108
131
|
|
|
109
132
|
Durable backend exchange uses immutable
|
|
110
|
-
`Phronomy::
|
|
133
|
+
`Phronomy::Storage::DurableRecord` values with:
|
|
111
134
|
|
|
112
135
|
```text
|
|
113
136
|
record_type
|