[EPIC] Give rlm_subagent runtime-defaulted deadlines with optional model override #175

Closed
opened 2026-08-22 22:02:31 +00:00 by lost-rob0t · 6 comments
lost-rob0t commented 2026-08-22 22:02:31 +00:00 (Migrated from github.com)

Goal

Make the existing model-visible rlm_subagent tool own a sane task timeout by default while allowing the model to request a different timeout explicitly when needed.

The model must normally be able to call:

{"query":"investigate this"}

with no timeout argument at all.

It may optionally call:

{"query":"run the longer investigation","timeout_seconds":120}

The default, maximum, validation, and final effective deadline remain host/runtime policy. The model is requesting a duration, not granting itself unbounded execution.

Do not create a second model-facing task API. Extend the existing rlm_subagent tool and existing completion/tool budget machinery.


Research: current implementation

prolog/rlm_subagent.pl

rlm_subagent_register/7 currently registers a normal rlm_tool schema:

arguments:_{
    type:object,
    required:[query],
    additional_properties:false,
    properties:_{query:_{type:string}}
},
limits:_{time_limit:30.0, max_output_bytes:65536}

The model therefore sees only query; there is no model-visible timeout override.

The trusted handler captures CompletionOptions at registration time and later calls:

rlm_completion(Query, Context, Options, CompletionOutcome)

with those host-owned options unchanged.

prolog/rlm_completion.pl

The completion supervisor already owns a semantic wall-time budget:

default_completion_budget(
    completion_budget{
        ...,
        time_limit:30.0
    }).

completion_budget/2 merges host budget(Dict) overrides into that default and validates time_limit as a positive number.

The actual completion is bounded with:

call_with_time_limit(Budget.time_limit, ...)

so the completion timeout is an execution budget, not merely a waiting timeout.

prolog/rlm_tool.pl

Tool schemas already carry trusted runtime limits. perform_tool_effect/... executes the handler through:

call_tool_with_limit(Handler, Args, Limits.time_limit, CallOutcome)

which itself uses call_with_time_limit/2 and returns a structured tool_error{kind:timeout,...}.

Therefore rlm_subagent currently has two 30-second layers:

  1. outer tool-handler wall-time (Schema.limits.time_limit = 30.0);
  2. inner RLM completion wall-time (completion_budget.time_limit = 30.0).

This happens to align at the default, but there is no explicit policy relationship between them.

prolog/rlm_async.pl

rlm_future_await(Future, Timeout, Outcome) is only a waiter timeout. The async docs explicitly state that an await timeout does not cancel or restart the underlying task.

This epic must not confuse Future-await timeouts with task execution deadlines.

test/rlm_subagent_test.pl

Current tests cover:

  • successful structured subagent envelope;
  • capability denial before child creation;
  • child-capability widening failure.

There is currently no timeout-policy coverage.


Design decision

Keep one interface

Continue using the existing ordinary tool:

rlm_subagent

Do not add rlm_task, spawn_task, a second task registry, or any parallel timeout API just to express this policy.

Extend the existing schema with one optional field:

"timeout_seconds": number

Canonical model-visible schema:

arguments:_{
    type:object,
    required:[query],
    additional_properties:false,
    properties:_{
        query:_{type:string},
        timeout_seconds:_{type:number,
                          exclusiveMinimum:0}
    }
}

query remains the only required argument.


Host-owned timeout policy

rlm_subagent_register/7 currently captures CompletionOptions; use the same host-controlled configuration path rather than adding another global subsystem.

Define a normalized host policy derived from registration options, conceptually:

subagent_timeout_policy{
    default_seconds:30.0,
    max_seconds:300.0,
    handler_grace_seconds:2.0
}

Exact field names may follow existing option conventions, but the semantics must be explicit.

Preferred registration options:

subagent_timeout_default(30.0)
subagent_timeout_max(300.0)
subagent_timeout_grace(2.0)

If no new registration option list is desired because CompletionOptions is already the canonical host configuration value, these may live inside CompletionOptions as dedicated host-only options. Do not expose the max/default policy to model control.

Resolution order

For each invocation:

model timeout_seconds present?
    yes -> validate requested duration
    no  -> use host default
              |
              v
must be > 0
              |
              v
must be <= host maximum
              |
              v
EffectiveTimeout

Do not silently convert an over-max request into the max value. Return a structured policy error so traces and tests can distinguish:

  • model asked for 120 and got 120;
  • model omitted timeout and got default 30;
  • model asked for 10000 and was rejected because host max is 300.

Suggested error shape:

subagent_error{
    phase:timeout_policy,
    kind:timeout_exceeds_maximum,
    requested:Requested,
    maximum:Maximum,
    message:"requested subagent timeout exceeds host policy"
}

Invalid zero/negative/non-number values should be rejected structurally before child creation.


Effective completion budget

The handler must derive the child completion options without mutating the host-captured base options.

Conceptually:

resolve_subagent_timeout(Args, TimeoutPolicy, EffectiveTimeout),
completion_options_with_timeout(BaseCompletionOptions,
                                EffectiveTimeout,
                                EffectiveCompletionOptions),
rlm_completion(Query,
               Context,
               EffectiveCompletionOptions,
               CompletionOutcome).

completion_options_with_timeout/... must update only:

budget.time_limit

while preserving every other host-controlled completion budget field:

  • max iterations;
  • recursion depth;
  • concurrent subcalls;
  • model-call limit;
  • tool-call limit;
  • context-op limit;
  • token limit;
  • cost limit;
  • output limit.

If CompletionOptions already contains:

budget(ExistingBudgetUpdates)

merge the effective time_limit into that dict rather than replacing the entire budget option.

The model must never be able to alter other budget fields through rlm_subagent arguments in this epic.


Outer tool-handler deadline

The tool runtime already enforces Schema.limits.time_limit around the entire trusted handler.

That outer limit must not remain fixed at 30 seconds if the host allows a 120/300-second model request, otherwise the outer tool wrapper will terminate the task before the inner completion budget can honor the requested timeout.

At registration time derive the tool-handler limit from host policy:

HandlerLimit = MaxTimeout + CleanupGrace

For example:

default task timeout: 30s
maximum task timeout: 300s
cleanup grace:         2s
tool handler limit:  302s

The model still normally gets 30 seconds because the inner completion budget is set to the default. The larger outer limit is only a safety envelope allowing legitimate host-approved overrides plus cleanup.

Do not use an infinite outer tool limit.


Enclosing parent deadline

A subagent is invoked from inside a parent operation that may itself have a smaller remaining wall-time budget.

The implementation must document and test this invariant:

child requested/default deadline does not widen enclosing parent lifetime

