Implement typed allow-listed plan runtime (#7) #26

Merged
lost-rob0t merged 10 commits from feature/issue-7-typed-plan-runtime into main 2026-08-12 11:16:04 +00:00
lost-rob0t commented 2026-08-12 02:34:02 +00:00 (Migrated from github.com)

Closes #7.

Closed typed plan AST

  • add rlm_plan parser, normalizer, whole-plan validator, interpreter, and shared runtime budgets
  • model JSON is decoded as JSON only; there is no Prolog read_term fallback
  • supported operations: context, model, recursive RLM, tool, parallel, retry, checkpoint, final
  • supported expressions are closed references/literals/lists/objects/field access
  • final/1 must be unique and last
  • variable bindings are statically checked for ordering and duplication

Capability and execution boundary

  • every operation requires an explicit granted capability
  • context transform/reducer/partition/selector vocabularies are allow-listed
  • every named provider/tool is preflighted across the entire validated plan before the first side effect
  • model-selected tool names do not become callables; only host-supplied trusted closures from tools([tool(Name, Handler)]) can be invoked
  • there is no model-exposed unrestricted call/1, shell, consult, filesystem, or arbitrary evaluator path

Budgets

  • static worst-case checks for steps, recursion depth, parallel width, model calls, tool calls, and context operations
  • retry multiplies nested worst-case cost
  • partial budget dicts overlay explicit defaults before validation
  • global runtime counters are shared through recursive/retry/parallel execution
  • output byte budget is global across intermediate bindings and final values
  • wall-time budget is enforced with structured timeout errors

Structured execution

  • structured parse/validation/preflight/execute failures
  • structured transitions contain sequence, operation, bind, status but no provider credentials/headers or model content
  • checkpoints are runtime state only, not implicit persistence or I/O

Deterministic tests

Coverage includes:

  • model JSON and fenced JSON parsing
  • context -> trusted tool -> final execution
  • rejection of raw call(...) and unknown JSON operators
  • capability denial before side effects
  • unknown tool/provider preflight before prior context work
  • duplicate/unbound bindings
  • retry/depth/static budgets
  • shared nested output budgets
  • parallel result collection
  • retry with a trusted flaky test closure
  • checkpoint transitions
  • invalid context map transform and final ordering

REAL OpenRouter typed-plan test

The live suite now performs a second real OpenRouter inference that asks the routed model to select a JSON typed plan. That actual model-produced plan is parsed and then executes:

REAL OpenRouter model -> typed JSON plan -> opaque context search -> trusted count_items tool -> final result

The test requires final value 2 and structured context/tool/final transitions. No fake provider appears in this path. The live log emits only allow-listed plan_* evidence fields; it never prints generated plan JSON, response text, reasoning text, API keys, Authorization headers, or environment dumps.

This PR must not merge until both deterministic CI and the same-repository REAL OpenRouter job are green and the final credential/diff scan is clean.

Closes #7. ## Closed typed plan AST - add `rlm_plan` parser, normalizer, whole-plan validator, interpreter, and shared runtime budgets - model JSON is decoded as JSON only; there is no Prolog `read_term` fallback - supported operations: context, model, recursive RLM, tool, parallel, retry, checkpoint, final - supported expressions are closed references/literals/lists/objects/field access - `final/1` must be unique and last - variable bindings are statically checked for ordering and duplication ## Capability and execution boundary - every operation requires an explicit granted capability - context transform/reducer/partition/selector vocabularies are allow-listed - every named provider/tool is preflighted across the entire validated plan before the first side effect - model-selected tool names do not become callables; only host-supplied trusted closures from `tools([tool(Name, Handler)])` can be invoked - there is no model-exposed unrestricted `call/1`, shell, consult, filesystem, or arbitrary evaluator path ## Budgets - static worst-case checks for steps, recursion depth, parallel width, model calls, tool calls, and context operations - retry multiplies nested worst-case cost - partial budget dicts overlay explicit defaults before validation - global runtime counters are shared through recursive/retry/parallel execution - output byte budget is global across intermediate bindings and final values - wall-time budget is enforced with structured timeout errors ## Structured execution - structured parse/validation/preflight/execute failures - structured transitions contain sequence, operation, bind, status but no provider credentials/headers or model content - checkpoints are runtime state only, not implicit persistence or I/O ## Deterministic tests Coverage includes: - model JSON and fenced JSON parsing - context -> trusted tool -> final execution - rejection of raw `call(...)` and unknown JSON operators - capability denial before side effects - unknown tool/provider preflight before prior context work - duplicate/unbound bindings - retry/depth/static budgets - shared nested output budgets - parallel result collection - retry with a trusted flaky test closure - checkpoint transitions - invalid context map transform and final ordering ## REAL OpenRouter typed-plan test The live suite now performs a second real OpenRouter inference that asks the routed model to select a JSON typed plan. That actual model-produced plan is parsed and then executes: `REAL OpenRouter model -> typed JSON plan -> opaque context search -> trusted count_items tool -> final result` The test requires final value `2` and structured context/tool/final transitions. No fake provider appears in this path. The live log emits only allow-listed `plan_*` evidence fields; it never prints generated plan JSON, response text, reasoning text, API keys, Authorization headers, or environment dumps. This PR must not merge until both deterministic CI and the same-repository REAL OpenRouter job are green and the final credential/diff scan is clean.
Sign in to join this conversation.
No description provided.