phronomy 0.23.0 → 0.24.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (71) hide show
  1. checksums.yaml +4 -4
  2. data/.mutant.yml +2 -2
  3. data/CHANGELOG.md +15 -0
  4. data/CONTRIBUTING.md +2 -2
  5. data/README.md +1 -1
  6. data/docs/architecture/multi-agent-handoff.md +35 -40
  7. data/docs/architecture/persistence.md +19 -8
  8. data/docs/architecture.md +8 -1
  9. data/docs/decisions/016-semantic-multi-agent-handoff.md +3 -1
  10. data/docs/decisions/028-preparing-recovery-replay-contract.md +106 -0
  11. data/docs/decisions/029-semantic-completion-and-application-effect-boundary.md +220 -0
  12. data/docs/decisions/030-agent-handoff-domain-and-durable-responsibility.md +235 -0
  13. data/docs/decisions/031-durable-multi-agent-coordination.md +301 -0
  14. data/docs/decisions/README.md +5 -1
  15. data/docs/design/durable-semantic-coordination/CHANGELOG_V2_REVISION_2.md +33 -0
  16. data/docs/design/durable-semantic-coordination/CONTINUATION_DECISION_REFACTOR.md +191 -0
  17. data/docs/design/durable-semantic-coordination/IMPLEMENTATION_DESIGN_V2.md +862 -0
  18. data/docs/design/durable-semantic-coordination/IMPLEMENTATION_REPORT.md +106 -0
  19. data/docs/design/durable-semantic-coordination/RECOVERY_CONTRACT_CLARIFICATIONS.md +179 -0
  20. data/docs/design/durable-semantic-coordination/RESPONSIBILITY_BOUNDARY_REVIEW.md +302 -0
  21. data/docs/features.md +35 -1
  22. data/docs/migrations/durable-semantic-coordination-v2.md +65 -0
  23. data/docs/persistence-backends.md +42 -3
  24. data/lib/phronomy/agent/agent_execution.rb +2 -2
  25. data/lib/phronomy/agent/agent_invocation.rb +1 -1
  26. data/lib/phronomy/agent/async_event_api.rb +18 -1
  27. data/lib/phronomy/agent/base.rb +28 -0
  28. data/lib/phronomy/agent/context_assembler.rb +1 -1
  29. data/lib/phronomy/agent/exact_execution.rb +153 -0
  30. data/lib/phronomy/agent/execution_cancellation.rb +25 -0
  31. data/lib/phronomy/agent/execution_coordinator.rb +484 -27
  32. data/lib/phronomy/{multi_agent → agent}/handoff.rb +4 -4
  33. data/lib/phronomy/{multi_agent → agent}/handoff_capability_factory.rb +3 -45
  34. data/lib/phronomy/{multi_agent → agent}/handoff_context.rb +26 -1
  35. data/lib/phronomy/{multi_agent/execution_coordinator.rb → agent/handoff_execution_coordinator.rb} +32 -5
  36. data/lib/phronomy/{multi_agent → agent}/handoff_policy.rb +7 -1
  37. data/lib/phronomy/{multi_agent → agent}/handoff_projection.rb +18 -2
  38. data/lib/phronomy/{multi_agent → agent}/handoff_request.rb +2 -2
  39. data/lib/phronomy/agent/handoff_runner.rb +178 -0
  40. data/lib/phronomy/agent/handoff_state.rb +43 -0
  41. data/lib/phronomy/agent/recovery_coordinator/continuation.rb +114 -211
  42. data/lib/phronomy/agent/recovery_coordinator/installation.rb +84 -130
  43. data/lib/phronomy/agent/recovery_coordinator/resolution.rb +76 -200
  44. data/lib/phronomy/agent/recovery_coordinator.rb +11 -5
  45. data/lib/phronomy/agent/recovery_support.rb +15 -23
  46. data/lib/phronomy/agent/ruby_llm_materializer.rb +2 -8
  47. data/lib/phronomy/agent/tool_invocation.rb +4 -2
  48. data/lib/phronomy/engine/runtime/team_ownership_registry.rb +77 -0
  49. data/lib/phronomy/engine/runtime.rb +16 -1
  50. data/lib/phronomy/multi_agent/durable_subagent_coordinator.rb +134 -0
  51. data/lib/phronomy/multi_agent/orchestrator.rb +59 -11
  52. data/lib/phronomy/multi_agent/team_coordinator.rb +473 -125
  53. data/lib/phronomy/multi_agent/team_execution.rb +44 -0
  54. data/lib/phronomy/multi_agent/team_root.rb +41 -0
  55. data/lib/phronomy/persistence/durable_codec.rb +60 -0
  56. data/lib/phronomy/persistence/in_memory.rb +264 -2
  57. data/lib/phronomy/persistence/repository_facades.rb +221 -2
  58. data/lib/phronomy/persistence.rb +95 -1
  59. data/lib/phronomy/testing/persistence_contract/a_persistence_backend.rb +1 -0
  60. data/lib/phronomy/testing/persistence_contract/coordination_repositories.rb +137 -0
  61. data/lib/phronomy/testing/persistence_contract.rb +5 -0
  62. data/lib/phronomy/tools/agent.rb +1 -1
  63. data/lib/phronomy/version.rb +1 -1
  64. data/scripts/api_snapshot.rb +3 -3
  65. data/sig/phronomy/handoff.rbs +41 -0
  66. data/sig/phronomy/multi_agent.rbs +28 -32
  67. data/sig/phronomy/persistence.rbs +64 -3
  68. metadata +30 -12
  69. data/lib/phronomy/multi_agent/coordination_state.rb +0 -18
  70. data/lib/phronomy/multi_agent/coordinator.rb +0 -154
  71. data/lib/phronomy/multi_agent/runner.rb +0 -98
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ffed6b796d049192f4f782aea75353504c166b23c5b6e1f336ab73eb90bbeb54
4
- data.tar.gz: 5655635e8ef6331496d0bb057dad602b2154cabae97ec87f4906123824b8c45d
3
+ metadata.gz: 1c8712213b18692b6bf9531110ffc38fa0f9d069509bf85b3424c5b77a76eb8e
4
+ data.tar.gz: c63a2cc058ad50b80306bcadfd7a99304f216ab02375272e43ab6cf5c38cb451
5
5
  SHA512:
