phronomy 0.22.0 → 0.23.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 (156) hide show
  1. checksums.yaml +4 -4
  2. data/.mutant.yml +3 -4
  3. data/CHANGELOG.md +200 -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 +152 -0
  15. data/docs/architecture/persistence.md +175 -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 +82 -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 +112 -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/README.md +172 -0
  45. data/docs/features.md +31 -11
  46. data/docs/getting-started.md +77 -45
  47. data/docs/migrations/0.19.md +14 -7
  48. data/docs/migrations/0.22.md +390 -0
  49. data/docs/persistence-backends.md +88 -38
  50. data/docs/runtime-and-concurrency.md +227 -33
  51. data/examples/README.md +13 -0
  52. data/lib/phronomy/agent/agent_execution.rb +19 -15
  53. data/lib/phronomy/agent/agent_invocation.rb +288 -93
  54. data/lib/phronomy/agent/agent_invocation_session_builder.rb +236 -202
  55. data/lib/phronomy/agent/agent_root.rb +3 -3
  56. data/lib/phronomy/agent/approval_evaluation_request.rb +37 -19
  57. data/lib/phronomy/agent/async_event_api.rb +145 -72
  58. data/lib/phronomy/agent/base.rb +388 -181
  59. data/lib/phronomy/agent/concerns/before_llm_input.rb +1 -1
  60. data/lib/phronomy/agent/context_assembler.rb +437 -178
  61. data/lib/phronomy/agent/context_candidate_resolver.rb +2 -2
  62. data/lib/phronomy/agent/context_plan.rb +18 -13
  63. data/lib/phronomy/agent/context_plan_validator.rb +246 -88
  64. data/lib/phronomy/agent/context_policies/default.rb +123 -34
  65. data/lib/phronomy/agent/context_policy.rb +109 -3
  66. data/lib/phronomy/agent/context_policy_input.rb +244 -0
  67. data/lib/phronomy/agent/context_policy_input_builder.rb +241 -0
  68. data/lib/phronomy/agent/execution_coordinator.rb +1975 -587
  69. data/lib/phronomy/agent/journal_record.rb +17 -4
  70. data/lib/phronomy/agent/llm_input_build_context.rb +1 -1
  71. data/lib/phronomy/agent/llm_input_manifest.rb +277 -2
  72. data/lib/phronomy/agent/llm_operation_result.rb +12 -7
  73. data/lib/phronomy/agent/phase_machine_builder.rb +19 -7
  74. data/lib/phronomy/agent/provider_call_outcome.rb +23 -7
  75. data/lib/phronomy/agent/recovery_coordinator/continuation.rb +271 -0
  76. data/lib/phronomy/agent/recovery_coordinator/installation.rb +427 -0
  77. data/lib/phronomy/agent/recovery_coordinator/resolution.rb +635 -0
  78. data/lib/phronomy/agent/recovery_coordinator.rb +211 -0
  79. data/lib/phronomy/agent/recovery_support.rb +512 -0
  80. data/lib/phronomy/agent/ruby_llm_materializer.rb +22 -13
  81. data/lib/phronomy/agent/selection/candidate.rb +53 -0
  82. data/lib/phronomy/agent/selection/constraint.rb +49 -0
  83. data/lib/phronomy/agent/shared_state.rb +38 -1
  84. data/lib/phronomy/agent/tool_approval_request.rb +33 -5
  85. data/lib/phronomy/agent/tool_definition_set.rb +49 -3
  86. data/lib/phronomy/agent/tool_invocation.rb +336 -102
  87. data/lib/phronomy/agent/tool_invocation_session_builder.rb +49 -45
  88. data/lib/phronomy/agent.rb +20 -2
  89. data/lib/phronomy/agent_already_exists_error.rb +5 -0
  90. data/lib/phronomy/agent_purged_error.rb +5 -0
  91. data/lib/phronomy/engine/concurrency/offload_pool.rb +17 -3
  92. data/lib/phronomy/engine/concurrency/physical_completion_task.rb +135 -0
  93. data/lib/phronomy/engine/event_loop.rb +622 -63
  94. data/lib/phronomy/engine/fsm_session.rb +194 -21
  95. data/lib/phronomy/engine/runtime/agent_ownership_registry.rb +352 -0
  96. data/lib/phronomy/engine/runtime.rb +77 -20
  97. data/lib/phronomy/generator_verifier.rb +12 -14
  98. data/lib/phronomy/invocation_context.rb +9 -29
  99. data/lib/phronomy/multi_agent/admission_registry.rb +51 -0
  100. data/lib/phronomy/multi_agent/coordination_state.rb +18 -0
  101. data/lib/phronomy/multi_agent/coordinator.rb +154 -0
  102. data/lib/phronomy/multi_agent/execution_coordinator.rb +116 -0
  103. data/lib/phronomy/multi_agent/fan_out_invocation.rb +24 -33
  104. data/lib/phronomy/multi_agent/fan_out_session_builder.rb +12 -19
  105. data/lib/phronomy/multi_agent/handoff.rb +24 -45
  106. data/lib/phronomy/multi_agent/handoff_capability_factory.rb +87 -0
  107. data/lib/phronomy/multi_agent/handoff_context.rb +95 -0
  108. data/lib/phronomy/multi_agent/handoff_policy.rb +137 -0
  109. data/lib/phronomy/multi_agent/handoff_projection.rb +191 -0
  110. data/lib/phronomy/multi_agent/handoff_request.rb +45 -0
  111. data/lib/phronomy/multi_agent/orchestrator.rb +12 -15
  112. data/lib/phronomy/multi_agent/runner.rb +98 -0
  113. data/lib/phronomy/persistence/durable_codec.rb +646 -0
  114. data/lib/phronomy/persistence/durable_record.rb +117 -0
  115. data/lib/phronomy/persistence/in_memory.rb +210 -134
  116. data/lib/phronomy/persistence/migration/initial_format_migration.rb +226 -0
  117. data/lib/phronomy/persistence/repository_facades.rb +316 -0
  118. data/lib/phronomy/persistence.rb +81 -41
  119. data/lib/phronomy/recovery.rb +186 -0
  120. data/lib/phronomy/testing/persistence_contract/a_journal_repository.rb +2 -2
  121. data/lib/phronomy/testing/persistence_contract/a_persistence_backend.rb +1 -1
  122. data/lib/phronomy/testing/persistence_contract/a_workflow_state_repository.rb +19 -19
  123. data/lib/phronomy/testing/persistence_contract/an_agent_repository.rb +3 -3
  124. data/lib/phronomy/testing/persistence_contract/an_execution_repository.rb +5 -5
  125. data/lib/phronomy/tracing/automatic.rb +176 -0
  126. data/lib/phronomy/tracing/base.rb +11 -2
  127. data/lib/phronomy/tracing/langfuse_tracer.rb +20 -12
  128. data/lib/phronomy/version.rb +1 -1
  129. data/lib/phronomy/workflow.rb +3 -6
  130. data/lib/phronomy/workflow_context.rb +14 -5
  131. data/lib/phronomy/workflow_recovery.rb +123 -0
  132. data/lib/phronomy/workflow_runner.rb +468 -256
  133. data/lib/phronomy.rb +6 -0
  134. data/scripts/api_snapshot.rb +12 -0
  135. data/sig/phronomy/agent.rbs +209 -7
  136. data/sig/phronomy/multi_agent.rbs +39 -0
  137. data/sig/phronomy/persistence.rbs +62 -4
  138. data/sig/phronomy/runtime.rbs +1 -4
  139. data/sig/phronomy/workflow.rbs +2 -2
  140. data/sig/phronomy.rbs +10 -0
  141. metadata +65 -17
  142. data/examples/workflows/agent_event_mapping.rb +0 -101
  143. data/examples/workflows/generic_task_event_mapping.rb +0 -66
  144. data/lib/phronomy/agent/activation_registry.rb +0 -28
  145. data/lib/phronomy/agent/agent_execution_activation.rb +0 -172
  146. data/lib/phronomy/agent/context_candidate.rb +0 -47
  147. data/lib/phronomy/agent/context_parts/budget/token_budget_packer.rb +0 -53
  148. data/lib/phronomy/agent/context_parts/requirements/required_context_resolver.rb +0 -56
  149. data/lib/phronomy/agent/context_parts/selectors/recent_first_selector.rb +0 -30
  150. data/lib/phronomy/agent/context_parts/unit_builders/dependency_aware_unit_builder.rb +0 -118
  151. data/lib/phronomy/agent/context_policy_descriptor.rb +0 -49
  152. data/lib/phronomy/agent/context_policy_registry.rb +0 -46
  153. data/lib/phronomy/agent/context_request.rb +0 -35
  154. data/lib/phronomy/agent/context_selection_unit.rb +0 -38
  155. data/lib/phronomy/agent/derived_content_spec.rb +0 -34
  156. data/lib/phronomy/agent/runner.rb +0 -97
