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
@@ -1,179 +1,178 @@
1
- # V2復旧契約の明確化 — 承認済み追補
1
+ # V2 Recovery Contract Clarifications - Approved Addendum
2
2
 
3
- 更新日: 2026-09-06 / 文書改訂: V2 revision 2
3
+ Updated: 2026-09-06 / Document revision: V2 revision 2
4
4
 
5
- ## 0. 位置づけ
5
+ ## 0. Purpose and authority
6
6
 
7
- 本追補は、V2への追加提案5点に対するユーザーの承認を反映した規範的な実装契約である。
8
- ADR-029/030/031およびImplementation Design V2と合わせて適用する。
9
- 元のV2責務境界を維持し、結果参照・保存成否不明・wiring互換性・キャンセル・保証表現を明確化する。
10
- 同じ論点の旧記述と差がある場合、本改訂の明確化を優先する。それ以外の既存ADRの契約を置き換えない。
7
+ This addendum is a normative implementation contract reflecting the user's approval of five additions to V2.
8
+ Apply it together with ADR-029/030/031 and Implementation Design V2.
9
+ It preserves the original V2 responsibility boundaries while clarifying result access, unknown persistence outcomes, wiring compatibility, cancellation, and guarantee wording.
10
+ Where an earlier statement on the same issue differs, these clarifications take precedence. They do not otherwise replace existing ADR contracts.
11
11
 
12
- 対象baselineは `5472116cd99a63ec27875024c955ea82be612d6b` のままとする。
13
- これは仕様の承認であり、実装完了やテスト成功を意味しない。
14
- 公開メソッド名・例外名・既存キャンセル実装への対応付けはbaseline確認後に確定する。
15
- 本書の要件IDは追跡用の文書上のIDであり、新しいRuntime ID・永続ID・APIではない。
12
+ The baseline remains `5472116cd99a63ec27875024c955ea82be612d6b`.
13
+ This is specification approval, not evidence of implementation completion or successful tests.
14
+ Public method names, exception names, and mappings to the existing cancellation implementation will be finalized after inspecting the baseline.
15
+ Requirement IDs in this document are for traceability; they are not new Runtime IDs, persistent IDs, or APIs.
16
16
 
17
- ## 1. RC-01 — 確定結果の参照と実行の発見
17
+ ## 1. RC-01: Accessing final results and discovering executions
18
18
 
19
- ### 必須契約
19
+ ### Required contract
20
20
 
21
- - Applicationはsemantic execution IDを指定して、owner identity、実行状態、確定結果またはエラーを読み取り専用で取得できる。
22
- - 対象はAgentExecutionとTeamExecution。Handoff/Orchestratorは既存のrouting anchor・parent execution・予約済みchild/Target IDを使用し、参照のための新しい実行entityを作らない。
23
- - Handoffでは指定した実行に結び付いたTarget outcomeを識別する。後続ターンの「最新のactive Agentの結果」を過去の呼び出し結果として代用しない。
24
- - admissionがcommitした後、Applicationが実行IDを受け取る前に停止する場合に備え、既知のagent_id/team_idから実行候補を発見できる公開経路を用意する。activeだけでなくterminalとなった実行も対象とする。
25
- - 結果参照・候補列挙はProvider/Tool起動、Agent continuation、callback再配送、ownership取得を伴わない。復旧を起動する操作とは区別する。
26
- - 結果が未確定、不存在、参照不能を区別する。Persistence障害やresult materialization失敗を「実行なし」「処理中」「成功で結果なし」に変換しない。
27
- - 基本状態と確定結果は保存済みrecordから取得する。継続実行に必要なgraph/Procを結果参照だけのために要求しない。既存codec/schemaの互換性要件は維持する。
21
+ - Application can obtain the owner identity, execution state, and committed result or error by semantic execution ID through read-only access.
22
+ - This covers AgentExecution and TeamExecution. Handoff/Orchestrator use existing routing anchors, parent executions, and reserved child/Target IDs; they do not create a new execution entity just for result access.
23
+ - Handoff identifies the Target outcome associated with the specified execution. The latest active Agent result from a later turn must not substitute for an earlier invocation's result.
24
+ - Provide a public path to discover execution candidates from a known agent_id/team_id, covering an interruption after admission commits but before Application receives the execution ID. Include terminal as well as active executions.
25
+ - Result access and candidate enumeration must not invoke Providers/Tools, continue Agent execution, redeliver callbacks, or acquire ownership. Distinguish these operations from operations that initiate recovery.
26
+ - Distinguish an unresolved result, absence, and inability to read. Do not translate Persistence failures or result-materialization failures into no execution, in progress, or successful completion without a result.
27
+ - Read basic state and committed results from persisted records. Do not require the graph/Procs needed for continuation merely to access results. Preserve existing codec/schema compatibility requirements.
28
28
 
29
- ### 範囲の制限
29
+ ### Scope limitations
30
30
 
31
- 候補の発見は、Applicationのリクエストとの自動一意対応やsubmissionのexactly-onceを保証しない。
32
- 複数候補がある場合、時刻が最新という理由だけで対象と断定せず、Applicationが保持する相関情報と照合する。
33
- Application固有のrequest ID・outbox・dedupはApplication責務であり、参照要件だけを理由に汎用idempotency基盤を追加しない。
31
+ Candidate discovery does not guarantee automatic unique correspondence to an Application request or exactly-once submission.
32
+ When multiple candidates exist, do not select one merely because it has the latest timestamp; Application must match its own correlation information.
33
+ Application-specific request IDs, outboxes, and deduplication remain Application responsibilities. Do not add generic idempotency infrastructure solely to meet result-access requirements.
34
34
 