6
- metadata.gz: 242dcb66e87b5beaaa55e19541fc852821adccf971cad68c06d65bcf705352a670b67012fa8c706ea0263f69eb03793a9b67d0bc3d61df422d201b3e3b6aa1c2
7
- data.tar.gz: 0b889a029056ad0a458a7318eacf0d3813072adf0f6b7ef8a448a02dd0a476b9146fcbdf90d4170ea3823058ba51a82aa4a0b7fb31e24f7e031404d9b7b27924
6
+ metadata.gz: 64de5d992461ceaccc2d579bbd6b3046b8ce711ca65f68b14cfb9f9fe45d724c2db0646ef547fe7d6a4502a7ca6657b9330d33898e1f24e694418fe9e41c324d
7
+ data.tar.gz: 507d16006d00d4304db2d1e2e67a61e605dbabfc190dc7cdbbf198e17e4648fc5a0767904f503e2da826f7744859c78ec99f7585732b45ace6251e1296cb274a
data/.mutant.yml CHANGED
@@ -17,6 +17,6 @@ matcher:
17
17
  - Phronomy::Agent::ContextPolicies::Default
18
18
  - Phronomy::Agent::ContextPolicyInputBuilder
19
19
  - Phronomy::Agent::ContextPlanValidator
20
- - Phronomy::MultiAgent::HandoffPolicy
21
- - Phronomy::MultiAgent::HandoffProjection
20
+ - Phronomy::Agent::HandoffPolicy
21
+ - Phronomy::Agent::HandoffProjection
22
22
  - Phronomy::VectorStore::InMemory
data/CHANGELOG.md CHANGED
@@ -12,6 +12,21 @@ Release history for 0.14.0 and earlier is archived in
12
12
 
13
13
  ## [Unreleased]
14
14
 