If the runtime already exposes a reliable enclosing remaining deadline by implementation time, compute:

EffectiveTimeout = min(RequestedOrDefault,
                       HostMax,
                       ParentRemaining)

and record the parent-bound reduction explicitly in trace/envelope metadata.

If no reliable remaining-deadline API exists yet, do not invent one inside rlm_subagent. Preserve the existing parent call_with_time_limit behavior and document that the enclosing completion may terminate first. File a separate generic deadline-propagation issue only if live source review demonstrates it is needed across multiple operations.

This epic must not grow into an rlm_async redesign merely to expose an optional subagent timeout.


Result / trace observability

Successful or failed subagent envelopes should expose enough non-secret policy metadata to explain timeout behavior without leaking host internals.

Preferred addition:

timeout:subagent_timeout{
    source:default|model_request|parent_bound,
    requested_seconds:RequestedOrNone,
    effective_seconds:Effective
}

Do not expose callable handlers or unrelated host configuration.

Timeout completion failures should retain the existing structured completion error:

completion_error{
    phase:runtime,
    kind:timeout,
    ...
}

and the subagent envelope should remain:

subagent_result{
    status:failed,
    ...,
    error:Error
}

Avoid translating the same timeout through several incompatible error vocabularies.


Exact implementation files

1. prolog/rlm_subagent.pl

rlm_subagent_register/7

Change the generated rlm_subagent schema:

  • keep query required;
  • add optional timeout_seconds numeric property;
  • derive limits.time_limit from host maximum + cleanup grace rather than hard-coded 30.0;
  • capture a normalized timeout policy in the trusted handler closure.

The model must still see this as the same normal rlm_subagent tool.

rlm_subagent_handler/...

Extend the trusted handler closure/arity as needed to receive the normalized host timeout policy.

Before agent_spawn/5:

  1. resolve and validate timeout;
  2. build effective completion options;
  3. reject invalid/out-of-policy requests before creating a child;
  4. only then spawn the child and call rlm_completion.

Add private helpers with single ownership, conceptually:

subagent_timeout_policy(+CompletionOptions, -Policy).
subagent_requested_timeout(+Args, -RequestedOrDefaultMarker).
subagent_effective_timeout(+Args, +Policy, -Outcome).
subagent_completion_options(+BaseOptions, +Timeout, -EffectiveOptions).

Exact names may follow module conventions, but timeout parsing/merging must not be duplicated across tests or callers.

subagent_after_spawn/...

Pass the effective completion options rather than the untouched registration options.

subagent_completion_envelope/...

Add timeout provenance/effective value to the envelope if this can be done without breaking the existing result shape contract. If backwards compatibility requires avoiding new required keys, add it as an additional optional dict key.

2. test/rlm_subagent_test.pl

Add the full regression matrix described below.

3. docs/agent-runtime.md

Add a dedicated subsection under the model-visible subagent/tool discussion:

## RLM subagent task deadlines

Document:

  • timeout is optional to the model;
  • host default is used when absent;
  • host maximum is authoritative;
  • timeout changes only child wall-time, not capabilities or other budgets;
  • outer tool limit is a host safety envelope, not the model default;
  • Future-await timeout is unrelated;
  • enclosing parent may terminate first unless a generic remaining-deadline contract exists.

Include JSON examples with and without timeout_seconds.

4. docs/completion-runtime.md

Clarify that completion_budget.time_limit is the execution wall-time used by subagent task policy after host validation, and that model-facing tools must not directly mutate arbitrary completion-budget fields.

5. docs/async-runtime.md

Add one explicit cross-reference in ### Timeout behavior:

Future await timeout controls how long a caller waits. Domain task deadlines such as rlm_subagent completion budgets are execution limits and are enforced by the owning domain runtime/tool.

Do not change rlm_future_await/3 semantics in this epic.

6. Research/design artifact

Create:

research/RLM-RESEARCH-026-task-deadlines.org

This is currently the next unused research number after RLM-RESEARCH-025-lem-ui.org on main.

Required sections:

Research Question
Current Runtime Evidence
Timeout Vocabulary
Model-visible vs Host-owned Policy
Deadline Resolution
Nested/Parent Deadline Semantics
Tool Handler vs Completion Limit
Cancellation Interaction
Rejected Alternatives
Implementation Implications
Acceptance Experiments
Open Questions

The note must explicitly distinguish:

await timeout != task execution timeout != cancellation

and record why this slice extends the existing rlm_subagent interface rather than creating a new task subsystem.


Required tests

Add at least these tests to test/rlm_subagent_test.pl:

  1. subagent_timeout_omitted_uses_host_default

    • invoke with only query;
    • assert successful normal call;
    • assert timeout metadata shows source:default and expected effective value.
  2. subagent_timeout_explicit_override_is_honored

    • request a valid timeout different from default;
    • use deterministic test handler/timing so test does not actually wait a long duration;
    • assert effective timeout equals request.
  3. subagent_timeout_above_host_max_is_rejected_before_spawn

    • record children before;
    • request > max;
    • assert structured timeout-policy error;
    • assert children unchanged.
  4. subagent_timeout_zero_is_rejected_before_spawn

  5. subagent_timeout_negative_is_rejected_before_spawn

  6. subagent_timeout_non_number_is_schema_rejected

  7. subagent_timeout_does_not_replace_other_completion_budget_fields

    • host completion options include non-default token/model/tool limits;
    • override timeout;
    • verify other limits remain preserved.
  8. subagent_default_timeout_does_not_require_model_field

    • assert schema required list remains exactly [query].
  9. subagent_schema_exposes_optional_timeout_seconds

    • discover registered schema;
    • assert property exists and is optional.
  10. outer_tool_limit_covers_host_maximum_plus_grace

    • register with small deterministic test policy;
    • inspect schema limits;
    • assert outer limit cannot preempt an allowed override.
  11. subagent_completion_timeout_returns_structured_failed_envelope

    • deterministic child completion exceeds tiny effective limit;
    • assert status:failed and error.kind == timeout (within existing completion error envelope).
  12. timeout_request_does_not_widen_capabilities

    • combine valid long timeout request with forbidden child capability situation;
    • capability denial remains authoritative.
  13. timeout_policy_is_host_owned

    • model arguments cannot set max/default/grace or arbitrary budget keys because schema has additional_properties:false.
  14. sync_tool_timeout_does_not_depend_on_future_await_timeout

    • regression proving task execution deadline is distinct from rlm_future_await/3 waiter behavior.
  15. subagent_timeout_cleanup_does_not_leave_running_child_work

    • after deterministic timeout, inspect child/runtime state and prove no worker/task continues normal execution indefinitely.