35
- 既存のretention/delete契約を維持する。削除済み結果の復元、無期限保存、新しい履歴管理サービスは要求しない。
36
- 一覧の範囲・順序・ページング等は既存API/SPIを確認して最小限の公開経路に対応付ける。
37
- 既存APIで満たせない箇所のみ追加し、内部repositoryをそのまま公開契約として露出させない。
35
+ Preserve existing retention/deletion contracts. Restoring deleted results, indefinite retention, and a new history-management service are not required.
36
+ Inspect existing API/SPI behavior and map list scope, ordering, pagination, and similar concerns to the smallest necessary public path.
37
+ Add only capabilities that existing APIs cannot provide; do not expose internal repositories directly as the public contract.
38
38
 
39
- ## 2. RC-02 — 不存在・競合・保存成否不明の区別
39
+ ## 2. RC-02: Distinguishing absence, conflicts, and unknown persistence outcomes
40
40
 
41
- ### 共通判断規則
41
+ ### Shared decision rules
42
42
 
43
- | 観測 | 許可する判断・動作 |
43
+ | Observation | Permitted decision or action |
44
44
  |---|---|
45
- | 正常なauthoritative readで予約済みIDの不存在を確認 | 親の最新状態・予約・キャンセル条件を確認し、同じ予約済みIDでadmissionを試みる |
46
- | exact IDのnonterminalを確認 | 同じ実行の既存Recovery契約へ進む |
47
- | exact IDのterminalを確認 | 保存済みoutcomeを利用する。replacement executionを作らない |
48
- | read timeout / I/O failure / record decode failure | 不存在とみなさず、状態を保持して既存のerror/retry契約へ進む |
49
- | write応答消失などでcommit成否不明 | 同じoperation identity・予約済みIDを保持してreadbackする。確認前に別IDや別assignmentを作らない |
50
- | 明確なrevision/admission競合 | 最新のauthoritative factsを再読し、予約・owner・入力との整合を検証する。競合を単純な成功とみなさない |
45
+ | A successful authoritative read confirms that the reserved ID is absent | Check the parent's latest state, reservation, and cancellation conditions, then attempt admission with the same reserved ID |
46
+ | The exact ID is confirmed nonterminal | Follow the existing Recovery contract for the same execution |
47
+ | The exact ID is confirmed terminal | Use the persisted outcome; do not create a replacement execution |
48
+ | Read timeout / I/O failure / record decode failure | Preserve state and follow existing error/retry contracts; do not treat the failure as absence |
49
+ | Commit outcome is unknown, for example after a lost write acknowledgement | Retain the same operation identity and reserved ID for readback; do not create another ID or assignment before confirmation |
50
+ | A definite revision/admission conflict | Reread the latest authoritative facts and validate consistency with the reservation, owner, and input; do not treat the conflict as success by itself |
51
51
 
52
- readbackが利用する整合性は、admission/CASを保護する既存Persistence契約を満たすこと。
53
- cache/indexの不一致や読み取り障害を新規admissionの根拠にしない。
54
- 不存在確認とadmissionの間の競合は既存のatomic admission/CASで防ぐ。
55
- 外部semantic workはadmissionの成功が確定した後にのみ開始する。
52
+ Readback consistency must satisfy the existing Persistence contract that protects admission/CAS.
53
+ Cache/index discrepancies and read failures must not justify new admission.
54
+ Use existing atomic admission/CAS to prevent races between confirming absence and admission.
55
+ Start external semantic work only after admission success is confirmed.
56
56
 
57
- 適用対象: Source Handoff transfer、Target admission/stabilization、parent child reservation/outcome、
58
- Team admission/enqueue/finalize/assignment/worker outcome/terminal。
59
- Team-owned enqueue/finalizeは既存方針のstable tool_invocation_idによるfact照合を維持する。
57
+ Scope: Source Handoff transfer, Target admission/stabilization, parent child reservation/outcome,
58
+ and Team admission/enqueue/finalize/assignment/worker outcome/terminal state.
59
+ Team-owned enqueue/finalize retain the existing policy of fact reconciliation using a stable tool_invocation_id.
60
60
 
61
- 成否不明を解決できない間は、確定していないローカル推測で次のsemantic処理へ進まない。
62
- 無期限に同期待機せず、既存のPersistence error/retry経路へ制御を返す。
63
- Applicationにストレージ上の事実を創作させるmanual resolutionは追加しない。
64
- 既存Agent/Persistenceの成否不明処理を再利用し、coordination専用の第二transaction engineを作らない。
61
+ While an unknown outcome remains unresolved, do not advance to the next semantic operation based on unconfirmed local assumptions.
62
+ Return control through existing Persistence error/retry paths instead of waiting synchronously without a bound.
63
+ Do not add manual resolution that requires Application to invent storage facts.
64
+ Reuse existing Agent/Persistence handling of unknown outcomes; do not create a second transaction engine dedicated to coordination.
65
65
 
66
- ## 3. RC-03 — 復旧時wiringの最低互換性
66
+ ## 3. RC-03: Minimum wiring compatibility for recovery
67
67
 
68
- ### 照合対象
68
+ ### Required checks
69
69
 