15
+ ### Fixed
16
+
17
+ - Run recovered output filtering inside the ordinary Agent FSM so filter
18
+ exceptions commit a failed execution and release admission, including after
19
+ another restart. Preserve explicit filter blocking as the `blocked` status.
20
+ - Propagate a coordinator's blocked outcome, and a worker's blocked outcome
21
+ under `on_error: :raise`, to Team failure. Preserve skipped worker errors and
22
+ committed failure precedence over later cancellation across restart.
23
+ - Keep Recovery content materialization, approval restoration reads, and F1
24
+ resolution readback off EventLoop. Apply prepared invocation state only on
25
+ EventLoop, reject stale results, and retain confirmed resolution facts when
26
+ later content reads fail.
27
+ - Avoid reading Orchestrator Knowledge again while constructing invocation-owned
28
+ Tools; those children inherit the Knowledge already saved with their slots.
29
+
15
30
  ---
16
31
 
17
32
  ## [0.23.0] - 2026-08-29
data/CONTRIBUTING.md CHANGED
@@ -225,8 +225,8 @@ The authoritative subject list is `.mutant.yml`. It currently includes:
225
225
  - `Phronomy::Agent::ContextPolicies::Default`
226
226
  - `Phronomy::Agent::ContextPolicyInputBuilder`
227
227
  - `Phronomy::Agent::ContextPlanValidator`
228
- - `Phronomy::MultiAgent::HandoffPolicy`
229
- - `Phronomy::MultiAgent::HandoffProjection`
228
+ - `Phronomy::Agent::HandoffPolicy`
229
+ - `Phronomy::Agent::HandoffProjection`
230
230
  - `Phronomy::VectorStore::InMemory`
231
231
 
232
232
  The nightly mutation matrix mirrors this authoritative list so each subject can
data/README.md CHANGED
@@ -19,7 +19,7 @@ tracking `main` directly.
19
19
  - **Persistence** — unified durable backend for Agent state and Workflow `workflow_states`.
20
20
  - **Workflow** — state-machine-driven application workflow with explicit events and wait states.
21
21
  - **Tool / Capability** — callable application capability exposed to an Agent; application-defined Tools subclass `Phronomy::Tool::Base`.
22
- - **Multi-Agent Handoff** — semantic Source-to-Target responsibility transfer with policy-bounded Context projection and Runtime-local active-Agent continuity.
22
+ - **Multi-Agent Handoff** — semantic Source-to-Target responsibility transfer with policy-bounded Context projection and persisted active responsibility and exact Target recovery within one Persistence domain.
23
23
  - **EventLoop + FSMSession** — the framework control plane for logical lifecycle coordination.
24
24
  - **OffloadPool** — bounded operating-system-thread execution boundary for synchronous work that must not run on EventLoop.
25
25
  - **Task** — the common thread-free completion handle returned by Phronomy asynchronous APIs, including OffloadPool-backed work.
@@ -20,19 +20,19 @@ 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-016](../decisions/016-semantic-multi-agent-handoff.md).
23
+ [ADR-030](../decisions/030-agent-handoff-domain-and-durable-responsibility.md).
24
24
 
25
25
  ## 2. Public API
26
26
 
