phronomy 0.30.0 → 0.31.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 (45) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +76 -0
  3. data/README.md +7 -2
  4. data/docs/architecture/agent-tool-child-lifetime.md +141 -0
  5. data/docs/architecture/dx05-agent-scope.md +4 -2
  6. data/docs/architecture/r8-unit1.md +68 -68
  7. data/docs/architecture/r8-unit2.md +34 -34
  8. data/docs/architecture/structured-output-and-scope.md +73 -13
  9. data/docs/decisions/029-semantic-completion-and-application-effect-boundary.md +1 -1
  10. data/docs/decisions/044-agent-default-and-one-shot-composition.md +5 -0
  11. data/docs/design/durable-semantic-coordination/CHANGELOG_V2_REVISION_2.md +23 -23
  12. data/docs/design/durable-semantic-coordination/IMPLEMENTATION_REPORT.md +99 -99
  13. data/docs/design/durable-semantic-coordination/RECOVERY_CONTRACT_CLARIFICATIONS.md +135 -136
  14. data/docs/getting-started.md +26 -0
  15. data/docs/migrations/0.31.md +72 -0
  16. data/lib/phronomy/agent/async_event_api.rb +17 -8
  17. data/lib/phronomy/agent/base.rb +27 -2
  18. data/lib/phronomy/agent/composition/run_once.rb +11 -10
  19. data/lib/phronomy/agent/context_preparation.rb +1 -0
  20. data/lib/phronomy/agent/execution/dispatch_preparation.rb +1 -1
  21. data/lib/phronomy/agent/execution/exact_execution.rb +5 -3
  22. data/lib/phronomy/agent/execution/execution_coordinator.rb +6 -0
  23. data/lib/phronomy/agent/execution/execution_outcome_committer.rb +1 -6
  24. data/lib/phronomy/agent/execution/initial_preparation.rb +1 -1
  25. data/lib/phronomy/agent/execution/invocation_actions.rb +17 -15
  26. data/lib/phronomy/agent/execution_change.rb +4 -0
  27. data/lib/phronomy/agent/output_contract.rb +47 -5
  28. data/lib/phronomy/agent/persistence/codec.rb +16 -2
  29. data/lib/phronomy/agent/recovery/recovery_coordinator/continuation.rb +1 -0
  30. data/lib/phronomy/agent/runtime_binding/engine_session_builder.rb +2 -2
  31. data/lib/phronomy/agent/runtime_input.rb +7 -0
  32. data/lib/phronomy/engine/fsm_session.rb +7 -0
  33. data/lib/phronomy/execution/async_operation.rb +16 -0
  34. data/lib/phronomy/execution/concurrency/result_finalization.rb +106 -0
  35. data/lib/phronomy/generation/generator_verifier/agent_operation.rb +3 -3
  36. data/lib/phronomy/generation/generator_verifier.rb +6 -3
  37. data/lib/phronomy/llm_adapter/backends/ruby_llm.rb +1 -1
  38. data/lib/phronomy/llm_adapter/backends/structured_response_capture.rb +3 -1
  39. data/lib/phronomy/tools/agent.rb +58 -22
  40. data/lib/phronomy/version.rb +1 -1
  41. data/sig/phronomy/agent.rbs +7 -5
  42. data/sig/phronomy/execution/async_operation.rbs +1 -0
  43. data/sig/phronomy/generation/generator_verifier.rbs +1 -1
  44. data/sig/phronomy/tools/agent.rbs +14 -0
  45. metadata +6 -2
@@ -8,7 +8,11 @@ authorization and any decision to start another attempt.
8
8
  ## Public behavior
9
9
 
10
10
  `Agent::Base#invoke`, `invoke_async`, `stream`, `stream_async` and
11
- `start_reserved_async` accept `output_schema: nil`. `run_once` forwards this option.
11
+ `start_reserved_async` accept `output_schema: nil` and `schema_delivery: nil`.
12
+ `run_once` forwards both options. With a schema, omitted/nil delivery means
13
+ `:native`; explicit `:native` and `:none` are supported. A non-nil delivery without
14
+ a schema, or any other value, raises ArgumentError before admission. The same
15
+ keywords and final-output semantics apply to sync/async and invoke/stream.
12
16
  Without a schema the existing free-text behavior remains. With a schema, successful
13
17
  `output` and `result` are deeply frozen JSON objects with String keys; `raw_output`
14
18
  preserves the model text. Token events are provisional, not validated objects.
@@ -45,9 +49,21 @@ values and String/Symbol keys, snapshots recursively, and rejects duplicate norm
45
49
  keys, Ruby objects and cycles. Generic schema interpretation belongs to C17, not
46
50
  Tool::Schema, Agent's caller or Generation.
47
51
 
48
- ## Native transport and completion facts
52
+ ## Schema delivery and completion facts
49
53
 