70
- | 対象 | 継続前に必要な照合 |
70
+ | Subject | Checks required before continuation |
71
71
  |---|---|
72
- | Agent/Team定義 | 保存されたdefinition id/versionと現在の定義。既存の明示的な互換・移行契約がなければ一致を要求 |
73
- | Orchestrator child | 保存済みslotとstatic subagent登録から解決した定義、予約済みagent_id/execution_id、ownerとの一致 |
74
- | Handoff | original main anchor、保存済みactive/Target ID、必要なgraph接続、同じPersistence instance/domain |
75
- | Team worker/coordinator | Team lineage、保存済みworker slotと定義、予約済みAgent/実行ID、保存済みassignmentとの一致 |
72
+ | Agent/Team definition | Compare the persisted definition id/version with the current definition; require equality unless an existing explicit compatibility/migration contract permits otherwise |
73
+ | Orchestrator child | Match the persisted slot, the definition resolved from static subagent registration, reserved agent_id/execution_id, and owner |
74
+ | Handoff | Match the original main anchor, persisted active/Target IDs, required graph connections, and the same Persistence instance/domain |
75
+ | Team worker/coordinator | Match Team lineage, the persisted worker slot and definition, reserved Agent/execution IDs, and the persisted assignment |
76
76
 
77
- 必要な登録やTargetがない、定義が不一致、Persistence境界が異なる場合は、semantic workを開始せずfail closedとする。
78
- エラーから対象identityと不足・不整合の種類が分かるようにする。既存のconfiguration/rehydration error契約を使う。
79
- 結果の読み取りだけに不要な実行wiringを要求しない(RC-01)。
77
+ If a required registration or Target is missing, a definition is incompatible, or the Persistence boundary differs, fail closed without starting semantic work.
78
+ Use existing configuration/rehydration error contracts and make the affected identity and type of missing/inconsistent information clear from the error.
79
+ Do not require execution wiring unnecessary for read-only result access (RC-01).
80
80
 
81
- ### 確定済みfactの優先
81
+ ### Committed facts take precedence
82
82
 
83
- - 確定済みHandoffContextを現在のHandoffPolicyで再投影しない。
84
- - 確定済みchild input/configを現在のデフォルトで置き換えない。
85
- - 確定済みassignmentを現在のschedulerで選び直さない。
86
- - 確定済みchild/worker/final aggregate outcomeを再計算しない。
87
- - 未確定のscheduler/aggregateは既存V2のreplay-safe契約に従って再実行できる。保存済み入力に対する意味の互換性をApplicationが保つ。
83
+ - Do not reproject committed HandoffContext using the current HandoffPolicy.
84
+ - Do not replace committed child input/config with current defaults.
85
+ - Do not reselect committed assignments using the current scheduler.
86
+ - Do not recompute committed child/worker/final aggregate outcomes.
87
+ - Uncommitted scheduler/aggregate computations may rerun under the existing V2 replay-safe contract. Application must preserve semantic compatibility with the persisted inputs.
88
88
 
89
- Phronomyが検査できるのは宣言されたidentity/versionと構造であり、Rubyコードの意味の同一性ではない。
90
- 同じversionのまま非互換な実装に変更しないことはApplication責務。
91
- versionを上げるだけで旧実行の復旧が自動的に可能になるわけではなく、対応する定義または既存の明示的移行契約が必要。
92
- Proc/Classの永続化、ソースハッシュ、policy descriptor、global generic class registryは追加しない。
89
+ Phronomy can check declared identity/version and structure, not semantic equivalence of Ruby code.
90
+ Application is responsible for not introducing incompatible implementations under an unchanged version.
91
+ Increasing a version alone does not automatically enable recovery of old executions; the corresponding definition or an existing explicit migration contract is required.
92
+ Do not add Proc/Class persistence, source hashes, policy descriptors, or a global generic class registry.
93
93
 
94
- ## 4. RC-04 — 待機終了とsemantic cancellation
94
+ ## 4. RC-04: Ending observation and semantic cancellation
95
95
 
96
- ### 操作の区別
96
+ ### Distinguish operations
97
97
 
98
- | 操作・状態 | 契約 |
98
+ | Operation or state | Contract |
99
99
  |---|---|
100
- | Applicationが待機をやめる・接続が切れる・観測timeout | それだけではdurable executionへのsemantic cancellationとしない |
101
- | Runtime shutdown / process loss | それだけではsemantic cancellationを確定しない。既存shutdown/draining契約で実行を保存・復旧可能に保つ |
102
- | 明示的なsemantic cancellation要求 | 既存Agent cancellation契約に従い、対象owner/runと予約済み実行に対応付ける |
103
- | recovery resolution / approval待ち | failureや自動cancelへ変換せず、既存V2のrehydration経路を維持する |
100
+ | Application stops waiting, a connection is lost, or observation times out | This alone is not semantic cancellation of the durable execution |
101
+ | Runtime shutdown / process loss | This alone does not establish semantic cancellation; preserve execution and recoverability under existing shutdown/draining contracts |
102
+ | Explicit semantic cancellation request | Map it to the target owner/run and reserved executions under the existing Agent cancellation contract |
103
+ | Waiting for recovery resolution / approval | Preserve existing V2 rehydration paths; do not convert waiting into failure or automatic cancellation |
104
104
 