27
27
  ```ruby
28
- handoff = Phronomy::MultiAgent::Handoff.new(
28
+ handoff = Phronomy::Agent::Handoff.new(
29
29
  source_agent: triage,
30
30
  target_agent: billing,
31
31
  description: "Transfer billing responsibility",
32
32
  policy: policy
33
33
  )
34
34
 
35
- runner = Phronomy::MultiAgent::Runner.new(
35
+ runner = Phronomy::Agent::HandoffRunner.new(
36
36
  main_agent: triage,
37
37
  handoffs: [handoff]
38
38
  )
@@ -113,40 +113,35 @@ state changes only through normal Target-owned execution/mutation paths.
113
113
  A Target Agent execution has its own `execution_id`; Source execution identity is
114
114
  provenance/audit context, not Target execution identity.
115
115
 
116
- ## 9. Next-turn continuity and durability
117
-
118
- The same `main_agent` instance plus the same Runtime define one coordination
119
- lifetime.
120
-
121
- Within that lifetime, the active Target remains active on later turns and across
122
- Runner-facade recreation. Runtime admission rejects racing concurrent turns for
123
- the same coordination lifetime.
124
-
125
- Active routing is **not durably rehydrated**. Runtime/process reset starts a new
126
- coordination lifetime at `main_agent`. Historical Handoff audit facts do not
127
- reconstruct active Target ownership.
128
-
129
- ## 10. Cancellation and tracing
130
-
131
- Handoff does not create a separate cancellation domain; active Agent execution
132
- uses normal Agent semantics.
133
-
134
- One Runner user turn is automatically observable as `multi_agent.turn`. Source
135
- and Target Agent/LLM/Tool logical operations keep their own automatic spans and
136
- semantic IDs. Handoff adds no generic correlation identity or cross-Runtime
137
- parent-span guarantee.
138
-
139
- See [Tracing](tracing.md).
140
-
141
- ## 11. Safety and removed API
142
-
143
- `Phronomy::MultiAgent::Runner::MAX_HANDOFFS` bounds transfers in one user turn.
144
-
145
- Not current contracts:
146
-
147
- - sentinel Handoff Tool results;
148
- - `Phronomy::Agent::Runner`;
149
- - `agents:` / `routes:` Runner configuration;
150
- - Agent-owned Handoff Tool registration;
151
- - generated Tool-name identity;
152
- - blanket Source history/Knowledge copying.
116
+ ## 9. Persisted responsibility and recovery
117
+
118
+ The original main Agent ID anchors `HandoffState`; the active Agent is retained
119
+ across compatible Runtime restarts. The graph must use one Persistence instance.
120
+ Source `handed_off`, its journal/root transition, immutable HandoffContext and the
121
+ reserved Target execution ID commit atomically. The Target is admitted under
122
+ that ID only after an authoritative absence read and the usual Agent admission.
123
+ An active exact Target uses Agent Recovery; a terminal Target result is reused.
124
+ Target terminal settlement and routing stabilization share a transaction.
125
+
126
+ A new Runtime supplies the graph/current definitions again. Tool transport names
127
+ are deterministic from stable Source/Target Agent IDs and are resolved from that
128
+ graph, without a global class registry. Persisted Context is not reprojected under
129
+ current policy. Missing graph edges/definitions or a different Persistence domain
130
+ fail before semantic continuation.
131
+
132
+ `HandoffRunner#result(source_execution_id)` follows retained transfer links.
133
+ `cancel(execution_id)` records a request against that exact turn; pending absent
134
+ Targets are stopped without admission, active Targets use their existing Agent
135
+ cancellation token, terminal outcomes remain immutable. No cancellation or
136
+ observer loss rewinds active responsibility to the main Agent. Cancellation is
137
+ not compensation for external effects; unresolved X0 still needs Agent Recovery.
138
+
139
+ F1 commit response loss is resolved by exact readback. Read/decode failure is not
140
+ absence. F4 recovery requires retained storage and compatible current wiring.
141
+ `on_event` is Runtime-only; terminal results can be read without redelivery.
142
+
143
+ Current graph objects and observers are not durably rehydrated; Application
144
+ supplies compatible wiring. Source execution identity links each completed
145
+ transfer to its exact reserved Target execution, independently of later turns.
146
+ `Persistence#handoff_result(source_execution_id)` reads that turn without loading
147
+ Agent owners, graph definitions, or listeners.
@@ -12,14 +12,16 @@
12
12
  `Phronomy::Persistence` is the single durable-state backend abstraction for
13
13
  stateful Agents and durable Workflows.
14
14
 
15
- ```text
16
- Persistence
17
- ├─ contents
18
- ├─ agents
19
- ├─ journals
20
- ├─ executions
21
- └─ workflow_states
22
- ```
15
+ | Repository | Durable authority |
16
+ |---|---|
17
+ | `contents` | Immutable content and manifests |
18
+ | `agents` | AgentRoot |
19
+ | `journals` | Append-only Agent journal |
20
+ | `executions` | AgentExecution and owned child coordination |
21
+ | `workflow_states` | Workflow snapshots |
22
+ | `handoff_states` | Active responsibility and exact Target reservation |
23
+ | `teams` | TeamRoot |
24
+ | `team_executions` | Team tasks, assignments and outcomes |
23
25
 
24
26
  Persistence stores defined durable logical state. It is not serialization of the
25
27
  currently running Runtime object graph.