50
- C09 `LLMAdapter::Request#response_schema` carries the immutable schema; each model
54
+ `:native` sends the declared schema to the provider. `:none` omits native schema
55
+ configuration on every turn, including Tool follow-ups, but retains the same
56
+ strict local validation, completion checks, output filters, frozen values and
57
+ OutputError reasons. It does not send JSON mode, rewrite prompts, infer behavior
58
+ from provider/model names, fall back after rejection or regenerate malformed
59
+ output. Applications must already ask for the declared JSON shape in their
60
+ instructions. Tools and their authorization rules remain unchanged.
61
+
62
+ Use `schema_delivery: :none` explicitly where native schema delivery cannot be
63
+ combined with the application's Tools. This does not repair LM Studio PEG errors:
64
+ a provider failure before a usable response remains a provider failure.
65
+
66
+ With `:native`, C09 `LLMAdapter::Request#response_schema` carries the immutable schema; each model
51
67
  turn retains it. RubyLLM `with_schema` sends native schema configuration. The
52
68
  transport tests cover RubyLLM 2.0.0 OpenAI/Azure Chat Completions and Responses,
53
69
  Anthropic, Gemini and Ollama's OpenAI-compatible endpoint. Constraints are compared
@@ -77,7 +93,7 @@ unknown), refusal and raw_finish_reason metadata. Only normal final completion c
77
93
  be a structured success. Tool requests are intermediate; they retain existing
78
94
  approval, denial, cancellation and recovery behavior. RubyLLM 2.0 loses streamed
79
95
  refusal fields in Chunk values; operation-local Protocol subclasses capture these
80
- raw facts. No SDK global class or shared protocol registry is patched. The SDK's
96
+ raw facts on every stream, independently of native schema delivery. No SDK global class or shared protocol registry is patched. The SDK's
81
97
  raw finish information is retained through saved-response recovery.
82
98
 
83
99
  JSON 2.21.2 is the verified minimum for the strict decoding flags and deterministic
@@ -104,21 +120,28 @@ no arbitrary class name is constantized. Other transport, cancellation, Tool and
104
120
  internal failures keep their existing behavior. Output failure never triggers an
105
121
  automatic regeneration or replay of a completed Tool operation.
106
122
 
107
- Execution metadata stores `output_contract` version 1, schema_ref and schema_digest
108
- at admission. Digest is SHA-256 of UTF-8 JSON generated with recursively sorted keys
123
+ New structured executions store `output_contract` version 2, schema_ref,
124
+ schema_digest and schema_delivery (`"native"` or `"none"`) at admission. Digest is SHA-256 of UTF-8 JSON generated with recursively sorted keys
109
125
  (JSON 2.21.2 `sort_keys: true`); the exact same representation is saved in ContentStore.
110
126
  This format preserves arbitrary JSON integers and finite floats, including -0.0,
111
127
  without applying the narrower Common canonical-domain number rules. Each Context
112
- Manifest retains response_schema_ref, including budget projection and recovery.
113
- New executions may choose another schema; existing executions cannot replace their
114
- schema on resume/approval or by reusing a reserved ID with a different digest.
115
- Generic config/provider schema overrides are rejected.
128
+ Manifest carries response_schema_ref only for native delivery. The output
129
+ contract always keeps schema_ref, including with `:none`, so local validation
130
+ survives recovery. The digest identifies the schema alone; exact execution identity
131
+ also compares delivery. Resume/approval restore the saved choice, and a reserved
132
+ ID cannot be reused with a different schema or delivery. Generic config/provider
133
+ schema overrides are rejected.
116
134
 
117
135
  Structured success stores JSON result plus raw_output_ref and result_format=json.
118
136
  Old records without output_contract remain facts from a free-text execution; no
119
- schema is added retroactively. The execution codec stays at 0.2: its extensible
120
- metadata contains the explicitly versioned output contract. Unknown output-contract
121
- versions or digest mismatch fail closed. Saved LLM responses include finish_reason,
137
+ schema is added retroactively. Existing output_contract version 1 is read as
138
+ native delivery and is not rewritten merely by reading. Version-2 contracts use
139
+ AgentExecution envelope 0.3; old/freeform executions retain envelope 0.2. New
140
+ readers accept both explicitly. Older readers reject envelope 0.3, including for
141
+ completed executions, instead of silently losing delivery policy. Deploy compatible
142
+ readers before writing new structured executions; do not downgrade a store that
143
+ contains 0.3 records to older readers. Unknown versions and digest mismatch fail
144
+ closed. Saved LLM responses include finish_reason,
122
145
  refusal and metadata; missing finish evidence is unknown, never assumed normal.
123
146
  Fresh-runtime and new SQL connection-pool tests verify success, failure and approval
124
147
  continuation without replay of confirmed LLM/Tool work. This is a durable-facts
@@ -126,6 +149,11 @@ claim, not an external side-effect exactly-once guarantee.
126
149
 
127
150
  ## Generation evaluation
128
151
 