@@ -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,152 @@
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-016](../decisions/016-semantic-multi-agent-handoff.md).
24
+
25
+ ## 2. Public API
26
+
27
+ ```ruby
28
+ handoff = Phronomy::MultiAgent::Handoff.new(
29
+ source_agent: triage,
30
+ target_agent: billing,
31
+ description: "Transfer billing responsibility",
32
+ policy: policy
33
+ )
34
+
35
+ runner = Phronomy::MultiAgent::Runner.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. Next-turn continuity and durability
117
+
118
+ The same `main_agent` instance plus the same Runtime define one coordination
119
+ lifetime.
120
+
121
+ Within that lifetime, the active Target remains active on later turns and across
122
+ Runner-facade recreation. Runtime admission rejects racing concurrent turns for
123
+ the same coordination lifetime.
124
+
125
+ Active routing is **not durably rehydrated**. Runtime/process reset starts a new
126
+ coordination lifetime at `main_agent`. Historical Handoff audit facts do not
127
+ reconstruct active Target ownership.
128
+
129
+ ## 10. Cancellation and tracing
130
+
131
+ Handoff does not create a separate cancellation domain; active Agent execution
132
+ uses normal Agent semantics.
133
+
134
+ One Runner user turn is automatically observable as `multi_agent.turn`. Source
135
+ and Target Agent/LLM/Tool logical operations keep their own automatic spans and
136
+ semantic IDs. Handoff adds no generic correlation identity or cross-Runtime
137
+ parent-span guarantee.
138
+
139
+ See [Tracing](tracing.md).
140
+
141
+ ## 11. Safety and removed API
142
+
143
+ `Phronomy::MultiAgent::Runner::MAX_HANDOFFS` bounds transfers in one user turn.
144
+
145
+ Not current contracts:
146
+
147
+ - sentinel Handoff Tool results;
148
+ - `Phronomy::Agent::Runner`;
149
+ - `agents:` / `routes:` Runner configuration;
150
+ - Agent-owned Handoff Tool registration;
151
+ - generated Tool-name identity;
152
+ - blanket Source history/Knowledge copying.
@@ -0,0 +1,175 @@
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
+ ```text
16
+ Persistence
17
+ ├─ contents
18
+ ├─ agents
19
+ ├─ journals
20
+ ├─ executions
21
+ └─ workflow_states
22
+ ```
23
+
24
+ Persistence stores defined durable logical state. It is not serialization of the
25
+ currently running Runtime object graph.
26
+
27
+ Detailed custom-backend method/codec contracts belong in
28
+ [Persistence backends](../persistence-backends.md).
29
+
30
+ Normative durability vocabulary is
31
+ [ADR-018](../decisions/018-durability-guarantees-and-failure-model.md).
32
+
33
+ ## 2. Durable versus Runtime-only state
34
+
35
+ Durable examples include AgentRoot, Journal records, AgentExecution records,
36
+ content/Manifest references, and durable Workflow snapshots.
37
+
38
+ Runtime-only examples include FSMSession objects/IDs, AgentInvocation objects,
39
+ Task instances/callbacks, EventLoop entries, Runtime admission entries, and
40
+ in-flight Provider/Tool operation objects.
41
+
42
+ Runtime/process loss removes Runtime-only objects but does not imply confirmed
43
+ durable state was lost.
44
+
45
+ ## 3. Agent live ownership
46
+
47
+ After create/load, one live Agent instance owns current mutable logical Agent
48
+ state for that `agent_id` within one Runtime/process.
49
+
50
+ During execution, EventLoop is the single writer of Phronomy-managed live Agent
51
+ execution state.
52
+
53
+ ```text
54
+ EventLoop authoritative snapshot
55
+ -> OffloadPool command
56
+ -> Persistence transaction
57
+ -> immutable operation-specific result
58
+ -> EventLoop authority validation
59
+ -> live apply
60
+ ```
61
+
62
+ See
63
+ [ADR-024](../decisions/024-event-loop-single-writer-agent-runtime.md).
64
+
65
+ ## 4. Durable transitions and conflicts
66
+
67
+ Defined semantic durable transitions are atomic according to the Persistence
68
+ transaction contract and conforming backend.
69
+
70
+ Revision/watermark/CAS checks reject stale durable transitions with
71
+ `Persistence::ConflictError` rather than silently merging/reloading competing
72
+ state.
73
+
74
+ Conflict detection is not competing-execution exclusion and cannot undo an
75
+ external side effect already performed.
76
+
77
+ ## 5. Agent and Workflow admission
78
+
79
+ Within one Runtime/process, Agent admission prevents prohibited competing
80
+ top-level execution for one logical Agent owner.
81
+
82
+ The canonical logical/durable Workflow identity is `workflow_instance_id`, which
83
+ is separate from one Runtime `fsm_session_id`.
84
+
85
+ Workflow same-process admission is acquired before durable hydration and retained
86
+ through the authoritative terminal/halted save barrier. The caller-facing Task
87
+ settles after that authoritative durable barrier.
88
+
89
+ See
90
+ [ADR-025](../decisions/025-process-local-agent-ownership-and-runtime-admission.md),
91
+ [ADR-020](../decisions/020-canonical-workflow-instance-identity.md), and
92
+ [ADR-026](../decisions/026-workflow-runtime-admission-and-durable-terminal-barrier.md).
93
+
94
+ ## 6. Cross-process guarantee
95
+
96
+ Cross-process competing-execution exclusion is conditional.
97
+
98
+ A multi-process deployment must provide stable routing/partitioning by logical
99
+ identity or another coordination mechanism that establishes exclusive authority.
100
+ Persistence CAS/revision checks alone detect stale commits; they do not prevent
101
+ duplicate semantic execution from starting.
102
+
103
+ Phronomy does not claim arbitrary external exactly-once side effects.
104
+
105
+ ## 7. Durable codec
106
+
107
+ Durable backend exchange uses immutable
108
+ `Phronomy::Persistence::DurableRecord` values with:
109
+
110
+ ```text
111
+ record_type
112
+ format_version
113
+ payload
114
+ ```
115
+
116
+ `format_version` is a durable representation version, not Agent definition
117
+ version, Workflow identity, or Runtime incarnation identity.
118
+
119
+ Payloads follow the canonical durable value/codec contract. A backend may use its
120
+ own physical storage representation but must return an equivalent logical
121
+ DurableRecord.
122
+
123
+ ## 8. Recovery model
124
+
125
+ Recovery reconstructs logical state from confirmed durable evidence; it does not
126
+ restore the old Runtime object graph.
127
+
128
+ The shared Recovery vocabulary classifies unfinished work as:
129
+
130
+ ```text
131
+ resumable
132
+ reconcilable
133
+ resolution_required
134
+ ```
135
+
136
+ Where outcome is uncertain, Phronomy does not infer "not performed" merely from
137
+ connection/process failure and does not blindly re-dispatch an external
138
+ operation.
139
+
140
+ Application resolution, when required, records one of:
141
+
142
+ ```text
143
+ succeeded
144
+ failed
145
+ not_performed
146
+ ```
147
+
148
+ before dependent continuation may proceed.
149
+
150
+ Agent Recovery is integrated into supported `Agent.load` lifecycle semantics.
151
+
152
+ ## 9. Manifest authority during Recovery
153
+
154
+ A finalized historical `LLMInputManifest` is reused for the Provider input it
155
+ represents. Recovery does not rerun historical ContextPolicy code to reconstruct
156
+ that finalized input.
157
+
158
+ ## 10. External-effect boundary
159
+
160
+ External Provider/Tool/Application effects are outside the ordinary Phronomy
161
+ Persistence transaction boundary (`X0` in ADR-018).
162
+
163
+ Therefore:
164
+
165
+ - durable-transition atomicity is not external-effect atomicity;
166
+ - semantic IDs alone do not prevent duplicate external effects;
167
+ - retry eligibility depends on outcome certainty plus operation-specific
168
+ idempotency/reconciliation contracts; and
169
+ - arbitrary exactly-once external side-effect execution is not an unconditional
170
+ Phronomy guarantee.
171
+
172
+ ## 11. Reference backend details are not architecture
173
+
174
+ InMemory implementation mechanisms do not become requirements for external
175
+ backends unless the Backend SPI states the corresponding semantic property.
@@ -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.