Backwards compatibility

  • Existing model calls with only {query:...} remain valid.
  • Default effective timeout remains 30 seconds unless host changes policy.
  • Existing host CompletionOptions remain accepted.
  • Existing capability narrowing is unchanged.
  • Existing rlm_tool schema/result enforcement is unchanged.
  • Existing rlm_future_await/3 behavior is unchanged.
  • Existing subagent_result fields remain available; timeout metadata should be additive.

Non-goals

  • no second model-visible task API;
  • no general worker-kill timer inside rlm_async;
  • no change to Future-await timeout semantics;
  • no model ability to request infinite;
  • no model ability to change token/cost/capability/recursion budgets through this timeout field;
  • no silent widening above host maximum;
  • no arbitrary model-supplied completion option dict;
  • no replacement of the normal rlm_tool schema/handler interface.

Acceptance gate

This epic is complete when:

  • rlm_subagent remains the single normal model-facing delegation tool;
  • timeout is optional in its schema;
  • omission uses host default automatically;
  • explicit valid model timeout is honored;
  • host maximum is enforced before child creation;
  • outer tool-handler limit can never accidentally preempt a host-allowed child timeout;
  • effective child completion_budget.time_limit is changed without mutating other host budget fields;
  • timeout failure is structured and leaves no indefinite child work;
  • capability/authority rules remain unchanged;
  • docs clearly distinguish await timeout, execution timeout, and cancellation;
  • research/RLM-RESEARCH-026-task-deadlines.org records the design rationale and rejected alternatives;
  • focused subagent/tool/completion tests and the deterministic aggregate suite pass.

Implementation agents must inspect live main before editing and adjust exact helper names if main has changed, but must preserve this contract rather than inventing a parallel task subsystem.

