phronomy 0.22.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.
- checksums.yaml +4 -4
- data/.mutant.yml +3 -4
- data/CHANGELOG.md +215 -10
- data/CONTRIBUTING.md +81 -9
- data/README.md +15 -6
- data/VERIFY.sh +587 -0
- data/benchmark/bench_agent_invoke.rb +2 -2
- data/benchmark/bench_context_assembler.rb +39 -68
- data/benchmark/bench_regression.rb +2 -2
- data/docs/architecture/agent-context.md +174 -0
- data/docs/architecture/before-llm-input.md +78 -0
- data/docs/architecture/context-management.md +232 -0
- data/docs/architecture/knowledge-and-rag.md +130 -0
- data/docs/architecture/multi-agent-handoff.md +147 -0
- data/docs/architecture/persistence.md +186 -0
- data/docs/architecture/removed/agent-context.md +72 -0
- data/docs/architecture/security-boundaries.md +173 -0
- data/docs/architecture/tracing.md +194 -0
- data/docs/architecture.md +89 -0
- data/docs/archive/design/archived/04_api_design.md +507 -0
- data/docs/archive/design/archived/09_guardrails.md +186 -0
- data/docs/archive/design/archived/17_rails_integration.md +175 -0
- data/docs/archive/design/historical/00_design_philosophy.md +122 -0
- data/docs/archive/design/historical/01_rubyllm_evaluation.md +178 -0
- data/docs/archive/design/historical/06_design_decisions.md +143 -0
- data/docs/changelog/0.14-and-earlier.md +1 -1
- data/docs/decisions/001-rubyllm-as-provider-layer.md +6 -1
- data/docs/decisions/002-workflow-context-immutability.md +26 -1
- data/docs/decisions/006-no-built-in-guardrails.md +2 -1
- data/docs/decisions/012-canonical-execution-log-and-context-policy.md +120 -38
- data/docs/decisions/014-unified-persistence-durable-state.md +9 -2
- data/docs/decisions/016-semantic-multi-agent-handoff.md +114 -0
- data/docs/decisions/017-design-authority-and-adr-governance.md +200 -0
- data/docs/decisions/018-durability-guarantees-and-failure-model.md +488 -0
- data/docs/decisions/019-filter-contract-and-security-boundaries.md +229 -0
- data/docs/decisions/020-canonical-workflow-instance-identity.md +177 -0
- data/docs/decisions/021-generic-agent-invocation-identity-removal.md +119 -0
- data/docs/decisions/022-agent-execution-parent-identity-and-runtime-routing-boundary.md +193 -0
- data/docs/decisions/023-fsm-session-incarnation-identity-and-routing.md +139 -0
- data/docs/decisions/024-event-loop-single-writer-agent-runtime.md +188 -0
- data/docs/decisions/025-process-local-agent-ownership-and-runtime-admission.md +249 -0
- data/docs/decisions/026-workflow-runtime-admission-and-durable-terminal-barrier.md +257 -0
- data/docs/decisions/027-llm-adapter-provider-boundary.md +93 -0
- data/docs/decisions/028-preparing-recovery-replay-contract.md +106 -0
- data/docs/decisions/029-semantic-completion-and-application-effect-boundary.md +220 -0
- data/docs/decisions/030-agent-handoff-domain-and-durable-responsibility.md +235 -0
- data/docs/decisions/031-durable-multi-agent-coordination.md +301 -0
- data/docs/decisions/README.md +176 -0
- data/docs/design/durable-semantic-coordination/CHANGELOG_V2_REVISION_2.md +33 -0
- data/docs/design/durable-semantic-coordination/CONTINUATION_DECISION_REFACTOR.md +191 -0
- data/docs/design/durable-semantic-coordination/IMPLEMENTATION_DESIGN_V2.md +862 -0
- data/docs/design/durable-semantic-coordination/IMPLEMENTATION_REPORT.md +106 -0
- data/docs/design/durable-semantic-coordination/RECOVERY_CONTRACT_CLARIFICATIONS.md +179 -0
- data/docs/design/durable-semantic-coordination/RESPONSIBILITY_BOUNDARY_REVIEW.md +302 -0
- data/docs/features.md +65 -11
- data/docs/getting-started.md +77 -45
- data/docs/migrations/0.19.md +14 -7
- data/docs/migrations/0.22.md +390 -0
- data/docs/migrations/durable-semantic-coordination-v2.md +65 -0
- data/docs/persistence-backends.md +129 -40
- data/docs/runtime-and-concurrency.md +227 -33
- data/examples/README.md +13 -0
- data/lib/phronomy/agent/agent_execution.rb +21 -17
- data/lib/phronomy/agent/agent_invocation.rb +288 -93
- data/lib/phronomy/agent/agent_invocation_session_builder.rb +236 -202
- data/lib/phronomy/agent/agent_root.rb +3 -3
- data/lib/phronomy/agent/approval_evaluation_request.rb +37 -19
- data/lib/phronomy/agent/async_event_api.rb +162 -72
- data/lib/phronomy/agent/base.rb +416 -181
- data/lib/phronomy/agent/concerns/before_llm_input.rb +1 -1
- data/lib/phronomy/agent/context_assembler.rb +437 -178
- data/lib/phronomy/agent/context_candidate_resolver.rb +2 -2
- data/lib/phronomy/agent/context_plan.rb +18 -13
- data/lib/phronomy/agent/context_plan_validator.rb +246 -88
- data/lib/phronomy/agent/context_policies/default.rb +123 -34
- data/lib/phronomy/agent/context_policy.rb +109 -3
- data/lib/phronomy/agent/context_policy_input.rb +244 -0
- data/lib/phronomy/agent/context_policy_input_builder.rb +241 -0
- data/lib/phronomy/agent/exact_execution.rb +153 -0
- data/lib/phronomy/agent/execution_cancellation.rb +25 -0
- data/lib/phronomy/agent/execution_coordinator.rb +2417 -572
- data/lib/phronomy/agent/handoff.rb +43 -0
- data/lib/phronomy/agent/handoff_capability_factory.rb +45 -0
- data/lib/phronomy/agent/handoff_context.rb +120 -0
- data/lib/phronomy/agent/handoff_execution_coordinator.rb +143 -0
- data/lib/phronomy/agent/handoff_policy.rb +143 -0
- data/lib/phronomy/agent/handoff_projection.rb +207 -0
- data/lib/phronomy/agent/handoff_request.rb +45 -0
- data/lib/phronomy/agent/handoff_runner.rb +178 -0
- data/lib/phronomy/agent/handoff_state.rb +43 -0
- data/lib/phronomy/agent/journal_record.rb +17 -4
- data/lib/phronomy/agent/llm_input_build_context.rb +1 -1
- data/lib/phronomy/agent/llm_input_manifest.rb +277 -2
- data/lib/phronomy/agent/llm_operation_result.rb +12 -7
- data/lib/phronomy/agent/phase_machine_builder.rb +19 -7
- data/lib/phronomy/agent/provider_call_outcome.rb +23 -7
- data/lib/phronomy/agent/recovery_coordinator/continuation.rb +174 -0
- data/lib/phronomy/agent/recovery_coordinator/installation.rb +381 -0
- data/lib/phronomy/agent/recovery_coordinator/resolution.rb +511 -0
- data/lib/phronomy/agent/recovery_coordinator.rb +217 -0
- data/lib/phronomy/agent/recovery_support.rb +504 -0
- data/lib/phronomy/agent/ruby_llm_materializer.rb +16 -13
- data/lib/phronomy/agent/selection/candidate.rb +53 -0
- data/lib/phronomy/agent/selection/constraint.rb +49 -0
- data/lib/phronomy/agent/shared_state.rb +38 -1
- data/lib/phronomy/agent/tool_approval_request.rb +33 -5
- data/lib/phronomy/agent/tool_definition_set.rb +49 -3
- data/lib/phronomy/agent/tool_invocation.rb +339 -103
- data/lib/phronomy/agent/tool_invocation_session_builder.rb +49 -45
- data/lib/phronomy/agent.rb +20 -2
- data/lib/phronomy/agent_already_exists_error.rb +5 -0
- data/lib/phronomy/agent_purged_error.rb +5 -0
- data/lib/phronomy/engine/concurrency/offload_pool.rb +17 -3
- data/lib/phronomy/engine/concurrency/physical_completion_task.rb +135 -0
- data/lib/phronomy/engine/event_loop.rb +622 -63
- data/lib/phronomy/engine/fsm_session.rb +194 -21
- data/lib/phronomy/engine/runtime/agent_ownership_registry.rb +352 -0
- data/lib/phronomy/engine/runtime/team_ownership_registry.rb +77 -0
- data/lib/phronomy/engine/runtime.rb +92 -20
- data/lib/phronomy/generator_verifier.rb +12 -14
- data/lib/phronomy/invocation_context.rb +9 -29
- data/lib/phronomy/multi_agent/admission_registry.rb +51 -0
- data/lib/phronomy/multi_agent/durable_subagent_coordinator.rb +134 -0
- data/lib/phronomy/multi_agent/fan_out_invocation.rb +24 -33
- data/lib/phronomy/multi_agent/fan_out_session_builder.rb +12 -19
- data/lib/phronomy/multi_agent/orchestrator.rb +71 -26
- data/lib/phronomy/multi_agent/team_coordinator.rb +473 -125
- data/lib/phronomy/multi_agent/team_execution.rb +44 -0
- data/lib/phronomy/multi_agent/team_root.rb +41 -0
- data/lib/phronomy/persistence/durable_codec.rb +706 -0
- data/lib/phronomy/persistence/durable_record.rb +117 -0
- data/lib/phronomy/persistence/in_memory.rb +471 -133
- data/lib/phronomy/persistence/migration/initial_format_migration.rb +226 -0
- data/lib/phronomy/persistence/repository_facades.rb +535 -0
- data/lib/phronomy/persistence.rb +174 -40
- data/lib/phronomy/recovery.rb +186 -0
- data/lib/phronomy/testing/persistence_contract/a_journal_repository.rb +2 -2
- data/lib/phronomy/testing/persistence_contract/a_persistence_backend.rb +2 -1
- data/lib/phronomy/testing/persistence_contract/a_workflow_state_repository.rb +19 -19
- data/lib/phronomy/testing/persistence_contract/an_agent_repository.rb +3 -3
- data/lib/phronomy/testing/persistence_contract/an_execution_repository.rb +5 -5
- data/lib/phronomy/testing/persistence_contract/coordination_repositories.rb +137 -0
- data/lib/phronomy/testing/persistence_contract.rb +5 -0
- data/lib/phronomy/tools/agent.rb +1 -1
- data/lib/phronomy/tracing/automatic.rb +176 -0
- data/lib/phronomy/tracing/base.rb +11 -2
- data/lib/phronomy/tracing/langfuse_tracer.rb +20 -12
- data/lib/phronomy/version.rb +1 -1
- data/lib/phronomy/workflow.rb +3 -6
- data/lib/phronomy/workflow_context.rb +14 -5
- data/lib/phronomy/workflow_recovery.rb +123 -0
- data/lib/phronomy/workflow_runner.rb +468 -256
- data/lib/phronomy.rb +6 -0
- data/scripts/api_snapshot.rb +12 -0
- data/sig/phronomy/agent.rbs +209 -7
- data/sig/phronomy/handoff.rbs +41 -0
- data/sig/phronomy/multi_agent.rbs +35 -0
- data/sig/phronomy/persistence.rbs +123 -4
- data/sig/phronomy/runtime.rbs +1 -4
- data/sig/phronomy/workflow.rbs +2 -2
- data/sig/phronomy.rbs +10 -0
- metadata +84 -18
- data/examples/workflows/agent_event_mapping.rb +0 -101
- data/examples/workflows/generic_task_event_mapping.rb +0 -66
- data/lib/phronomy/agent/activation_registry.rb +0 -28
- data/lib/phronomy/agent/agent_execution_activation.rb +0 -172
- data/lib/phronomy/agent/context_candidate.rb +0 -47
- data/lib/phronomy/agent/context_parts/budget/token_budget_packer.rb +0 -53
- data/lib/phronomy/agent/context_parts/requirements/required_context_resolver.rb +0 -56
- data/lib/phronomy/agent/context_parts/selectors/recent_first_selector.rb +0 -30
- data/lib/phronomy/agent/context_parts/unit_builders/dependency_aware_unit_builder.rb +0 -118
- data/lib/phronomy/agent/context_policy_descriptor.rb +0 -49
- data/lib/phronomy/agent/context_policy_registry.rb +0 -46
- data/lib/phronomy/agent/context_request.rb +0 -35
- data/lib/phronomy/agent/context_selection_unit.rb +0 -38
- data/lib/phronomy/agent/derived_content_spec.rb +0 -34
- data/lib/phronomy/agent/runner.rb +0 -97
- data/lib/phronomy/multi_agent/handoff.rb +0 -64
|
@@ -0,0 +1,301 @@
|
|
|
1
|
+
# ADR-031: Durable Multi-Agent Semantic Coordination
|
|
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 exposes:
|
|
17
|
+
|
|
18
|
+
- `MultiAgent::Orchestrator < Agent::Base`, with child Agents/Tools and fan-out
|
|
19
|
+
helpers; and
|
|
20
|
+
- `MultiAgent::TeamCoordinator`, with coordinator-generated tasks and a worker pool.
|
|
21
|
+
|
|
22
|
+
Individual AgentExecutions are durable, but process-local coordination state is
|
|
23
|
+
not. Losing child identities, task assignments or confirmed worker outcomes can
|
|
24
|
+
cause Phronomy to repeat semantic work it owns.
|
|
25
|
+
|
|
26
|
+
The previous proposal also attempted to make standalone fan-out convenience APIs,
|
|
27
|
+
arbitrary Team aggregation callbacks and terminal Application callbacks durable.
|
|
28
|
+
Responsibility review found those parts too broad.
|
|
29
|
+
|
|
30
|
+
This ADR therefore defines durability at the **framework-owned semantic
|
|
31
|
+
coordination boundary**, not at every callback/convenience API boundary.
|
|
32
|
+
|
|
33
|
+
## Decision
|
|
34
|
+
|
|
35
|
+
### 1. MultiAgent durability means semantic progress recovery
|
|
36
|
+
|
|
37
|
+
For a durable MultiAgent operation:
|
|
38
|
+
|
|
39
|
+
```text
|
|
40
|
+
process/runtime loss
|
|
41
|
+
-> reconstruct from durable coordination facts
|
|
42
|
+
-> reuse confirmed child/worker outcomes
|
|
43
|
+
-> recover exact unfinished executions
|
|
44
|
+
-> admit absent reserved executions only after authoritative read/admission
|
|
45
|
+
-> resolve unknown external effects through existing Agent Recovery
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
FSMSession, Task, callback and Runtime queues remain disposable.
|
|
49
|
+
|
|
50
|
+
### 2. Orchestrator durability is rooted in an existing Orchestrator AgentExecution
|
|
51
|
+
|
|
52
|
+
`MultiAgent::Orchestrator < Agent::Base` already has canonical Agent identity.
|
|
53
|
+
|
|
54
|
+
When child coordination occurs **inside an existing Orchestrator AgentExecution**,
|
|
55
|
+
that AgentExecution references an immutable coordination snapshot containing, as
|
|
56
|
+
needed:
|
|
57
|
+
|
|
58
|
+
```text
|
|
59
|
+
coordination kind / phase
|
|
60
|
+
child slot
|
|
61
|
+
child Agent definition identity/version
|
|
62
|
+
reserved child agent_id
|
|
63
|
+
reserved child execution_id
|
|
64
|
+
restart-required input/config refs
|
|
65
|
+
child semantic state
|
|
66
|
+
result_ref / error_ref
|
|
67
|
+
on_error / max_concurrency semantic options
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
No separate Orchestrator repository or generic multi-agent execution ID is added.
|
|
71
|
+
|
|
72
|
+
### 3. Existing fan-out Runtime FSM remains reconstructable machinery
|
|
73
|
+
|
|
74
|
+
`FanOutInvocation` / `FSMSession` remain Runtime projections.
|
|
75
|
+
|
|
76
|
+
Recovery builds a fresh runtime invocation/session from the durable coordination
|
|
77
|
+
snapshot and fresh Runtime identities.
|
|
78
|
+
|
|
79
|
+
### 4. Framework-owned child identities are reserved before semantic work
|
|
80
|
+
|
|
81
|
+
Before a durable Orchestrator child begins:
|
|
82
|
+
|
|
83
|
+
```text
|
|
84
|
+
reserve child agent_id
|
|
85
|
+
reserve child execution_id
|
|
86
|
+
persist parent child slot + restart-required refs
|
|
87
|
+
then create/load child and start exact reserved execution
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
Recovery distinguishes absent/nonterminal/terminal exact child state and never
|
|
91
|
+
creates a replacement simply because Runtime callbacks were lost.
|
|
92
|
+
|
|
93
|
+
### 5. Durable child definitions must be reconstructable from stable wiring
|
|
94
|
+
|
|
95
|
+
For the durable path, a child Agent class must be resolvable from stable current
|
|
96
|
+
Orchestrator/Application wiring, initially the concrete Orchestrator class's
|
|
97
|
+
registered subagents.
|
|
98
|
+
|
|
99
|
+
Invocation-only anonymous/arbitrary class handles are not persisted.
|
|
100
|
+
|
|
101
|
+
This restriction applies only to APIs/paths that claim restart durability.
|
|
102
|
+
|
|
103
|
+
### 6. Standalone `dispatch_parallel*` / `fan_out*` remain Runtime-only convenience APIs
|
|
104
|
+
|
|
105
|
+
A direct Application call to:
|
|
106
|
+
|
|
107
|
+
```ruby
|
|
108
|
+
orchestrator.dispatch_parallel(...)
|
|
109
|
+
orchestrator.fan_out(...)
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
outside a live parent Orchestrator AgentExecution does **not** create a synthetic
|
|
113
|
+
AgentExecution solely for durability.
|
|
114
|
+
|
|
115
|
+
It keeps current-process semantics and may continue accepting Runtime-only Agent
|
|
116
|
+
class wiring.
|
|
117
|
+
|
|
118
|
+
If durable fan-out is required, the Application must place the work under:
|
|
119
|
+
|
|
120
|
+
- an Orchestrator AgentExecution with stable child wiring; or
|
|
121
|
+
- an Application Workflow when the operation is application-process
|
|
122
|
+
orchestration.
|
|
123
|
+
|
|
124
|
+
This avoids inventing durable parent identity for a convenience call.
|
|
125
|
+
|
|
126
|
+
### 7. Durable framework-owned Orchestrator children share the parent Persistence domain
|
|
127
|
+
|
|
128
|
+
A durable parent/child coordination path uses the same Persistence domain.
|
|
129
|
+
|
|
130
|
+
External remote effects reached through Tools/Application integration remain X0
|
|
131
|
+
external effects.
|
|
132
|
+
|
|
133
|
+
### 8. TeamCoordinator is a purpose-specific durable semantic entity
|
|
134
|
+
|
|
135
|
+
TeamCoordinator remains under `MultiAgent`, not `Agent::Base`.
|
|
136
|
+
|
|
137
|
+
It gains:
|
|
138
|
+
|
|
139
|
+
```text
|
|
140
|
+
team_id
|
|
141
|
+
team_execution_id
|
|
142
|
+
team_definition id/version
|
|
143
|
+
TeamRoot
|
|
144
|
+
TeamExecution
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
This is retained because Phronomy itself owns the Team queue/assignment/worker
|
|
148
|
+
abstraction.
|
|
149
|
+
|
|
150
|
+
### 9. Team task queue and worker assignment are durable facts
|
|
151
|
+
|
|
152
|
+
TeamExecution durably records:
|
|
153
|
+
|
|
154
|
+
```text
|
|
155
|
+
canonical tasks
|
|
156
|
+
task-generation finalized state
|
|
157
|
+
worker slots / stable worker agent_id
|
|
158
|
+
task -> worker assignment
|
|
159
|
+
reserved worker execution_id
|
|
160
|
+
worker terminal result/error
|
|
161
|
+
final Team result/error
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
Before worker semantic execution starts, its assignment and reserved exact
|
|
165
|
+
execution identity are committed.
|
|
166
|
+
|
|
167
|
+
### 10. Worker identity is stable within one TeamExecution
|
|
168
|
+
|
|
169
|
+
A worker slot reuses its logical Agent identity for that TeamExecution so worker
|
|
170
|
+
context/transcript semantics remain coherent across assigned tasks.
|
|
171
|
+
|
|
172
|
+
This ADR does not require worker identity/history to survive into another
|
|
173
|
+
TeamExecution.
|
|
174
|
+
|
|
175
|
+
### 11. Team scheduler is a replay-safe decision function
|
|
176
|
+
|
|
177
|
+
Application `schedule` may run again while no assignment has been durably
|
|
178
|
+
committed.
|
|
179
|
+
|
|
180
|
+
Contract:
|
|
181
|
+
|
|
182
|
+
- it must not perform externally observable one-shot effects;
|
|
183
|
+
- it selects from the supplied available worker projection;
|
|
184
|
+
- repeated execution before assignment commit is allowed;
|
|
185
|
+
- after assignment commit, recovery uses the durable assignment and does not
|
|
186
|
+
rerun scheduling for that task.
|
|
187
|
+
|
|
188
|
+
No scheduler result needs a separate unknown-outcome protocol.
|
|
189
|
+
|
|
190
|
+
### 12. Team aggregation is pure/replay-safe result computation
|
|
191
|
+
|
|
192
|
+
Application `aggregate` receives canonical durable assignment results.
|
|
193
|
+
|
|
194
|
+
Contract:
|
|
195
|
+
|
|
196
|
+
- no externally observable one-shot side effects;
|
|
197
|
+
- repeated invocation with the same canonical assignments must be semantically
|
|
198
|
+
equivalent;
|
|
199
|
+
- if process loss occurs before aggregate result/error is durably committed,
|
|
200
|
+
Phronomy may invoke `aggregate` again;
|
|
201
|
+
- on normal return/raise, Phronomy durably records the final result/error before
|
|
202
|
+
Team terminalization.
|
|
203
|
+
|
|
204
|
+
There is no `aggregation=started -> outcome unknown -> manual resolve` protocol.
|
|
205
|
+
|
|
206
|
+
Applications perform external post-Team effects after obtaining/reconciling the
|
|
207
|
+
Team result.
|
|
208
|
+
|
|
209
|
+
### 13. Team progress and terminal callbacks are Runtime-only
|
|
210
|
+
|
|
211
|
+
Streaming task-completion callbacks and final Application notifications are
|
|
212
|
+
current-process observations.
|
|
213
|
+
|
|
214
|
+
Canonical task/worker/Team semantic outcomes are durable; callback delivery is
|
|
215
|
+
not.
|
|
216
|
+
|
|
217
|
+
No Team delivery-pending index or restart redelivery obligation is introduced.
|
|
218
|
+
|
|
219
|
+
### 14. Workflow remains the Application process-orchestration domain
|
|
220
|
+
|
|
221
|
+
Public domain ownership remains:
|
|
222
|
+
|
|
223
|
+
```text
|
|
224
|
+
Agent
|
|
225
|
+
Agent semantic execution + Agent Handoff
|
|
226
|
+
|
|
227
|
+
MultiAgent
|
|
228
|
+
durable framework-owned Orchestrator child coordination
|
|
229
|
+
durable Team queue/assignment/worker coordination
|
|
230
|
+
Runtime-only convenience fan-out outside a durable parent
|
|
231
|
+
|
|
232
|
+
Workflow
|
|
233
|
+
explicit Application-defined durable process/state-machine orchestration
|
|
234
|
+
durable ordering of Application-owned steps/effects when modeled by the app
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
### 15. Recovery contract clarifications
|
|
238
|
+
|
|
239
|
+
The normative [RC-01 through RC-05 contracts](../design/durable-semantic-coordination/RECOVERY_CONTRACT_CLARIFICATIONS.md)
|
|
240
|
+
apply to existing Orchestrator executions and Team executions:
|
|
241
|
+
|
|
242
|
+
- expose read-only status/result access and retained execution discovery;
|
|
243
|
+
- distinguish authoritative absence from read failure/unknown commit outcome;
|
|
244
|
+
- reconcile writes with the same reserved identities using existing Persistence
|
|
245
|
+
protocols, including Team-owned operation facts;
|
|
246
|
+
- verify declared definition id/version, registered slot wiring and reserved
|
|
247
|
+
owner/Agent/execution identities before continuation;
|
|
248
|
+
- preserve committed inputs/config, assignments and outcomes instead of
|
|
249
|
+
recalculating them with changed current code;
|
|
250
|
+
- distinguish observation loss/shutdown from semantic cancellation;
|
|
251
|
+
- stop new dispatch on accepted parent-run cancellation, reconcile already
|
|
252
|
+
admitted children using existing Agent cancellation and terminal barriers,
|
|
253
|
+
retain terminal outcomes and exact identities needed after restart;
|
|
254
|
+
- restrict cancellation to the current run's owned children, never unrelated
|
|
255
|
+
executions or later runs.
|
|
256
|
+
|
|
257
|
+
Stable version declarations do not prove Ruby code equivalence. Application code
|
|
258
|
+
must maintain declared compatibility; no Proc hash or generic registry is added.
|
|
259
|
+
Uncommitted replay-safe schedule/aggregate computation remains replayable.
|
|
260
|
+
No dedicated cancellation execution engine or callback recovery service is added.
|
|
261
|
+
|
|
262
|
+
## Persistence changes
|
|
263
|
+
|
|
264
|
+
The durable root surface expands to include:
|
|
265
|
+
|
|
266
|
+
```text
|
|
267
|
+
handoff_states
|
|
268
|
+
teams
|
|
269
|
+
team_executions
|
|
270
|
+
```
|
|
271
|
+
|
|
272
|
+
Orchestrator continues to use Agent repositories.
|
|
273
|
+
|
|
274
|
+
No execution/team terminal-delivery pending index is added.
|
|
275
|
+
|
|
276
|
+
## Required invariants
|
|
277
|
+
|
|
278
|
+
1. Durable coordination is claimed only where a durable semantic root exists.
|
|
279
|
+
2. Confirmed child/worker terminal work is never blindly rerun.
|
|
280
|
+
3. Child/worker semantic work begins only after exact recoverable identity is
|
|
281
|
+
durably known.
|
|
282
|
+
4. Orchestrator durable child coordination uses its existing AgentExecution.
|
|
283
|
+
5. Standalone convenience fan-out is explicitly Runtime-only.
|
|
284
|
+
6. Team has stable identity/execution and durable tasks/assignments/worker results.
|
|
285
|
+
7. Scheduler and aggregator are replay-safe Application functions, not arbitrary
|
|
286
|
+
side-effect transaction boundaries.
|
|
287
|
+
8. Callback/Task/FSMSession/Proc objects are never persisted.
|
|
288
|
+
9. Workflow remains the appropriate domain for Application-defined durable process
|
|
289
|
+
orchestration.
|
|
290
|
+
|
|
291
|
+
## Non-goals
|
|
292
|
+
|
|
293
|
+
This ADR does not:
|
|
294
|
+
|
|
295
|
+
- make standalone convenience fan-out restart-durable;
|
|
296
|
+
- make external Provider/Tool/Application effects exactly once;
|
|
297
|
+
- persist scheduler/aggregator Procs or callbacks;
|
|
298
|
+
- provide restart-spanning Team callback delivery;
|
|
299
|
+
- require worker history across TeamExecutions;
|
|
300
|
+
- add a generic global Agent class registry;
|
|
301
|
+
- turn MultiAgent into a public Workflow alias.
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
# Architecture Decision Records
|
|
2
|
+
|
|
3
|
+
This directory contains Phronomy Architecture Decision Records (ADRs).
|
|
4
|
+
|
|
5
|
+
The repository-wide architecture authority model is defined by
|
|
6
|
+
[`017-design-authority-and-adr-governance`](017-design-authority-and-adr-governance.md).
|
|
7
|
+
This index is the canonical navigation surface for ADR identity, status, and
|
|
8
|
+
supersession relationships.
|
|
9
|
+
|
|
10
|
+
## Canonical ADR identity
|
|
11
|
+
|
|
12
|
+
The **canonical decision key** is the ADR filename basename, for example:
|
|
13
|
+
|
|
14
|
+
```text
|
|
15
|
+
012-canonical-execution-log-and-context-policy
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
The three-digit numeric prefix is an ordering/display number. It is not, by
|
|
19
|
+
itself, a globally unique historical identifier because this repository
|
|
20
|
+
already contains two legacy ADRs numbered `011`.
|
|
21
|
+
|
|
22
|
+
Therefore:
|
|
23
|
+
|
|
24
|
+
- new or modified normative material SHOULD link to the ADR file or use its
|
|
25
|
+
full canonical decision key;
|
|
26
|
+
- the bare label `ADR-011` is ambiguous and MUST NOT be used to identify one
|
|
27
|
+
of the two legacy `011` decisions;
|
|
28
|
+
- existing historical text is not rewritten merely to normalize old
|
|
29
|
+
references.
|
|
30
|
+
|
|
31
|
+
## Status and authority
|
|
32
|
+
|
|
33
|
+
ADR status has architecture meaning:
|
|
34
|
+
|
|
35
|
+
- **Accepted** — normative architecture intent unless explicitly superseded.
|
|
36
|
+
- **Amended** — normative architecture intent including its recorded
|
|
37
|
+
amendments.
|
|
38
|
+
- **Superseded** — retained as decision history; non-normative for the
|
|
39
|
+
superseded scope.
|
|
40
|
+
- **Proposed** — not normative until accepted.
|
|
41
|
+
|
|
42
|
+
An Accepted ADR can temporarily disagree with implementation reality. That is
|
|
43
|
+
an **architecture inconsistency**, not permission to silently treat whichever
|
|
44
|
+
artifact is newer as authoritative. The inconsistency must be tracked and
|
|
45
|
+
resolved explicitly.
|
|
46
|
+
|
|
47
|
+
## ADR index
|
|
48
|
+
|
|
49
|
+
| Canonical decision key | Status | Normative now? | Supersession / note |
|
|
50
|
+
|---|---|---:|---|
|
|
51
|
+
| [`001-rubyllm-as-provider-layer`](001-rubyllm-as-provider-layer.md) | Superseded | No | Superseded by [`027-llm-adapter-provider-boundary`](027-llm-adapter-provider-boundary.md); historical RubyLLM adoption rationale retained. |
|
|
52
|
+
| [`002-workflow-context-immutability`](002-workflow-context-immutability.md) | Amended | Yes | `WorkflowContext#merge` remains new-instance semantics; direct generated field writers are EventLoop-owned guarded mutation APIs. |
|
|
53
|
+
| [`003-event-loop-singleton`](003-event-loop-singleton.md) | Accepted | Yes | Current until explicitly superseded/refined. |
|
|
54
|
+
| [`004-invoke-timeout-is-not-cancellation`](004-invoke-timeout-is-not-cancellation.md) | Superseded | No | Superseded by [`011-delegate-transport-policy-to-adapters`](011-delegate-transport-policy-to-adapters.md). |
|
|
55
|
+
| [`005-static-knowledge-class-level-cache`](005-static-knowledge-class-level-cache.md) | Superseded | No | Superseded by [`013-journal-backed-knowledge-as-context-candidates`](013-journal-backed-knowledge-as-context-candidates.md). |
|
|
56
|
+
| [`006-no-built-in-guardrails`](006-no-built-in-guardrails.md) | Superseded | No | Superseded by [`019-filter-contract-and-security-boundaries`](019-filter-contract-and-security-boundaries.md); historical minimal-built-in/Guardrail rationale retained. |
|
|
57
|
+
| [`007-mcp-is-beta-stability`](007-mcp-is-beta-stability.md) | Accepted | Yes | Current. |
|
|
58
|
+
| [`008-orchestrator-uses-os-threads`](008-orchestrator-uses-os-threads.md) | Superseded | No | Superseded by [`010-cooperative-first-concurrency`](010-cooperative-first-concurrency.md). |
|
|
59
|
+
| [`009-state-store-abstraction`](009-state-store-abstraction.md) | Superseded | No | Superseded by [`014-unified-persistence-durable-state`](014-unified-persistence-durable-state.md). |
|
|
60
|
+
| [`010-cooperative-first-concurrency`](010-cooperative-first-concurrency.md) | Accepted | Yes | Current until explicitly refined/superseded. |
|
|
61
|
+
| [`011-build-context-as-single-llm-input-authority`](011-build-context-as-single-llm-input-authority.md) | Superseded | No | Superseded by [`012-canonical-execution-log-and-context-policy`](012-canonical-execution-log-and-context-policy.md). |
|
|
62
|
+
| [`011-delegate-transport-policy-to-adapters`](011-delegate-transport-policy-to-adapters.md) | Accepted | Yes | Legacy duplicate numeric prefix; use the full canonical key. |
|
|
63
|
+
| [`012-canonical-execution-log-and-context-policy`](012-canonical-execution-log-and-context-policy.md) | Accepted | Yes | Current Journal / Manifest / Context authority. |
|
|
64
|
+
| [`013-journal-backed-knowledge-as-context-candidates`](013-journal-backed-knowledge-as-context-candidates.md) | Accepted | Yes | Current persistent Knowledge authority. |
|
|
65
|
+
| [`014-unified-persistence-durable-state`](014-unified-persistence-durable-state.md) | Accepted | Yes | Durable-backend and live-owner/no-reload intent remains current; live Agent execution mutation is refined by ADR-024, same-process Agent identity/admission ownership by ADR-025, and same-process Workflow admission/terminal-barrier ordering by ADR-026. Workflow identity terminology is superseded by ADR-020, generic `InvocationContext` / Agent correlation semantics by ADR-021, and concrete FSMSession/Agent-Tool routing identity by ADR-023. |
|
|
66
|
+
| [`015-tool-public-facade-and-rbs-boundary`](015-tool-public-facade-and-rbs-boundary.md) | Accepted | Yes | Current Tool façade / extension-SPI / RBS boundary. |
|
|
67
|
+
| [`016-semantic-multi-agent-handoff`](016-semantic-multi-agent-handoff.md) | Superseded | No | Superseded by [ADR-030](030-agent-handoff-domain-and-durable-responsibility.md), including Agent-domain ownership and exact Target recovery. |
|
|
68
|
+
| [`017-design-authority-and-adr-governance`](017-design-authority-and-adr-governance.md) | Accepted | Yes | Repository-wide architecture authority and ADR governance. |
|
|
69
|
+
| [`018-durability-guarantees-and-failure-model`](018-durability-guarantees-and-failure-model.md) | Accepted | Yes | Repository-wide durability/concurrency/external-effect guarantee vocabulary and F0-F4/X0 failure model. |
|
|
70
|
+
| [`019-filter-contract-and-security-boundaries`](019-filter-contract-and-security-boundaries.md) | Accepted | Yes | Current Filter transform/block and bounded PromptInjectionFilter/isolation boundaries; the follow-up review adds no fourth Context Filter call site and places semantic Context trust in Application ContextPolicy. |
|
|
71
|
+
| [`020-canonical-workflow-instance-identity`](020-canonical-workflow-instance-identity.md) | Accepted | Yes | Canonical logical/durable Workflow identity and CG-01 clean-break migration. |
|
|
72
|
+
| [`021-generic-agent-invocation-identity-removal`](021-generic-agent-invocation-identity-removal.md) | Accepted | Yes | Removes generic Agent/InvocationContext identity and canonical Journal `correlation_id`; CG-02 is closed, with targeted legacy durable-key read compatibility and no eager rewrite. |
|
|
73
|
+
| [`022-agent-execution-parent-identity-and-runtime-routing-boundary`](022-agent-execution-parent-identity-and-runtime-routing-boundary.md) | Accepted | Yes | Canonicalizes Agent-owned Tool/approval logical parent as `execution_id`; CG-03a is reconciled, ADR-023 supplies incarnation routing, and ADR-024 supplies EventLoop result/live-state authority. |
|
|
74
|
+
| [`023-fsm-session-incarnation-identity-and-routing`](023-fsm-session-incarnation-identity-and-routing.md) | Accepted | Yes | FSMSession-owned incarnation identity, session-local Agent/Tool/Multi-Agent routing, and stale-target drop remain current. Its transitional Workflow identity-reservation/admission bridge is superseded by ADR-026; Agent result authority is completed by ADR-024. |
|
|
75
|
+
| [`024-event-loop-single-writer-agent-runtime`](024-event-loop-single-writer-agent-runtime.md) | Accepted | Yes | EventLoop is the single writer of Phronomy-managed live Agent execution state; removes Activation/ActivationRegistry and defines operation-specific Offload result application with current FSM + semantic-ID authority. |
|
|
76
|
+
| [`025-process-local-agent-ownership-and-runtime-admission`](025-process-local-agent-ownership-and-runtime-admission.md) | Accepted | Yes | One mutable live Agent owner per `agent_id` per Runtime; EventLoop is the primary same-process top-level admission authority while Persistence admission remains durable defense. |
|
|
77
|
+
| [`026-workflow-runtime-admission-and-durable-terminal-barrier`](026-workflow-runtime-admission-and-durable-terminal-barrier.md) | Accepted | Yes | EventLoop-owned opaque Workflow admission owner, admission-before-hydration ordering, and FSMSession-integrated durable terminal save barrier with fail-closed uncertain outcomes. |
|
|
78
|
+
| [`027-llm-adapter-provider-boundary`](027-llm-adapter-provider-boundary.md) | Accepted | Yes | Phronomy-owned Provider-call extension boundary; RubyLLM is the default adapter/integration while current input materialization remains RubyLLM-specific. |
|
|
79
|
+
| [`028-preparing-recovery-replay-contract`](028-preparing-recovery-replay-contract.md) | Accepted | Yes | Adds replay-safe same-`execution_id` recovery for durably admitted Agent `:preparing` executions when replayability is durably established; unsupported Runtime-only dependencies fail closed. |
|
|
80
|
+
| [`029-semantic-completion-and-application-effect-boundary`](029-semantic-completion-and-application-effect-boundary.md) | Accepted | Yes | V2 revision 2; framework semantic coordination and Application effect boundary. |
|
|
81
|
+
| [`030-agent-handoff-domain-and-durable-responsibility`](030-agent-handoff-domain-and-durable-responsibility.md) | Accepted | Yes | V2 revision 2; framework semantic coordination and Application effect boundary. |
|
|
82
|
+
| [`031-durable-multi-agent-coordination`](031-durable-multi-agent-coordination.md) | Accepted | Yes | V2 revision 2; framework semantic coordination and Application effect boundary. |
|
|
83
|
+
|
|
84
|
+
## Legacy duplicate `011`
|
|
85
|
+
|
|
86
|
+
The repository intentionally preserves both legacy files:
|
|
87
|
+
|
|
88
|
+
```text
|
|
89
|
+
011-build-context-as-single-llm-input-authority
|
|
90
|
+
011-delegate-transport-policy-to-adapters
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
They are different decisions. The first is superseded by ADR-012; the second
|
|
94
|
+
remains Accepted.
|
|
95
|
+
|
|
96
|
+
They MUST NOT be silently renumbered. Their filenames are stable historical
|
|
97
|
+
decision keys. New decisions may not introduce another duplicate numeric
|
|
98
|
+
prefix.
|
|
99
|
+
|
|
100
|
+
## Allocating a new ADR identifier
|
|
101
|
+
|
|
102
|
+
For a new ADR:
|
|
103
|
+
|
|
104
|
+
1. inspect all `NNN-*.md` files in this directory;
|
|
105
|
+
2. allocate `max(existing numeric prefix) + 1`;
|
|
106
|
+
3. format the number with three decimal digits;
|
|
107
|
+
4. never fill an old gap and never reuse an existing prefix;
|
|
108
|
+
5. if two unmerged changes select the same number, the change merged later
|
|
109
|
+
rebases and renumbers **only its new, not-yet-historical ADR**;
|
|
110
|
+
6. add the ADR to this index in the same change.
|
|
111
|
+
|
|
112
|
+
Existing ADRs are not renumbered merely because a numbering defect is later
|
|
113
|
+
discovered. `016-semantic-multi-agent-handoff` is therefore preserved as-is.
|
|
114
|
+
Under this rule the Design Authority decision is ADR-017.
|
|
115
|
+
|
|
116
|
+
## Superseding or amending a decision
|
|
117
|
+
|
|
118
|
+
Do not rewrite historical rationale into a fictional current history.
|
|
119
|
+
|
|
120
|
+
When superseding an ADR:
|
|
121
|
+
|
|
122
|
+
- add a new decision describing the new architecture;
|
|
123
|
+
- update the old ADR's status/supersession note only as needed;
|
|
124
|
+
- preserve the old rationale;
|
|
125
|
+
- update this index in the same change;
|
|
126
|
+
- use canonical decision keys/links where a numeric label would be ambiguous.
|
|
127
|
+
|
|
128
|
+
Amendments are appropriate only when the original decision remains the same
|
|
129
|
+
decision and the amendment can be understood without erasing the historical
|
|
130
|
+
rationale. Materially different architecture should normally be a new ADR.
|
|
131
|
+
|
|
132
|
+
## Architecture inconsistency process
|
|
133
|
+
|
|
134
|
+
Architecture intent, public contract, and implementation reality are separate
|
|
135
|
+
authority domains. If they disagree, do not resolve the conflict by recency.
|
|
136
|
+
|
|
137
|
+
An unresolved architecture inconsistency must be recorded in the active
|
|
138
|
+
repository work item (normally a GitHub issue or PR) with at least:
|
|
139
|
+
|
|
140
|
+
```text
|
|
141
|
+
Concern
|
|
142
|
+
Normative authority
|
|
143
|
+
Implementation / contract reality
|
|
144
|
+
Conflict
|
|
145
|
+
Resolution dependency
|
|
146
|
+
Status: OPEN | DEFERRED | RESOLVING | RESOLVED
|
|
147
|
+
Final resolution
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
Existing Workstream carry-forward (`CF-*`) and architecture-inconsistency
|
|
151
|
+
(`AI-*`) registers are discovery/planning evidence, not normative architecture.
|
|
152
|
+
During the current reconciliation program their unresolved contents are
|
|
153
|
+
consolidated into named Architecture Change Sets (ACS) and Compatibility Gates
|
|
154
|
+
(CG). A repository change that resolves such an item should identify the
|
|
155
|
+
corresponding ACS/CG in its PR/commit rationale.
|
|
156
|
+
|
|
157
|
+
A legacy carry-forward proposition is closed only by one of:
|
|
158
|
+
|
|
159
|
+
- adoption into current source/public contract/current documentation;
|
|
160
|
+
- an Accepted ADR;
|
|
161
|
+
- explicit rejection/non-carry disposition; or
|
|
162
|
+
- an open repository work item when the resolution is intentionally deferred.
|
|
163
|
+
|
|
164
|
+
Working registers must not be copied wholesale into current architecture
|
|
165
|
+
documentation as if they were normative decisions.
|
|
166
|
+
|
|
167
|
+
## Relationship to explanatory architecture documentation
|
|
168
|
+
|
|
169
|
+
ADRs record normative decisions. Explanatory architecture documents describe
|
|
170
|
+
the current reconciled system but do not supersede ADRs merely by being newer.
|
|
171
|
+
|
|
172
|
+
Current explanatory architecture starts at
|
|
173
|
+
[`docs/architecture.md`](../architecture.md). Non-current design snapshots are
|
|
174
|
+
segregated under `docs/archive/design/` and are non-normative. Explanatory
|
|
175
|
+
architecture documents describe the reconciled current system but do not
|
|
176
|
+
supersede ADRs merely by being newer.
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# V2 revision 2 — 改訂内容
|
|
2
|
+
|
|
3
|
+
更新日: 2026-09-06 / 状態: Accepted
|
|
4
|
+
|
|
5
|
+
## 合意反映
|
|
6
|
+
|
|
7
|
+
| 項目 | 今回の修正 |
|
|
8
|
+
|---|---|
|
|
9
|
+
| RC-01 結果参照 | exact実行IDで状態・結果を読み取る契約と、ID受領前の停止に備えたownerからの候補発見を追加 |
|
|
10
|
+
| RC-02 保存成否不明 | 正常な不存在、read障害、CAS競合、commit成否不明を区別。同じ予約済みidentityで照合 |
|
|
11
|
+
| RC-03 wiring互換性 | 定義id/version・slot・graph・Persistence境界の最低照合と、確定済みfactの優先を明記 |
|
|
12
|
+
| RC-04 cancellation | 観測終了/shutdownとsemantic cancelを区別。子の状態別処理、競合、restart後の再発見を明記 |
|
|
13
|
+
| RC-05 保証表現 | 確定outcome再利用・同一identity復旧・外部成否不明は既存Recovery、に統一 |
|
|
14
|
+
|
|
15
|
+
ADR-029/030/031、実装設計、責務境界レビュー、READMEへ対応する規範的記述を反映した。
|
|
16
|
+
詳細契約と検証条件はRECOVERY_CONTRACT_CLARIFICATIONS.mdにまとめ、資料間で参照する。
|
|
17
|
+
承認前のProposed表記をAcceptedへ更新した。新機能の再承認を要求しない。
|
|
18
|
+
|
|
19
|
+
## 実装状態の訂正
|
|
20
|
+
|
|
21
|
+
引き継ぎ文書の旧実装件数・静的検証成功は、前セッションの報告として残す。
|
|
22
|
+
この分岐先で実装を再検証した事実にはしない。現在取得できたのは設計資料と引き継ぎ文書であり、
|
|
23
|
+
旧overlay/apply.py/APPLY.sh/VERIFY.shは未取得。再開手順も実ファイルの回収から始める形に更新した。
|
|
24
|
+
|
|
25
|
+
## 今回実施した確認
|
|
26
|
+
|
|
27
|
+
- 対象資料の承認状態、baseline、相互参照の整合確認。
|
|
28
|
+
- 旧い「未承認のため実装停止」表現と、外部効果のexactly-onceに読める保証表現の修正。
|
|
29
|
+
- RC-01〜05のADR・実装設計・検証条件への対応確認。
|
|
30
|
+
- ZIP構成、全文書のSHA256SUMS、ZIP/引き継ぎ文書の外部SHA256の検証。
|
|
31
|
+
|
|
32
|
+
対象repositoryのコード変更・RSpec実行は行っていない。
|
|
33
|
+
API名や例外名は未確認のものを作らず、baselineへの対応付けを実装前の必須作業とした。
|