105
- 既存Taskの明示cancelなど、もともとsemantic cancellationを要求するAPIはその契約を維持する。
106
- 単なる観測終了と同じ操作として扱わない。具体的な公開API対応はbaseline確認時に記載する。
105
+ APIs that already request semantic cancellation, such as explicit cancellation of an existing Task, retain that contract.
106
+ Do not treat them as equivalent to merely ending observation. Record concrete public API mappings when inspecting the baseline.
107
107
 
108
- ### 子実行への適用
108
+ ### Applying cancellation to child executions
109
109
 
110
- | 子の状態 | 親runへのsemantic cancellationが受理された場合 |
110
+ | Child state | Behavior after semantic cancellation of the parent run is accepted |
111
111
  |---|---|
112
- | 予約済み・未開始 | 現在の親runに属する新規dispatchを止める。予約情報を失わず、キャンセルのために子を起動しない |
113
- | 実行中・admission競合中 | exact reserved IDの状態を確認し、既存Agent cancellationを適用する。単にローカルTaskを破棄して処理済みとみなさない |
114
- | terminal | durable outcomeを維持する。過去の成功・失敗をキャンセル済みに書き換えたり補償再実行したりしない |
112
+ | Reserved, not started | Stop new dispatch owned by the current parent run; retain reservation information and do not start a child just to cancel it |
113
+ | Running, or racing with admission | Check the exact reserved ID's state and apply existing Agent cancellation; discarding a local Task alone does not complete cancellation handling |
114
+ | Terminal | Preserve the durable outcome; do not rewrite historical success/failure as cancellation or rerun it for compensation |
115
115
 
116
- 親cancelと子admissionの競合は、最新の親run状態・既存admission契約で処理する。
117
- 既にadmitされた子は実行中の規則で照合し、別IDの子を作らない。
118
- 親terminalizationと子settlementの順序は既存Agentのcancel/terminal barrier契約へ対応付ける。
119
- 未完了の子がある場合、そのexact IDと必要なcancel/reconciliation状態を失ってはならない。
120
- restart後にも既存の復旧経路から対象を発見できることを必須とし、未対応の子を忘れたまま親の全処理完了を主張しない。
121
- 新規の公開terminal statusや別のcancel schedulerを本追補だけで追加しない。
116
+ Handle races between parent cancellation and child admission using the latest parent-run state and existing admission contracts.
117
+ Reconcile an already admitted child under the running-child rules; do not create a child with a different ID.
118
+ Map the ordering of parent terminalization and child settlement to existing Agent cancellation/terminal-barrier contracts.
119
+ If a child is incomplete, retain its exact ID and required cancellation/reconciliation state.
120
+ Require rediscovery through existing recovery paths after restart; do not claim that all parent work is complete while forgetting an unhandled child.
121
+ Do not add a new public terminal status or a separate cancellation scheduler solely for this addendum.
122
122
 
123
- キャンセルの範囲は当該親runが所有する子に限定し、共有Agentの別実行・後続Team runへ波及させない。
124
- HandoffのSourceはtransfer commit後にhanded_offであり、後からSourceをcancelしてtransferを取り消したことにしない。
125
- 現在のHandoff turnに対する明示cancelは、保存済みrouting/予約から該当Target実行へ対応付ける。
126
- 観測終了・cancelを理由にactive responsibilityを元のmain Agentへ戻さない。
123
+ Limit cancellation to children owned by the affected parent run; it must not affect other executions of a shared Agent or later Team runs.
124
+ A Handoff Source is handed_off after transfer commits. Cancelling Source later must not be treated as reversing the transfer.
125
+ Map explicit cancellation of the current Handoff turn to the relevant Target execution using persisted routing/reservations.
126
+ Do not return active responsibility to the original main Agent because observation ends or cancellation occurs.
127
127
 
128
- 外部Provider/Toolのcancelは副作用の取り消しを保証しない。成否不明は既存Agent Recovery契約で解決する。
129
- 既存機構で上記の順序・再発見を満たせず第二実行エンジン等が必要なら、Stop Conditionとして報告する。
128
+ Cancellation of external Providers/Tools does not guarantee reversal of side effects. Resolve uncertain outcomes through the existing Agent Recovery contract.
129
+ If existing mechanisms cannot satisfy the required ordering and rediscovery without a second execution engine or similar addition, report a Stop Condition.
130
130
 
131
- ## 5. RC-05 — durability保証の統一表現
131
+ ## 5. RC-05: Consistent durability guarantee wording
132
132
 
133
- > 確定済みのdurable outcomeは再利用する。未完了の実行は同じsemantic identityで復旧する。
134
- > 外部Provider/Tool処理の成否不明は既存Agent Recovery契約に従って解決する。
133
+ > Reuse committed durable outcomes. Recover incomplete executions with the same semantic identity.
134
+ > Resolve uncertain outcomes of external Provider/Tool operations under the existing Agent Recovery contract.
135
135
 
136
- 「開始していないと確認できた場合だけ開始」はframework-owned execution admissionの判断を指す。
137
- 外部システムへのリクエストが一度も届いていないことや、外部副作用のexactly-onceを意味しない。
138
- 未完了実行を同じIDで復旧することも、内部の全Provider/Tool呼び出しの無条件再送を意味しない。
139
- callback喪失、ローカルTask喪失、観測timeoutをsemantic work再実行の理由にしない。
136
+ Starting only when execution is confirmed not to have started refers to framework-owned execution admission.
137
+ It does not mean that no request ever reached an external system, nor does it guarantee exactly-once external side effects.
138
+ Recovering an incomplete execution with the same ID also does not mean unconditionally resending every internal Provider/Tool call.
139
+ Loss of a callback or local Task, or an observation timeout, must not justify rerunning semantic work.
140
140
 