## Goal Make the existing **model-visible `rlm_subagent` tool** own a sane task timeout by default while allowing the model to request a different timeout explicitly when needed. The model must normally be able to call: ```json {"query":"investigate this"} ``` with **no timeout argument at all**. It may optionally call: ```json {"query":"run the longer investigation","timeout_seconds":120} ``` The default, maximum, validation, and final effective deadline remain host/runtime policy. The model is requesting a duration, not granting itself unbounded execution. Do not create a second model-facing task API. Extend the existing `rlm_subagent` tool and existing completion/tool budget machinery. --- ## Research: current implementation ### `prolog/rlm_subagent.pl` `rlm_subagent_register/7` currently registers a normal `rlm_tool` schema: ```prolog arguments:_{ type:object, required:[query], additional_properties:false, properties:_{query:_{type:string}} }, limits:_{time_limit:30.0, max_output_bytes:65536} ``` The model therefore sees only `query`; there is no model-visible timeout override. The trusted handler captures `CompletionOptions` at registration time and later calls: ```prolog rlm_completion(Query, Context, Options, CompletionOutcome) ``` with those host-owned options unchanged. ### `prolog/rlm_completion.pl` The completion supervisor already owns a semantic wall-time budget: ```prolog default_completion_budget( completion_budget{ ..., time_limit:30.0 }). ``` `completion_budget/2` merges host `budget(Dict)` overrides into that default and validates `time_limit` as a positive number. The actual completion is bounded with: ```prolog call_with_time_limit(Budget.time_limit, ...) ``` so the completion timeout is an **execution budget**, not merely a waiting timeout. ### `prolog/rlm_tool.pl` Tool schemas already carry trusted runtime limits. `perform_tool_effect/...` executes the handler through: ```prolog call_tool_with_limit(Handler, Args, Limits.time_limit, CallOutcome) ``` which itself uses `call_with_time_limit/2` and returns a structured `tool_error{kind:timeout,...}`. Therefore `rlm_subagent` currently has **two 30-second layers**: 1. outer tool-handler wall-time (`Schema.limits.time_limit = 30.0`); 2. inner RLM completion wall-time (`completion_budget.time_limit = 30.0`). This happens to align at the default, but there is no explicit policy relationship between them. ### `prolog/rlm_async.pl` `rlm_future_await(Future, Timeout, Outcome)` is only a waiter timeout. The async docs explicitly state that an await timeout does **not** cancel or restart the underlying task. This epic must not confuse Future-await timeouts with task execution deadlines. ### `test/rlm_subagent_test.pl` Current tests cover: - successful structured subagent envelope; - capability denial before child creation; - child-capability widening failure. There is currently no timeout-policy coverage. --- # Design decision ## Keep one interface Continue using the existing ordinary tool: ```text rlm_subagent ``` Do **not** add `rlm_task`, `spawn_task`, a second task registry, or any parallel timeout API just to express this policy. Extend the existing schema with one optional field: ```json "timeout_seconds": number ``` Canonical model-visible schema: ```prolog arguments:_{ type:object, required:[query], additional_properties:false, properties:_{ query:_{type:string}, timeout_seconds:_{type:number, exclusiveMinimum:0} } } ``` `query` remains the only required argument. --- # Host-owned timeout policy `rlm_subagent_register/7` currently captures `CompletionOptions`; use the same host-controlled configuration path rather than adding another global subsystem. Define a normalized host policy derived from registration options, conceptually: ```prolog subagent_timeout_policy{ default_seconds:30.0, max_seconds:300.0, handler_grace_seconds:2.0 } ``` Exact field names may follow existing option conventions, but the semantics must be explicit. Preferred registration options: ```prolog subagent_timeout_default(30.0) subagent_timeout_max(300.0) subagent_timeout_grace(2.0) ``` If no new registration option list is desired because `CompletionOptions` is already the canonical host configuration value, these may live inside `CompletionOptions` as dedicated host-only options. Do not expose the max/default policy to model control. ## Resolution order For each invocation: ```text model timeout_seconds present? yes -> validate requested duration no -> use host default | v must be > 0 | v must be <= host maximum | v EffectiveTimeout ``` Do **not** silently convert an over-max request into the max value. Return a structured policy error so traces and tests can distinguish: - model asked for 120 and got 120; - model omitted timeout and got default 30; - model asked for 10000 and was rejected because host max is 300. Suggested error shape: ```prolog subagent_error{ phase:timeout_policy, kind:timeout_exceeds_maximum, requested:Requested, maximum:Maximum, message:"requested subagent timeout exceeds host policy" } ``` Invalid zero/negative/non-number values should be rejected structurally before child creation. --- # Effective completion budget The handler must derive the child completion options without mutating the host-captured base options. Conceptually: ```prolog resolve_subagent_timeout(Args, TimeoutPolicy, EffectiveTimeout), completion_options_with_timeout(BaseCompletionOptions, EffectiveTimeout, EffectiveCompletionOptions), rlm_completion(Query, Context, EffectiveCompletionOptions, CompletionOutcome). ``` `completion_options_with_timeout/...` must update only: ```prolog budget.time_limit ``` while preserving every other host-controlled completion budget field: - max iterations; - recursion depth; - concurrent subcalls; - model-call limit; - tool-call limit; - context-op limit; - token limit; - cost limit; - output limit. If `CompletionOptions` already contains: ```prolog budget(ExistingBudgetUpdates) ``` merge the effective `time_limit` into that dict rather than replacing the entire budget option. The model must never be able to alter other budget fields through `rlm_subagent` arguments in this epic. --- # Outer tool-handler deadline The tool runtime already enforces `Schema.limits.time_limit` around the entire trusted handler. That outer limit must not remain fixed at 30 seconds if the host allows a 120/300-second model request, otherwise the outer tool wrapper will terminate the task before the inner completion budget can honor the requested timeout. At registration time derive the tool-handler limit from host policy: ```text HandlerLimit = MaxTimeout + CleanupGrace ``` For example: ```text default task timeout: 30s maximum task timeout: 300s cleanup grace: 2s tool handler limit: 302s ``` The model still normally gets 30 seconds because the **inner completion budget** is set to the default. The larger outer limit is only a safety envelope allowing legitimate host-approved overrides plus cleanup. Do not use an infinite outer tool limit. --- # Enclosing parent deadline A subagent is invoked from inside a parent operation that may itself have a smaller remaining wall-time budget. The implementation must document and test this invariant: ```text child requested/default deadline does not widen enclosing parent lifetime ``` If the runtime already exposes a reliable enclosing remaining deadline by implementation time, compute: ```text EffectiveTimeout = min(RequestedOrDefault, HostMax, ParentRemaining) ``` and record the parent-bound reduction explicitly in trace/envelope metadata. If no reliable remaining-deadline API exists yet, **do not invent one inside `rlm_subagent`**. Preserve the existing parent `call_with_time_limit` behavior and document that the enclosing completion may terminate first. File a separate generic deadline-propagation issue only if live source review demonstrates it is needed across multiple operations. This epic must not grow into an `rlm_async` redesign merely to expose an optional subagent timeout. --- # Result / trace observability Successful or failed subagent envelopes should expose enough non-secret policy metadata to explain timeout behavior without leaking host internals. Preferred addition: ```prolog timeout:subagent_timeout{ source:default|model_request|parent_bound, requested_seconds:RequestedOrNone, effective_seconds:Effective } ``` Do not expose callable handlers or unrelated host configuration. Timeout completion failures should retain the existing structured completion error: ```prolog completion_error{ phase:runtime, kind:timeout, ... } ``` and the subagent envelope should remain: ```prolog subagent_result{ status:failed, ..., error:Error } ``` Avoid translating the same timeout through several incompatible error vocabularies. --- # Exact implementation files ## 1. `prolog/rlm_subagent.pl` ### `rlm_subagent_register/7` Change the generated `rlm_subagent` schema: - keep `query` required; - add optional `timeout_seconds` numeric property; - derive `limits.time_limit` from host maximum + cleanup grace rather than hard-coded `30.0`; - capture a normalized timeout policy in the trusted handler closure. The model must still see this as the same normal `rlm_subagent` tool. ### `rlm_subagent_handler/...` Extend the trusted handler closure/arity as needed to receive the normalized host timeout policy. Before `agent_spawn/5`: 1. resolve and validate timeout; 2. build effective completion options; 3. reject invalid/out-of-policy requests **before creating a child**; 4. only then spawn the child and call `rlm_completion`. Add private helpers with single ownership, conceptually: ```prolog subagent_timeout_policy(+CompletionOptions, -Policy). subagent_requested_timeout(+Args, -RequestedOrDefaultMarker). subagent_effective_timeout(+Args, +Policy, -Outcome). subagent_completion_options(+BaseOptions, +Timeout, -EffectiveOptions). ``` Exact names may follow module conventions, but timeout parsing/merging must not be duplicated across tests or callers. ### `subagent_after_spawn/...` Pass the effective completion options rather than the untouched registration options. ### `subagent_completion_envelope/...` Add timeout provenance/effective value to the envelope if this can be done without breaking the existing result shape contract. If backwards compatibility requires avoiding new required keys, add it as an additional optional dict key. ## 2. `test/rlm_subagent_test.pl` Add the full regression matrix described below. ## 3. `docs/agent-runtime.md` Add a dedicated subsection under the model-visible subagent/tool discussion: ```text ## RLM subagent task deadlines ``` Document: - timeout is optional to the model; - host default is used when absent; - host maximum is authoritative; - timeout changes only child wall-time, not capabilities or other budgets; - outer tool limit is a host safety envelope, not the model default; - Future-await timeout is unrelated; - enclosing parent may terminate first unless a generic remaining-deadline contract exists. Include JSON examples with and without `timeout_seconds`. ## 4. `docs/completion-runtime.md` Clarify that `completion_budget.time_limit` is the execution wall-time used by subagent task policy after host validation, and that model-facing tools must not directly mutate arbitrary completion-budget fields. ## 5. `docs/async-runtime.md` Add one explicit cross-reference in `### Timeout behavior`: ```text Future await timeout controls how long a caller waits. Domain task deadlines such as rlm_subagent completion budgets are execution limits and are enforced by the owning domain runtime/tool. ``` Do not change `rlm_future_await/3` semantics in this epic. ## 6. Research/design artifact Create: ```text research/RLM-RESEARCH-026-task-deadlines.org ``` This is currently the next unused research number after `RLM-RESEARCH-025-lem-ui.org` on main. Required sections: ```text Research Question Current Runtime Evidence Timeout Vocabulary Model-visible vs Host-owned Policy Deadline Resolution Nested/Parent Deadline Semantics Tool Handler vs Completion Limit Cancellation Interaction Rejected Alternatives Implementation Implications Acceptance Experiments Open Questions ``` The note must explicitly distinguish: ```text await timeout != task execution timeout != cancellation ``` and record why this slice extends the existing `rlm_subagent` interface rather than creating a new task subsystem. --- # Required tests Add at least these tests to `test/rlm_subagent_test.pl`: 1. `subagent_timeout_omitted_uses_host_default` - invoke with only `query`; - assert successful normal call; - assert timeout metadata shows `source:default` and expected effective value. 2. `subagent_timeout_explicit_override_is_honored` - request a valid timeout different from default; - use deterministic test handler/timing so test does not actually wait a long duration; - assert effective timeout equals request. 3. `subagent_timeout_above_host_max_is_rejected_before_spawn` - record children before; - request > max; - assert structured timeout-policy error; - assert children unchanged. 4. `subagent_timeout_zero_is_rejected_before_spawn` 5. `subagent_timeout_negative_is_rejected_before_spawn` 6. `subagent_timeout_non_number_is_schema_rejected` 7. `subagent_timeout_does_not_replace_other_completion_budget_fields` - host completion options include non-default token/model/tool limits; - override timeout; - verify other limits remain preserved. 8. `subagent_default_timeout_does_not_require_model_field` - assert schema required list remains exactly `[query]`. 9. `subagent_schema_exposes_optional_timeout_seconds` - discover registered schema; - assert property exists and is optional. 10. `outer_tool_limit_covers_host_maximum_plus_grace` - register with small deterministic test policy; - inspect schema limits; - assert outer limit cannot preempt an allowed override. 11. `subagent_completion_timeout_returns_structured_failed_envelope` - deterministic child completion exceeds tiny effective limit; - assert `status:failed` and `error.kind == timeout` (within existing completion error envelope). 12. `timeout_request_does_not_widen_capabilities` - combine valid long timeout request with forbidden child capability situation; - capability denial remains authoritative. 13. `timeout_policy_is_host_owned` - model arguments cannot set max/default/grace or arbitrary `budget` keys because schema has `additional_properties:false`. 14. `sync_tool_timeout_does_not_depend_on_future_await_timeout` - regression proving task execution deadline is distinct from `rlm_future_await/3` waiter behavior. 15. `subagent_timeout_cleanup_does_not_leave_running_child_work` - after deterministic timeout, inspect child/runtime state and prove no worker/task continues normal execution indefinitely. --- # Backwards compatibility - Existing model calls with only `{query:...}` remain valid. - Default effective timeout remains 30 seconds unless host changes policy. - Existing host `CompletionOptions` remain accepted. - Existing capability narrowing is unchanged. - Existing `rlm_tool` schema/result enforcement is unchanged. - Existing `rlm_future_await/3` behavior is unchanged. - Existing `subagent_result` fields remain available; timeout metadata should be additive. --- # Non-goals - no second model-visible task API; - no general worker-kill timer inside `rlm_async`; - no change to Future-await timeout semantics; - no model ability to request `infinite`; - no model ability to change token/cost/capability/recursion budgets through this timeout field; - no silent widening above host maximum; - no arbitrary model-supplied completion option dict; - no replacement of the normal `rlm_tool` schema/handler interface. --- # Acceptance gate This epic is complete when: - `rlm_subagent` remains the single normal model-facing delegation tool; - timeout is optional in its schema; - omission uses host default automatically; - explicit valid model timeout is honored; - host maximum is enforced before child creation; - outer tool-handler limit can never accidentally preempt a host-allowed child timeout; - effective child `completion_budget.time_limit` is changed without mutating other host budget fields; - timeout failure is structured and leaves no indefinite child work; - capability/authority rules remain unchanged; - docs clearly distinguish await timeout, execution timeout, and cancellation; - `research/RLM-RESEARCH-026-task-deadlines.org` records the design rationale and rejected alternatives; - focused subagent/tool/completion tests and the deterministic aggregate suite pass. Implementation agents must inspect live main before editing and adjust exact helper names if main has changed, but must preserve this contract rather than inventing a parallel task subsystem.
lost-rob0t commented 2026-08-26 02:06:50 +00:00 (Migrated from github.com)

