docs(design): record D6-11 plan-native deterministic mutations (#355) #348

Open
nsaspy wants to merge 3 commits from issue-355 into main
Owner

Runtime invariant implemented

Records D6-11 verbatim in docs/research/spec-plan-authority.md §6.3 (operator decision, Forgejo #293 comment 3762), amending D6-8:

D6-11 plan-native deterministic mutations. The closed set sync_remote/1, run/1, index/1, delete/1 executes at the plan layer through the canonical boundary (schema → capability → authority → durable effect admission → dispatch → observe), exactly like a tool/3 step — never ambient shell/git access in plan code. They are excluded from expert mapping and from the future expert registry. Model-payload mutations (edit/2, create/2) remain write-expert-owned per §8.3.

D6-8 now explicitly references the D6-11 exclusion, so the two rules no longer sit in tension; §6.2 and the §8.1 expert-contract record carry matching cross-references.

Design-gate evidence (rage/288 BASE, pinned 71a10ae)

New plan_native_checks gate group, verified against the loaded BASE module:

  • plan_native_set_closed_in_base_vocabulary — the four ops stay inside the closed BASE vocabulary; edit/2/create/2 are never members.
  • plan_native_capability_denied_fail_closed / plan_native_capability_exact_admission — ungranted capability is a validation error; the required term is exactly tool(Op) (plan-layer capability, not an expert-contract capability).
  • plan_native_desugar_is_canonical_tool_step — each op desugars mechanically to plan([tool(Op, literal(Args), Bind), final(var(Bind))]).

Behavioral evidence (merged main)

test/rlm_plan_native_ops_test.pl (registered in the deterministic corpus) executes the canonical desugared form through the rlm_plan validate/execute ABIs with plan-native host handlers routed through the canonical rlm_tool registry — the same wiring the plan-graph reconciliation will use:

  • ungranted capability fails closed at whole-plan validation before any dispatch (externally observable adapter counter stays at zero);
  • an admitted effect produces the content-derived normalized fingerprint — a sha256:-prefixed scalar on the durable observed attempt, identical across fresh effect stores;
  • an identical re-execution replays off that fingerprint with no second external dispatch and no second durable attempt;
  • the observation op (index, effect class observation) re-executes fresh and never enters the durable effect store;
  • edit/2/create/2 have no plan-native path in the suite (the set is pinned closed).

Reconciliation in the same slice

  • RLM-RESEARCH-353 (docs/research/expert-direct-tool-projection.org) scope boundary: the plan-native set is never projected as direct-mode expert tools; direct mode reaches these ops only via typed_plan_execute.
  • docs/prolog-agent-roadmap.md: D6-11 noted in the SPEC/PLAN substrate paragraph.
  • Parent issue #288 body prose reconciled (expert-registry role now states the D6-11 exclusion; the effect-boundary invariant line no longer calls these ops "experts").

Non-goals

  • No implementation of the plan-graph executor itself (parent #288 owns it; the BASE branch is unchanged).
  • No new external-effect path in the plan interpreter: plan code gains no ambient shell/git authority; the adapters in the test are host-supplied static closures behind the canonical registry boundary.
  • No expert registry/contract implementation (S5/S10 slices).

Evidence

  • swipl -q -s scripts/design_gate.pl — ALL CHECKS PASSED (incl. new group)
  • swipl -q -s test/run_tests.pl — 1183/1183 (97 suites, incl. rlm_plan_native_ops)
  • swipl -q -s test/check_runtime.pl, swipl -q -s test/load_all.pl, swipl -q -s benchmark/run.pl -- deterministic, bin/prolog-rlm.pl -- demo --json, make research-approval, git diff --check — all green
  • prolog-verify check — verification passed at the exact PR head (machine-recorded observations in .prolog/)

Refs #355 #288

## Runtime invariant implemented Records **D6-11** verbatim in `docs/research/spec-plan-authority.md` §6.3 (operator decision, Forgejo #293 comment 3762), amending D6-8: > **D6-11 plan-native deterministic mutations.** The closed set `sync_remote/1`, `run/1`, `index/1`, `delete/1` executes at the plan layer through the canonical boundary (schema → capability → authority → durable effect admission → dispatch → observe), exactly like a `tool/3` step — never ambient shell/git access in plan code. They are excluded from expert mapping and from the future expert registry. Model-payload mutations (`edit/2`, `create/2`) remain write-expert-owned per §8.3. D6-8 now explicitly references the D6-11 exclusion, so the two rules no longer sit in tension; §6.2 and the §8.1 expert-contract record carry matching cross-references. ## Design-gate evidence (rage/288 BASE, pinned `71a10ae`) New `plan_native_checks` gate group, verified against the loaded BASE module: - `plan_native_set_closed_in_base_vocabulary` — the four ops stay inside the closed BASE vocabulary; `edit/2`/`create/2` are never members. - `plan_native_capability_denied_fail_closed` / `plan_native_capability_exact_admission` — ungranted capability is a validation error; the required term is exactly `tool(Op)` (plan-layer capability, not an expert-contract capability). - `plan_native_desugar_is_canonical_tool_step` — each op desugars mechanically to `plan([tool(Op, literal(Args), Bind), final(var(Bind))])`. ## Behavioral evidence (merged main) `test/rlm_plan_native_ops_test.pl` (registered in the deterministic corpus) executes the canonical desugared form through the `rlm_plan` validate/execute ABIs with plan-native host handlers routed through the canonical `rlm_tool` registry — the same wiring the plan-graph reconciliation will use: - ungranted capability fails closed at whole-plan validation **before any dispatch** (externally observable adapter counter stays at zero); - an admitted effect produces the content-derived normalized fingerprint — a `sha256:`-prefixed scalar on the durable observed attempt, **identical across fresh effect stores**; - an identical re-execution replays off that fingerprint with **no second external dispatch and no second durable attempt**; - the observation op (`index`, effect class `observation`) re-executes fresh and never enters the durable effect store; - `edit/2`/`create/2` have no plan-native path in the suite (the set is pinned closed). ## Reconciliation in the same slice - RLM-RESEARCH-353 (`docs/research/expert-direct-tool-projection.org`) scope boundary: the plan-native set is never projected as direct-mode expert tools; direct mode reaches these ops only via `typed_plan_execute`. - `docs/prolog-agent-roadmap.md`: D6-11 noted in the SPEC/PLAN substrate paragraph. - Parent issue #288 body prose reconciled (expert-registry role now states the D6-11 exclusion; the effect-boundary invariant line no longer calls these ops "experts"). ## Non-goals - No implementation of the plan-graph executor itself (parent #288 owns it; the BASE branch is unchanged). - No new external-effect path in the plan interpreter: plan code gains no ambient shell/git authority; the adapters in the test are host-supplied static closures behind the canonical registry boundary. - No expert registry/contract implementation (S5/S10 slices). ## Evidence - `swipl -q -s scripts/design_gate.pl` — ALL CHECKS PASSED (incl. new group) - `swipl -q -s test/run_tests.pl` — 1183/1183 (97 suites, incl. `rlm_plan_native_ops`) - `swipl -q -s test/check_runtime.pl`, `swipl -q -s test/load_all.pl`, `swipl -q -s benchmark/run.pl -- deterministic`, `bin/prolog-rlm.pl -- demo --json`, `make research-approval`, `git diff --check` — all green - `prolog-verify check` — verification passed at the exact PR head (machine-recorded observations in `.prolog/`) Refs #355 #288
Records D6-11 verbatim in docs/research/spec-plan-authority.md §6.3 per
the operator decision on Forgejo #293 (comment 3762): the closed set
sync_remote/1, run/1, index/1, delete/1 executes at the plan layer
through the canonical boundary (schema -> capability -> authority ->
durable effect admission -> dispatch -> observe), exactly like a tool/3
step — never ambient shell/git access in plan code. D6-8 now explicitly
references the exclusion, so the two rules no longer sit in tension;
edit/2 and create/2 remain write-expert-owned per §8.3.

Design gate: new plan_native_checks group pins the closed set against
the loaded rage/288 BASE module — vocabulary containment, per-op
capability fail-closed (ungranted -> validation error) and exact
admission (tool(Op)), and the canonical desugared form
plan([tool(Op, literal(Args), Bind), final(var(Bind))]).

Behavioral evidence on merged main: test/rlm_plan_native_ops_test.pl
executes the canonical desugared form through the rlm_plan
validate/execute ABIs with plan-native handlers routed through the
canonical rlm_tool registry — an ungranted capability fails closed
before any dispatch (externally observable counter stays at zero), an
admitted effect produces the content-derived normalized fingerprint
(deterministic across fresh stores), an identical re-execution replays
off that fingerprint without a second dispatch or durable attempt, and
the observation op (index) re-executes fresh and never enters the
durable effect store. edit/create have no plan-native path.

RLM-RESEARCH-353 scope boundary: the plan-native set is never projected
as direct-mode expert tools; direct mode reaches these ops only via
typed_plan_execute. Roadmap and parent issue #288 prose reconciled in
the same slice.
style: whitespace hygiene in research records (unblocks CI base diff)
Some checks failed
Tree-sitter FFI / Direct SWI-Prolog Tree-sitter FFI (pull_request) Failing after 38s
CI / Deterministic unit and load checks (pull_request) Successful in 1m59s
CI / REAL OpenRouter integration (pull_request) Has been skipped
Nix flake / Flake package and clean runtime load (pull_request) Failing after 5s
Clean SWI pack install / Install and load copied pack (pull_request) Successful in 1m13s
Paid OpenRouter / Pinned paid OpenRouter integration (pull_request) Failing after 55s
6d82a20281
Trailing whitespace in expert-direct-tool-projection.org (Q5 answer
blank lines) and rage/97-query-capture-apis.org (line 24), and a blank
line at EOF in rage/97-query-capture-notes.org. The GitHub mirror's
main is 23 commits behind Forgejo main, so the PR base diff includes
these lines as additions and the CI whitespace gate fails on them.
Whitespace-only: no content change.
Some checks failed
Tree-sitter FFI / Direct SWI-Prolog Tree-sitter FFI (pull_request) Failing after 38s
CI / Deterministic unit and load checks (pull_request) Successful in 1m59s
CI / REAL OpenRouter integration (pull_request) Has been skipped
Nix flake / Flake package and clean runtime load (pull_request) Failing after 5s
Clean SWI pack install / Install and load copied pack (pull_request) Successful in 1m13s
Paid OpenRouter / Pinned paid OpenRouter integration (pull_request) Failing after 55s
This pull request has changes conflicting with the target branch.
  • .prolog/facts.kb
  • .prolog/verify.pl
  • scripts/design_gate.pl
  • test/rlm_plan_native_ops_test.pl
View command line instructions

Manual merge helper

Use this merge commit message when completing the merge manually.

Checkout

From your project repository, check out a new branch and test the changes.
git fetch -u origin issue-355:issue-355
git switch issue-355

Merge

Merge the changes and update on Forgejo.

Warning: The "Autodetect manual merge" setting is not enabled for this repository, you will have to mark this pull request as manually merged afterwards.

git switch main
git merge --no-ff issue-355
git switch issue-355
git rebase main
git switch main
git merge --ff-only issue-355
git switch issue-355
git rebase main
git switch main
git merge --no-ff issue-355
git switch main
git merge --squash issue-355
git switch main
git merge --ff-only issue-355
git switch main
git merge issue-355
git push origin main
Sign in to join this conversation.
No description provided.