summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lua/clever_f/sequence_coordinator.lua27
-rw-r--r--tests/run.lua27
2 files changed, 53 insertions, 1 deletions
diff --git a/lua/clever_f/sequence_coordinator.lua b/lua/clever_f/sequence_coordinator.lua
index e369a8b..9e6a9b6 100644
--- a/lua/clever_f/sequence_coordinator.lua
+++ b/lua/clever_f/sequence_coordinator.lua
@@ -242,6 +242,25 @@ function SequenceCoordinator:resolve_acquisition(descriptor, invocation)
return self:fresh_primary_resolution(descriptor, result, invocation)
end
+function SequenceCoordinator:evaluate_repeat_timeout(invocation)
+ if type(invocation) ~= "table" then
+ fail("repeat timeout requires primary invocation state", 2)
+ end
+ local record = coordinator_records[self]
+ if type(record.repeat_resolver.evaluate_timeout) ~= "function" then
+ fail("SequenceCoordinator repeat resolver must evaluate timeout", 2)
+ end
+ local window = record.host:read_window()
+ local decision, elapsed_ms, cleanup =
+ record.repeat_resolver:evaluate_timeout(window)
+ return {
+ decision = decision,
+ elapsed_ms = elapsed_ms,
+ cleanup = cleanup,
+ window = window,
+ }
+end
+
function SequenceCoordinator:primary(value)
local descriptor = self:validate_primary_descriptor(value)
local invocation = self:read_primary_invocation()
@@ -254,7 +273,13 @@ function SequenceCoordinator:primary(value)
if invocation.repeat_decision == repeat_resolver_factory.Decision.ACQUIRE then
return self:resolve_acquisition(descriptor, invocation)
end
- return descriptor
+ local timeout = self:evaluate_repeat_timeout(invocation)
+ return {
+ kind = "repeat",
+ invocation = invocation,
+ pressed_descriptor = descriptor,
+ timeout = timeout,
+ }
end
function M.new(options)
diff --git a/tests/run.lua b/tests/run.lua
index 7caeb6c..089f6dc 100644
--- a/tests/run.lua
+++ b/tests/run.lua
@@ -7311,6 +7311,33 @@ test("Fresh primary resolution reuses acquired plans and marks empty motion", fu
truthy(resolution.skip_destination)
end)
+test("Repeated primary coordination evaluates timeout before reuse", function()
+ local _, transitions = fresh_sequence_state()
+ local landing = domain.Position.new(1, 3)
+ transitions:BeginAcquisition("n", "f")
+ transitions:CommitAcquiredTarget("n", target("a"), 100)
+ transitions:CommitCommandSuccess("n", landing, true)
+ local host = MemoryHost.new({
+ buffer_lines = { "aba" },
+ cursor = landing,
+ time_values_ms = { 150 },
+ configuration = { repeat_timeout_ms = 75 },
+ })
+
+ local resolution = sequence_coordinator.new({ host = host }):primary("f")
+
+ same("repeat", resolution.kind)
+ same(repeat_resolver.Decision.REPEAT, resolution.timeout.decision)
+ same(50, resolution.timeout.elapsed_ms)
+ local time_read
+ for index, operation in ipairs(host:operations()) do
+ if operation.operation == "read_time_ms" then
+ time_read = index
+ end
+ end
+ truthy(time_read ~= nil)
+end)
+
for _, item in ipairs(tests) do
local ok, failure = xpcall(item.body, debug.traceback)
if not ok then