phronomy 0.22.0 → 0.24.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (178) hide show
  1. checksums.yaml +4 -4
  2. data/.mutant.yml +3 -4
  3. data/CHANGELOG.md +215 -10
  4. data/CONTRIBUTING.md +81 -9
  5. data/README.md +15 -6
  6. data/VERIFY.sh +587 -0
  7. data/benchmark/bench_agent_invoke.rb +2 -2
  8. data/benchmark/bench_context_assembler.rb +39 -68
  9. data/benchmark/bench_regression.rb +2 -2
  10. data/docs/architecture/agent-context.md +174 -0
  11. data/docs/architecture/before-llm-input.md +78 -0
  12. data/docs/architecture/context-management.md +232 -0
  13. data/docs/architecture/knowledge-and-rag.md +130 -0
  14. data/docs/architecture/multi-agent-handoff.md +147 -0
  15. data/docs/architecture/persistence.md +186 -0
  16. data/docs/architecture/removed/agent-context.md +72 -0
  17. data/docs/architecture/security-boundaries.md +173 -0
  18. data/docs/architecture/tracing.md +194 -0
  19. data/docs/architecture.md +89 -0
  20. data/docs/archive/design/archived/04_api_design.md +507 -0
  21. data/docs/archive/design/archived/09_guardrails.md +186 -0
  22. data/docs/archive/design/archived/17_rails_integration.md +175 -0
  23. data/docs/archive/design/historical/00_design_philosophy.md +122 -0
  24. data/docs/archive/design/historical/01_rubyllm_evaluation.md +178 -0
  25. data/docs/archive/design/historical/06_design_decisions.md +143 -0
  26. data/docs/changelog/0.14-and-earlier.md +1 -1
  27. data/docs/decisions/001-rubyllm-as-provider-layer.md +6 -1
  28. data/docs/decisions/002-workflow-context-immutability.md +26 -1
  29. data/docs/decisions/006-no-built-in-guardrails.md +2 -1
  30. data/docs/decisions/012-canonical-execution-log-and-context-policy.md +120 -38
  31. data/docs/decisions/014-unified-persistence-durable-state.md +9 -2
  32. data/docs/decisions/016-semantic-multi-agent-handoff.md +114 -0
  33. data/docs/decisions/017-design-authority-and-adr-governance.md +200 -0
  34. data/docs/decisions/018-durability-guarantees-and-failure-model.md +488 -0
  35. data/docs/decisions/019-filter-contract-and-security-boundaries.md +229 -0
  36. data/docs/decisions/020-canonical-workflow-instance-identity.md +177 -0
  37. data/docs/decisions/021-generic-agent-invocation-identity-removal.md +119 -0
  38. data/docs/decisions/022-agent-execution-parent-identity-and-runtime-routing-boundary.md +193 -0
  39. data/docs/decisions/023-fsm-session-incarnation-identity-and-routing.md +139 -0
  40. data/docs/decisions/024-event-loop-single-writer-agent-runtime.md +188 -0
  41. data/docs/decisions/025-process-local-agent-ownership-and-runtime-admission.md +249 -0
  42. data/docs/decisions/026-workflow-runtime-admission-and-durable-terminal-barrier.md +257 -0
  43. data/docs/decisions/027-llm-adapter-provider-boundary.md +93 -0
  44. data/docs/decisions/028-preparing-recovery-replay-contract.md +106 -0
  45. data/docs/decisions/029-semantic-completion-and-application-effect-boundary.md +220 -0
  46. data/docs/decisions/030-agent-handoff-domain-and-durable-responsibility.md +235 -0
  47. data/docs/decisions/031-durable-multi-agent-coordination.md +301 -0
  48. data/docs/decisions/README.md +176 -0
  49. data/docs/design/durable-semantic-coordination/CHANGELOG_V2_REVISION_2.md +33 -0
  50. data/docs/design/durable-semantic-coordination/CONTINUATION_DECISION_REFACTOR.md +191 -0
  51. data/docs/design/durable-semantic-coordination/IMPLEMENTATION_DESIGN_V2.md +862 -0
  52. data/docs/design/durable-semantic-coordination/IMPLEMENTATION_REPORT.md +106 -0
  53. data/docs/design/durable-semantic-coordination/RECOVERY_CONTRACT_CLARIFICATIONS.md +179 -0
  54. data/docs/design/durable-semantic-coordination/RESPONSIBILITY_BOUNDARY_REVIEW.md +302 -0
  55. data/docs/features.md +65 -11
  56. data/docs/getting-started.md +77 -45
  57. data/docs/migrations/0.19.md +14 -7
  58. data/docs/migrations/0.22.md +390 -0
  59. data/docs/migrations/durable-semantic-coordination-v2.md +65 -0
  60. data/docs/persistence-backends.md +129 -40
  61. data/docs/runtime-and-concurrency.md +227 -33
  62. data/examples/README.md +13 -0
  63. data/lib/phronomy/agent/agent_execution.rb +21 -17
  64. data/lib/phronomy/agent/agent_invocation.rb +288 -93
  65. data/lib/phronomy/agent/agent_invocation_session_builder.rb +236 -202
  66. data/lib/phronomy/agent/agent_root.rb +3 -3
  67. data/lib/phronomy/agent/approval_evaluation_request.rb +37 -19
  68. data/lib/phronomy/agent/async_event_api.rb +162 -72
  69. data/lib/phronomy/agent/base.rb +416 -181
  70. data/lib/phronomy/agent/concerns/before_llm_input.rb +1 -1
  71. data/lib/phronomy/agent/context_assembler.rb +437 -178
  72. data/lib/phronomy/agent/context_candidate_resolver.rb +2 -2
  73. data/lib/phronomy/agent/context_plan.rb +18 -13
  74. data/lib/phronomy/agent/context_plan_validator.rb +246 -88
  75. data/lib/phronomy/agent/context_policies/default.rb +123 -34
  76. data/lib/phronomy/agent/context_policy.rb +109 -3
  77. data/lib/phronomy/agent/context_policy_input.rb +244 -0
  78. data/lib/phronomy/agent/context_policy_input_builder.rb +241 -0
  79. data/lib/phronomy/agent/exact_execution.rb +153 -0
  80. data/lib/phronomy/agent/execution_cancellation.rb +25 -0
  81. data/lib/phronomy/agent/execution_coordinator.rb +2417 -572
  82. data/lib/phronomy/agent/handoff.rb +43 -0
  83. data/lib/phronomy/agent/handoff_capability_factory.rb +45 -0
  84. data/lib/phronomy/agent/handoff_context.rb +120 -0
  85. data/lib/phronomy/agent/handoff_execution_coordinator.rb +143 -0
  86. data/lib/phronomy/agent/handoff_policy.rb +143 -0
  87. data/lib/phronomy/agent/handoff_projection.rb +207 -0
  88. data/lib/phronomy/agent/handoff_request.rb +45 -0
  89. data/lib/phronomy/agent/handoff_runner.rb +178 -0
  90. data/lib/phronomy/agent/handoff_state.rb +43 -0
  91. data/lib/phronomy/agent/journal_record.rb +17 -4
  92. data/lib/phronomy/agent/llm_input_build_context.rb +1 -1
  93. data/lib/phronomy/agent/llm_input_manifest.rb +277 -2
  94. data/lib/phronomy/agent/llm_operation_result.rb +12 -7
  95. data/lib/phronomy/agent/phase_machine_builder.rb +19 -7
  96. data/lib/phronomy/agent/provider_call_outcome.rb +23 -7
  97. data/lib/phronomy/agent/recovery_coordinator/continuation.rb +174 -0
  98. data/lib/phronomy/agent/recovery_coordinator/installation.rb +381 -0
  99. data/lib/phronomy/agent/recovery_coordinator/resolution.rb +511 -0
  100. data/lib/phronomy/agent/recovery_coordinator.rb +217 -0
  101. data/lib/phronomy/agent/recovery_support.rb +504 -0
  102. data/lib/phronomy/agent/ruby_llm_materializer.rb +16 -13
  103. data/lib/phronomy/agent/selection/candidate.rb +53 -0
  104. data/lib/phronomy/agent/selection/constraint.rb +49 -0
  105. data/lib/phronomy/agent/shared_state.rb +38 -1
  106. data/lib/phronomy/agent/tool_approval_request.rb +33 -5
  107. data/lib/phronomy/agent/tool_definition_set.rb +49 -3
  108. data/lib/phronomy/agent/tool_invocation.rb +339 -103
  109. data/lib/phronomy/agent/tool_invocation_session_builder.rb +49 -45
  110. data/lib/phronomy/agent.rb +20 -2
  111. data/lib/phronomy/agent_already_exists_error.rb +5 -0
  112. data/lib/phronomy/agent_purged_error.rb +5 -0
  113. data/lib/phronomy/engine/concurrency/offload_pool.rb +17 -3
  114. data/lib/phronomy/engine/concurrency/physical_completion_task.rb +135 -0
  115. data/lib/phronomy/engine/event_loop.rb +622 -63
  116. data/lib/phronomy/engine/fsm_session.rb +194 -21
  117. data/lib/phronomy/engine/runtime/agent_ownership_registry.rb +352 -0
  118. data/lib/phronomy/engine/runtime/team_ownership_registry.rb +77 -0
  119. data/lib/phronomy/engine/runtime.rb +92 -20
  120. data/lib/phronomy/generator_verifier.rb +12 -14
  121. data/lib/phronomy/invocation_context.rb +9 -29
  122. data/lib/phronomy/multi_agent/admission_registry.rb +51 -0
  123. data/lib/phronomy/multi_agent/durable_subagent_coordinator.rb +134 -0
  124. data/lib/phronomy/multi_agent/fan_out_invocation.rb +24 -33
  125. data/lib/phronomy/multi_agent/fan_out_session_builder.rb +12 -19
  126. data/lib/phronomy/multi_agent/orchestrator.rb +71 -26
  127. data/lib/phronomy/multi_agent/team_coordinator.rb +473 -125
  128. data/lib/phronomy/multi_agent/team_execution.rb +44 -0
  129. data/lib/phronomy/multi_agent/team_root.rb +41 -0
  130. data/lib/phronomy/persistence/durable_codec.rb +706 -0
  131. data/lib/phronomy/persistence/durable_record.rb +117 -0
  132. data/lib/phronomy/persistence/in_memory.rb +471 -133
  133. data/lib/phronomy/persistence/migration/initial_format_migration.rb +226 -0
  134. data/lib/phronomy/persistence/repository_facades.rb +535 -0
  135. data/lib/phronomy/persistence.rb +174 -40
  136. data/lib/phronomy/recovery.rb +186 -0
  137. data/lib/phronomy/testing/persistence_contract/a_journal_repository.rb +2 -2
  138. data/lib/phronomy/testing/persistence_contract/a_persistence_backend.rb +2 -1
  139. data/lib/phronomy/testing/persistence_contract/a_workflow_state_repository.rb +19 -19
  140. data/lib/phronomy/testing/persistence_contract/an_agent_repository.rb +3 -3
  141. data/lib/phronomy/testing/persistence_contract/an_execution_repository.rb +5 -5
  142. data/lib/phronomy/testing/persistence_contract/coordination_repositories.rb +137 -0
  143. data/lib/phronomy/testing/persistence_contract.rb +5 -0
  144. data/lib/phronomy/tools/agent.rb +1 -1
  145. data/lib/phronomy/tracing/automatic.rb +176 -0
  146. data/lib/phronomy/tracing/base.rb +11 -2
  147. data/lib/phronomy/tracing/langfuse_tracer.rb +20 -12
  148. data/lib/phronomy/version.rb +1 -1
  149. data/lib/phronomy/workflow.rb +3 -6
  150. data/lib/phronomy/workflow_context.rb +14 -5
  151. data/lib/phronomy/workflow_recovery.rb +123 -0
  152. data/lib/phronomy/workflow_runner.rb +468 -256
  153. data/lib/phronomy.rb +6 -0
  154. data/scripts/api_snapshot.rb +12 -0
  155. data/sig/phronomy/agent.rbs +209 -7
  156. data/sig/phronomy/handoff.rbs +41 -0
  157. data/sig/phronomy/multi_agent.rbs +35 -0
  158. data/sig/phronomy/persistence.rbs +123 -4
  159. data/sig/phronomy/runtime.rbs +1 -4
  160. data/sig/phronomy/workflow.rbs +2 -2
  161. data/sig/phronomy.rbs +10 -0
  162. metadata +84 -18
  163. data/examples/workflows/agent_event_mapping.rb +0 -101
  164. data/examples/workflows/generic_task_event_mapping.rb +0 -66
  165. data/lib/phronomy/agent/activation_registry.rb +0 -28
  166. data/lib/phronomy/agent/agent_execution_activation.rb +0 -172
  167. data/lib/phronomy/agent/context_candidate.rb +0 -47
  168. data/lib/phronomy/agent/context_parts/budget/token_budget_packer.rb +0 -53
  169. data/lib/phronomy/agent/context_parts/requirements/required_context_resolver.rb +0 -56
  170. data/lib/phronomy/agent/context_parts/selectors/recent_first_selector.rb +0 -30
  171. data/lib/phronomy/agent/context_parts/unit_builders/dependency_aware_unit_builder.rb +0 -118
  172. data/lib/phronomy/agent/context_policy_descriptor.rb +0 -49
  173. data/lib/phronomy/agent/context_policy_registry.rb +0 -46
  174. data/lib/phronomy/agent/context_request.rb +0 -35
  175. data/lib/phronomy/agent/context_selection_unit.rb +0 -38
  176. data/lib/phronomy/agent/derived_content_spec.rb +0 -34
  177. data/lib/phronomy/agent/runner.rb +0 -97
  178. data/lib/phronomy/multi_agent/handoff.rb +0 -64
