phronomy 0.23.0 → 0.24.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.mutant.yml +2 -2
- data/CHANGELOG.md +15 -0
- data/CONTRIBUTING.md +2 -2
- data/README.md +1 -1
- data/docs/architecture/multi-agent-handoff.md +35 -40
- data/docs/architecture/persistence.md +19 -8
- data/docs/architecture.md +8 -1
- data/docs/decisions/016-semantic-multi-agent-handoff.md +3 -1
- 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 +5 -1
- 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 +35 -1
- data/docs/migrations/durable-semantic-coordination-v2.md +65 -0
- data/docs/persistence-backends.md +42 -3
- data/lib/phronomy/agent/agent_execution.rb +2 -2
- data/lib/phronomy/agent/agent_invocation.rb +1 -1
- data/lib/phronomy/agent/async_event_api.rb +18 -1
- data/lib/phronomy/agent/base.rb +28 -0
- data/lib/phronomy/agent/context_assembler.rb +1 -1
- 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 +484 -27
- data/lib/phronomy/{multi_agent → agent}/handoff.rb +4 -4
- data/lib/phronomy/{multi_agent → agent}/handoff_capability_factory.rb +3 -45
- data/lib/phronomy/{multi_agent → agent}/handoff_context.rb +26 -1
- data/lib/phronomy/{multi_agent/execution_coordinator.rb → agent/handoff_execution_coordinator.rb} +32 -5
- data/lib/phronomy/{multi_agent → agent}/handoff_policy.rb +7 -1
- data/lib/phronomy/{multi_agent → agent}/handoff_projection.rb +18 -2
- data/lib/phronomy/{multi_agent → agent}/handoff_request.rb +2 -2
- data/lib/phronomy/agent/handoff_runner.rb +178 -0
- data/lib/phronomy/agent/handoff_state.rb +43 -0
- data/lib/phronomy/agent/recovery_coordinator/continuation.rb +114 -211
- data/lib/phronomy/agent/recovery_coordinator/installation.rb +84 -130
- data/lib/phronomy/agent/recovery_coordinator/resolution.rb +76 -200
- data/lib/phronomy/agent/recovery_coordinator.rb +11 -5
- data/lib/phronomy/agent/recovery_support.rb +15 -23
- data/lib/phronomy/agent/ruby_llm_materializer.rb +2 -8
- data/lib/phronomy/agent/tool_invocation.rb +4 -2
- data/lib/phronomy/engine/runtime/team_ownership_registry.rb +77 -0
- data/lib/phronomy/engine/runtime.rb +16 -1
- data/lib/phronomy/multi_agent/durable_subagent_coordinator.rb +134 -0
- data/lib/phronomy/multi_agent/orchestrator.rb +59 -11
- 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 +60 -0
- data/lib/phronomy/persistence/in_memory.rb +264 -2
- data/lib/phronomy/persistence/repository_facades.rb +221 -2
- data/lib/phronomy/persistence.rb +95 -1
- data/lib/phronomy/testing/persistence_contract/a_persistence_backend.rb +1 -0
- 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/version.rb +1 -1
- data/scripts/api_snapshot.rb +3 -3
- data/sig/phronomy/handoff.rbs +41 -0
- data/sig/phronomy/multi_agent.rbs +28 -32
- data/sig/phronomy/persistence.rbs +64 -3
- metadata +30 -12
- data/lib/phronomy/multi_agent/coordination_state.rb +0 -18
- data/lib/phronomy/multi_agent/coordinator.rb +0 -154
- data/lib/phronomy/multi_agent/runner.rb +0 -98
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
# Durable Semantic Coordination V2 revision 2 — Implementation report
|
|
2
|
+
|
|
3
|
+
作成日: 2026-09-07。設計承認日: 2026-09-06。
|
|
4
|
+
対象baseline: `5472116cd99a63ec27875024c955ea82be612d6b`。
|
|
5
|
+
承認済みADR-029/030/031とRC-01〜05に対する新規実装です。
|
|
6
|
+
旧Complete Durability overlay、既存の作業ZIP、synthetic fan-out executionは使用しません。
|
|
7
|
+
|
|
8
|
+
## 実装範囲
|
|
9
|
+
|
|
10
|
+
| 対象 | 実装した動作 |
|
|
11
|
+
|---|---|
|
|
12
|
+
| Persistence | root/transaction viewともに8 repository。新しい3 recordはcurrent format `0.1`。Backendはopaque DurableRecordと明示的なidentity/revision/index metadataを扱う |
|
|
13
|
+
| Handoff | Agent-domain APIへ移設。Source terminal・Context・exact Target予約・責務移転を同じtransactionで保存。Target terminalとrouting安定化も同一transaction |
|
|
14
|
+
| Orchestrator | 既存parent AgentExecutionのstatic subagent Toolにchild ID/input/knowledge/config/outcomeを保存。直接の`dispatch_parallel`/`fan_out`にはsynthetic parentを作らない |
|
|
15
|
+
| Team | TeamRoot/TeamExecution、task、worker slot、exact assignment/outcomeをCASで保存。coordinator/workerは既存Agent engineを使用。スケジューリングは既存の逐次方式 |
|
|
16
|
+
| Team内部操作 | 保存済みのauthorized Tool batchをProvider順に適用。各`tool_invocation_id`の結果を保持し、`enqueue_task`/`finalize`を自動照合 |
|
|
17
|
+
| Aggregate | pure/replay-safeな計算。canonical JSON結果またはエラーをterminal commit。保存前のクラッシュでは再計算可能、保存済みterminalでは再計算しない |
|
|
18
|
+
| Runtime | Teamのprocess-local所有・admission・drainを追加。新しいTeam FSM/Workflow engineは追加しない |
|
|
19
|
+
| Recovery | framework-owned操作はexact factから再開。外部Toolと混在したbatchでは外部の事実だけを既存Recovery APIで解決する |
|
|
20
|
+
| 終了・削除 | exact子のcancel/reconciliation情報を保持。idle main Agentの`purge!`はHandoff anchorも同時削除。未完了turnのanchor削除は拒否 |
|
|
21
|
+
|
|
22
|
+
Handoff graphは同じPersistence **instance**を使います。元main Agent IDがrouting anchorです。
|
|
23
|
+
保存済みContextを新しいpolicyで再投影せず、保存済みworker割当を現在のschedulerで選び直しません。
|
|
24
|
+
RuntimeのClass/Proc、listener、Task、CancellationTokenは永続化しません。
|
|
25
|
+
|
|
26
|
+
## 公開経路
|
|
27
|
+
|
|
28
|
+
| 目的 | API / 返却値 |
|
|
29
|
+
|---|---|
|
|
30
|
+
| Agent結果参照 | `store.execution_result(execution_id)`。owner、status、phase、result/errorと参照IDの凍結Hash |
|
|
31
|
+
| Handoff結果参照 | `store.handoff_result(source_execution_id)`。そのturnのexact Targetまで辿る。graph/Agent hydration不要 |
|
|
32
|
+
| Agent実行発見 | `store.list_executions(agent_id, after: nil, limit: 100)`。immutable execution records。active/terminal双方 |
|
|
33
|
+
| Team結果参照 | `store.team_execution_result(run_id)` または `team.result(run_id)` |
|
|
34
|
+
| Team実行発見 | `store.list_team_executions(team_id, after: nil, limit: 100)` または `team.executions(...)` |
|
|
35
|
+
| Handoffの実行/復旧 | `Agent::HandoffRunner.new(main_agent:, handoffs:).invoke(input, config: {})`。未完了turnがあれば保存済み予約・入力を使用 |
|
|
36
|
+
| static childの復旧 | `Orchestrator#resume(execution_id, config: {})` |
|
|
37
|
+
| Teamの作成/復旧 | `team_definition id:, version:`、`create(team_id:, persistence:)`、`load(team_id, persistence:, on_event:)`、`resume(run_id)` |
|
|
38
|
+
| 明示cancel | `team.cancel(run_id)` / `handoff_runner.cancel(execution_id)`。Orchestratorを含むAgentの既存操作は`config[:cancellation_token]` |
|
|
39
|
+
|
|
40
|
+
一覧順はsemantic IDの辞書順、`after`は排他的ID cursor、`limit`は正の整数です。
|
|
41
|
+
時刻順やリクエスト一意対応を意味しません。Applicationは候補を自身の相関情報と照合します。
|
|
42
|
+
|
|
43
|
+
Agentの結果statusは既存Symbol、Teamの結果statusはcanonical Stringです。
|
|
44
|
+
Teamのdefault aggregate結果もcanonical JSONのためHash keyはString、errorは例外オブジェクトではなく
|
|
45
|
+
`class`/`message`等のデータです。aggregateに渡すassignmentのトップレベルとtask keyはSymbolです。
|
|
46
|
+
|
|
47
|
+
Handoffの未開始Target予約は`status: :active, phase: :target_pending, reserved: true`で識別します。
|
|
48
|
+
明示cancelした未開始Targetは予約IDを保持し、過去turnの結果に後続turnを代用しません。
|
|
49
|
+
不存在は`Persistence::NotFoundError`、読み取り/復号失敗はそのエラーを返します。
|
|
50
|
+
削除された結果を復元する機能や無期限retentionは追加していません。
|
|
51
|
+
|
|
52
|
+
`Team.load`はTeam factsのhydrationのみです。子の実行/復旧は`resume`で開始します。
|
|
53
|
+
Agentの`load`は既存Recovery契約を維持します。結果だけが必要なら上記Persistence参照APIを使います。
|
|
54
|
+
Teamの`on_event`はhidden Agentsへ渡し、必要なRecovery/approval eventを受け取ります。
|
|
55
|
+
`Team.stream`はcommit済みassignmentのRuntime通知です。新しい通知配送保証はありません。
|
|
56
|
+
|
|
57
|
+
## RC対応表
|
|
58
|
+
|
|
59
|
+
パスはリポジトリroot相対です。共通の追加障害specは
|
|
60
|
+
`spec/phronomy/multi_agent/durable_coordination_spec.rb`です。
|
|
61
|
+
|
|
62
|
+
| 要件 | 主な実装 | 検証根拠 |
|
|
63
|
+
|---|---|---|
|
|
64
|
+
| RC-01-A/B | `Persistence#execution_result` / `list_executions`、Team対応API | owner未loadの再構築環境でactive/terminal候補・ページング・結果を読み、Provider/所有登録を増やさない |
|
|
65
|
+
| RC-01-C | `Persistence#handoff_result`、読み取り専用materialization | graph/ownerなしの予約参照、read障害、purge済み結果のNotFound。callback政策は既存`stream_callback_error_policy_spec.rb`でも検証 |
|
|
66
|
+
| RC-02-A | Agent準備の既存F1 readback、`reconcile_terminal_error`、Team `admit`/`update` | Teamの各revision commit直後の応答喪失、Source移転の応答喪失、確定worker/child outcomeの再利用 |
|
|
67
|
+
| RC-02-B/C | exact予約照合・atomic admission/CAS・bounded readback | read失敗と不存在を区別。Team admission後のreadback失敗ではdispatchなし。Backend契約はstale CAS、active重複、8 repository rollbackを検証 |
|
|
68
|
+
| RC-03-A | Team definition snapshot、static child slot定義、Handoff graph/Target照合 | worker version不一致とTarget/graph不足でfail closed。既存Handoff統合specで別Persistenceを拒否 |
|
|
69
|
+
| RC-03-B | immutable Context/input/knowledge/assignment/outcome | 現在policyを変更しても保存済みHandoffContextを使用。worker結果・static child結果・knowledge metadataを保持 |
|
|
70
|
+
| RC-04-A | 既存Task待機/Runtime shutdown契約 | `task_spec.rb`、`agent/acs16_task_quiescence_spec.rb`、Runtime/admission specs。Runtime再構築テストで暗黙cancelを追加しない |
|
|
71
|
+
| 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と合わせて確認 |
|
|
72
|
+
| RC-04-E | Source terminal linkとTarget cancel。責務はTargetのまま | transfer後cancel→再起動→後続turnでもSourceへ戻らず、過去の予約IDとcancel結果を維持 |
|
|
73
|
+
| RC-05 | callback/外部効果とsemantic recordの分離 | mixed external/framework Tool batchは外部factだけresolveし、完了childを再実行しない。内部`finalize`の事実をApplicationへ問い合わせない |
|
|
74
|
+
|
|
75
|
+
`lib/phronomy/testing/persistence_contract/coordination_repositories.rb`の新shared examplesは、
|
|
76
|
+
外部backendにも公開される`phronomy/testing/persistence_contract`経由で実行されます。
|
|
77
|
+
raw SPI/API snapshot/RBS、旧Handoff定数削除、EventLoop単一writer/causal barrier、
|
|
78
|
+
logical-operation tracingの既存guardも維持しています。
|
|
79
|
+
|
|
80
|
+
## 検証の範囲と限界
|
|
81
|
+
|
|
82
|
+
実測環境はRuby 3.3.6。使用gemは配布ZIPの`verification/gems.txt`に記録します。
|
|
83
|
+
配布対象に対する実測コマンド、結果、ログは同梱の検証記録を参照してください。
|
|
84
|
+
|
|
85
|
+
- 通常RSpecは外部LLMへの接続を要するintegration tagを除外します。
|
|
86
|
+
- 選択したHandoff/Orchestrator/Team integrationはWebMockで実行します。
|
|
87
|
+
- 追加F4テストは、commit済みDurableRecordを複製し、新Backendと新Runtimeで復旧するモデルです。
|
|
88
|
+
これは実OSプロセスの強制終了や物理ディスクへのfsyncの実証ではありません。
|
|
89
|
+
- 実LLM、Redis、PostgreSQL、OpenTelemetry等を使う別スイートは今回の実測対象外です。
|
|
90
|
+
optional依存/service未設定59件と既存obsolete2件の計61件がpendingです。
|
|
91
|
+
- 外部backendのF4保存性と複数processの排他は、そのbackendとdeploymentの契約に依存します。
|
|
92
|
+
InMemory自身はプロセス終了後の保存を保証しません。
|
|
93
|
+
- semantic cancellationは外部効果のrollbackではありません。TokenオブジェクトはRuntime-onlyです。
|
|
94
|
+
durable cancel flag/factがcommitした後は保持し、未確定外部処理は既存Recoveryで照合します。
|
|
95
|
+
fact/approval待ちをfailedにして子を忘れず、`ExecutionRehydrationRequiredError`で制御を返します。
|
|
96
|
+
|
|
97
|
+
Frameworkが実施するのは、確定outcomeの再利用と未完了実行の同じsemantic identityでの復旧です。
|
|
98
|
+
callback outbox/ACK、global generic class registry、Proc/Class永続化、distributed transaction、
|
|
99
|
+
Team専用の第二execution engineは追加していません。
|
|
100
|
+
|
|
101
|
+
## パッケージ
|
|
102
|
+
|
|
103
|
+
完全版ファイルと削除manifestを同梱します。baseline/適用前後のハッシュを検査して適用します。
|
|
104
|
+
新しいClassの配置をZeitwerkの命名規則に合わせ、旧overlayのdecorator ignoreは不要です。
|
|
105
|
+
旧`MultiAgent::Handoff*`、`Runner`、`Coordinator`、`CoordinationState`の実装を削除します。
|
|
106
|
+
適用・依存関係・VERIFY手順は配布rootの`README_APPLY_JA.md`を参照してください。
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
# V2復旧契約の明確化 — 承認済み追補
|
|
2
|
+
|
|
3
|
+
更新日: 2026-09-06 / 文書改訂: V2 revision 2
|
|
4
|
+
|
|
5
|
+
## 0. 位置づけ
|
|
6
|
+
|
|
7
|
+
本追補は、V2への追加提案5点に対するユーザーの承認を反映した規範的な実装契約である。
|
|
8
|
+
ADR-029/030/031およびImplementation Design V2と合わせて適用する。
|
|
9
|
+
元のV2責務境界を維持し、結果参照・保存成否不明・wiring互換性・キャンセル・保証表現を明確化する。
|
|
10
|
+
同じ論点の旧記述と差がある場合、本改訂の明確化を優先する。それ以外の既存ADRの契約を置き換えない。
|
|
11
|
+
|
|
12
|
+
対象baselineは `5472116cd99a63ec27875024c955ea82be612d6b` のままとする。
|
|
13
|
+
これは仕様の承認であり、実装完了やテスト成功を意味しない。
|
|
14
|
+
公開メソッド名・例外名・既存キャンセル実装への対応付けはbaseline確認後に確定する。
|
|
15
|
+
本書の要件IDは追跡用の文書上のIDであり、新しいRuntime ID・永続ID・APIではない。
|
|
16
|
+
|
|
17
|
+
## 1. RC-01 — 確定結果の参照と実行の発見
|
|
18
|
+
|
|
19
|
+
### 必須契約
|
|
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の互換性要件は維持する。
|
|
28
|
+
|
|
29
|
+
### 範囲の制限
|
|
30
|
+
|
|
31
|
+
候補の発見は、Applicationのリクエストとの自動一意対応やsubmissionのexactly-onceを保証しない。
|
|
32
|
+
複数候補がある場合、時刻が最新という理由だけで対象と断定せず、Applicationが保持する相関情報と照合する。
|
|
33
|
+
Application固有のrequest ID・outbox・dedupはApplication責務であり、参照要件だけを理由に汎用idempotency基盤を追加しない。
|
|
34
|
+
|
|
35
|
+
既存のretention/delete契約を維持する。削除済み結果の復元、無期限保存、新しい履歴管理サービスは要求しない。
|
|
36
|
+
一覧の範囲・順序・ページング等は既存API/SPIを確認して最小限の公開経路に対応付ける。
|
|
37
|
+
既存APIで満たせない箇所のみ追加し、内部repositoryをそのまま公開契約として露出させない。
|
|
38
|
+
|
|
39
|
+
## 2. RC-02 — 不存在・競合・保存成否不明の区別
|
|
40
|
+
|
|
41
|
+
### 共通判断規則
|
|
42
|
+
|
|
43
|
+
| 観測 | 許可する判断・動作 |
|
|
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・入力との整合を検証する。競合を単純な成功とみなさない |
|
|
51
|
+
|
|
52
|
+
readbackが利用する整合性は、admission/CASを保護する既存Persistence契約を満たすこと。
|
|
53
|
+
cache/indexの不一致や読み取り障害を新規admissionの根拠にしない。
|
|
54
|
+
不存在確認とadmissionの間の競合は既存のatomic admission/CASで防ぐ。
|
|
55
|
+
外部semantic workはadmissionの成功が確定した後にのみ開始する。
|
|
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照合を維持する。
|
|
60
|
+
|
|
61
|
+
成否不明を解決できない間は、確定していないローカル推測で次のsemantic処理へ進まない。
|
|
62
|
+
無期限に同期待機せず、既存のPersistence error/retry経路へ制御を返す。
|
|
63
|
+
Applicationにストレージ上の事実を創作させるmanual resolutionは追加しない。
|
|
64
|
+
既存Agent/Persistenceの成否不明処理を再利用し、coordination専用の第二transaction engineを作らない。
|
|
65
|
+
|
|
66
|
+
## 3. RC-03 — 復旧時wiringの最低互換性
|
|
67
|
+
|
|
68
|
+
### 照合対象
|
|
69
|
+
|
|
70
|
+
| 対象 | 継続前に必要な照合 |
|
|
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との一致 |
|
|
76
|
+
|
|
77
|
+
必要な登録やTargetがない、定義が不一致、Persistence境界が異なる場合は、semantic workを開始せずfail closedとする。
|
|
78
|
+
エラーから対象identityと不足・不整合の種類が分かるようにする。既存のconfiguration/rehydration error契約を使う。
|
|
79
|
+
結果の読み取りだけに不要な実行wiringを要求しない(RC-01)。
|
|
80
|
+
|
|
81
|
+
### 確定済みfactの優先
|
|
82
|
+
|
|
83
|
+
- 確定済みHandoffContextを現在のHandoffPolicyで再投影しない。
|
|
84
|
+
- 確定済みchild input/configを現在のデフォルトで置き換えない。
|
|
85
|
+
- 確定済みassignmentを現在のschedulerで選び直さない。
|
|
86
|
+
- 確定済みchild/worker/final aggregate outcomeを再計算しない。
|
|
87
|
+
- 未確定のscheduler/aggregateは既存V2のreplay-safe契約に従って再実行できる。保存済み入力に対する意味の互換性をApplicationが保つ。
|
|
88
|
+
|
|
89
|
+
Phronomyが検査できるのは宣言されたidentity/versionと構造であり、Rubyコードの意味の同一性ではない。
|
|
90
|
+
同じversionのまま非互換な実装に変更しないことはApplication責務。
|
|
91
|
+
versionを上げるだけで旧実行の復旧が自動的に可能になるわけではなく、対応する定義または既存の明示的移行契約が必要。
|
|
92
|
+
Proc/Classの永続化、ソースハッシュ、policy descriptor、global generic class registryは追加しない。
|
|
93
|
+
|
|
94
|
+
## 4. RC-04 — 待機終了とsemantic cancellation
|
|
95
|
+
|
|
96
|
+
### 操作の区別
|
|
97
|
+
|
|
98
|
+
| 操作・状態 | 契約 |
|
|
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経路を維持する |
|
|
104
|
+
|
|
105
|
+
既存Taskの明示cancelなど、もともとsemantic cancellationを要求するAPIはその契約を維持する。
|
|
106
|
+
単なる観測終了と同じ操作として扱わない。具体的な公開API対応はbaseline確認時に記載する。
|
|
107
|
+
|
|
108
|
+
### 子実行への適用
|
|
109
|
+
|
|
110
|
+
| 子の状態 | 親runへのsemantic cancellationが受理された場合 |
|
|
111
|
+
|---|---|
|
|
112
|
+
| 予約済み・未開始 | 現在の親runに属する新規dispatchを止める。予約情報を失わず、キャンセルのために子を起動しない |
|
|
113
|
+
| 実行中・admission競合中 | exact reserved IDの状態を確認し、既存Agent cancellationを適用する。単にローカルTaskを破棄して処理済みとみなさない |
|
|
114
|
+
| terminal | durable outcomeを維持する。過去の成功・失敗をキャンセル済みに書き換えたり補償再実行したりしない |
|
|
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を本追補だけで追加しない。
|
|
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へ戻さない。
|
|
127
|
+
|
|
128
|
+
外部Provider/Toolのcancelは副作用の取り消しを保証しない。成否不明は既存Agent Recovery契約で解決する。
|
|
129
|
+
既存機構で上記の順序・再発見を満たせず第二実行エンジン等が必要なら、Stop Conditionとして報告する。
|
|
130
|
+
|
|
131
|
+
## 5. RC-05 — durability保証の統一表現
|
|
132
|
+
|
|
133
|
+
> 確定済みのdurable outcomeは再利用する。未完了の実行は同じsemantic identityで復旧する。
|
|
134
|
+
> 外部Provider/Tool処理の成否不明は既存Agent Recovery契約に従って解決する。
|
|
135
|
+
|
|
136
|
+
「開始していないと確認できた場合だけ開始」はframework-owned execution admissionの判断を指す。
|
|
137
|
+
外部システムへのリクエストが一度も届いていないことや、外部副作用のexactly-onceを意味しない。
|
|
138
|
+
未完了実行を同じIDで復旧することも、内部の全Provider/Tool呼び出しの無条件再送を意味しない。
|
|
139
|
+
callback喪失、ローカルTask喪失、観測timeoutをsemantic work再実行の理由にしない。
|
|
140
|
+
|
|
141
|
+
## 6. 検証条件・対応付け
|
|
142
|
+
|
|
143
|
+
以下は必要な振る舞いの検証条件であり、新しいspecファイルの本数指定ではない。
|
|
144
|
+
既存specが契約を検証している場合はその根拠を記録し、不足ケースのみ追加する。
|
|
145
|
+
|
|
146
|
+
| ID | 検証シナリオ | 必須結果 |
|
|
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
|
+
本追補の責務境界と必須契約は変更しない。
|
|
@@ -0,0 +1,302 @@
|
|
|
1
|
+
# Phronomy Durability Responsibility-Boundary Review
|
|
2
|
+
|
|
3
|
+
Status: Accepted V2 revision 2, 2026-09-06.
|
|
4
|
+
|
|
5
|
+
## 1. Purpose
|
|
6
|
+
|
|
7
|
+
The earlier "Complete Durability" plan attempted to make every visible completion
|
|
8
|
+
boundary resilient to process loss. That produced technically defensible
|
|
9
|
+
protocols, but responsibility analysis showed that several of those protocols
|
|
10
|
+
belonged outside the Phronomy semantic execution engine.
|
|
11
|
+
|
|
12
|
+
This review narrows durability to the state Phronomy **owns and can reconcile
|
|
13
|
+
authoritatively**.
|
|
14
|
+
|
|
15
|
+
The objective is not "persist everything". The objective is:
|
|
16
|
+
|
|
17
|
+
> Preserve framework-owned semantic progress across process/runtime loss without
|
|
18
|
+
> blindly repeating work already known to have completed.
|
|
19
|
+
|
|
20
|
+
## 2. Responsibility test
|
|
21
|
+
|
|
22
|
+
A fact belongs to Phronomy durability when all of the following are true:
|
|
23
|
+
|
|
24
|
+
1. Phronomy creates or owns the semantic operation.
|
|
25
|
+
2. Phronomy has a canonical durable identity for that operation.
|
|
26
|
+
3. Phronomy can determine its authoritative state from `Persistence`.
|
|
27
|
+
4. Repeating the operation after losing Runtime state could duplicate semantic
|
|
28
|
+
work or violate the public abstraction.
|
|
29
|
+
5. The required recovery does not require Phronomy to emulate an Application
|
|
30
|
+
transaction coordinator.
|
|
31
|
+
|
|
32
|
+
A concern remains Application responsibility when one or more of the following
|
|
33
|
+
are true:
|
|
34
|
+
|
|
35
|
+
1. it is an arbitrary callback or external side effect;
|
|
36
|
+
2. its exactly-once/idempotency semantics depend on an external system;
|
|
37
|
+
3. the Application can naturally handle it with an outbox, job queue,
|
|
38
|
+
idempotency key, database transaction, or its own Workflow;
|
|
39
|
+
4. persisting it would force Phronomy to serialize or reconstruct Application
|
|
40
|
+
code/Runtime objects;
|
|
41
|
+
5. the API is only a convenience operation and has no existing durable semantic
|
|
42
|
+
root.
|
|
43
|
+
|
|
44
|
+
## 3. Revised boundary
|
|
45
|
+
|
|
46
|
+
| Concern | Owner | Restart-spanning guarantee |
|
|
47
|
+
|---|---|---|
|
|
48
|
+
| AgentExecution semantic status | Phronomy | Yes |
|
|
49
|
+
| Agent result/error durable evidence | Phronomy | Yes |
|
|
50
|
+
| Agent `on_event` callback invocation | Runtime/Application | No |
|
|
51
|
+
| Callback side-effect deduplication | Application | No framework guarantee |
|
|
52
|
+
| Handoff active Agent responsibility | Phronomy | Yes |
|
|
53
|
+
| Handoff reserved Target execution | Phronomy | Yes |
|
|
54
|
+
| Handoff graph/Policy Ruby objects | Application Runtime wiring | Re-supplied, not persisted |
|
|
55
|
+
| Orchestrator child reservation/outcome inside an AgentExecution | Phronomy | Yes |
|
|
56
|
+
| Standalone `dispatch_parallel` / `fan_out` convenience call | Runtime | No |
|
|
57
|
+
| Team task queue | Phronomy | Yes |
|
|
58
|
+
| Team task -> worker assignment | Phronomy | Yes |
|
|
59
|
+
| Team worker execution/result | Phronomy | Yes |
|
|
60
|
+
| Team scheduler callback | Application pure/replay-safe function | May be rerun before assignment commit |
|
|
61
|
+
| Team aggregator callback | Application pure/replay-safe function | May be rerun until result commit |
|
|
62
|
+
| Team progress/terminal callback | Runtime/Application | No |
|
|
63
|
+
| Email/webhook/DB side effect triggered by a result | Application | Use Application transaction/outbox/idempotency |
|
|
64
|
+
|
|
65
|
+
## 4. Why restart-spanning `on_event` is removed
|
|
66
|
+
|
|
67
|
+
The earlier design stored a terminal-delivery descriptor, indexed pending
|
|
68
|
+
deliveries, redelivered them from `Agent.load`, and acknowledged callback attempts
|
|
69
|
+
with a second CAS write.
|
|
70
|
+
|
|
71
|
+
That protocol solved "terminal commit succeeded but callback was not observed".
|
|
72
|
+
It did **not** solve exactly-once effects. If the process died after the callback
|
|
73
|
+
performed an external action but before ACK, the callback could run again.
|
|
74
|
+
|
|
75
|
+
Therefore the Application still needed idempotency/deduplication. Phronomy would
|
|
76
|
+
have been maintaining an outbox-like protocol while being unable to own the
|
|
77
|
+
external transaction.
|
|
78
|
+
|
|
79
|
+
The revised boundary is:
|
|
80
|
+
|
|
81
|
+
```text
|
|
82
|
+
semantic completion Phronomy
|
|
83
|
+
same-process event observation Runtime
|
|
84
|
+
external side effect Application
|
|
85
|
+
restart-spanning notification Application outbox/job/Workflow when required
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
Process loss after semantic terminal commit but before `on_event` is therefore
|
|
89
|
+
allowed to lose the callback observation. It must **not** lose or replay the
|
|
90
|
+
semantic result.
|
|
91
|
+
|
|
92
|
+
## 5. Why Team aggregation is replay-safe instead of uncertainty-managed
|
|
93
|
+
|
|
94
|
+
The earlier design treated arbitrary `aggregate` as an X0 callback:
|
|
95
|
+
|
|
96
|
+
```text
|
|
97
|
+
mark aggregation started
|
|
98
|
+
invoke callback
|
|
99
|
+
if process dies -> outcome unknown -> manual resolution
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
That is appropriate for an arbitrary external effect, but `aggregate` is part of
|
|
103
|
+
Team result computation. Letting it perform one-shot external effects makes a
|
|
104
|
+
simple result-composition hook behave like an application transaction.
|
|
105
|
+
|
|
106
|
+
The revised contract is:
|
|
107
|
+
|
|
108
|
+
- `aggregate` receives canonical durable assignment results;
|
|
109
|
+
- it must have no externally observable one-shot side effects;
|
|
110
|
+
- repeated invocation with the same canonical inputs must be semantically
|
|
111
|
+
equivalent;
|
|
112
|
+
- if the process dies before the aggregate result is durably committed, Phronomy
|
|
113
|
+
may call `aggregate` again;
|
|
114
|
+
- external actions based on the Team result happen **after** Team completion in
|
|
115
|
+
Application code.
|
|
116
|
+
|
|
117
|
+
This removes `aggregation=started`, unknown-outcome recovery and manual
|
|
118
|
+
aggregation resolution.
|
|
119
|
+
|
|
120
|
+
## 6. Why standalone Orchestrator fan-out is Runtime-only
|
|
121
|
+
|
|
122
|
+
`Orchestrator` already has a canonical durable root when it is executing as an
|
|
123
|
+
Agent:
|
|
124
|
+
|
|
125
|
+
```text
|
|
126
|
+
Orchestrator AgentRoot
|
|
127
|
+
-> Orchestrator AgentExecution
|
|
128
|
+
-> durable child coordination snapshot
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
A direct Application call to:
|
|
132
|
+
|
|
133
|
+
```ruby
|
|
134
|
+
orchestrator.dispatch_parallel(...)
|
|
135
|
+
orchestrator.fan_out(...)
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
has no such parent execution.
|
|
139
|
+
|
|
140
|
+
The previous plan created a synthetic private AgentExecution only to make this
|
|
141
|
+
convenience method durable. That:
|
|
142
|
+
|
|
143
|
+
- changed Agent admission semantics;
|
|
144
|
+
- restricted arbitrary invocation-only Agent classes;
|
|
145
|
+
- required a new direct-fan-out recovery mode;
|
|
146
|
+
- made a helper method participate in durable execution identity merely to satisfy
|
|
147
|
+
a blanket "everything durable" statement.
|
|
148
|
+
|
|
149
|
+
The revised rule is:
|
|
150
|
+
|
|
151
|
+
```text
|
|
152
|
+
inside an existing Orchestrator AgentExecution
|
|
153
|
+
-> durable child coordination
|
|
154
|
+
|
|
155
|
+
direct standalone convenience call
|
|
156
|
+
-> Runtime-only; current-process completion only
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
If an Application requires durable fan-out, it should run it through an
|
|
160
|
+
Orchestrator AgentExecution or model the application process as a Workflow.
|
|
161
|
+
|
|
162
|
+
## 7. Handoff remains framework-durable
|
|
163
|
+
|
|
164
|
+
Handoff is not an Application notification problem.
|
|
165
|
+
|
|
166
|
+
If Phronomy exposes "active responsibility moved A -> B", then process loss must
|
|
167
|
+
not make the framework forget that B is active and rerun A merely to rediscover
|
|
168
|
+
the route.
|
|
169
|
+
|
|
170
|
+
Therefore Phronomy continues to own:
|
|
171
|
+
|
|
172
|
+
- `main_agent.agent_id` as the durable Handoff routing anchor;
|
|
173
|
+
- durable active Agent identity;
|
|
174
|
+
- immutable transferred HandoffContext reference;
|
|
175
|
+
- reserved exact Target `execution_id`;
|
|
176
|
+
- target absent/active/terminal reconciliation;
|
|
177
|
+
- multi-hop routing state.
|
|
178
|
+
|
|
179
|
+
Application code still owns the current Handoff graph and Policy objects and must
|
|
180
|
+
re-supply compatible wiring after restart.
|
|
181
|
+
|
|
182
|
+
## 8. TeamCoordinator remains durable, but only for Team semantics
|
|
183
|
+
|
|
184
|
+
The TeamCoordinator durable scope is retained because Phronomy itself owns the
|
|
185
|
+
queue/assignment/worker abstraction.
|
|
186
|
+
|
|
187
|
+
Phronomy therefore persists:
|
|
188
|
+
|
|
189
|
+
```text
|
|
190
|
+
TeamRoot
|
|
191
|
+
TeamExecution
|
|
192
|
+
canonical task records
|
|
193
|
+
worker slot identities
|
|
194
|
+
task -> worker assignment
|
|
195
|
+
reserved worker Agent/execution IDs
|
|
196
|
+
worker terminal result/error
|
|
197
|
+
final Team result/error
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
It does **not** persist:
|
|
201
|
+
|
|
202
|
+
```text
|
|
203
|
+
scheduler Proc
|
|
204
|
+
aggregator Proc
|
|
205
|
+
stream callbacks
|
|
206
|
+
terminal callbacks
|
|
207
|
+
Task handles
|
|
208
|
+
FSMSession
|
|
209
|
+
external side effects
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
This is a deliberate product boundary. If durable Team semantics still proves
|
|
213
|
+
disproportionately expensive after these reductions, implementation must stop and
|
|
214
|
+
report that fact rather than silently expanding framework responsibilities again.
|
|
215
|
+
|
|
216
|
+
## 9. Persistence consequence
|
|
217
|
+
|
|
218
|
+
The durable root still expands to:
|
|
219
|
+
|
|
220
|
+
```text
|
|
221
|
+
contents
|
|
222
|
+
agents
|
|
223
|
+
journals
|
|
224
|
+
executions
|
|
225
|
+
workflow_states
|
|
226
|
+
handoff_states
|
|
227
|
+
teams
|
|
228
|
+
team_executions
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
However the following previous additions are removed:
|
|
232
|
+
|
|
233
|
+
```text
|
|
234
|
+
executions.list_delivery_pending
|
|
235
|
+
execution delivery_pending backend index
|
|
236
|
+
team_executions.list_delivery_pending
|
|
237
|
+
Team terminal-delivery descriptor/index
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
No second CAS terminal-delivery ACK protocol is required.
|
|
241
|
+
|
|
242
|
+
## 10. Recovery consequence
|
|
243
|
+
|
|
244
|
+
Recovery is now about semantic execution/coordination only:
|
|
245
|
+
|
|
246
|
+
```text
|
|
247
|
+
Agent
|
|
248
|
+
active/nonterminal execution recovery
|
|
249
|
+
|
|
250
|
+
Handoff
|
|
251
|
+
active responsibility / exact Target continuation
|
|
252
|
+
|
|
253
|
+
Orchestrator
|
|
254
|
+
existing parent AgentExecution + exact child reconciliation
|
|
255
|
+
|
|
256
|
+
Team
|
|
257
|
+
active TeamExecution + task/assignment/worker reconciliation
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
It is **not** responsible for reconstructing missed Application callback delivery.
|
|
261
|
+
|
|
262
|
+
## 11. Explicit non-goals
|
|
263
|
+
|
|
264
|
+
This redesign does not provide:
|
|
265
|
+
|
|
266
|
+
- exactly-once Provider, Tool, callback, webhook, email or database effects;
|
|
267
|
+
- restart-spanning delivery of arbitrary callbacks;
|
|
268
|
+
- recovered process-local Tasks;
|
|
269
|
+
- a distributed transaction across external systems;
|
|
270
|
+
- persistence of Ruby Classes, Procs, callbacks, FSMSessions or EventLoop queues;
|
|
271
|
+
- durable semantics for every convenience method simply because it exists.
|
|
272
|
+
|
|
273
|
+
## 12. Acceptance criterion for future implementation work
|
|
274
|
+
|
|
275
|
+
Before adding any new durable field/protocol, ask:
|
|
276
|
+
|
|
277
|
+
> If this state is lost, does Phronomy risk rerunning or misrouting semantic work
|
|
278
|
+
> that Phronomy itself owns?
|
|
279
|
+
|
|
280
|
+
If **no**, the state should normally remain Runtime/Application responsibility.
|
|
281
|
+
|
|
282
|
+
If **yes**, add the smallest purpose-specific durable fact needed to reconcile it.
|
|
283
|
+
|
|
284
|
+
## 13. Accepted clarification after V2 review
|
|
285
|
+
|
|
286
|
+
The five accepted [recovery contracts](RECOVERY_CONTRACT_CLARIFICATIONS.md)
|
|
287
|
+
make the existing responsibility boundary testable:
|
|
288
|
+
|
|
289
|
+
1. Read-only outcome access and retained execution discovery replace reliance on
|
|
290
|
+
callback observation, without promising notification delivery or request dedup.
|
|
291
|
+
2. Failed reads and unknown commit outcomes never authorize replacement work;
|
|
292
|
+
use existing authoritative reads, atomic admission and CAS reconciliation.
|
|
293
|
+
3. Declared definition/slot/graph compatibility is checked before continuation;
|
|
294
|
+
committed facts outrank changed current wiring. Code compatibility is an
|
|
295
|
+
Application obligation, not Proc serialization or code hashing.
|
|
296
|
+
4. Observation loss/shutdown and semantic cancellation are distinct. Cancellation
|
|
297
|
+
respects exact owned child executions and existing Agent terminal barriers.
|
|
298
|
+
5. Durability means confirmed outcome reuse and exact execution recovery;
|
|
299
|
+
unknown external effects remain under existing Agent Recovery, not exactly once.
|
|
300
|
+
|
|
301
|
+
These are implementation contracts within the accepted scope. No callback outbox,
|
|
302
|
+
standalone synthetic parent, generic registry or second Team engine is authorized.
|
data/docs/features.md
CHANGED
|
@@ -78,7 +78,7 @@ rather than implicitly inheriting the parent revision. The Stable
|
|
|
78
78
|
| Feature | Stability |
|
|
79
79
|
|---|---|
|
|
80
80
|
| **Workflow asynchronous pattern** — Start async work, return immediately, and continue through `Workflow#signal` | Beta |
|
|
81
|
-
| **
|
|
81
|
+
| **Durable Agent Handoff** — `Agent::Handoff` and `Agent::HandoffRunner` persist responsibility, immutable Context and exact Target reservation in one Persistence domain; current graph wiring is required for continuation | Beta |
|
|
82
82
|
| **GeneratorVerifier** — Generator-Verifier loop with injectable prompts/parsers | Beta |
|
|
83
83
|
| **`Phronomy::MultiAgent::Orchestrator`** — Parallel subagent dispatch, fan-out, and `subagent` DSL | Beta |
|
|
84
84
|
| **`Phronomy::MultiAgent::TeamCoordinator`** — LLM coordinator with stateful worker Agents | Beta |
|
|
@@ -140,3 +140,37 @@ current compatibility contract.
|
|
|
140
140
|
|
|
141
141
|
For runtime ownership and the distinction between public lifecycle APIs and
|
|
142
142
|
private execution machinery, see [Runtime and concurrency](runtime-and-concurrency.md).
|
|
143
|
+
|
|
144
|
+
### Durable semantic coordination (V2 revision 2)
|
|
145
|
+
|
|
146
|
+
Static `Orchestrator.subagent` Tools invoked inside a parent AgentExecution reserve
|
|
147
|
+
child Agent/execution identities before dispatch and reuse retained outcomes.
|
|
148
|
+
Direct `dispatch_parallel` / `fan_out` calls remain Runtime-only convenience APIs.
|
|
149
|
+
`Orchestrator#resume(execution_id)` continues retained parent coordination.
|
|
150
|
+
|
|
151
|
+
`TeamCoordinator` requires `team_definition id:, version:` and provides
|
|
152
|
+
`create`, `load`, `get`, `resume`, `executions`, `result` and scoped `cancel`.
|
|
153
|
+
Team tasks, worker assignments, exact child identities and aggregate outcomes
|
|
154
|
+
are durable facts. Workers still execute sequentially through the existing Agent
|
|
155
|
+
engine. `schedule` and `aggregate` must be pure and replay-safe; aggregate returns
|
|
156
|
+
canonical JSON data. Default assignment results have string keys and error data
|
|
157
|
+
contains class/message strings. Arbitrary Ruby objects are not durable results.
|
|
158
|
+
|
|
159
|
+
`Persistence#execution_result` / `team_execution_result` read exact results;
|
|
160
|
+
`list_executions` / `list_team_executions` discover retained active and terminal
|
|
161
|
+
runs by known owner ID. Reads do not load Runtime owners or deliver callbacks.
|
|
162
|
+
The cursor is an exclusive lexical execution ID and limit must be positive.
|
|
163
|
+
Retention and request correlation remain Application/backend policy.
|
|
164
|
+
|
|
165
|
+
Guarantee: confirmed outcomes are reused, unfinished work keeps its semantic ID,
|
|
166
|
+
and external outcome uncertainty uses Agent Recovery. For F1/F4 this is
|
|
167
|
+
conditional on a conforming retained Persistence domain and compatible current
|
|
168
|
+
wiring. InMemory provides transaction/CAS semantics but is not durable disk storage.
|
|
169
|
+
Callbacks/streams/Tasks are Runtime observations; there is no restart-spanning
|
|
170
|
+
notification outbox, ACK, synthetic fan-out execution or external exactly-once
|
|
171
|
+
claim. See [the migration](migrations/durable-semantic-coordination-v2.md).
|
|
172
|
+
|
|
173
|
+
`Persistence#handoff_result(source_execution_id)` also resolves the exact Handoff
|
|
174
|
+
turn read-only, including a current absent-but-reserved Target, without graph or
|
|
175
|
+
Agent hydration. Purging an idle main Agent removes its Handoff anchor; pending
|
|
176
|
+
coordination rejects purge rather than discarding its reservation.
|