@@ -173,3 +175,12 @@ Therefore:
173
175
 
174
176
  InMemory implementation mechanisms do not become requirements for external
175
177
  backends unless the Backend SPI states the corresponding semantic property.
178
+
179
+ ## Durable semantic coordination extension
180
+
181
+ ADR-031 extends the single transaction domain to `handoff_states`, `teams` and
182
+ `team_executions`, alongside the existing five repositories. Current root and
183
+ transaction views require all eight. Explicit identity/revision/admission metadata
184
+ remains separate from opaque DurableRecord payloads. See the normative
185
+ [backend contract](../persistence-backends.md) and
186
+ [recovery clarifications](../design/durable-semantic-coordination/RECOVERY_CONTRACT_CLARIFICATIONS.md).
data/docs/architecture.md CHANGED
@@ -50,7 +50,7 @@ explicit compatibility decision.
50
50
  | Journal-backed Knowledge and retrieval integration | [Knowledge and RAG](architecture/knowledge-and-rag.md) |
51
51
  | Filter, Context trust policy, approval, and isolation boundaries | [Security Boundaries](architecture/security-boundaries.md) |
52
52
  | Automatic logical-operation tracing and custom tracer SPI | [Tracing](architecture/tracing.md) |
53
- | Semantic Source-to-Target responsibility transfer | [Multi-Agent Handoff](architecture/multi-agent-handoff.md) |
53
+ | Durable Agent-domain responsibility transfer | [Multi-Agent Handoff](architecture/multi-agent-handoff.md) |
54
54
  | Durable state, Runtime ownership, recovery, and codec boundaries | [Persistence](architecture/persistence.md) |
55
55
  | Request-scoped pre-Manifest customization | [before_llm_input](architecture/before-llm-input.md) |
56
56
  | Removed Agent Context / Memory architectures that must not return | [Removed Agent Context Architecture](architecture/removed/agent-context.md) |
@@ -80,3 +80,10 @@ It must not be used as a current implementation or compatibility contract.
80
80
 
81
81
  The old `spec/design/` documentation location is not part of the current
82
82
  documentation architecture.
83
+
84
+ Durable multi-agent coordination is described by [ADR-029](decisions/029-semantic-completion-and-application-effect-boundary.md),
85
+ [ADR-030](decisions/030-agent-handoff-domain-and-durable-responsibility.md) and
86
+ [ADR-031](decisions/031-durable-multi-agent-coordination.md).
87
+ TeamExecution is a purpose-specific CAS authority delegating coordinator/workers
88
+ to ordinary Agents, with no Team FSMSession or second Workflow engine.
89
+ Static subagent reservation lives in the existing parent AgentExecution metadata.
@@ -2,7 +2,9 @@
2
2
 
3
3
  ## Status
4
4
 
5
- Accepted.
5
+ Superseded by [ADR-030](030-agent-handoff-domain-and-durable-responsibility.md).
6
+ The semantic Context-transfer rationale is retained in ADR-030; the namespace and
7
+ Runtime-only routing contract below are historical.
6
8
 
7
9
  ## Context
8
10
 
