mirrors-sdk 0.1.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.
@@ -0,0 +1,303 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "test_helper"
4
+ require "timeout"
5
+
6
+ class CaptureTest < Minitest::Test
7
+ Settings = Struct.new(:agent_id, :timeout_ms)
8
+
9
+ class ScriptedTransport
10
+ attr_reader :calls
11
+
12
+ def initialize(&handler)
13
+ @calls, @handler, @lock = [], handler, Mutex.new
14
+ end
15
+
16
+ def request(endpoint, body, deadline:, cancel: nil, final_recovery: false)
17
+ @lock.synchronize { @calls << [endpoint, body, deadline, final_recovery] }
18
+ request = JSON.parse(body)
19
+ value = @handler ? @handler.call(request, cancel) : CaptureTest.response(request)
20
+ raise MirrorsSDK::TransportError.new("transport", permanent: true) unless yield(value)
21
+ value
22
+ end
23
+ end
24
+
25
+ def self.response(request)
26
+ result = {
27
+ "protocol" => 3, "agentId" => request["agentId"], "traceId" => request["trace"]["id"],
28
+ "requestId" => request["requestId"], "ordinal" => request["ordinal"], "final" => request["final"],
29
+ "captureOnly" => true, "decisionId" => "receipt", "expiresAt" => "2026-01-01T00:00:00.000Z",
30
+ "mode" => "off", "role" => "system", "context" => nil,
31
+ "ingestion" => request["final"] ? { "status" => "queued", "jobId" => "job" } : nil
32
+ }
33
+ result["terminal"] = request["terminal"] if request.key?("terminal")
34
+ result
35
+ end
36
+
37
+ def input(id = "run", final: false, text: "original", **fields)
38
+ value = {
39
+ "trace" => { "id" => id, "messages" => [{ "role" => "user", "content" => text }] }.merge(fields.transform_keys(&:to_s)),
40
+ "final" => final, "captureOnly" => true
41
+ }
42
+ value["terminal"] = "completed" if final
43
+ value
44
+ end
45
+
46
+ def runtime(transport = ScriptedTransport.new)
47
+ MirrorsSDK::CaptureRuntime.new(transport, Settings.new("agent", nil))
48
+ end
49
+
50
+ def now
51
+ Process.clock_gettime(Process::CLOCK_MONOTONIC)
52
+ end
53
+
54
+ def send_capture(runtime, value, timeout: 2, cancel: nil)
55
+ runtime.send(value, deadline: now + timeout, cancel: cancel)
56
+ end
57
+
58
+ def wait_for(&condition)
59
+ Timeout.timeout(2) { sleep(0.001) until condition.call }
60
+ end
61
+
62
+ def test_owned_identity_and_advancing_ordinals
63
+ transport = ScriptedTransport.new
64
+ capture = runtime(transport)
65
+ %w[first second].each { |text| assert_equal "accepted", send_capture(capture, input(text: text)).status }
66
+ requests = transport.calls.map { |call| JSON.parse(call[1]) }
67
+ assert_equal [1, 2], requests.map { |request| request["ordinal"] }
68
+ refute_equal requests[0]["requestId"], requests[1]["requestId"]
69
+ assert requests.all? { |request| request["captureOnly"] && request["agentId"] == "agent" }
70
+ end
71
+
72
+ def test_uncertain_write_reconciles_exact_bytes_before_changed_evidence
73
+ count = 0
74
+ transport = ScriptedTransport.new do |request, _|
75
+ count += 1
76
+ raise MirrorsSDK::TransportError.new("transport") if count == 1
77
+ self.class.response(request)
78
+ end
79
+ capture = runtime(transport)
80
+ first = input(text: "one")
81
+ assert_equal "unconfirmed", send_capture(capture, first).status
82
+ first["trace"]["messages"][0]["content"] = "mutated"
83
+ assert_equal "accepted", send_capture(capture, input(text: "two")).status
84
+ assert_equal transport.calls[0][1], transport.calls[1][1]
85
+ assert_equal "one", JSON.parse(transport.calls[1][1])["trace"]["messages"][0]["content"]
86
+ assert_equal 2, JSON.parse(transport.calls[2][1])["ordinal"]
87
+ assert_equal transport.calls[1][2], transport.calls[2][2]
88
+ end
89
+
90
+ def test_failed_reconciliation_never_sends_new_evidence
91
+ transport = ScriptedTransport.new { raise MirrorsSDK::TransportError.new("transport") }
92
+ capture = runtime(transport)
93
+ send_capture(capture, input(text: "one"))
94
+ send_capture(capture, input(text: "two"))
95
+ assert_equal 2, transport.calls.length
96
+ assert_equal transport.calls[0][1], transport.calls[1][1]
97
+ end
98
+
99
+ def test_final_retries_once_and_retains_immutable_receipt
100
+ count = 0
101
+ transport = ScriptedTransport.new do |request, _|
102
+ count += 1
103
+ raise MirrorsSDK::TransportError.new("transport") if count == 1
104
+ self.class.response(request)
105
+ end
106
+ capture = runtime(transport)
107
+ receipt = send_capture(capture, input(final: true))
108
+ assert_equal "accepted", receipt.status
109
+ assert_equal transport.calls[0], transport.calls[1]
110
+ assert_equal({ "status" => "queued", "jobId" => "job" }, receipt.ingestion)
111
+ assert_same receipt, send_capture(capture, input(final: true))
112
+ assert_equal "terminal_conflict", send_capture(capture, input(final: true, text: "different")).reason
113
+ assert_equal 2, transport.calls.length
114
+ end
115
+
116
+ def test_permanent_failure_does_not_retry_and_releases_final_capacity
117
+ transport = ScriptedTransport.new { raise MirrorsSDK::TransportError.new("transport", permanent: true) }
118
+ capture = runtime(transport)
119
+ 140.times do |index|
120
+ assert_equal "unconfirmed", send_capture(capture, input("final-#{index}", final: true)).status
121
+ end
122
+ assert_equal 140, transport.calls.length
123
+ assert_equal({ active: 0, terminal: 0, recent: 128 }, capture.diagnostics)
124
+ end
125
+
126
+ def test_metadata_is_fixed_but_final_user_and_latency_may_change
127
+ transport = ScriptedTransport.new
128
+ capture = runtime(transport)
129
+ assert_equal "accepted", send_capture(capture, input(model: "a", user: { "id" => "first" })).status
130
+ assert_equal "invalid_evidence", send_capture(capture, input(model: "b")).reason
131
+ result = send_capture(capture, input(final: true, model: "a", user: { "id" => "second" }, turnLatencyMs: 0))
132
+ assert_equal "accepted", result.status
133
+ assert_equal 2, transport.calls.length
134
+ end
135
+
136
+ def test_metadata_key_order_has_no_semantic_effect
137
+ capture = runtime
138
+ flags = { "ended" => "unknown", "history" => "truncated", "original_content" => "partial" }
139
+ assert_equal "accepted", send_capture(capture, input(completeness: flags)).status
140
+ assert_equal "accepted", send_capture(capture, input(completeness: flags.to_a.reverse.to_h)).status
141
+ end
142
+
143
+ def test_prefix_capacity_is_independent_from_finals
144
+ capture = runtime
145
+ 64.times { |i| assert_equal "accepted", send_capture(capture, input("run-#{i}")).status }
146
+ assert_equal "capacity", send_capture(capture, input("overflow")).reason
147
+ assert_equal "accepted", send_capture(capture, input("final-only", final: true)).status
148
+ end
149
+
150
+ def test_invalid_metadata_final_releases_prefix_state
151
+ capture = runtime
152
+ send_capture(capture, input(model: "original"))
153
+ assert_equal "invalid_evidence", send_capture(capture, input(final: true, model: "changed")).reason
154
+ assert_equal 0, capture.diagnostics[:active]
155
+ end
156
+
157
+ def test_same_trace_serializes_without_blocking_other_traces
158
+ gate = Queue.new
159
+ transport = ScriptedTransport.new do |request, _|
160
+ gate.pop if request["trace"]["id"] == "run" && request["ordinal"] == 1
161
+ self.class.response(request)
162
+ end
163
+ capture = runtime(transport)
164
+ first = Thread.new { send_capture(capture, input) }
165
+ wait_for { transport.calls.length == 1 }
166
+ second = Thread.new { send_capture(capture, input(text: "second")) }
167
+ assert_equal "accepted", send_capture(capture, input("other")).status
168
+ assert_equal 2, transport.calls.length
169
+ gate << true
170
+ assert_equal "accepted", first.value.status
171
+ assert_equal "accepted", second.value.status
172
+ assert_equal 2, JSON.parse(transport.calls.last[1])["ordinal"]
173
+ ensure
174
+ gate << true if gate
175
+ [first, second].compact.each { |thread| thread.join(2) }
176
+ end
177
+
178
+ def test_waiting_for_trace_respects_call_deadline
179
+ gate = Queue.new
180
+ transport = ScriptedTransport.new do |request, _|
181
+ gate.pop
182
+ self.class.response(request)
183
+ end
184
+ capture = runtime(transport)
185
+ first = Thread.new { send_capture(capture, input) }
186
+ wait_for { transport.calls.length == 1 }
187
+ assert_equal "timeout", send_capture(capture, input(text: "queued"), timeout: 0.02).reason
188
+ assert_equal 1, transport.calls.length
189
+ ensure
190
+ gate << true if gate
191
+ first.join(2) if first
192
+ end
193
+
194
+ def test_release_cancels_prefix_but_preserves_admitted_final
195
+ transport = ScriptedTransport.new do |_request, cancel|
196
+ sleep(0.001) until cancel.canceled?
197
+ raise MirrorsSDK::TransportError.new("canceled")
198
+ end
199
+ capture = runtime(transport)
200
+ prefix = Thread.new { send_capture(capture, input) }
201
+ wait_for { transport.calls.length == 1 }
202
+ capture.release("run")
203
+ assert_equal "unconfirmed", prefix.value.status
204
+ capture.clear
205
+ assert_equal "closed", send_capture(capture, input("next")).reason
206
+ ensure
207
+ capture.clear if capture
208
+ prefix.join(2) if prefix
209
+ end
210
+
211
+ def test_final_seals_before_waiting_and_release_keeps_upload
212
+ gate = Queue.new
213
+ transport = ScriptedTransport.new do |request, _|
214
+ gate.pop
215
+ self.class.response(request)
216
+ end
217
+ capture = runtime(transport)
218
+ prefix = Thread.new { send_capture(capture, input) }
219
+ wait_for { transport.calls.length == 1 }
220
+ final = Thread.new { send_capture(capture, input(final: true)) }
221
+ wait_for { capture.diagnostics[:terminal] == 1 }
222
+ assert_equal "terminal_conflict", send_capture(capture, input(text: "late")).reason
223
+ capture.release("run")
224
+ gate << true
225
+ assert_equal "accepted", prefix.value.status
226
+ wait_for { transport.calls.length == 2 }
227
+ gate << true
228
+ assert_equal "accepted", final.value.status
229
+ ensure
230
+ 2.times { gate << true } if gate
231
+ [prefix, final].compact.each { |thread| thread.join(2) }
232
+ end
233
+
234
+ def test_final_recovery_applies_to_uncertain_prefix_and_new_final
235
+ count = 0
236
+ transport = ScriptedTransport.new do |request, _|
237
+ count += 1
238
+ raise MirrorsSDK::TransportError.new("transport") if count == 1
239
+ self.class.response(request)
240
+ end
241
+ capture = runtime(transport)
242
+ send_capture(capture, input)
243
+ assert_equal "accepted", send_capture(capture, input(final: true)).status
244
+ assert_equal [false, true, true], transport.calls.map(&:last)
245
+ assert_equal transport.calls[0][1], transport.calls[1][1]
246
+ assert_equal 2, JSON.parse(transport.calls.last[1])["ordinal"]
247
+ end
248
+
249
+ def test_host_sequence_supersedes_unsent_older_snapshot
250
+ transport = ScriptedTransport.new
251
+ capture = runtime(transport)
252
+ newer = capture.send(input(text: "newer"), deadline: now + 2, sequence: 2)
253
+ older = capture.send(input(text: "older"), deadline: now + 2, sequence: 1)
254
+ assert_equal "accepted", newer.status
255
+ assert_equal "superseded", older.reason
256
+ assert_equal 1, transport.calls.length
257
+ final = capture.send(input(final: true), deadline: now + 2, sequence: 3)
258
+ assert_equal "accepted", final.status
259
+ assert_equal 2, JSON.parse(transport.calls.last[1])["ordinal"]
260
+ end
261
+
262
+ def test_caller_cancellation_does_not_poison_execution_state
263
+ transport = ScriptedTransport.new
264
+ capture = runtime(transport)
265
+ cancellation = MirrorsSDK::Cancellation.new
266
+ cancellation.cancel("canceled")
267
+ assert_equal "unconfirmed", send_capture(capture, input, cancel: cancellation).status
268
+ assert_empty transport.calls
269
+ assert_equal "accepted", send_capture(capture, input(text: "retry")).status
270
+ end
271
+
272
+ def test_terminal_capacity_is_bounded_and_rejected_final_releases_prefix
273
+ gate = Queue.new
274
+ transport = ScriptedTransport.new do |request, _|
275
+ gate.pop if request["final"]
276
+ self.class.response(request)
277
+ end
278
+ capture = runtime(transport)
279
+ send_capture(capture, input("prefix"))
280
+ finals = 16.times.map do |index|
281
+ Thread.new { send_capture(capture, input("final-#{index}", final: true)) }
282
+ end
283
+ wait_for { capture.diagnostics[:terminal] == 16 }
284
+ assert_equal "capacity", send_capture(capture, input("prefix", final: true)).reason
285
+ assert_equal 0, capture.diagnostics[:active]
286
+ assert_equal "terminal_conflict", send_capture(capture, input("final-0", final: true, text: "changed")).reason
287
+ assert_equal 16, capture.diagnostics[:terminal]
288
+ 16.times { gate << true }
289
+ assert finals.all? { |thread| thread.value.status == "accepted" }
290
+ ensure
291
+ 16.times { gate << true } if gate
292
+ finals&.each { |thread| thread.join(2) }
293
+ end
294
+
295
+ def test_capture_ordinal_stops_at_contract_limit
296
+ transport = ScriptedTransport.new
297
+ capture = runtime(transport)
298
+ send_capture(capture, input)
299
+ capture.instance_variable_get(:@active)["run"].ordinal = 10_000
300
+ assert_equal "capacity", send_capture(capture, input(text: "next")).reason
301
+ assert_equal 1, transport.calls.length
302
+ end
303
+ end
@@ -0,0 +1,64 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "test_helper"
4
+ require "mirrors_sdk/configuration"
5
+
6
+ class ConfigurationTest < Minitest::Test
7
+ def config(**options)
8
+ MirrorsSDK::Config.new(**{ api_url: "https://example.invalid", api_key: "fixture-key", agent_id: "agent" }.merge(options))
9
+ end
10
+
11
+ def test_copies_and_freezes_settings_and_hides_credentials
12
+ key = +"secret-fixture"
13
+ value = config(api_key: key)
14
+ key.replace("modified")
15
+ assert_equal "secret-fixture", value.api_key
16
+ assert value.frozen?
17
+ assert value.api_key.frozen?
18
+ refute_includes value.inspect, "secret-fixture"
19
+ assert_equal 1000, value.heartbeat_interval_ms
20
+ end
21
+
22
+ def test_only_https_and_literal_loopback_http_are_allowed
23
+ ["https://example.invalid/api", "http://localhost:8000", "http://127.0.0.1:8000", "http://[::1]:8000"].each do |url|
24
+ assert_equal url, config(api_url: url).api_url
25
+ end
26
+ ["http://example.invalid", "http://127.1", "https://user:pass@example.invalid", "https://example.invalid?x",
27
+ "https://example.invalid#x", "https://example.invalid\\x", "https://example.invalid:99999", "https://example.invalid/\n"].each do |url|
28
+ assert_raises(ArgumentError) { config(api_url: url) }
29
+ end
30
+ end
31
+
32
+ def test_invalid_numeric_options_flags_and_credentials_are_rejected
33
+ [{ timeout_ms: 0 }, { timeout_ms: 30_001 }, { timeout_ms: 1.0 }, { failure_threshold: 0 },
34
+ { cooldown_ms: 300_001 }, { enabled: 1 }, { heartbeat_interval_ms: 19 }, { mode_lease_ms: 3001 },
35
+ { heartbeat_interval_ms: 200, mode_lease_ms: 200 }, { api_key: "key\n" }, { api_key: "" },
36
+ { agent_id: "bad/id" }].each do |options|
37
+ assert_raises(ArgumentError) { config(**options) }
38
+ end
39
+ end
40
+
41
+ def test_custom_options_cannot_invoke_comparison_or_string_hooks
42
+ hostile = Object.new
43
+ def hostile.==(*)
44
+ raise "comparison hook"
45
+ end
46
+ def hostile.instance_of?(*)
47
+ raise "type hook"
48
+ end
49
+ def hostile.nil?
50
+ raise "nil hook"
51
+ end
52
+ [:enabled, :timeout_ms, :api_url, :api_key, :agent_id].each do |option|
53
+ assert_raises(ArgumentError) { config(**{ option => hostile }) }
54
+ end
55
+ key = +"fixture-key"
56
+ def key.bytesize
57
+ raise "string hook"
58
+ end
59
+ def key.match?(*)
60
+ raise "string hook"
61
+ end
62
+ assert_equal "fixture-key", config(api_key: key).api_key
63
+ end
64
+ end
@@ -0,0 +1,295 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "test_helper"
4
+ require "time"
5
+
6
+ class ContextTest < Minitest::Test
7
+ class ManualExecutor
8
+ attr_reader :jobs
9
+
10
+ def initialize
11
+ @jobs = []
12
+ end
13
+
14
+ def submit(&block)
15
+ future = MirrorsSDK::Future.new
16
+ @jobs << [future, block]
17
+ future
18
+ end
19
+ end
20
+
21
+ class ClockedHost < MirrorsSDK::ContextHost
22
+ attr_accessor :monotonic_offset, :wall_offset
23
+
24
+ def initialize(*args)
25
+ super
26
+ @monotonic_offset = @wall_offset = 0
27
+ end
28
+
29
+ private
30
+
31
+ def now
32
+ super + @monotonic_offset
33
+ end
34
+
35
+ def wall
36
+ super + @wall_offset
37
+ end
38
+ end
39
+
40
+ def setup
41
+ @config = MirrorsSDK::Config.new(api_url: "https://example.invalid", api_key: "test", agent_id: "agent")
42
+ @executor = ManualExecutor.new
43
+ @host = ClockedHost.new(@config, Object.new, @executor)
44
+ end
45
+
46
+ def teardown
47
+ @host.stop
48
+ end
49
+
50
+ def lease(mode = "active", version: "v1", duration: 3000, offset: 0)
51
+ issued = Time.now.utc + offset / 1000.0
52
+ { "protocol" => 1, "agentId" => "agent", "mode" => mode, "version" => version,
53
+ "issuedAt" => issued.iso8601(3), "expiresAt" => (issued + duration / 1000.0).iso8601(3) }
54
+ end
55
+
56
+ def stamp(offset = 0)
57
+ (Time.now.utc + offset / 1000.0).iso8601(3)
58
+ end
59
+
60
+ def activate
61
+ @host.observe_mode(lease, monotonic)
62
+ end
63
+
64
+ def start(id = "execution", timeout_ms: 1000)
65
+ @host.start(trace(id), timeout_ms: timeout_ms, started: monotonic)
66
+ end
67
+
68
+ def accept(wait, changes = {})
69
+ value = { "protocol" => 1, "agentId" => "agent", "traceId" => wait.trace_id,
70
+ "requestId" => wait.identifier, "decisionId" => "decision", "modeVersion" => "v1",
71
+ "issuedAt" => stamp, "expiresAt" => stamp(4000), "mode" => "active",
72
+ "role" => "system", "context" => "Check the account.", "reason" => "matched" }.merge(changes)
73
+ wait.job.resolve(value)
74
+ value
75
+ end
76
+
77
+ def test_unknown_off_and_expired_modes_do_not_schedule_requests
78
+ assert_equal "mode_unknown", @host.get(trace).reason
79
+ @host.observe_mode(lease("off"), monotonic)
80
+ assert_equal "off", @host.get(trace).reason
81
+ @host.observe_mode(lease("active", duration: 50), monotonic - 0.1)
82
+ assert_equal "mode_expired", @host.get(trace).reason
83
+ assert_empty @executor.jobs
84
+ end
85
+
86
+ def test_active_result_is_bound_to_request_and_releases_capacity_at_return
87
+ activate
88
+ wait = start
89
+ value = accept(wait)
90
+ assert_equal 1, @host.diagnostics[:pending_context]
91
+ result = @host.await(wait)
92
+ assert_equal "accepted", result.delivery
93
+ assert_equal "Check the account.", result.context
94
+ assert_equal value["requestId"], result.freshness.request_id
95
+ assert_equal value["expiresAt"], result.freshness.expires_at
96
+ assert_equal 0, @host.diagnostics[:pending_context]
97
+ assert_operator result.elapsed_ms, :>=, 0
98
+ assert_equal "superseded", @host.await(wait).reason
99
+ end
100
+
101
+ def test_ready_decision_is_rechecked_when_the_caller_resumes
102
+ activate
103
+ wait = start
104
+ accept(wait)
105
+ @host.monotonic_offset = 1.01
106
+ result = @host.await(wait)
107
+ assert_equal "timeout", result.reason
108
+ assert_empty result.context
109
+ assert_operator result.elapsed_ms, :>=, 1000
110
+ end
111
+
112
+ def test_context_lifetime_cannot_gain_time_from_clock_offset
113
+ activate
114
+ wait = start
115
+ @host.monotonic_offset = 0.02
116
+ accept(wait, "issuedAt" => stamp(100), "expiresAt" => stamp(101))
117
+ assert_equal "expired", @host.await(wait).reason
118
+ end
119
+
120
+ def test_mode_expiry_checks_wall_clock_and_request_start_monotonic_lifetime
121
+ @host.observe_mode(lease(duration: 50, offset: 100), monotonic)
122
+ @host.wall_offset = -10
123
+ @host.monotonic_offset = 0.06
124
+ assert_equal "mode_expired", @host.get(trace).reason
125
+
126
+ @host.monotonic_offset = @host.wall_offset = 0
127
+ activate
128
+ @host.wall_offset = 10
129
+ result = @host.get(trace)
130
+ assert_equal "mode_expired", result.reason
131
+ assert_equal "shadow", result.mode
132
+ end
133
+
134
+ def test_lease_configuration_and_invalid_request_anchors_cannot_extend_mode
135
+ activate
136
+ [Float::NAN, Float::INFINITY, true, monotonic + 1].each do |invalid|
137
+ @host.observe_mode(lease("off", version: "v2"), invalid)
138
+ assert_equal "active", @host.diagnostics[:mode]
139
+ end
140
+ @host.monotonic_offset = 3.1
141
+ assert_equal "mode_expired", @host.get(trace).reason
142
+ end
143
+
144
+ def test_shadow_returns_immediately_but_retains_bounded_background_work
145
+ @host.observe_mode(lease("shadow"), monotonic)
146
+ wait = start
147
+ result = @host.await(wait)
148
+ assert_equal "shadow", result.reason
149
+ assert_empty result.context
150
+ assert_equal 1, @executor.jobs.length
151
+ assert_equal 1, @host.diagnostics[:pending_context]
152
+ accept(wait)
153
+ assert_equal 0, @host.diagnostics[:pending_context]
154
+ assert_empty @host.await(wait).context
155
+ end
156
+
157
+ def test_context_work_carries_shadow_only_and_full_copied_evidence
158
+ @host.observe_mode(lease("shadow"), monotonic)
159
+ transport = Object.new
160
+ requests = []
161
+ transport.define_singleton_method(:request) do |endpoint, body, **_options, &_validator|
162
+ requests << [endpoint, JSON.parse(body)]
163
+ {}
164
+ end
165
+ @host = ClockedHost.new(@config, transport, @executor)
166
+ @host.observe_mode(lease("shadow"), monotonic)
167
+ original = trace
168
+ wait = @host.start(original, started: monotonic)
169
+ original["messages"][0]["content"] = "mutated"
170
+ @executor.jobs.last[1].call(MirrorsSDK::Cancellation.new)
171
+ assert_equal "retrieve-context", requests[0][0]
172
+ assert_equal true, requests[0][1]["shadowOnly"]
173
+ assert_equal "Hello", requests[0][1]["trace"]["messages"][0]["content"]
174
+ assert_equal wait.identifier, requests[0][1]["requestId"]
175
+ end
176
+
177
+ def test_new_retrieval_and_changed_capture_invalidate_older_decisions
178
+ activate
179
+ first = start
180
+ second = start
181
+ assert_equal "superseded", @host.await(first).reason
182
+ @host.observe("execution", MirrorsSDK::Wire.encode(trace))
183
+ refute second.job.done?
184
+ changed = trace
185
+ changed["messages"] << { "role" => "assistant", "content" => "Done" }
186
+ @host.observe("execution", MirrorsSDK::Wire.encode(changed))
187
+ assert_equal "superseded", @host.await(second).reason
188
+ end
189
+
190
+ def test_release_disable_shutdown_and_mode_change_invalidate_ready_results
191
+ actions = [
192
+ ["execution_closed", -> { @host.release("execution") }],
193
+ ["disabled", -> { @host.set_enabled(false) }],
194
+ ["closed", -> { @host.stop }],
195
+ ["mode_changed", -> { @host.observe_mode(lease("active", version: "v2"), monotonic) }]
196
+ ]
197
+ actions.each do |reason, action|
198
+ @host = ClockedHost.new(@config, Object.new, @executor)
199
+ activate
200
+ wait = start
201
+ accept(wait)
202
+ action.call
203
+ assert_equal reason, @host.await(wait).reason
204
+ assert_equal 0, @host.diagnostics[:pending_context]
205
+ end
206
+ end
207
+
208
+ def test_retrieval_capacity_includes_accepted_unconsumed_results
209
+ activate
210
+ waits = 16.times.map { |index| start("execution-#{index}") }
211
+ waits.each { |wait| accept(wait) }
212
+ assert_equal "capacity", @host.get(trace("overflow")).reason
213
+ assert_equal 16, @executor.jobs.length
214
+ @host.await(waits.first)
215
+ start("replacement")
216
+ assert_equal 16, @host.diagnostics[:pending_context]
217
+ assert_equal 17, @executor.jobs.length
218
+ end
219
+
220
+ def test_total_deadline_includes_time_before_preparation
221
+ activate
222
+ wait = @host.start(trace, timeout_ms: 20, started: monotonic - 0.03)
223
+ assert_equal "timeout", @host.await(wait).reason
224
+ assert_empty @executor.jobs
225
+ end
226
+
227
+ def test_wait_timeout_and_cancellation_cancel_transport_without_reusing_late_results
228
+ activate
229
+ wait = start(timeout_ms: 20)
230
+ assert_equal "timeout", @host.await(wait).reason
231
+ assert wait.job.token.canceled?
232
+ refute wait.job.resolve({})
233
+
234
+ cancel = MirrorsSDK::Cancellation.new
235
+ wait = start
236
+ thread = Thread.new { sleep 0.01; cancel.cancel }
237
+ result = @host.await(wait, cancel: cancel)
238
+ thread.join
239
+ assert_equal "canceled", result.delivery
240
+ assert_equal "canceled", result.reason
241
+ assert wait.job.token.canceled?
242
+ assert_equal 0, @host.diagnostics[:pending_context]
243
+ end
244
+
245
+ def test_already_canceled_calls_do_not_schedule_work
246
+ activate
247
+ cancel = MirrorsSDK::Cancellation.new
248
+ cancel.cancel
249
+ assert_equal "canceled", @host.get(trace, cancel: cancel).reason
250
+ assert_empty @executor.jobs
251
+ end
252
+
253
+ def test_release_during_snapshot_preparation_cannot_resurrect_a_wait
254
+ activate
255
+ original = MirrorsSDK::Wire.method(:snapshot)
256
+ copying = lambda do |value, **options|
257
+ @host.release("execution")
258
+ original.call(value, **options)
259
+ end
260
+ MirrorsSDK::Wire.stub(:snapshot, copying) do
261
+ assert_equal "execution_closed", @host.get(trace).reason
262
+ end
263
+ assert_empty @executor.jobs
264
+ assert_equal 0, @host.diagnostics[:pending_context]
265
+ end
266
+
267
+ def test_host_thread_interruption_releases_retrieval_capacity
268
+ activate
269
+ wait = start
270
+ entered = Queue.new
271
+ thread = Thread.new { entered << true; @host.await(wait) }
272
+ entered.pop
273
+ eventually { thread.status == "sleep" }
274
+ thread.kill
275
+ thread.join
276
+ assert wait.job.token.canceled?
277
+ assert_equal 0, @host.diagnostics[:pending_context]
278
+ ensure
279
+ thread&.kill
280
+ thread&.join
281
+ end
282
+
283
+ def test_fail_open_for_invalid_options_evidence_and_transport
284
+ activate
285
+ [nil, 0, 1001, 1.5, true].each do |timeout|
286
+ assert_equal "invalid_options", @host.get(trace, timeout_ms: timeout).reason
287
+ end
288
+ assert_equal "invalid_evidence", @host.get({ "id" => "bad", "messages" => [Object.new] }).reason
289
+ wait = start
290
+ wait.job.reject(StandardError.new("scripted failure"))
291
+ assert_equal "transport", @host.await(wait).reason
292
+ invalid = MirrorsSDK::ContextHost.new(nil)
293
+ assert_equal "invalid_options", invalid.get(trace).reason
294
+ end
295
+ end