152
+ `GeneratorVerifier.new` and `.open` accept `schema_delivery: :native` (default) or
153
+ `:none`. One choice applies to both draft and review operations. Their independent
154
+ schemas and C03 evaluation policy remain unchanged; no role-specific flags or
155
+ automatic fallback are introduced.
156
+
129
157
  C03 specifies the fixed protocol: draft answer/string, confidence/number in 0..1,
130
158
  citations/array; review approved/boolean, score/number in 0..1, feedback/string.
131
159
  All outer fields are required and additional properties are forbidden. Default
@@ -168,6 +196,38 @@ Neither API implicitly cancels work, answers approval, deletes saved data or
168
196
  closes the application Store. The application decides how unfinished work becomes
169
197
  safe before retrying through the cleanup error's scope/pipeline handle.
170
198
 
199
+ ## Single-invocation ownership
200
+
201
+ `Agent.run_once(definition:, input:, context: nil, knowledge: [], on_event: nil,
202
+ **invoke_options, &event_block)` creates a fresh ephemeral Store and owns one
203
+ Agent through `Agent.open_scope`. The definition must be an `Agent::Base`
204
+ subclass. It forwards the input and invocation options, including the output
205
+ schema and delivery selection, and releases the live Agent before returning.
206
+ The application-level Store configuration is not used or changed.
207
+
208
+ Successful cleanup preserves the invocation value or the identical invocation
209
+ exception. A cleanup failure raises `Agent::ScopeCleanupError`: `result` retains
210
+ a successful value, `primary_error` retains an invocation failure, `failures`
211
+ identifies unreleased owners, and `scope.release!` can retry release. It does not
212
+ repeat the invocation, model request or Tool work. Release does not purge records,
213
+ close shared storage or shut down Runtime. No keep-alive option or legacy path
214
+ is provided; use `create`/`load` or an explicit scope for a reusable Agent.
215
+
216
+ The synchronous call cannot run on EventLoop. It rejects that entry before
217
+ creating its Store or Agent. Supplying both `on_event:` and a listener block is
218
+ also rejected before acquisition. The existing listener-error policy is preserved.
219
+
220
+ Approval waits are not completion. The Agent remains owned while the invocation
221
+ waits; the application still decides approval through the existing API. Use
222
+ `approve_async` when another operation is already waiting for the same execution.
223
+ A concurrent synchronous approval or other accepted operation can still own a
224
+ lease when the invocation returns. In that case cleanup reports the busy owner
225
+ through `ScopeCleanupError`; finish the other operation before retrying release.
226
+ Logical cancellation likewise cannot authorize release of physically active work.
227
+ The convenience API neither answers approval nor cancels or waits for unrelated
228
+ work to make cleanup succeed. Applications needing notifications or other work
229
+ after the invocation should express that whole lifetime with `open_scope`.
230
+
171
231
  ## Dependencies and implementation units
172
232
 
173
233
  - Remove C03 Generation → C17 OutputParser; C03 continues to use public C04 Agent,
@@ -153,7 +153,7 @@ request deduplication or unambiguous correlation. Existing retention applies.
153
153
 
154
154
  Reuse existing APIs where they meet this contract; map missing capabilities only
155
155
  after baseline inspection. Do not invent a framework outbox or request registry.