@@ -0,0 +1,106 @@
1
+ # ADR-028: Replay-safe recovery for durably admitted `:preparing` Agent executions
2
+
3
+ Status: Accepted
4
+
5
+ ## Context
6
+
7
+ ADR-018 defines Agent execution resumption as continuation of the same logical
8
+ `execution_id` from durable recovery state when there is no unresolved semantic
9
+ operation that prevents safe continuation. The implementation already persists a
10
+ new `AgentExecution` in `status: :preparing, phase: :preparing` before input
11
+ filters, `before_llm_input`, Context Policy, and Manifest finalization run.
12
+
13
+ Before this decision, process loss in that window left a durable active execution
14
+ with no automatic continuation path.
15
+
16
+ ## Decision
17
+
18
+ A `:preparing` execution may be resumed automatically only when the framework
19
+ durably recorded `preparation_replayable == true`. Missing, false, or unsupported
20
+ values fail closed. The recovered continuation keeps the same `execution_id`.
21
+
22
+ The preparation region is **replay-safe, not deterministic**. Input filtering,
23
+ `before_llm_input`, Context Policy, retrieval, and other preparation work may be
24
+ executed again after process loss. Applications must ensure those callbacks are
25
+ safe under at-least-once execution. The framework does not require repeated
26
+ preparation to produce byte-identical results.
27
+
28
+ Before Manifest finalization, preparation results may be recomputed. After the
29
+ Manifest is durably committed, the Manifest is the authority and existing
30
+ post-Manifest recovery rules apply.
31
+
32
+ ### Durable application context
33
+
34
+ `config` remains a runtime/application Hash and is not generally durable. An
35
+ Application value that affects preparation semantics and must survive restart is
36
+ placed under one reserved key:
37
+
38
+ ```ruby
39
+ config: {
40
+ durable_context: {
41
+ "tenant" => "A",
42
+ "search_profile" => "legal"
43
+ }
44
+ }
45
+ ```
46
+
47
+ `config[:durable_context]`, when present, must be a Hash accepted by
48
+ `Phronomy::CanonicalJSON`. The framework performs a Canonical JSON round trip
49
+ before execution admission and uses the detached immutable snapshot for both the
50
+ initial run and any recovery replay. `durable_context: nil` and non-Hash values
51
+ are rejected before an `AgentExecution` is created. Missing and explicit `{}` are
52
+ distinct.
53
+
54
+ The snapshot is stored in the Content Store and the execution retains only
55
+ `durable_context_ref`.
56
+
57
+ ### Conservative replay eligibility
58
+
59
+ This change intentionally does not add a new arbitrary raw-input serialization
60
+ format. Current initial admission stores `extract_message(input)` as text, while
61
+ filters and instruction construction may inspect the original Ruby input.
62
+ Therefore automatic `:preparing` replay is enabled only for String invocation
63
+ inputs. Non-String inputs fail closed after process loss at this phase.
64
+
65
+ Automatic preparation replay is also disabled when the framework can see a
66
+ Runtime-only semantic dependency that it cannot reconstruct, including:
67
+
68
+ - Multi-Agent handoff/routing wiring;
69
+ - a custom Agent invocation approval policy;
70
+ - invocation-context approval/redaction/token-budget policy values.
71
+
72
+ These conditions are represented by the single durable boolean
73
+ `preparation_replayable`; the framework does not persist those Runtime objects.
74
+ A true value records that no framework-known blocker was present; it does not
75
+ replace the Application replay-safety contract for callbacks or custom config.
76
+
77
+ Applications that use other ordinary `config` entries to influence preparation,
78
+ Provider-adapter, Tool, or other continuation semantics are responsible for moving
79
+ restart-required values into `config[:durable_context]` and reading them from that
80
+ sub-Hash after recovery.
81
+
82
+ ### Agent definition compatibility
83
+
84
+ Existing `agent_definition_id` / `agent_definition_version` load validation
85
+ continues to guard runtime definition compatibility. Applications must increment
86
+ the Agent definition version when a change to filters, hooks, Context Policy, or
87
+ other preparation behavior is not recovery-compatible.
88
+
89
+ ## Non-goals
90
+
91
+ This decision does not add:
92
+
93
+ - recovery of caller `Task` objects;
94
+ - durable Multi-Agent active routing or Handoff Context;
95
+ - a durable execution-query API;
96
+ - a new Recovery event;
97
+ - Content Store garbage collection;
98
+ - Workflow checkpoint changes;
99
+ - deterministic replay of Application callbacks.
100
+
101
+ ## Consequences
102
+
103
+ Direct, replay-safe String invocations can continue the same durable logical
104
+ execution after process loss in the initial preparation window. Unsupported or
105
+ ambiguous cases remain fail-closed rather than being guessed or silently
106
+ abandoned.
@@ -0,0 +1,220 @@
1
+ # ADR-029: Semantic Completion and Application Effect Boundary
2
+
3
+ ## Status
4
+
5
+ Accepted. V2 revision 2, 2026-09-06.
6
+
7
+ User approval covers the V2 boundary and the five recovery-contract clarifications.
8
+ Acceptance is design authority; it is not a claim of repository integration or test success.
9
+
10
+ ## Date
11
+
12
+ 2026-09-06
13
+
14
+ ## Context
15
+
16
+ Phronomy durably records Agent semantic execution progress and terminal outcomes.
17
+ After a terminal durable commit, Runtime may notify Application code through
18
+ `on_event` and settle process-local caller Tasks.
19
+
20
+ A previous proposal attempted to make terminal callback delivery itself durable
21
+ across process loss by storing a pending-delivery descriptor, rediscovering
22
+ pending callbacks on `Agent.load`, and durably acknowledging callback attempts.
23
+
24
+ That approach crossed an architectural boundary.
25
+
26
+ An arbitrary Application callback may perform an external effect outside
27
+ Phronomy's Persistence transaction domain. Phronomy cannot make that effect
28
+ exactly once. A process can die after the callback has produced an effect but
29
+ before Phronomy records an acknowledgement, so retrying the callback still
30
+ requires Application-level idempotency.
31
+
32
+ Maintaining a framework outbox/ACK protocol therefore does not remove the
33
+ Application responsibility that matters most, while it adds persistence indexes,
34
+ recovery ordering, acknowledgement reconciliation and callback-specific state to
35
+ the Agent execution engine.
36
+
37
+ ## Decision
38
+
39
+ ### 1. Semantic terminal state remains the durable boundary
40
+
41
+ The existing AgentExecution terminal statuses remain semantic terminal states:
42
+
43
+ ```text
44
+ completed
45
+ handed_off
46
+ failed
47
+ cancelled
48
+ rejected
49
+ blocked
50
+ ```
51
+
52
+ Phronomy does not add a callback-only `:completing` status.
53
+
54
+ A known-successful terminal durable transition ends the logical AgentExecution and
55
+ releases normal Agent admission according to ADR-025.
56
+
57
+ ### 2. Terminal semantic result/error evidence is durable
58
+
59
+ The terminal transaction continues to persist the canonical semantic evidence
60
+ already required by Agent durability, including as applicable:
61
+
62
+ ```text
63
+ terminal AgentExecution
64
+ AgentRoot revision/lifecycle state
65
+ Journal terminal facts
66
+ result_ref / error_ref
67
+ Provider / Tool durable evidence already owned by Agent execution
68
+ ```
69
+
70
+ Process loss after this commit must not cause the semantic execution to be rerun
71
+ merely because the Application did not observe its completion callback.
72
+
73
+ ### 3. `on_event` is a process-local observation contract
74
+
75
+ Application `on_event` callbacks are Runtime observations.
76
+
77
+ Phronomy invokes them in the current process according to the existing callback
78
+ error policy, but does not create a restart-spanning delivery obligation.
79
+
80
+ Phronomy does not persist:
81
+
82
+ ```text
83
+ terminal_delivery
84
+ delivery_pending
85
+ callback attempt_count
86
+ callback acknowledgement state
87
+ callback/Proc/Task references
88
+ ```
89
+
90
+ `Agent.load` does not scan for or redeliver missed terminal callbacks.
91
+
92
+ ### 4. Callback loss after process loss is allowed
93
+
94
+ The following failure is explicitly permitted:
95
+
96
+ ```text
97
+ terminal semantic commit succeeds
98
+ -> process dies before Application callback
99
+ -> callback is not reconstructed/redelivered
100
+ ```
101
+
102
+ The semantic outcome remains authoritative and must not be replayed.
103
+
104
+ An Application that requires restart-spanning notification must implement that
105
+ requirement in an Application-owned durable mechanism such as:
106
+
107
+ ```text
108
+ outbox
109
+ job queue
110
+ database transaction/status row
111
+ idempotency key
112
+ Application Workflow
113
+ ```
114
+
115
+ ### 5. Callback effects are outside Phronomy's exactly-once guarantee
116
+
117
+ Phronomy does not claim exactly-once semantics for:
118
+
119
+ ```text
120
+ email
121
+ webhook
122
+ external database mutation
123
+ message-broker publication
124
+ arbitrary Application callback side effect
125
+ ```
126
+
127
+ Applications own idempotency/deduplication appropriate to those systems.
128
+
129
+ ### 6. Caller Tasks remain Runtime-only
130
+
131
+ A caller-facing Task can observe same-process success/failure and callback policy.
132
+ It is not rehydrated after process loss.
133
+
134
+ No durable state exists solely to recreate or settle a lost caller Task.
135
+
136
+ ### 7. Handoff routing is independent from callback delivery
137
+
138
+ A Source Agent may terminalize as `:handed_off`.
139
+
140
+ Durable Handoff responsibility transfer is governed by ADR-030 and does not depend
141
+ on whether a local `:handoff` Application event was observed.
142
+
143
+ Losing the local callback must not lose the Target routing state.
144
+
145
+ ### 8. Read-only outcome access and execution discovery
146
+
147
+ Applications must be able to query an execution's owner, status and durable
148
+ result/error by exact semantic execution ID without invoking/recovering it or
149
+ redelivering callbacks. If admission committed before the caller received its ID,
150
+ a public discovery path from the known Agent/Team identity must cover retained
151
+ terminal as well as active executions. Candidate discovery does not guarantee
152
+ request deduplication or unambiguous correlation. Existing retention applies.
153
+
154
+ Reuse existing APIs where they meet this contract; map missing capabilities only
155
+ after baseline inspection. Do not invent a framework outbox or request registry.
156
+ See [RC-01](RECOVERY_CONTRACT_CLARIFICATIONS.md#1-rc-01--確定結果の参照と実行の発見).
157
+
158
+ ### 9. Unknown commit outcome and cancellation
159
+
160
+ A failed read is not proof of absence. A lost commit acknowledgement requires
161
+ readback with the same operation/reserved identities before new semantic work.
162
+ Unresolved storage uncertainty follows existing Persistence error/retry rules,
163
+ not Application factual invention (RC-02).
164
+
165
+ Stopping observation, losing a caller, or shutting down Runtime does not by
166
+ itself request semantic cancellation. Explicit semantic cancellation uses the
167
+ existing Agent contract and preserves exact child identities and confirmed
168
+ outcomes through its existing terminal/settlement boundaries (RC-04).
169
+
170
+ The guarantee is reuse of confirmed durable outcomes and recovery of unfinished
171
+ executions under the same semantic identity. Unknown external Provider/Tool
172
+ effects follow existing Agent Recovery; external effects are not exactly once
173
+ (RC-05).
174
+
175
+ ## Persistence / Runtime boundary
176
+
177
+ The ordering remains:
178
+
179
+ ```text
180
+ EventLoop-owned live authority
181
+ -> OffloadPool durable semantic transaction
182
+ -> Persistence commit
183
+ -> EventLoop apply / release admission
184
+ -> optional current-process Application callback
185
+ -> current-process Task settlement
186
+ ```
187
+
188
+ No callback acknowledgement transaction follows.
189
+
190
+ ## Relationship to existing ADRs
191
+
192
+ - Clarifies ADR-018 X0 boundaries: Application effects remain external.
193
+ - Preserves ADR-023: Runtime routing identities remain non-durable.
194
+ - Preserves ADR-024: EventLoop remains live-state writer.
195
+ - Preserves ADR-025: AgentExecution lifetime ends at semantic terminal commit.
196
+ - Does not alter ADR-028 preparation replay rules.
197
+ - ADR-030/031 may persist additional **semantic coordination facts**, but not
198
+ restart-spanning Application callback delivery.
199
+
200
+ ## Required invariants
201
+
202
+ 1. Known terminal semantic work is never replayed merely because a callback may
203
+ have been lost.
204
+ 2. No terminal callback-delivery metadata/index/ACK protocol is required.
205
+ 3. Callbacks, Tasks and external side effects remain Runtime/Application concerns.
206
+ 4. Agent terminal statuses remain semantic states, not notification states.
207
+ 5. Phronomy does not claim exactly-once external effects.
208
+ 6. Read-only result access and retained execution discovery do not trigger work.
209
+ 7. Read/commit uncertainty and observation loss do not authorize replacement work.
210
+
211
+ ## Non-goals
212
+
213
+ This ADR does not:
214
+
215
+ - provide restart-spanning callback delivery;
216
+ - provide arbitrary callback-side-effect deduplication;
217
+ - recover caller Tasks;
218
+ - introduce an Application outbox inside Persistence;
219
+ - change Handoff routing semantics;
220
+ - change cross-process ownership guarantees.