RAGE reconciliation — deadline policy vs current main

Live re-audit against canonical main 49d86f88730b4a0f5dc4a7cf300b8f09ef5845b0 found that PR #212 is now a diverged transaction, not a merge candidate. Its head 0109d25e2b22190d6d3339528f76c04748462c45 is two commits ahead of the old merge base 36cb418b833c77e24438fa94e596062a90088fa3 and one commit behind current main.

The conflict is semantic, not just textual: #172 landed typed/compiler-authenticated delegation policy in the same rlm_subagent.pl path. Current main now includes rlm_subagent_register_command/8, prompt_command_subagent_options/3, authenticated subagent_delegation_source(...), fingerprint/prompt-id validation, uniqueness checks for explicit skills, and preservation of delegation source in child/result provenance. #212's deadline implementation predates those contracts and cannot replace them.

Correct realization boundary

Port the existing deadline semantics into the current #172 subagent path, preserving all of these current-main invariants:

  • compiler-authenticated command registration remains canonical;
  • role/skill/source provenance stays intact and inert;
  • authenticated delegation fingerprint/prompt-id validation stays fail-closed;
  • capability/authority narrowing is unchanged;
  • timeout policy is orthogonal host/runtime policy and grants no authority;
  • invalid/over-max timeout is rejected before child creation;
  • one effective task deadline feeds completion budget + supervised-call/outer handler envelopes;
  • Future waiter timeout remains distinct.

The model-visible schema may add optional timeout_seconds, but command-authenticated role/skill/source policy must continue to come from the trusted compiler/host path, not model arguments.

CI evidence

Exact #212 head 0109d25e... currently has REAL OpenRouter, Paid OpenRouter, Nix, clean SWI pack and Tree-sitter green, but the deterministic PlUnit job fails; all subsequent deterministic gates are skipped. That is a real blocker, not desired TDD state. Negative timeout/rejection contracts should assert the expected structured failure while the suite remains green; no intentional-red/xfail/skip convention.

Decision

GO to reconcile/port #212 onto current main, HOLD merge. Do not merge or overwrite current #172 semantics. Re-run focused subagent tests and the complete exact-head repository gate after the semantic port; any new head invalidates the old green provider/Nix evidence.