@@ -0,0 +1,130 @@
1
+ > **CURRENT explanatory architecture**
2
+ >
3
+ > This document describes the reconciled current Phronomy system. Normative
4
+ > architecture decisions remain in the [ADR index](../decisions/README.md);
5
+ > source/runtime behavior remains implementation reality and does not silently
6
+ > amend an ADR.
7
+
8
+ # Knowledge and RAG
9
+
10
+ ## 1. Boundary
11
+
12
+ Phronomy separates information acquisition from Agent Context management.
13
+
14
+ ```text
15
+ Application / Tool / retrieval pipeline
16
+ |
17
+ v
18
+ plain logical Knowledge content
19
+ |
20
+ +-- persist: Agent Journal (`kind: :knowledge`)
21
+ |
22
+ +-- request-scoped: before_llm_input candidate
23
+ |
24
+ v
25
+ ContextPolicyInput.knowledge
26
+ |
27
+ v
28
+ ContextPolicy
29
+ |
30
+ v
31
+ Manifest
32
+ ```
33
+
34
+ Phronomy does not define a core hierarchy of `StaticKnowledge`,
35
+ `EntityKnowledge`, `RAGKnowledge`, or `KnowledgeSource` objects. How information
36
+ was obtained is not a Context-selection type.
37
+
38
+ Persistent Knowledge authority is defined by
39
+ [ADR-013](../decisions/013-journal-backed-knowledge-as-context-candidates.md).
40
+
41
+ ## 2. Persistent Knowledge
42
+
43
+ Persistent Knowledge is registered on a live Agent:
44
+
45
+ ```ruby
46
+ agent = ResearchAgent.new(
47
+ knowledge: [
48
+ "Account type: enterprise",
49
+ "Data residency: Japan"
50
+ ]
51
+ )
52
+
53
+ agent.add_knowledge(
54
+ "Customer locale: ja-JP",
55
+ metadata: {"origin" => "customer_profile"}
56
+ )
57
+ ```
58
+
59
+ Content is stored through the durable content/Journal path and remains available
60
+ after Agent reload.
61
+
62
+ `clear_knowledge!` logically invalidates prior Knowledge for future Context
63
+ selection without deleting historical Journal records. `clear_transcript!` does
64
+ not clear Knowledge. `reset_context!` resets both relevant eligibility domains
65
+ without rewriting old Journal facts.
66
+
67
+ ## 3. Request-scoped Knowledge
68
+
69
+ Information needed for only one LLM Call should not be persisted merely to make
70
+ it available to Context Policy.
71
+
72
+ `before_llm_input` may return an `LLMInputPatch` with a Knowledge
73
+ `segment_candidate`. The candidate enters the same typed Policy path and is not
74
+ automatically journaled.
75
+
76
+ See [before_llm_input](before-llm-input.md).
77
+
78
+ ## 4. Retrieval paths
79
+
80
+ RAG can enter Agent reasoning through more than one ordinary application path.
81
+
82
+ ### Tool-result retrieval
83
+
84
+ A Tool may query a VectorStore/external search system and return results to the
85
+ Agent. The Tool result participates in the normal Tool protocol and can influence
86
+ later Context through normal Journal/Context rules.
87
+
88
+ ### Pre-Manifest retrieval
89
+
90
+ Application code may retrieve/rank content before Context finalization and supply
91
+ selected logical Knowledge through `before_llm_input` or an Application
92
+ `ContextPolicy`.
93
+
94
+ The core does not require one vector-retrieval lifecycle to be the universal RAG
95
+ path.
96
+
97
+ ## 5. Vector/embedding responsibility
98
+
99
+ Vector stores, loaders, splitters, embeddings, ranking, and external retrieval
100
+ are acquisition/integration capabilities. They are not themselves durable Agent
101
+ Knowledge state.
102
+
103
+ An application may:
104
+
105
+ 1. retrieve content;
106
+ 2. rank/filter it;
107
+ 3. convert it to plain logical Knowledge;
108
+ 4. persist it with `add_knowledge`, or keep it request-scoped.
109
+
110
+ ## 6. Selection and budget
111
+
112
+ Knowledge is optional by default. Context Policy decides whether it enters one
113
+ LLM Call and may omit it under budget pressure.
114
+
115
+ Information that is structurally required for the call must be represented
116
+ through the corresponding required Context mechanism; registration as Knowledge
117
+ does not make content mandatory merely by existence.
118
+
119
+ ## 7. Trust/security boundary
120
+
121
+ Phronomy does not apply a universal semantic security Filter when Knowledge is
122
+ added or retrieved. Source validation, retrieval policy, ingestion sanitization,
123
+ and domain-specific trust decisions are Application/Tool responsibilities.
124
+
125
+ At one-call Context selection time, Application `ContextPolicy` may inspect
126
+ Knowledge provenance/metadata and decide whether to select, derive/sanitize, or
127
+ fail the preparation. Framework validation still enforces structural authority
128
+ and final Manifest invariants.
129
+
130
+ See [Security Boundaries](security-boundaries.md).
@@ -0,0 +1,147 @@
1
+ > **CURRENT explanatory architecture**
2
+ >
3
+ > This document describes the reconciled current Phronomy system. Normative
4
+ > architecture decisions remain in the [ADR index](../decisions/README.md);
5
+ > source/runtime behavior remains implementation reality and does not silently
6
+ > amend an ADR.
7
+
8
+ # Semantic Multi-Agent Handoff
9
+
10
+ ## 1. Meaning
11
+
12
+ Handoff transfers active responsibility from one live Source Agent to one live
13
+ Target Agent together with sufficient policy-bounded Context for the Target to
14
+ continue.
15
+
16
+ It is a control-plane operation, not an ordinary Tool-result protocol.
17
+
18
+ Handoff is distinct from Agent-as-Tool delegation. Delegation performs work and
19
+ returns control to the caller. Handoff changes the active Agent for the current
20
+ coordination lifetime.
21
+
22
+ Normative Handoff intent is
23
+ [ADR-030](../decisions/030-agent-handoff-domain-and-durable-responsibility.md).
24
+
25
+ ## 2. Public API
26
+
27
+ ```ruby
28
+ handoff = Phronomy::Agent::Handoff.new(
29
+ source_agent: triage,
30
+ target_agent: billing,
31
+ description: "Transfer billing responsibility",
32
+ policy: policy
33
+ )
34
+
35
+ runner = Phronomy::Agent::HandoffRunner.new(
36
+ main_agent: triage,
37
+ handoffs: [handoff]
38
+ )
39
+
40
+ result = runner.invoke("My invoice is wrong")
41
+ ```
42
+
43
+ The current public Runner facade is synchronous `#invoke`. Handoff architecture
44
+ does not add async/stream APIs merely for symmetry.
45
+
46
+ ## 3. Private transport
47
+
48
+ Outgoing Handoffs are represented to the Source LLM through generated Tool
49
+ schemas. The generated Tool name is private transport encoding, not Handoff
50
+ identity or public semantic contract.
51
+
52
+ Phronomy intercepts the Provider Tool Call into a typed private
53
+ `HandoffRequest`. It does not execute an ordinary `ToolInvocation` or emit a
54
+ sentinel Tool result.
55
+
56
+ ## 4. Handoff Policy
57
+
58
+ `HandoffPolicy` controls what material from the effective finalized Source
59
+ Manifest may cross the Agent boundary.
60
+
61
+ ```text
62
+ current_request
63
+ history
64
+ knowledge
65
+ tool_exchanges
66
+ ```
67
+
68
+ Each category is required, forbidden, or selectable. Handoff selection is bounded
69
+ to the finalized Source Manifest.
70
+
71
+ ## 5. Context Policy relationship
72
+
73
+ ```text
74
+ Source ContextPolicy
75
+ -> Source LLMInputManifest
76
+
77
+ HandoffPolicy
78
+ -> what may cross Source -> Target
79
+
80
+ immutable HandoffContext
81
+ -> request-scoped Target material
82
+
83
+ Target ContextPolicy
84
+ -> what enters one Target LLM Call
85
+ ```
86
+
87
+ Transfer does not automatically append content to Target Journal or persistent
88
+ Knowledge.
89
+
90
+ ## 6. Conversation/Tool dependencies
91
+
92
+ An assistant Tool Call and its corresponding Tool-role result message(s) remain
93
+ an indivisible conversation group across the Handoff boundary.
94
+
95
+ Framework-owned semantic/category/content-format metadata is carried only through
96
+ the trusted typed Handoff boundary.
97
+
98
+ ## 7. Responsibility and provenance
99
+
100
+ Transferred `responsibility` is the dynamic instruction for what the Target must
101
+ continue. `description` is the static edge/capability description. No mandatory
102
+ generic `handoff_reason` identity field is added.
103
+
104
+ Handoff Context preserves origin Agent and, where available, Journal record,
105
+ Agent execution, LLM call, and Tool call provenance. Multi-hop transfers extend
106
+ the transfer path while retaining original provenance.
107
+
108
+ ## 8. Target state ownership
109
+
110
+ Handoff does not give Source authority to mutate Target canonical state. Target
111
+ state changes only through normal Target-owned execution/mutation paths.
112
+
113
+ A Target Agent execution has its own `execution_id`; Source execution identity is
114
+ provenance/audit context, not Target execution identity.
115
+
116
+ ## 9. Persisted responsibility and recovery
117
+
118
+ The original main Agent ID anchors `HandoffState`; the active Agent is retained
119
+ across compatible Runtime restarts. The graph must use one Persistence instance.
120
+ Source `handed_off`, its journal/root transition, immutable HandoffContext and the
121
+ reserved Target execution ID commit atomically. The Target is admitted under
122
+ that ID only after an authoritative absence read and the usual Agent admission.
123
+ An active exact Target uses Agent Recovery; a terminal Target result is reused.
124
+ Target terminal settlement and routing stabilization share a transaction.
125
+
126
+ A new Runtime supplies the graph/current definitions again. Tool transport names
127
+ are deterministic from stable Source/Target Agent IDs and are resolved from that
128
+ graph, without a global class registry. Persisted Context is not reprojected under
129
+ current policy. Missing graph edges/definitions or a different Persistence domain
130
+ fail before semantic continuation.
131
+
132
+ `HandoffRunner#result(source_execution_id)` follows retained transfer links.
133
+ `cancel(execution_id)` records a request against that exact turn; pending absent
134
+ Targets are stopped without admission, active Targets use their existing Agent
135
+ cancellation token, terminal outcomes remain immutable. No cancellation or
136
+ observer loss rewinds active responsibility to the main Agent. Cancellation is
137
+ not compensation for external effects; unresolved X0 still needs Agent Recovery.
138
+
139
+ F1 commit response loss is resolved by exact readback. Read/decode failure is not
140
+ absence. F4 recovery requires retained storage and compatible current wiring.
141
+ `on_event` is Runtime-only; terminal results can be read without redelivery.
142
+
143
+ Current graph objects and observers are not durably rehydrated; Application
144
+ supplies compatible wiring. Source execution identity links each completed
145
+ transfer to its exact reserved Target execution, independently of later turns.
146
+ `Persistence#handoff_result(source_execution_id)` reads that turn without loading
147
+ Agent owners, graph definitions, or listeners.
@@ -0,0 +1,186 @@
1
+ > **CURRENT explanatory architecture**
2
+ >
3
+ > This document describes the reconciled current Phronomy system. Normative
4
+ > architecture decisions remain in the [ADR index](../decisions/README.md);
5
+ > source/runtime behavior remains implementation reality and does not silently
6
+ > amend an ADR.
7
+
8
+ # Persistence, Durability, and Recovery
9
+
10
+ ## 1. Durable boundary
11
+
12
+ `Phronomy::Persistence` is the single durable-state backend abstraction for
13
+ stateful Agents and durable Workflows.
14
+
15
+ | Repository | Durable authority |
16
+ |---|---|
17
+ | `contents` | Immutable content and manifests |
18
+ | `agents` | AgentRoot |
19
+ | `journals` | Append-only Agent journal |
20
+ | `executions` | AgentExecution and owned child coordination |
21
+ | `workflow_states` | Workflow snapshots |
22
+ | `handoff_states` | Active responsibility and exact Target reservation |
23
+ | `teams` | TeamRoot |
24
+ | `team_executions` | Team tasks, assignments and outcomes |
25
+
26
+ Persistence stores defined durable logical state. It is not serialization of the
27
+ currently running Runtime object graph.
28
+
29
+ Detailed custom-backend method/codec contracts belong in
30
+ [Persistence backends](../persistence-backends.md).
31
+
32
+ Normative durability vocabulary is
33
+ [ADR-018](../decisions/018-durability-guarantees-and-failure-model.md).
34
+
35
+ ## 2. Durable versus Runtime-only state
36
+
37
+ Durable examples include AgentRoot, Journal records, AgentExecution records,
38
+ content/Manifest references, and durable Workflow snapshots.
39
+
40
+ Runtime-only examples include FSMSession objects/IDs, AgentInvocation objects,
41
+ Task instances/callbacks, EventLoop entries, Runtime admission entries, and
42
+ in-flight Provider/Tool operation objects.
43
+
44
+ Runtime/process loss removes Runtime-only objects but does not imply confirmed
45
+ durable state was lost.
46
+
47
+ ## 3. Agent live ownership
48
+
49
+ After create/load, one live Agent instance owns current mutable logical Agent
50
+ state for that `agent_id` within one Runtime/process.
51
+
52
+ During execution, EventLoop is the single writer of Phronomy-managed live Agent
53
+ execution state.
54
+
55
+ ```text
56
+ EventLoop authoritative snapshot
57
+ -> OffloadPool command
58
+ -> Persistence transaction
59
+ -> immutable operation-specific result
60
+ -> EventLoop authority validation
61
+ -> live apply
62
+ ```
63
+
64
+ See
65
+ [ADR-024](../decisions/024-event-loop-single-writer-agent-runtime.md).
66
+
67
+ ## 4. Durable transitions and conflicts
68
+
69
+ Defined semantic durable transitions are atomic according to the Persistence
70
+ transaction contract and conforming backend.
71
+
72
+ Revision/watermark/CAS checks reject stale durable transitions with
73
+ `Persistence::ConflictError` rather than silently merging/reloading competing
74
+ state.
75
+
76
+ Conflict detection is not competing-execution exclusion and cannot undo an
77
+ external side effect already performed.
78
+
79
+ ## 5. Agent and Workflow admission
80
+
81
+ Within one Runtime/process, Agent admission prevents prohibited competing
82
+ top-level execution for one logical Agent owner.
83
+
84
+ The canonical logical/durable Workflow identity is `workflow_instance_id`, which
85
+ is separate from one Runtime `fsm_session_id`.
86
+
87
+ Workflow same-process admission is acquired before durable hydration and retained
88
+ through the authoritative terminal/halted save barrier. The caller-facing Task
89
+ settles after that authoritative durable barrier.
90
+
91
+ See
92
+ [ADR-025](../decisions/025-process-local-agent-ownership-and-runtime-admission.md),
93
+ [ADR-020](../decisions/020-canonical-workflow-instance-identity.md), and
94
+ [ADR-026](../decisions/026-workflow-runtime-admission-and-durable-terminal-barrier.md).
95
+
96
+ ## 6. Cross-process guarantee
97
+
98
+ Cross-process competing-execution exclusion is conditional.
99
+
100
+ A multi-process deployment must provide stable routing/partitioning by logical
101
+ identity or another coordination mechanism that establishes exclusive authority.
102
+ Persistence CAS/revision checks alone detect stale commits; they do not prevent
103
+ duplicate semantic execution from starting.
104
+
105
+ Phronomy does not claim arbitrary external exactly-once side effects.
106
+
107
+ ## 7. Durable codec
108
+
109
+ Durable backend exchange uses immutable
110
+ `Phronomy::Persistence::DurableRecord` values with:
111
+
112
+ ```text
113
+ record_type
114
+ format_version
115
+ payload
116
+ ```
117
+
118
+ `format_version` is a durable representation version, not Agent definition
119
+ version, Workflow identity, or Runtime incarnation identity.
120
+
121
+ Payloads follow the canonical durable value/codec contract. A backend may use its
122
+ own physical storage representation but must return an equivalent logical
123
+ DurableRecord.
124
+
125
+ ## 8. Recovery model
126
+
127
+ Recovery reconstructs logical state from confirmed durable evidence; it does not
128
+ restore the old Runtime object graph.
129
+
130
+ The shared Recovery vocabulary classifies unfinished work as:
131
+
132
+ ```text
133
+ resumable
134
+ reconcilable
135
+ resolution_required
136
+ ```
137
+
138
+ Where outcome is uncertain, Phronomy does not infer "not performed" merely from
139
+ connection/process failure and does not blindly re-dispatch an external
140
+ operation.
141
+
142
+ Application resolution, when required, records one of:
143
+
144
+ ```text
145
+ succeeded
146
+ failed
147
+ not_performed
148
+ ```
149
+
150
+ before dependent continuation may proceed.
151
+
152
+ Agent Recovery is integrated into supported `Agent.load` lifecycle semantics.
153
+
154
+ ## 9. Manifest authority during Recovery
155
+
156
+ A finalized historical `LLMInputManifest` is reused for the Provider input it
157
+ represents. Recovery does not rerun historical ContextPolicy code to reconstruct
158
+ that finalized input.
159
+
160
+ ## 10. External-effect boundary
161
+
162
+ External Provider/Tool/Application effects are outside the ordinary Phronomy
163
+ Persistence transaction boundary (`X0` in ADR-018).
164
+
165
+ Therefore:
166
+
167
+ - durable-transition atomicity is not external-effect atomicity;
168
+ - semantic IDs alone do not prevent duplicate external effects;
169
+ - retry eligibility depends on outcome certainty plus operation-specific
170
+ idempotency/reconciliation contracts; and
171
+ - arbitrary exactly-once external side-effect execution is not an unconditional
172
+ Phronomy guarantee.
173
+
174
+ ## 11. Reference backend details are not architecture
175
+
176
+ InMemory implementation mechanisms do not become requirements for external
177
+ backends unless the Backend SPI states the corresponding semantic property.
178
+
179
+ ## Durable semantic coordination extension
180
+
181
+ ADR-031 extends the single transaction domain to `handoff_states`, `teams` and
182
+ `team_executions`, alongside the existing five repositories. Current root and
183
+ transaction views require all eight. Explicit identity/revision/admission metadata
184
+ remains separate from opaque DurableRecord payloads. See the normative
185
+ [backend contract](../persistence-backends.md) and
186
+ [recovery clarifications](../design/durable-semantic-coordination/RECOVERY_CONTRACT_CLARIFICATIONS.md).
@@ -0,0 +1,72 @@
1
+ > **CURRENT negative architecture guidance**
2
+ >
3
+ > This document records removed Agent Context/Memory designs that must not be
4
+ > mistaken for current contracts. Current architecture starts at
5
+ > [Agent Context](../agent-context.md) and
6
+ > [Context Management](../context-management.md).
7
+
8
+ # Removed Agent Context and Memory Architecture
9
+
10
+ ## Mutable Provider chat as canonical state
11
+
12
+ RubyLLM/runtime message collections are projections/materializations, not
13
+ canonical Agent history. Canonical facts live in the append-only Journal and
14
+ each Provider input is fixed by an `LLMInputManifest`.
15
+
16
+ ## Generic Memory subsystem
17
+
18
+ Phronomy does not use `Memory::ConversationManager`, `Memory::WindowMemory`,
19
+ `SummaryMemory`, or another mutable Memory object as Agent Context authority.
20
+
21
+ Long-context selection/derivation belongs to Context Policy.
22
+
23
+ ## LlmContextWindow / ContextVersionCache
24
+
25
+ The removed window assembler/cache model is not a current extension boundary.
26
+ Context selection uses typed `ContextPolicyInput` and `ContextPlan`, with final
27
+ canonicalization/budget validation by `ContextAssembler`.
28
+
29
+ ## Automatic history rewriting / Memory Compression
30
+
31
+ Phronomy does not delete or rewrite canonical Journal history to fit a model
32
+ window.
33
+
34
+ Application Policy may omit optional source items for one call and create
35
+ derived/compacted current-call content. Canonical source facts remain unchanged.
36
+
37
+ There is no separate current Memory Compression subsystem and no automatic
38
+ Default-Policy summarization LLM call.
39
+
40
+ ## Static / Entity / RAG Knowledge hierarchy
41
+
42
+ Persistent Knowledge is Journal-backed logical Context, not a hierarchy of
43
+ source object classes. Retrieval/vector/entity extraction are acquisition
44
+ strategies owned by Application/Tool integrations.
45
+
46
+ ## Removed Context selection DSLs
47
+
48
+ Not current public contracts:
49
+
50
+ ```text
51
+ ContextRequest
52
+ ContextPolicyDescriptor
53
+ ContextPolicyRegistry
54
+ DerivedContentSpec
55
+ Selection::Unit
56
+ UnitBuilder / Selector / TokenBudgetPacker
57
+ ContextPlan#derived_contents
58
+ ContextPlan#ordering_hints
59
+ ```
60
+
61
+ ## Generic Agent session/thread identity
62
+
63
+ Agent Context is not keyed by a generic Application conversation/thread/session
64
+ identity. Phronomy uses purpose-specific logical/runtime operation identities.
65
+
66
+ ## Cross-Agent shared history as Handoff
67
+
68
+ Semantic Handoff does not merge Journal histories or automatically copy all
69
+ Source history/Knowledge into Target durable state. It transfers policy-bounded
70
+ immutable Context and Target ContextPolicy still decides one-call input.
71
+
72
+ See [Multi-Agent Handoff](../multi-agent-handoff.md).
@@ -0,0 +1,173 @@
1
+ > **CURRENT explanatory architecture**
2
+ >
3
+ > This document describes the reconciled current Phronomy system. Normative
4
+ > architecture decisions remain in the [ADR index](../decisions/README.md);
5
+ > source/runtime behavior remains implementation reality and does not silently
6
+ > amend an ADR.
7
+
8
+ # Security Boundaries
9
+
10
+ ## 1. Responsibility model
11
+
12
+ Phronomy deliberately keeps content-policy interception, Context semantic trust,
13
+ Tool authorization, and execution isolation as separate mechanisms.
14
+
15
+ ```text
16
+ raw invocation input
17
+ -> input_filter
18
+
19
+ Tool result
20
+ -> tool_result_filter
21
+
22
+ possible LLM Context material
23
+ -> ContextPolicyInput
24
+ -> Application ContextPolicy
25
+ semantic selection / omission / derivation /
26
+ source-aware trust/security policy
27
+ -> ContextPlan
28
+ -> Framework structural validation
29
+ -> LLMInputManifest
30
+
31
+ final Agent output
32
+ -> output_filter
33
+ ```
34
+
35
+ No mechanism above is an all-purpose security layer.
36
+
37
+ The current Filter contract is
38
+ [ADR-019](../decisions/019-filter-contract-and-security-boundaries.md).
39
+
40
+ ## 2. Explicit Filter call sites
41
+
42
+ `Phronomy::Filter::Base` may transform a value or block processing through
43
+ `FilterBlockError`.
44
+
45
+ Framework Filter call sites are explicit:
46
+
47
+ ```text
48
+ input
49
+ output
50
+ Tool result
51
+ ```
52
+
53
+ A Filter registered at one call site is not silently applied to every value that
54
+ may later reach an LLM.
55
+
56
+ In particular, Phronomy does **not** add a fourth `context_filter` /
57
+ `add_context_filter` Framework call site.
58
+
59
+ ## 3. Context semantic trust belongs to Application Policy
60
+
61
+ LLM Context is domain-dependent: content that is suspicious in one application
62
+ may be exactly the content another Agent is supposed to analyze.
63
+
64
+ The Framework therefore owns structural/integrity validation, while
65
+ Application-defined `ContextPolicy` owns semantic trust decisions for one LLM
66
+ Call.
67
+
68
+ An Application Policy may:
69
+
70
+ - inspect typed category/provenance/metadata;
71
+ - omit optional material;
72
+ - fail preparation when required material is unacceptable;
73
+ - derive sanitized/redacted current-call material;
74
+ - retrieve/rerank content; or
75
+ - call a `Filter::Base` instance internally as ordinary Ruby policy logic.
76
+
77
+ There is no separate Framework invocation guarantee when a Policy chooses to
78
+ compose a Filter internally.
79
+
80
+ ## 4. Non-destructive transformation
81
+
82
+ Context trust policy must not rewrite canonical Journal history.
83
+
84
+ For optional content, transformation follows the current Context model:
85
+
86
+ ```text
87
+ canonical/source item remains intact
88
+ |
89
+ Policy omits it for this call
90
+ +
91
+ Policy creates derived current-call item
92
+ |
93
+ ContextPlan -> Manifest
94
+ ```
95
+
96
+ Required material is protected by Framework invariants. A Policy cannot silently
97
+ drop a required source item; if the required input cannot be accepted, Context
98
+ preparation fails.
99
+
100
+ ## 5. Framework validation is not semantic filtering
101
+
102
+ After Policy selection, Phronomy validates:
103
+
104
+ - typed category/item identity;
105
+ - required material;
106
+ - Framework-owned metadata/provenance authority;
107
+ - conversation and Tool-call/result dependency structure;
108
+ - effective Tool wiring;
109
+ - canonical representation; and
110
+ - final token budget.
111
+
112
+ These checks establish integrity, not truth, safety, trustworthiness, or domain
113
+ appropriateness of arbitrary content.
114
+
115
+ ## 6. Knowledge/RAG boundary
116
+
117
+ Phronomy does not add a mandatory semantic security hook to `add_knowledge`.
118
+ Retrieval-source validation and ingestion policy remain Application/Tool
119
+ responsibilities.
120
+
121
+ Per-call use of Knowledge is decided by Context Policy.
122
+
123
+ See [Knowledge and RAG](knowledge-and-rag.md).
124
+
125
+ ## 7. Tool approval is authorization, not sanitization
126
+
127
+ Tool approval controls whether a side-effecting/capability operation may execute.
128
+ It does not sanitize arbitrary Tool arguments/results, establish prompt-injection
129
+ safety, or create an OS sandbox.
130
+
131
+ Authorization and content policy are separate concerns.
132
+
133
+ ## 8. PromptInjectionFilter
134
+
135
+ `Phronomy::Filter::PromptInjectionFilter` is an optional bounded heuristic for
136
+ common patterns.
137
+
138
+ It does not guarantee detection of all prompt injection, automatically inspect
139
+ all Context sources, or turn LLM execution into a security sandbox.
140
+
141
+ Applications remain responsible for domain-specific controls.
142
+
143
+ ## 9. Execution placement is not isolation
144
+
145
+ EventLoop, OffloadPool, cooperative cancellation, and Tool `execution_mode`
146
+ describe execution/lifecycle mechanics.
147
+
148
+ They do not provide:
149
+
150
+ - OS process isolation;
151
+ - container isolation;
152
+ - filesystem or network sandboxing;
153
+ - privilege separation; or
154
+ - containment of arbitrary malicious Application/Tool code.
155
+
156
+ Those properties are Application/deployment responsibilities unless a future
157
+ explicit isolation subsystem is accepted.
158
+
159
+ ## 10. No new security-policy SPI
160
+
161
+ This architecture does not add:
162
+
163
+ ```text
164
+ context_filter
165
+ SecurityContext
166
+ TrustLevel
167
+ security metadata authority API
168
+ sandbox SPI
169
+ ```
170
+
171
+ Arbitrary item `metadata` remains Application data except for
172
+ Framework-reserved control keys. Applications must not treat arbitrary metadata
173
+ as a Framework-certified trust assertion.