141
- ## 6. 検証条件・対応付け
141
+ ## 6. Validation conditions and implementation mapping
142
142
 
143
- 以下は必要な振る舞いの検証条件であり、新しいspecファイルの本数指定ではない。
144
- 既存specが契約を検証している場合はその根拠を記録し、不足ケースのみ追加する。
143
+ The following are behavioral validation conditions, not a required count of new spec files.
144
+ Where existing specs verify a contract, record that evidence and add only missing cases.
145
145
 
146
- | ID | 検証シナリオ | 必須結果 |
146
+ | ID | Validation scenario | Required outcome |
147
147
  |---|---|---|
148
- | RC-01-A | terminal commit後、callback前にprocess loss | exact IDで同じ結果を読み取れ、semantic work/callbackを再実行しない |
149
- | RC-01-B | admission応答前にcallerを失い、実行はterminalになる | owner identityから候補を発見できる。複数候補を勝手に一つへ決めない |
150
- | RC-01-C | graph/listenerなしで結果参照、または結果のread/decode失敗 | 不要なwiringを要求しない。参照失敗を成功・不存在に偽装しない |
151
- | RC-02-A | 各semantic commitの成功直後に応答を喪失 | readbackで既存factを採用し、別ID・二重assignmentを作らない |
152
- | RC-02-B | read障害、authoritative不存在、CAS競合を別々に注入 | 状態を混同せず、成功が確定したadmission後だけ実行する |
153
- | RC-02-C | 成否不明後のreadbackも失敗 | 状態を保ち制御を返す。無期限の同期待機・新規実行をしない |
154
- | RC-03-A | subagent登録削除、定義version不一致、Target不足 | 継続前にfail closed。別定義・別Targetに置き換えない |
155
- | RC-03-B | 互換な現在のwiringで復旧 | 確定済みContext/input/assignment/outcomeを再計算しない |
156
- | RC-04-A | 待機終了・shutdown・process loss | 暗黙のsemantic cancellationを確定しない |
157
- | RC-04-B | 親cancel時に子が未開始/active/terminal | 状態別規則を守り、exact ID・確定outcomeを維持する |
158
- | RC-04-C | 親cancelとchild admission/terminalを競合させる | 子を紛失せず、既存cancel/terminal barrierへ整合する |
159
- | RC-04-D | cancel要求後の各commit境界でprocess loss | 同じrunの未完了子を復旧経路から発見・照合できる |
160
- | RC-04-E | Handoff transfer後の観測終了・明示cancel | Sourceへ巻き戻さず、当該Target実行にだけ適用する |
161
- | RC-05-A | 外部Tool効果の成否不明とcallback喪失を別々に注入 | 前者は既存Recovery、後者は確定結果参照。盲目的再実行なし |
162
-
163
- baseline統合時には、各RC IDについて「公開API/SPI・実装箇所・既存/追加spec」を対応表に記録する。
164
- 特に結果発見API、互換version扱い、cancel/terminal barrierは未確認のメソッド名で完了扱いにしない。
165
- focused・backend・fault・full suiteの実行成功は、target checkoutでの実測が必要。
166
- 本資料改訂時点では実行していない。
167
-
168
- ## 7. 増やさない責務
169
-
170
- callback outbox/ACK、terminal-delivery index、standalone fan-out用synthetic execution、
171
- Proc/Class serialization、global generic registry、独立Persistence間のdistributed transaction、
172
- Team専用の第二execution engineは引き続き対象外。
173
- 公開結果参照はApplicationの通知配送・外部副作用dedupを代替しない。
174
-
175
- ## 8. 実装との対応
176
-
177
- 2026-09-07の実装・公開API/SPI・検証範囲は
178
- [IMPLEMENTATION_REPORT.md](IMPLEMENTATION_REPORT.md)を参照する。
179
- 本追補の責務境界と必須契約は変更しない。
148
+ | RC-01-A | Process loss after terminal commit and before callback | Read the same result by exact ID without rerunning semantic work or callbacks |
149
+ | RC-01-B | Caller is lost before the admission acknowledgement; execution later becomes terminal | Discover candidates from owner identity; do not arbitrarily choose one when multiple candidates exist |
150
+ | RC-01-C | Access results without a graph/listener, or inject result read/decode failure | Require no unnecessary wiring; do not disguise an access failure as success or absence |
151
+ | RC-02-A | Lose the acknowledgement immediately after each successful semantic commit | Adopt the existing fact through readback; create neither another ID nor duplicate assignments |
152
+ | RC-02-B | Independently inject read failure, authoritative absence, and CAS conflict | Keep the states distinct; execute only after admission success is confirmed |
153
+ | RC-02-C | Readback also fails after an unknown outcome | Preserve state and return control; do not wait synchronously without a bound or create a new execution |
154
+ | RC-03-A | Remove subagent registration, mismatch definition version, or omit Target | Fail closed before continuation; do not substitute another definition or Target |
155
+ | RC-03-B | Recover with compatible current wiring | Do not recompute committed Context/input/assignment/outcome |
156
+ | RC-04-A | End waiting, shut down Runtime, or lose the process | Do not establish implicit semantic cancellation |
157
+ | RC-04-B | Parent cancellation with an unstarted/active/terminal child | Follow state-specific rules and preserve exact IDs and committed outcomes |
158
+ | RC-04-C | Race parent cancellation against child admission/terminal state | Do not lose the child; remain consistent with existing cancellation/terminal barriers |
159
+ | RC-04-D | Lose the process at each commit boundary after a cancellation request | Rediscover and reconcile incomplete children of the same run through recovery paths |
160
+ | RC-04-E | End observation or explicitly cancel after Handoff transfer | Do not roll responsibility back to Source; apply cancellation only to the relevant Target execution |
161
+ | RC-05-A | Independently inject an uncertain external Tool effect and a lost callback | Use existing Recovery for the former and committed-result access for the latter; never rerun blindly |
162
+
163
+ When integrating with the baseline, record the public API/SPI, implementation locations, and existing/additional specs for each RC ID in a mapping table.
164
+ In particular, do not mark result-discovery APIs, compatible-version handling, or cancellation/terminal barriers complete using unverified method names.
165
+ Successful focused, backend, fault, and full-suite runs require actual measurement on the target checkout.
166
+ They have not been run at the time of this document revision.
167
+
168
+ ## 7. Responsibilities that remain out of scope
169
+
170
+ Callback outbox/ACK, a terminal-delivery index, synthetic executions for standalone fan-out,
171
+ Proc/Class serialization, a global generic registry, distributed transactions across independent Persistence instances,
172
+ and a second execution engine dedicated to Team remain out of scope.
173
+ Public result access does not replace Application notification delivery or deduplication of external effects.
174
+
175
+ ## 8. Implementation mapping
176
+
177
+ See [IMPLEMENTATION_REPORT.md](IMPLEMENTATION_REPORT.md) for the implementation, public API/SPI, and validation scope as of 2026-09-07.
178
+ The responsibility boundaries and required contracts in this addendum remain unchanged.
@@ -137,6 +137,26 @@ mutable Agent/Execution/Journal state before every LLM or Tool step. A conflicti
137
137
  external durable write is surfaced as `Phronomy::Persistence::StateConflictError` rather than