## RAGE reconciliation — deadline policy vs current `main` Live re-audit against canonical `main` `49d86f88730b4a0f5dc4a7cf300b8f09ef5845b0` found that PR #212 is now a diverged transaction, not a merge candidate. Its head `0109d25e2b22190d6d3339528f76c04748462c45` is two commits ahead of the old merge base `36cb418b833c77e24438fa94e596062a90088fa3` and one commit behind current `main`. The conflict is semantic, not just textual: #172 landed typed/compiler-authenticated delegation policy in the same `rlm_subagent.pl` path. Current main now includes `rlm_subagent_register_command/8`, `prompt_command_subagent_options/3`, authenticated `subagent_delegation_source(...)`, fingerprint/prompt-id validation, uniqueness checks for explicit skills, and preservation of delegation source in child/result provenance. #212's deadline implementation predates those contracts and cannot replace them. ### Correct realization boundary Port the existing deadline semantics **into the current #172 subagent path**, preserving all of these current-main invariants: - compiler-authenticated command registration remains canonical; - role/skill/source provenance stays intact and inert; - authenticated delegation fingerprint/prompt-id validation stays fail-closed; - capability/authority narrowing is unchanged; - timeout policy is orthogonal host/runtime policy and grants no authority; - invalid/over-max timeout is rejected before child creation; - one effective task deadline feeds completion budget + supervised-call/outer handler envelopes; - Future waiter timeout remains distinct. The model-visible schema may add optional `timeout_seconds`, but command-authenticated role/skill/source policy must continue to come from the trusted compiler/host path, not model arguments. ### CI evidence Exact #212 head `0109d25e...` currently has REAL OpenRouter, Paid OpenRouter, Nix, clean SWI pack and Tree-sitter green, but the deterministic PlUnit job fails; all subsequent deterministic gates are skipped. That is a real blocker, not desired TDD state. Negative timeout/rejection contracts should assert the expected structured failure while the suite remains green; no intentional-red/xfail/skip convention. ### Decision **GO to reconcile/port #212 onto current main, HOLD merge.** Do not merge or overwrite current #172 semantics. Re-run focused subagent tests and the complete exact-head repository gate after the semantic port; any new head invalidates the old green provider/Nix evidence.
lost-rob0t commented 2026-08-26 07:15:01 +00:00 (Migrated from github.com)

RAGE update — deterministic regression isolated against post-#216 main

Canonical main is now 267697bef10a3fffff7c093e1435ece770e7444b. Re-reading #175 and exact stale #212 head 0109d25e2b22190d6d3339528f76c04748462c45 isolated the deterministic failure precisely:

test/rlm_subagent_test.pl:365 child_completion_enforces_wall_time_budget expects error.kind == timeout, but gets capability_denied.

This is not capability flakiness. The stale timeout implementation rewrites an existing budget(completion_budget{time_limit:0.02}) to the dedicated timeout-policy default (30.0). The slow planner therefore survives the old 20ms wall-time expectation, reaches its deliberate unused tool plan, and correctly fails capability authorization. #175's current design confirms that dedicated subagent_timeout_default/max/grace policy owns subagent task lifetime and only rewrites budget.time_limit; other budget fields must remain preserved. Therefore the old generic wall-time regression must be migrated to set a tiny host subagent_timeout_default when testing subagent task timeout. Capability checks must not be weakened.

Analyze / research

  • #172 compiler-authenticated delegation is now canonical and must remain intact: rlm_subagent_register_command/8, trusted command-derived role/skill/source, delegation-source fingerprint/prompt-id validation, uniqueness checks, and child/result provenance.
  • #212 predates that code and cannot be rebased by replacing rlm_subagent.pl wholesale.
  • await timeout != task execution timeout != cancellation remains the vocabulary boundary.
  • Existing enclosing-parent lifetime remains authoritative; this slice will not invent a general remaining-deadline API.

Design

Recover #175 from current main on a new issue-scoped branch rather than force-moving the shared stale #212 history. Port only the deadline policy into the current #172 path:

  1. normalize host-only default/max/grace at registration;
  2. expose only optional model timeout_seconds in the existing rlm_subagent schema;
  3. validate invalid/over-max requests before spawn;
  4. merge the effective timeout into only budget.time_limit, preserving every other budget field;
  5. size outer tool + supervised-call envelopes from host maximum plus cleanup grace;
  6. add additive timeout provenance to structured subagent results;
  7. preserve authenticated delegation provenance/capability/authority semantics unchanged;
  8. keep Future-await timeout semantics untouched.

Adversarial review

  • timeout arguments cannot grant capabilities/authority;
  • model cannot set host max/default/grace or arbitrary budget keys because schema stays closed;
  • command-authenticated delegation metadata cannot be replaced by model args;
  • over-max/invalid requests must create no child;
  • existing budget fields other than time_limit must survive;
  • cancellation must still terminate child work;
  • the old wall-time test must be migrated to the new host-policy entrypoint, not deleted/weakened.

Decision

GO for a semantic recovery branch from exact 267697be…; keep stale #212 as preserved regression/history evidence and supersede it only after the current-main port has its own focused + full exact-head green evidence.

## RAGE update — deterministic regression isolated against post-#216 main Canonical `main` is now `267697bef10a3fffff7c093e1435ece770e7444b`. Re-reading #175 and exact stale #212 head `0109d25e2b22190d6d3339528f76c04748462c45` isolated the deterministic failure precisely: `test/rlm_subagent_test.pl:365 child_completion_enforces_wall_time_budget` expects `error.kind == timeout`, but gets `capability_denied`. This is not capability flakiness. The stale timeout implementation rewrites an existing `budget(completion_budget{time_limit:0.02})` to the dedicated timeout-policy default (`30.0`). The slow planner therefore survives the old 20ms wall-time expectation, reaches its deliberate `unused` tool plan, and correctly fails capability authorization. #175's current design confirms that dedicated `subagent_timeout_default/max/grace` policy owns subagent task lifetime and only rewrites `budget.time_limit`; other budget fields must remain preserved. Therefore the old generic wall-time regression must be migrated to set a tiny host `subagent_timeout_default` when testing subagent task timeout. Capability checks must not be weakened. ### Analyze / research - #172 compiler-authenticated delegation is now canonical and must remain intact: `rlm_subagent_register_command/8`, trusted command-derived role/skill/source, delegation-source fingerprint/prompt-id validation, uniqueness checks, and child/result provenance. - #212 predates that code and cannot be rebased by replacing `rlm_subagent.pl` wholesale. - `await timeout != task execution timeout != cancellation` remains the vocabulary boundary. - Existing enclosing-parent lifetime remains authoritative; this slice will not invent a general remaining-deadline API. ### Design Recover #175 from current main on a new issue-scoped branch rather than force-moving the shared stale #212 history. Port only the deadline policy into the current #172 path: 1. normalize host-only default/max/grace at registration; 2. expose only optional model `timeout_seconds` in the existing `rlm_subagent` schema; 3. validate invalid/over-max requests before spawn; 4. merge the effective timeout into only `budget.time_limit`, preserving every other budget field; 5. size outer tool + supervised-call envelopes from host maximum plus cleanup grace; 6. add additive timeout provenance to structured subagent results; 7. preserve authenticated delegation provenance/capability/authority semantics unchanged; 8. keep Future-await timeout semantics untouched. ### Adversarial review - timeout arguments cannot grant capabilities/authority; - model cannot set host max/default/grace or arbitrary budget keys because schema stays closed; - command-authenticated delegation metadata cannot be replaced by model args; - over-max/invalid requests must create no child; - existing budget fields other than `time_limit` must survive; - cancellation must still terminate child work; - the old wall-time test must be migrated to the new host-policy entrypoint, not deleted/weakened. ### Decision **GO** for a semantic recovery branch from exact `267697be…`; keep stale #212 as preserved regression/history evidence and supersede it only after the current-main port has its own focused + full exact-head green evidence.
lost-rob0t commented 2026-08-26 07:29:01 +00:00 (Migrated from github.com)