156
- See [RC-01](RECOVERY_CONTRACT_CLARIFICATIONS.md#1-rc-01--確定結果の参照と実行の発見).
156
+ See [RC-01](../design/durable-semantic-coordination/RECOVERY_CONTRACT_CLARIFICATIONS.md#1-rc-01-accessing-final-results-and-discovering-executions).
157
157
 
158
158
  ### 9. Unknown commit outcome and cancellation
159
159
 
@@ -5,6 +5,11 @@
5
5
  **Refines**: [038-responsibility-based-source-layout](038-responsibility-based-source-layout.md)
6
6
  and [040-configuration-default-composition](040-configuration-default-composition.md)
7
7
 
8
+ The original lifetime-preservation decision below is historical. The current
9
+ `run_once` contract owns a scope and releases its Agent; see
10
+ [single-invocation ownership](../architecture/structured-output-and-scope.md#single-invocation-ownership).
11
+ The composition placement and default-factory boundary remain in force.
12
+
8
13
  ## Problem
9
14
 
10
15
  `Agent::Base` selected the concrete default with `Persistence.in_memory`.
@@ -1,33 +1,33 @@
1
- # V2 revision 2 — 改訂内容
1
+ # V2 revision 2 - Changes
2
2
 
3
- 更新日: 2026-09-06 / 状態: Accepted
3
+ Updated: 2026-09-06 / Status: Accepted
4
4
 
5
- ## 合意反映
5
+ ## Accepted decisions reflected in this revision
6
6
 
7
- | 項目 | 今回の修正 |
7
+ | Item | Change in this revision |
8
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、に統一 |
9
+ | RC-01 Result access | Add contracts for reading status/results by exact execution ID and discovering candidates from the owner if execution is interrupted before the caller receives the ID |
10
+ | RC-02 Unknown persistence outcomes | Distinguish confirmed absence, read failure, CAS conflict, and unknown commit outcome; reconcile using the same reserved identity |
11
+ | RC-03 Wiring compatibility | Specify minimum checks for definition id/version, slot, graph, and Persistence boundary, and give precedence to committed facts |
12
+ | RC-04 Cancellation | Distinguish ending observation/shutdown from semantic cancellation; specify handling by child state, races, and rediscovery after restart |
13
+ | RC-05 Guarantee wording | Use consistent wording: reuse committed outcomes, recover with the same identity, and resolve uncertain external outcomes through existing Recovery |
14
14
 
15
- ADR-029/030/031、実装設計、責務境界レビュー、READMEへ対応する規範的記述を反映した。
16
- 詳細契約と検証条件はRECOVERY_CONTRACT_CLARIFICATIONS.mdにまとめ、資料間で参照する。
17
- 承認前のProposed表記をAcceptedへ更新した。新機能の再承認を要求しない。
15
+ The corresponding normative statements have been incorporated into ADR-029/030/031, the implementation design, the responsibility boundary review, and the README.
16
+ Detailed contracts and validation conditions are collected in RECOVERY_CONTRACT_CLARIFICATIONS.md and referenced across the documents.
17
+ The pre-approval Proposed status has been changed to Accepted. This does not request renewed approval of the new functionality.
18
18
 
19
- ## 実装状態の訂正
19
+ ## Correction of implementation status
20
20
 
21
- 引き継ぎ文書の旧実装件数・静的検証成功は、前セッションの報告として残す。
22
- この分岐先で実装を再検証した事実にはしない。現在取得できたのは設計資料と引き継ぎ文書であり、
23
- 旧overlay/apply.py/APPLY.sh/VERIFY.shは未取得。再開手順も実ファイルの回収から始める形に更新した。
21
+ Earlier implementation counts and successful static checks in the handoff document remain reports from the previous session.
22
+ They are not evidence that implementation was revalidated in this continuation. Only the design documents and handoff document are currently available;
23
+ the old overlay/apply.py/APPLY.sh/VERIFY.sh have not been recovered. The resumption procedure has also been updated to begin by recovering the actual files.
24
24
 
25
- ## 今回実施した確認
25
+ ## Checks performed for this revision
26
26
 
27
- - 対象資料の承認状態、baseline、相互参照の整合確認。
28
- - 旧い「未承認のため実装停止」表現と、外部効果のexactly-onceに読める保証表現の修正。
29
- - RC-01〜05のADR・実装設計・検証条件への対応確認。
30
- - ZIP構成、全文書のSHA256SUMS、ZIP/引き継ぎ文書の外部SHA256の検証。
27
+ - Check consistency of approval status, baseline, and cross-references in the affected documents.
28
+ - Correct obsolete statements that implementation was stopped pending approval and guarantee wording that could imply exactly-once external effects.
29
+ - Check the mapping of RC-01 through RC-05 to ADRs, implementation design, and validation conditions.
30
+ - Verify the ZIP layout, SHA256SUMS for all documents, and external SHA256 values for the ZIP and handoff document.
31
31
 
32
- 対象repositoryのコード変更・RSpec実行は行っていない。
33
- API名や例外名は未確認のものを作らず、baselineへの対応付けを実装前の必須作業とした。
32
+ No code changes or RSpec runs were performed in the target repository.
33
+ Unverified API or exception names were not invented; mapping the requirements to the baseline was made mandatory before implementation.
@@ -6,107 +6,107 @@
6
6
  > [ADR-034](../../decisions/034-handoff-runner-coordination-ownership.md).
7
7
  > Handoff and HandoffPolicy remain in Agent at this stage.
8
8
 
9
- 作成日: 2026-09-07。設計承認日: 2026-09-06。
10
- 対象baseline: `5472116cd99a63ec27875024c955ea82be612d6b`。
11
- 承認済みADR-029/030/031とRC-01〜05に対する新規実装です。
12
- 旧Complete Durability overlay、既存の作業ZIP、synthetic fan-out executionは使用しません。
9
+ Created: 2026-09-07. Design approved: 2026-09-06.
10
+ Baseline: `5472116cd99a63ec27875024c955ea82be612d6b`.
11
+ This is a new implementation of the approved ADR-029/030/031 and RC-01 through RC-05.
12
+ It does not use the old Complete Durability overlay, existing work ZIPs, or synthetic fan-out executions.
13
13
 
14
- ## 実装範囲
14
+ ## Implementation scope
15
15
 
16
- | 対象 | 実装した動作 |
16
+ | Area | Implemented behavior |
17
17
  |---|---|
18
- | Persistence | root/transaction viewともに8 repository。新しい3 recordはcurrent format `0.1`。Backendはopaque DurableRecordと明示的なidentity/revision/index metadataを扱う |
19
- | Handoff | Agent-domain APIへ移設。Source terminal・Context・exact Target予約・責務移転を同じtransactionで保存。Target terminalとrouting安定化も同一transaction |
20
- | Orchestrator | 既存parent AgentExecutionのstatic subagent Toolにchild ID/input/knowledge/config/outcomeを保存。直接の`dispatch_parallel`/`fan_out`にはsynthetic parentを作らない |
21
- | Team | TeamRoot/TeamExecution、task、worker slot、exact assignment/outcomeをCASで保存。coordinator/workerは既存Agent engineを使用。スケジューリングは既存の逐次方式 |
22
- | Team内部操作 | 保存済みのauthorized Tool batchをProvider順に適用。各`tool_invocation_id`の結果を保持し、`enqueue_task`/`finalize`を自動照合 |
23
- | Aggregate | pure/replay-safeな計算。canonical JSON結果またはエラーをterminal commit。保存前のクラッシュでは再計算可能、保存済みterminalでは再計算しない |
24
- | Runtime | Teamのprocess-local所有・admission・drainを追加。新しいTeam FSM/Workflow engineは追加しない |
25
- | Recovery | framework-owned操作はexact factから再開。外部Toolと混在したbatchでは外部の事実だけを既存Recovery APIで解決する |
26
- | 終了・削除 | exact子のcancel/reconciliation情報を保持。idle main Agentの`purge!`はHandoff anchorも同時削除。未完了turnのanchor削除は拒否 |
27
-
28
- Handoff graphは同じPersistence **instance**を使います。元main Agent IDがrouting anchorです。
29
- 保存済みContextを新しいpolicyで再投影せず、保存済みworker割当を現在のschedulerで選び直しません。
30
- RuntimeのClass/Proc、listener、Task、CancellationTokenは永続化しません。
31
-
32
- ## 公開経路
33
-
34
- | 目的 | API / 返却値 |
18
+ | Persistence | Eight repositories in both root and transaction views; the three new records use current format `0.1`. Backend handles opaque DurableRecords and explicit identity/revision/index metadata |
19
+ | Handoff | Moved to the Agent-domain API. Source terminal state, Context, exact Target reservation, and responsibility transfer are persisted in one transaction. Target terminal state and routing stabilization also share one transaction |
20
+ | Orchestrator | Stores child ID/input/knowledge/config/outcome for static subagent Tools in the existing parent AgentExecution. Direct `dispatch_parallel`/`fan_out` calls do not create synthetic parents |
21
+ | Team | Persists TeamRoot/TeamExecution, tasks, worker slots, and exact assignments/outcomes using CAS. Coordinators/workers use the existing Agent engine. Scheduling retains the existing sequential approach |
22
+ | Internal Team operations | Applies persisted authorized Tool batches in Provider order. Retains the result of each `tool_invocation_id` and automatically reconciles `enqueue_task`/`finalize` |
23
+ | Aggregate | Pure/replay-safe computation. Commits canonical JSON results or errors as terminal outcomes. Recalculation is possible after a crash before persistence, but not for a persisted terminal outcome |
24
+ | Runtime | Adds process-local Team ownership, admission, and draining. Does not add a new Team FSM/Workflow engine |
25
+ | Recovery | Resumes framework-owned operations from exact facts. In batches mixed with external Tools, only external facts are resolved through the existing Recovery API |
26
+ | Termination and deletion | Retains cancellation/reconciliation information for exact children. `purge!` on an idle main Agent also deletes the Handoff anchor; deleting an anchor for an incomplete turn is rejected |
27
+
28
+ A Handoff graph uses the same Persistence **instance**. The original main Agent ID is the routing anchor.
29
+ Persisted Context is not reprojected using a new policy, and persisted worker assignments are not reselected using the current scheduler.
30
+ Runtime Classes/Procs, listeners, Tasks, and CancellationTokens are not persisted.
31
+
32
+ ## Public entry points
33
+
34
+ | Purpose | API / return value |
35
35
  |---|---|
36
- | Agent結果参照 | `store.execution_result(execution_id)`。owner、status、phase、result/errorと参照IDの凍結Hash |
37
- | Handoff結果参照 | `store.handoff_result(source_execution_id)`。そのturnのexact Targetまで辿る。graph/Agent hydration不要 |
38
- | Agent実行発見 | `store.list_executions(agent_id, after: nil, limit: 100)`。immutable execution records。active/terminal双方 |
39
- | Team結果参照 | `store.team_execution_result(run_id)` または `team.result(run_id)` |
40
- | Team実行発見 | `store.list_team_executions(team_id, after: nil, limit: 100)` または `team.executions(...)` |
41
- | Handoffの実行/復旧 | `Agent::HandoffRunner.new(main_agent:, handoffs:).invoke(input, config: {})`。未完了turnがあれば保存済み予約・入力を使用 |
42
- | static childの復旧 | `Orchestrator#resume(execution_id, config: {})` |
43
- | Teamの作成/復旧 | `team_definition id:, version:`、`create(team_id:, persistence:)`、`load(team_id, persistence:, on_event:)`、`resume(run_id)` |
44
- | 明示cancel | `team.cancel(run_id)` / `handoff_runner.cancel(execution_id)`。Orchestratorを含むAgentの既存操作は`config[:cancellation_token]` |
45
-
46
- 一覧順はsemantic IDの辞書順、`after`は排他的ID cursor、`limit`は正の整数です。
47
- 時刻順やリクエスト一意対応を意味しません。Applicationは候補を自身の相関情報と照合します。
48
-
49
- Agentの結果statusは既存Symbol、Teamの結果statusはcanonical Stringです。
50
- Teamのdefault aggregate結果もcanonical JSONのためHash keyはString、errorは例外オブジェクトではなく
51
- `class`/`message`等のデータです。aggregateに渡すassignmentのトップレベルとtask keyはSymbolです。
52
-
53
- Handoffの未開始Target予約は`status: :active, phase: :target_pending, reserved: true`で識別します。
54
- 明示cancelした未開始Targetは予約IDを保持し、過去turnの結果に後続turnを代用しません。
55
- 不存在は`Persistence::NotFoundError`、読み取り/復号失敗はそのエラーを返します。
56
- 削除された結果を復元する機能や無期限retentionは追加していません。
57
-
58
- `Team.load`はTeam factsのhydrationのみです。子の実行/復旧は`resume`で開始します。
59
- Agentの`load`は既存Recovery契約を維持します。結果だけが必要なら上記Persistence参照APIを使います。
60
- Teamの`on_event`はhidden Agentsへ渡し、必要なRecovery/approval eventを受け取ります。
61
- `Team.stream`はcommit済みassignmentのRuntime通知です。新しい通知配送保証はありません。
62
-
63
- ## RC対応表
64
-
65
- パスはリポジトリroot相対です。共通の追加障害specは
66
- `spec/phronomy/multi_agent/durable_coordination_spec.rb`です。
67
-
68
- | 要件 | 主な実装 | 検証根拠 |
36
+ | Agent result access | `store.execution_result(execution_id)`; a frozen Hash containing owner, status, phase, result/error, and reference IDs |
37
+ | Handoff result access | `store.handoff_result(source_execution_id)`; follows the exact Target of that turn. No graph/Agent hydration is required |
38
+ | Agent execution discovery | `store.list_executions(agent_id, after: nil, limit: 100)`; immutable execution records, both active and terminal |
39
+ | Team result access | `store.team_execution_result(run_id)` or `team.result(run_id)` |
40
+ | Team execution discovery | `store.list_team_executions(team_id, after: nil, limit: 100)` or `team.executions(...)` |
41
+ | Handoff execution/recovery | `Agent::HandoffRunner.new(main_agent:, handoffs:).invoke(input, config: {})`; uses the persisted reservation and input if an incomplete turn exists |
42
+ | Static child recovery | `Orchestrator#resume(execution_id, config: {})` |
43
+ | Team creation/recovery | `team_definition id:, version:`, `create(team_id:, persistence:)`, `load(team_id, persistence:, on_event:)`, `resume(run_id)` |
44
+ | Explicit cancellation | `team.cancel(run_id)` / `handoff_runner.cancel(execution_id)`; existing Agent operations, including Orchestrator, use `config[:cancellation_token]` |
45
+
46
+ Lists are ordered lexicographically by semantic ID; `after` is an exclusive ID cursor, and `limit` is a positive integer.
47
+ This does not imply chronological ordering or unique correspondence to a request. Applications match candidates against their own correlation information.
48
+
49
+ Agent result status uses existing Symbols; Team result status uses canonical Strings.
50
+ The default Team aggregate result is also canonical JSON: Hash keys are Strings, and errors are data such as
51
+ `class`/`message`, not exception objects. Top-level assignment keys and task keys passed to aggregate are Symbols.
52
+
53
+ An unstarted Handoff Target reservation is identified by `status: :active, phase: :target_pending, reserved: true`.
54
+ Explicit cancellation of an unstarted Target preserves its reserved ID; a later turn never substitutes for the result of an earlier turn.
55
+ Absence produces `Persistence::NotFoundError`; read/decode failures produce their actual errors.
56
+ No facility to restore deleted results or retain them indefinitely has been added.
57
+
58
+ `Team.load` hydrates Team facts only. Child execution/recovery starts through `resume`.
59
+ Agent `load` retains its existing Recovery contract. Use the Persistence access APIs above when only results are needed.
60
+ Team's `on_event` is passed to hidden Agents to receive required Recovery/approval events.
61
+ `Team.stream` provides Runtime notifications of committed assignments; it adds no notification-delivery guarantee.
62
+
63
+ ## RC mapping
64
+
65
+ Paths are relative to the repository root. The shared additional fault specs are in
66
+ `spec/phronomy/multi_agent/durable_coordination_spec.rb`.
67
+
68
+ | Requirement | Main implementation | Validation evidence |
69
69
  |---|---|---|
70
- | RC-01-A/B | `Persistence#execution_result` / `list_executions`、Team対応API | owner未loadの再構築環境でactive/terminal候補・ページング・結果を読み、Provider/所有登録を増やさない |
71
- | RC-01-C | `Persistence#handoff_result`、読み取り専用materialization | graph/ownerなしの予約参照、read障害、purge済み結果のNotFound。callback政策は既存`stream_callback_error_policy_spec.rb`でも検証 |
72
- | RC-02-A | Agent準備の既存F1 readback、`reconcile_terminal_error`、Team `admit`/`update` | Teamの各revision commit直後の応答喪失、Source移転の応答喪失、確定worker/child outcomeの再利用 |
73
- | RC-02-B/C | exact予約照合・atomic admission/CAS・bounded readback | read失敗と不存在を区別。Team admission後のreadback失敗ではdispatchなし。Backend契約はstale CAS、active重複、8 repository rollbackを検証 |
74
- | RC-03-A | Team definition snapshot、static child slot定義、Handoff graph/Target照合 | worker version不一致とTarget/graph不足でfail closed。既存Handoff統合specで別Persistenceを拒否 |
75
- | RC-03-B | immutable Context/input/knowledge/assignment/outcome | 現在policyを変更しても保存済みHandoffContextを使用。worker結果・static child結果・knowledge metadataを保持 |
76
- | RC-04-A | 既存Task待機/Runtime shutdown契約 | `task_spec.rb`、`agent/acs16_task_quiescence_spec.rb`、Runtime/admission specs。Runtime再構築テストで暗黙cancelを追加しない |
77
- | RC-04-B/C/D | Team cancel flag、Handoff exact cancellation、Agent子admission条件、既存terminal barrier | 予約worker/Targetを起動せずID保持。外部fact待ちのactive childを持つparentはactiveのままcancel情報を保存し再起動後も保持。既存admission/physical-quiescence specsと合わせて確認 |
78
- | RC-04-E | Source terminal linkとTarget cancel。責務はTargetのまま | transfer後cancel→再起動→後続turnでもSourceへ戻らず、過去の予約IDとcancel結果を維持 |
79
- | RC-05 | callback/外部効果とsemantic recordの分離 | mixed external/framework Tool batchは外部factだけresolveし、完了childを再実行しない。内部`finalize`の事実をApplicationへ問い合わせない |
80
-
81
- `lib/phronomy/testing/persistence_contract/coordination_repositories.rb`の新shared examplesは、
82
- 外部backendにも公開される`phronomy/testing/persistence_contract`経由で実行されます。
83
- raw SPI/API snapshot/RBS、旧Handoff定数削除、EventLoop単一writer/causal barrier、
84
- logical-operation tracingの既存guardも維持しています。
85
-
86
- ## 検証の範囲と限界
87
-
88
- 実測環境はRuby 3.3.6。使用gemは配布ZIPの`verification/gems.txt`に記録します。
89
- 配布対象に対する実測コマンド、結果、ログは同梱の検証記録を参照してください。
90
-
91
- - 通常RSpecは外部LLMへの接続を要するintegration tagを除外します。
92
- - 選択したHandoff/Orchestrator/Team integrationはWebMockで実行します。
93
- - 追加F4テストは、commit済みDurableRecordを複製し、新Backendと新Runtimeで復旧するモデルです。
94
- これは実OSプロセスの強制終了や物理ディスクへのfsyncの実証ではありません。
95
- - 実LLM、Redis、PostgreSQL、OpenTelemetry等を使う別スイートは今回の実測対象外です。
96
- optional依存/service未設定59件と既存obsolete2件の計61件がpendingです。
97
- - 外部backendのF4保存性と複数processの排他は、そのbackendとdeploymentの契約に依存します。
98
- InMemory自身はプロセス終了後の保存を保証しません。
99
- - semantic cancellationは外部効果のrollbackではありません。TokenオブジェクトはRuntime-onlyです。
100
- durable cancel flag/factがcommitした後は保持し、未確定外部処理は既存Recoveryで照合します。
101
- fact/approval待ちをfailedにして子を忘れず、`ExecutionRehydrationRequiredError`で制御を返します。
102
-
103
- Frameworkが実施するのは、確定outcomeの再利用と未完了実行の同じsemantic identityでの復旧です。
104
- callback outbox/ACK、global generic class registry、Proc/Class永続化、distributed transaction、
105
- Team専用の第二execution engineは追加していません。
106
-
107
- ## パッケージ
108
-
109
- 完全版ファイルと削除manifestを同梱します。baseline/適用前後のハッシュを検査して適用します。
110
- 新しいClassの配置をZeitwerkの命名規則に合わせ、旧overlayのdecorator ignoreは不要です。
111
- 旧`MultiAgent::Handoff*`、`Runner`、`Coordinator`、`CoordinationState`の実装を削除します。
112
- 適用・依存関係・VERIFY手順は配布rootの`README_APPLY_JA.md`を参照してください。
70
+ | RC-01-A/B | `Persistence#execution_result` / `list_executions`, and corresponding Team APIs | Reads active/terminal candidates, pagination, and results in a reconstructed environment without loading the owner; does not invoke Providers or add ownership registrations |
71
+ | RC-01-C | `Persistence#handoff_result`, read-only materialization | Reservation access without graph/owner, read failures, and NotFound for purged results. Callback policy is also covered by the existing `stream_callback_error_policy_spec.rb` |
72
+ | RC-02-A | Existing F1 readback during Agent preparation, `reconcile_terminal_error`, Team `admit`/`update` | Lost acknowledgements immediately after each Team revision commit and Source transfer; reuse of committed worker/child outcomes |
73
+ | RC-02-B/C | Exact reservation reconciliation, atomic admission/CAS, bounded readback | Distinguishes read failure from absence. No dispatch after a failed readback following Team admission. Backend contracts check stale CAS, duplicate active records, and rollback across eight repositories |
74
+ | RC-03-A | Team definition snapshots, static child slot definitions, Handoff graph/Target matching | Fails closed on worker-version mismatch or missing Target/graph. Existing Handoff integration specs reject a different Persistence instance |
75
+ | RC-03-B | Immutable Context/input/knowledge/assignment/outcome | Uses persisted HandoffContext even when the current policy changes. Preserves worker results, static child results, and knowledge metadata |
76
+ | RC-04-A | Existing Task waiting/Runtime shutdown contracts | `task_spec.rb`, `agent/acs16_task_quiescence_spec.rb`, and Runtime/admission specs. Runtime reconstruction tests introduce no implicit cancellation |
77
+ | RC-04-B/C/D | Team cancellation flags, exact Handoff cancellation, Agent child-admission conditions, existing terminal barriers | Preserves reserved worker/Target IDs without starting them. A parent with an active child awaiting external facts remains active, persists cancellation information, and retains it after restart. Checked together with existing admission/physical-quiescence specs |
78
+ | RC-04-E | Source terminal link and Target cancellation; responsibility remains with Target | Cancellation after transfer, restart, and a later turn do not return responsibility to Source; historical reserved IDs and cancellation results are preserved |
79
+ | RC-05 | Separation of callbacks/external effects from semantic records | Mixed external/framework Tool batches resolve only external facts and do not rerun completed children. Application is not asked to determine facts about internal `finalize` |
80
+
81
+ The new shared examples in `lib/phronomy/testing/persistence_contract/coordination_repositories.rb`
82
+ run through `phronomy/testing/persistence_contract`, which is also exposed to external backends.
83
+ Existing guards for raw SPI/API snapshots/RBS, removal of old Handoff constants, the EventLoop single writer/causal barrier,
84
+ and logical-operation tracing are preserved.
85
+
86
+ ## Validation scope and limitations
87
+
88
+ The measured environment is Ruby 3.3.6. Gem versions are recorded in the distribution ZIP's `verification/gems.txt`.
89
+ See the accompanying verification records for commands, results, and logs measured against the distributed files.
90
+
91
+ - Ordinary RSpec runs exclude integration tags requiring connections to external LLMs.
92
+ - Selected Handoff/Orchestrator/Team integration tests run with WebMock.
93
+ - Added F4 tests model recovery by copying committed DurableRecords and using a new Backend and Runtime.
94
+ They do not demonstrate forced termination of a real OS process or fsync to physical storage.
95
+ - Separate suites using live LLMs, Redis, PostgreSQL, OpenTelemetry, and similar dependencies are outside this measurement.
96
+ There are 61 pending cases: 59 with optional dependencies/services unconfigured and two existing obsolete cases.
97
+ - F4 durability and exclusion across multiple processes for external backends depend on the backend and deployment contracts.
98
+ InMemory itself does not guarantee persistence after process termination.
99
+ - Semantic cancellation does not roll back external effects. Token objects are Runtime-only.
100
+ Committed durable cancellation flags/facts are retained, and uncertain external operations are reconciled through existing Recovery.
101
+ Waiting for facts/approval is not converted into failure that forgets a child; control returns through `ExecutionRehydrationRequiredError`.
102
+
103
+ The framework reuses committed outcomes and recovers incomplete executions with the same semantic identity.
104
+ It adds no callback outbox/ACK, global generic class registry, Proc/Class persistence, distributed transaction,
105
+ or second execution engine dedicated to Team.
106
+
107
+ ## Package
108
+
109
+ The package includes complete files and a deletion manifest. Application checks the baseline and pre/post-application hashes.
110
+ New Class locations follow Zeitwerk naming conventions; the old overlay's decorator ignore is unnecessary.
111
+ The old `MultiAgent::Handoff*`, `Runner`, `Coordinator`, and `CoordinationState` implementations are removed.
112
+ See `README_APPLY_JA.md` at the distribution root for application, dependencies, and VERIFY procedures.