138
138
  silently merged into the live instance.
139
139
 
140
+ Read persisted conversation values without interpreting Journal storage:
141
+
142
+ ```ruby
143
+ messages = agent.transcript_messages
144
+ messages.each { |message| puts "#{message.role}: #{message.content}" }
145
+ ```
146
+
147
+ `transcript_messages_async` returns a TaskResult with the same frozen array of
148
+ `LLMAdapter::Message` values. For the same durable root, these match
149
+ `result[:messages]`, including Tool calls, Tool results, non-text content and
150
+ opaque metadata. The operation selects root/generation and Journal records in one
151
+ transaction, then restores immutable content off EventLoop. It holds Agent
152
+ ownership until physical completion, including after logical cancellation.
153
+ The synchronous method refuses to wait on EventLoop. Content and integrity
154
+ failures propagate; an unreadable transcript is not an empty conversation.
155
+
156
+ `agent.transcript` remains a JournalRecord view. Knowledge is excluded from the
157
+ conversation. The application still owns authorization, role filtering and
158
+ presentation; reading invokes no LLM or Tool and changes no durable state.
159
+
140
160
  The active transcript and Knowledge views can be advanced independently without
141
161
  deleting the append-only canonical Journal:
142
162
 
@@ -379,6 +399,12 @@ Agent-backed Tools return control to EventLoop while the child lifecycle is
379
399
  waiting. They do not occupy an OffloadPool worker merely to wait for a child
380
400
  Agent result.
381
401
 
402
+ Each call owns and releases its fresh child Agent after physical work finishes.
403
+ Normal completion includes that release; a failed release preserves the result,
404
+ original error and child in `Tools::Agent::CleanupError`. See
405
+ [child lifetime and cleanup](architecture/agent-tool-child-lifetime.md) for
406
+ cancellation, approval and release-only retry rules.
407
+
382
408
  ## Filters
383
409
 
384
410
  Filters can transform or reject values at Agent boundaries:
@@ -0,0 +1,72 @@
1
+ # Migrating to Phronomy 0.31
2
+
3
+ Phronomy 0.31 adds explicit schema delivery and durable transcript reads, and
4
+ fixes ownership and release of one-shot and Agent Tool children. Review these
5
+ compatibility boundaries when upgrading from 0.30.1.
6
+
7
+ ## Stored executions
8
+
9
+ New structured executions store output-contract version 2 with `schema_delivery`
10
+ and use AgentExecution envelope 0.3. The schema remains saved and locally
11
+ validated even with `schema_delivery: :none`; omitting native schema delivery is
12
+ an explicit application choice, not an automatic fallback or output repair.
13
+
14
+ Deploy compatible readers before writing these records. Older readers reject
15
+ 0.3, including completed executions; do not downgrade a store containing them.
16
+ Version 0.31 still reads envelope 0.2 and existing version-1 native output
17
+ contracts without rewriting them merely on read. Existing free-text records do
18
+ not acquire a schema retroactively. See the
19
+ [structured-output persistence contract](../architecture/structured-output-and-scope.md#failure-and-persistence).
20
+
21
+ ## One-shot Agent ownership
22
+
23
+ `Agent.run_once` owns its fresh Agent and ephemeral Store through
24
+ `Agent.open_scope` and releases the live Agent before returning. A reusable
25
+ Agent must instead use `create`/`load` or an explicit ownership scope.
26
+
27
+ When release succeeds, the original invocation value or exception is preserved.
28
+ Unsafe or failed release raises `Agent::ScopeCleanupError`, retaining the result,
29
+ primary error, failed owners and scope. Resolve the release condition before
30
+ retrying `error.scope.release!`; this does not repeat model or Tool work.
31
+ Approval waits, physical work, independent leases, retention and recovery still
32
+ prevent unsafe release. No records are purged and no shared Store or Runtime is
33
+ shut down. See [single-invocation ownership](../architecture/structured-output-and-scope.md#single-invocation-ownership).
34
+
35
+ ## Agent-backed Tools
36
+
37
+ Both synchronous `execute` and asynchronous `call_async` now invoke the child
38
+ through `invoke_async`. A subclass that overrides only `invoke` no longer
39
+ changes the synchronous Tool path. Move the intended customization to the
40
+ asynchronous entry point and preserve its TaskResult contract.
41
+
42
+ Each call owns its fresh child and ephemeral Store until invocation and physical
43
+ work have finished and safe release completes. Normal return includes release;
44
+ successful output conversion remains unchanged. Waiting does not consume an
45
+ OffloadPool worker solely to join the child.
46
+
47
+ A release failure raises `Phronomy::Tools::Agent::CleanupError` with code
48
+ `tool.agent_cleanup_failed`. It retains `child_agent`, `agent_id`, `result`,
49
+ `primary_error` and `cleanup_error`; the cause is the primary failure when one
50
+ exists, otherwise the release failure. Resolve the release condition, then retry
51
+ `error.child_agent.unload_async` for release only. These live handles are
52
+ process-local and are not reconstructed from saved error diagnostics.
53
+
54
+ Cleanup failures are also diagnosed after observer cancellation and are not
55
+ hidden by ordinary Tool error suppression. Completed runtime wiring no longer
56
+ retains released children through generated callbacks, temporary tracker context
57
+ or completed participation changes. Session ownership, commit/readback ordering,
58
+ physical leases and recovery guards remain unchanged. See the
59
+ [Agent Tool child lifetime contract](../architecture/agent-tool-child-lifetime.md).
60
+
61
+ ## Live-provider limits
62
+
63
+ LM Studio/gpt-oss PEG output parsing remains unresolved. Known-error
64
+ identification and one bounded retry do not establish the root cause or prevent
65
+ recurrence. The existing evidence distinguishes a failed call stopped after two
66
+ POSTs from a separate application invocation that succeeded on its first POST;
67
+ it does not show recovery by retry within one call.
68
+
69
+ The DX1/DX2 normal live path, streaming, Tool use and history restoration remain
70
+ unverified in that environment. Source review, offline tests and CI support this
71
+ release; they do not establish live LLM acceptance. See the
72
+ [LM Studio policy and evidence limits](../architecture/lm-studio-output-failures.md).
@@ -12,12 +12,12 @@ module Phronomy
12
12
  # - approval notifications share the Agent listener as :approval_required;
13
13
  # - Recovery resolution uses resolve/resolve_async.
14
14
  module AsyncEventApi
15
- def start_reserved_async(reservation:, input:, config: {}, output_schema: nil)
15
+ def start_reserved_async(reservation:, input:, config: {}, output_schema: nil, schema_delivery: nil)
16
16
  __with_operation(async: true) do
17
17
  unless reservation.is_a?(ReservedExecution) && reservation.agent_id == agent_id
18
18
  raise ArgumentError, "reservation must belong to this Agent"
19
19
  end
20
- config = __invocation_config(_prepare_output_config(config, nil, output_schema))
20
+ config = __invocation_config(_prepare_output_config(config, nil, output_schema, schema_delivery))
21
21
  ExactExecution.start(agent: self, execution_id: reservation.execution_id, input: input,
22
22
  config: config.merge(phronomy_reservation: reservation.correlation))
23
23
  end
@@ -54,12 +54,13 @@ module Phronomy
54
54
  config: {},
55
55
  invocation_context: nil,
56
56
  output_schema: nil,
57
+ schema_delivery: nil,
57
58
  **removed_options,
58
59
  &removed_block
59
60
  )
60
61
  __with_operation do
61
62
  _reject_removed_invocation_listener_arguments!(removed_options, removed_block)
62
- config = _prepare_output_config(config, invocation_context, output_schema)
63
+ config = _prepare_output_config(config, invocation_context, output_schema, schema_delivery)
63
64
  _check_event_loop_reentrancy(:invoke, :invoke_async)
64
65
  _start_agent_operation(
65
66
  input,
@@ -75,12 +76,13 @@ module Phronomy
75
76
  config: {},
76
77
  invocation_context: nil,
77
78
  output_schema: nil,
79
+ schema_delivery: nil,
78
80
  **removed_options,
79
81
  &removed_block
80
82
  )
81
83
  __with_operation(async: true) do
82
84
  _reject_removed_invocation_listener_arguments!(removed_options, removed_block)
83
- config = _prepare_output_config(config, invocation_context, output_schema)
85
+ config = _prepare_output_config(config, invocation_context, output_schema, schema_delivery)
84
86
  _start_agent_operation(
85
87
  input,
86
88
  config: config,
@@ -95,13 +97,14 @@ module Phronomy
95
97
  config: {},
96
98
  invocation_context: nil,
97
99
  output_schema: nil,
100
+ schema_delivery: nil,
98
101
  **removed_options,
99
102
  &removed_block
100
103
  )
101
104
  __with_operation do
102
105
  _reject_removed_invocation_listener_arguments!(removed_options, removed_block)
103
106
  listener = _required_stream_listener!(:stream)
104
- config = _prepare_output_config(config, invocation_context, output_schema)
107
+ config = _prepare_output_config(config, invocation_context, output_schema, schema_delivery)
105
108
  _check_event_loop_reentrancy(:stream, :stream_async)
106
109
  _start_agent_operation(
107
110
  input,
@@ -117,13 +120,14 @@ module Phronomy
117
120
  config: {},
118
121
  invocation_context: nil,
119
122
  output_schema: nil,
123
+ schema_delivery: nil,
120
124
  **removed_options,
121
125
  &removed_block
122
126
  )
123
127
  __with_operation(async: true) do
124
128
  _reject_removed_invocation_listener_arguments!(removed_options, removed_block)
125
129
  listener = _required_stream_listener!(:stream_async)
126
- config = _prepare_output_config(config, invocation_context, output_schema)
130
+ config = _prepare_output_config(config, invocation_context, output_schema, schema_delivery)
127
131
  _start_agent_operation(
128
132
  input,
129
133
  config: config,
@@ -206,9 +210,14 @@ module Phronomy
206
210
 
207
211
  private
208
212
 
209
- def _prepare_output_config(config, invocation_context, schema)
213
+ def _prepare_output_config(config, invocation_context, schema, schema_delivery)
210
214
  config = _prepare_invocation_config(config, invocation_context)
211
- schema.nil? ? config : config.merge(phronomy_output_contract: OutputContract.new(schema))
215
+ if schema.nil?
216
+ raise ArgumentError, "schema_delivery requires output_schema" unless schema_delivery.nil?
217
+ return config
218
+ end
219
+ contract = OutputContract.new(schema, schema_delivery: schema_delivery.nil? ? :native : schema_delivery)
220
+ config.merge(phronomy_output_contract: contract)
212
221
  end
213
222
 
214
223
  def _start_agent_operation(input, config:, mode:, listener:)
@@ -400,6 +400,31 @@ module Phronomy
400
400
  end
401
401
  end
402
402
 
403
+ # Materializes the current durable transcript as immutable Message values.
404
+ # Application authorization and presentation filtering remain caller-owned.
405
+ # @return [Array<LLMAdapter::Message>]
406
+ # @api public
407
+ def transcript_messages
408
+ _check_event_loop_reentrancy(:transcript_messages, :transcript_messages_async)
409
+ transcript_messages_async.wait_result
410
+ end
411
+
412
+ # Holds Agent ownership until the submitted read physically completes.
413
+ # @return [TaskResult<Array<LLMAdapter::Message>>]
414
+ # @api public
415
+ def transcript_messages_async
416
+ __with_operation(async: true, read_only: true) do
417
+ __execution_environment.submit(on_full: :raise) do
418
+ root, records = persistence.transaction do |tx|
419
+ current = tx.agents.load(agent_id)
420
+ [current, tx.journals.read(agent_id, limit: current.journal_position)]
421
+ end
422
+ RuntimeInput.new(agent: self, persistence: persistence)
423
+ .materialize_transcript(root: root, records: records)
424
+ end
425
+ end
426
+ end
427
+
403
428
  def clear_transcript!
404
429
  __with_operation do
405
430
  mutate_context!(:transcript_cleared) do |root|
@@ -730,8 +755,8 @@ module Phronomy
730
755
  def _prepare_invocation_config(config, invocation_context)
731
756
  __assert_live_agent!
732
757
  _reject_removed_generic_identity_keys!(config)
733
- if config.keys.any? { |key| %w[output_schema response_schema phronomy_output_contract].include?(key.to_s) }
734
- raise ArgumentError, "Use the output_schema keyword on a new Agent execution"
758
+ if config.keys.any? { |key| %w[output_schema schema_delivery response_schema phronomy_output_contract].include?(key.to_s) }
759
+ raise ArgumentError, "Use the output_schema and schema_delivery keywords on a new Agent execution"
735
760
  end
736
761
  invocation_context ?
737
762
  config.merge(invocation_context: invocation_context) : config
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # This convenience API composes a fresh ephemeral Persistence with an Agent.
3
+ # This convenience API owns a fresh ephemeral Persistence and a scoped Agent.
4
4
  # The application entry loads the method definition; Agent execution does not
5
5
  # delegate to or require this higher-level composition implementation.
6
6
  module Phronomy
@@ -18,15 +18,16 @@ module Phronomy
18
18
  raise ArgumentError, "Provide either on_event: or a block, not both"
19
19
  end
20
20
 
21
- persistence = Phronomy::PersistenceComposition.agent
22
- agent = definition.create(
23
- context: context,
24
- knowledge: knowledge,
25
- persistence: persistence,
26
- on_event: on_event,
27
- &event_block
28
- )
29
- agent.invoke(input, **invoke_options)
21
+ open_scope do |scope|
22
+ persistence = Phronomy::PersistenceComposition.agent
23
+ agent = scope.create(definition,
24
+ context: context,
25
+ knowledge: knowledge,
26
+ persistence: persistence,
27
+ on_event: on_event,
28
+ &event_block)
29
+ agent.invoke(input, **invoke_options)
30
+ end
30
31
  end
31
32
  end
32
33
  end