RAGE adversarial gate — HOLD current #221 head

Re-audited #175 against current main 267697bef10a3fffff7c093e1435ece770e7444b, PR #221 exact head 134a87d1654ce79ce6520eba1d32cd6229ffb07e, its patch, downstream ownership, and exact-head CI.

What is good

  • The recovery preserves the current #172 compiler-authenticated rlm_subagent_register_command/8 path and role/skill/source provenance rather than replacing it with stale #212 code.
  • Timeout policy remains host-owned; model input only gets optional timeout_seconds.
  • Over-max requests fail before spawn; outer tool and supervised-call envelopes are bounded by host policy + cleanup grace.
  • Existing budget.time_limit is preserved as the legacy default when no dedicated subagent default exists, fixing the deterministic #212 precedence failure without weakening capability checks.
  • Exact head is mergeable and all returned workflows are green: deterministic CI including REAL OpenRouter, Paid OpenRouter, Nix flake, clean SWI pack, and Tree-sitter. Reviews/comments/threads are empty.

Adversarial blocker

The current green head does not yet satisfy #175's declared acceptance contract. #175 explicitly requires the full regression matrix and public runtime docs. #221 currently changes only:

  • prolog/rlm_subagent.pl
  • test/rlm_subagent_test.pl
  • research/RLM-RESEARCH-026-task-deadlines.org

The branch adds coverage for schema exposure, outer max+grace, omitted default, explicit override, and over-max pre-spawn rejection, while existing tests cover some generic timeout/capability/cancellation behavior. But the issue still explicitly requires focused contracts for zero/negative/schema-invalid input, preservation of non-time budget fields, host-owned rejection of max/default/grace/budget model fields, structured completion-timeout envelope, timeout-with-capability denial, Future-await independence, and cleanup/no-running-child semantics.

It also explicitly requires updates to docs/agent-runtime.md, docs/completion-runtime.md, and docs/async-runtime.md. None are present in the current PR, despite this being a public behavior change.

Decision

HOLD promotion/merge of 134a87d1…. Keep #221 draft. Do not weaken the issue checklist because the aggregate suite is green. Add the missing deterministic contracts and required docs, then invalidate this exact-head evidence and rerun the complete gate on the new SHA.

The stale CI report #220 for test-only head f4902c32… has been closed because the branch's current head resolves that specific reported failure.

## RAGE adversarial gate — HOLD current #221 head Re-audited #175 against current `main` `267697bef10a3fffff7c093e1435ece770e7444b`, PR #221 exact head `134a87d1654ce79ce6520eba1d32cd6229ffb07e`, its patch, downstream ownership, and exact-head CI. ### What is good - The recovery preserves the current #172 compiler-authenticated `rlm_subagent_register_command/8` path and role/skill/source provenance rather than replacing it with stale #212 code. - Timeout policy remains host-owned; model input only gets optional `timeout_seconds`. - Over-max requests fail before spawn; outer tool and supervised-call envelopes are bounded by host policy + cleanup grace. - Existing `budget.time_limit` is preserved as the legacy default when no dedicated subagent default exists, fixing the deterministic #212 precedence failure without weakening capability checks. - Exact head is mergeable and all returned workflows are green: deterministic CI including REAL OpenRouter, Paid OpenRouter, Nix flake, clean SWI pack, and Tree-sitter. Reviews/comments/threads are empty. ### Adversarial blocker The current green head does **not yet satisfy #175's declared acceptance contract**. #175 explicitly requires the full regression matrix and public runtime docs. #221 currently changes only: - `prolog/rlm_subagent.pl` - `test/rlm_subagent_test.pl` - `research/RLM-RESEARCH-026-task-deadlines.org` The branch adds coverage for schema exposure, outer max+grace, omitted default, explicit override, and over-max pre-spawn rejection, while existing tests cover some generic timeout/capability/cancellation behavior. But the issue still explicitly requires focused contracts for zero/negative/schema-invalid input, preservation of non-time budget fields, host-owned rejection of max/default/grace/budget model fields, structured completion-timeout envelope, timeout-with-capability denial, Future-await independence, and cleanup/no-running-child semantics. It also explicitly requires updates to `docs/agent-runtime.md`, `docs/completion-runtime.md`, and `docs/async-runtime.md`. None are present in the current PR, despite this being a public behavior change. ### Decision **HOLD promotion/merge of `134a87d1…`.** Keep #221 draft. Do not weaken the issue checklist because the aggregate suite is green. Add the missing deterministic contracts and required docs, then invalidate this exact-head evidence and rerun the complete gate on the new SHA. The stale CI report #220 for test-only head `f4902c32…` has been closed because the branch's current head resolves that specific reported failure.
lost-rob0t commented 2026-08-26 08:14:46 +00:00 (Migrated from github.com)

RAGE regression evidence on #221 exact head 9bf2431337d2604e4ad95ed2dc5a5d1464df9560:

The newly registered deadline acceptance suite made canonical deterministic CI fail 2/900 tests. Both failures are zero/negative timeout_seconds cases. The rlm_subagent schema declares timeout_seconds: {type:number, exclusiveMinimum:0}, but the generic rlm_tool schema validator currently checks only number(Value) and ignores exclusiveMinimum. As a result, zero/negative values cross the schema boundary and are rejected later by timeout policy as a successful tool execution carrying subagent_result{status:failed,error.kind:invalid_timeout,child:none} instead of a schema-level invocation rejection.

Analyze/research: validate_schema_definition/1 accepts numeric schemas; validate_schema_value/3 -> validate_type/4 enforces only the base type. This is a generic tool-schema correctness gap, not a subagent-only design problem. Non-number and closed-schema host-option rejection are already behaving correctly.

Design: teach the canonical rlm_tool validator the smallest required numeric keyword, exclusiveMinimum, including schema-definition validation (numeric bound, only valid for integer/number schemas) and runtime enforcement after the base numeric type check. Keep the #175 tests unchanged; zero/negative must be rejected before capability/authority/child creation. Do not move this into rlm_subagent preflight or accept the later failed envelope, because that would leave the declared schema contract false.

Adversarial review: this narrows accepted model data only; it cannot widen capability/authority/effect semantics. It also applies uniformly to edited operations because both invocation and edit validation use validate_schema/4. Invalid schema definitions should fail at registration rather than silently advertise unsupported constraints.

Decision: GO on the generic validator fix within the existing #221 transaction. The branch stays draft/red until the unchanged deadline regressions and full exact-head gate pass.

RAGE regression evidence on #221 exact head `9bf2431337d2604e4ad95ed2dc5a5d1464df9560`: The newly registered deadline acceptance suite made canonical deterministic CI fail 2/900 tests. Both failures are zero/negative `timeout_seconds` cases. The `rlm_subagent` schema declares `timeout_seconds: {type:number, exclusiveMinimum:0}`, but the generic `rlm_tool` schema validator currently checks only `number(Value)` and ignores `exclusiveMinimum`. As a result, zero/negative values cross the schema boundary and are rejected later by timeout policy as a successful tool execution carrying `subagent_result{status:failed,error.kind:invalid_timeout,child:none}` instead of a schema-level invocation rejection. Analyze/research: `validate_schema_definition/1` accepts numeric schemas; `validate_schema_value/3 -> validate_type/4` enforces only the base type. This is a generic tool-schema correctness gap, not a subagent-only design problem. Non-number and closed-schema host-option rejection are already behaving correctly. Design: teach the canonical `rlm_tool` validator the smallest required numeric keyword, `exclusiveMinimum`, including schema-definition validation (numeric bound, only valid for integer/number schemas) and runtime enforcement after the base numeric type check. Keep the #175 tests unchanged; zero/negative must be rejected before capability/authority/child creation. Do not move this into `rlm_subagent` preflight or accept the later failed envelope, because that would leave the declared schema contract false. Adversarial review: this narrows accepted model data only; it cannot widen capability/authority/effect semantics. It also applies uniformly to edited operations because both invocation and edit validation use `validate_schema/4`. Invalid schema definitions should fail at registration rather than silently advertise unsupported constraints. Decision: GO on the generic validator fix within the existing #221 transaction. The branch stays draft/red until the unchanged deadline regressions and full exact-head gate pass.
lost-rob0t commented 2026-08-26 08:16:23 +00:00 (Migrated from github.com)

RAGE design correction after reconciling the exact CI evidence with this issue's acceptance text:

My prior note over-constrained cases 4/5. #175 says zero and negative requests must be rejected before spawn, with the suggested failure subagent_error{phase:timeout_policy,kind:invalid_timeout,...}. Exact head 9bf24313... returned precisely that structured failed subagent_result, with correlation.child == none; it did not create a child. Only case 6 explicitly requires schema rejection for a non-number, and that case passes.

So the two CI failures are test-contract bugs in the newly added acceptance helper, not a #175 runtime failure. Per RAGE semantics I am not patching production around a disproven test assumption. I will change only the zero/negative assertions to require the exact structured timeout-policy failure plus no child creation. The non-number and host-only closed-schema cases continue to require tool/schema rejection.

Separate finding retained for later backlog work: generic rlm_tool currently advertises but does not enforce numeric exclusiveMinimum at invocation validation. That is a real generic schema-feature gap, but #175 already has an explicit host-side positive-number guard and does not require zero/negative to fail specifically at schema phase. It should not be smuggled into this deadline PR unless separately scoped/TDD'd.

RAGE design correction after reconciling the exact CI evidence with this issue's acceptance text: My prior note over-constrained cases 4/5. #175 says zero and negative requests must be **rejected before spawn**, with the suggested failure `subagent_error{phase:timeout_policy,kind:invalid_timeout,...}`. Exact head `9bf24313...` returned precisely that structured failed `subagent_result`, with `correlation.child == none`; it did not create a child. Only case 6 explicitly requires schema rejection for a non-number, and that case passes. So the two CI failures are test-contract bugs in the newly added acceptance helper, not a #175 runtime failure. Per RAGE semantics I am not patching production around a disproven test assumption. I will change only the zero/negative assertions to require the exact structured timeout-policy failure plus no child creation. The non-number and host-only closed-schema cases continue to require tool/schema rejection. Separate finding retained for later backlog work: generic `rlm_tool` currently advertises but does not enforce numeric `exclusiveMinimum` at invocation validation. That is a real generic schema-feature gap, but #175 already has an explicit host-side positive-number guard and does not require zero/negative to fail specifically at schema phase. It should not be smuggled into this deadline PR unless separately scoped/TDD'd.
lost-rob0t commented 2026-08-26 08:20:18 +00:00 (Migrated from github.com)

Exact-head verification / promotion update:

Candidate 1dc3fc0f4f8b4e6dd51819e744e57af0cb70c63d is now green on every returned required workflow. Canonical deterministic CI reports 79 suites / 900 discovered / 900 planned / 900 completed / 900 passed, with 0 failed, timeout, blocked, or fixme. Deterministic benchmark/conformance is 16/16; deep recursion is 15/15. Credential-backed REAL OpenRouter passed core, structured repair, benchmark, depth 0/1/2 and CLI smoke. Paid OpenRouter, Nix flake, clean SWI-pack install, and Tree-sitter FFI are also successful.

The deadline-specific acceptance matrix and all three required public docs are now present. PR #221 is based directly on current main (behind_by:0), GitHub reports it mergeable, and it has no reviews/comments/unresolved threads. Adversarial decision is now GO; PR #221 has been promoted from draft to ready-for-review.

I am not merging in this step because the repository-level AGENTS.md merge rule still requires explicit merge-on-green authorization for the transaction.

Exact-head verification / promotion update: Candidate `1dc3fc0f4f8b4e6dd51819e744e57af0cb70c63d` is now green on every returned required workflow. Canonical deterministic CI reports 79 suites / 900 discovered / 900 planned / 900 completed / **900 passed**, with 0 failed, timeout, blocked, or fixme. Deterministic benchmark/conformance is 16/16; deep recursion is 15/15. Credential-backed REAL OpenRouter passed core, structured repair, benchmark, depth 0/1/2 and CLI smoke. Paid OpenRouter, Nix flake, clean SWI-pack install, and Tree-sitter FFI are also successful. The deadline-specific acceptance matrix and all three required public docs are now present. PR #221 is based directly on current `main` (`behind_by:0`), GitHub reports it mergeable, and it has no reviews/comments/unresolved threads. Adversarial decision is now GO; PR #221 has been promoted from draft to ready-for-review. I am not merging in this step because the repository-level `AGENTS.md` merge rule still requires explicit merge-on-green authorization for the transaction.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
nsaspy/prolog-rlm#175
No description provided.