[P0] Canonicalize anonymous SWI dict tags across deterministic runtime identities #154

Closed
opened 2026-08-21 22:12:09 +00:00 by lost-rob0t · 1 comment
lost-rob0t commented 2026-08-21 22:12:09 +00:00 (Migrated from github.com)

Failure

Restoring the real aggregate PlUnit runner in #151/#152 exposed a shared deterministic-normalization defect across multiple merged runtime surfaces.

SWI anonymous dict syntax such as _{a:1} carries a variable dict tag. Several core canonicalizers preserve that representation-only variable tag or reject the entire otherwise-ground payload as nonground. This makes logically identical values unstable or invalid across repeated calls.

Concrete evidence from the restored suite includes:

  • rlm_authority: two calls to rlm_operation_fingerprint/3 over the same operation produce different SHA-256 fingerprints;
  • authority hardening: incidental-correlation equivalence fingerprints differ;
  • rlm_effect: otherwise-ground requests/options containing anonymous nested dicts fail as nonground/instantiation errors;
  • completion/spec/evolution/compiler tests show the same family of failures.

This is the same representation issue already fixed narrowly for recursive-plan fingerprints in #135, where canonical_recursive_dict_tag/2 maps a variable dict tag to the stable sentinel rlm_anonymous_dict.

Root cause pattern

Canonicalizers currently do variants of:

dict_pairs(Value, Tag, Pairs0),
...
dict_pairs(Canonical, Tag, Pairs).

or apply ground/1 to the whole dict term before treating an anonymous tag as representation-only.

A variable anonymous tag must not become semantic identity and must not make a closed dict payload fail deterministic normalization.

Required invariant

For closed data APIs, anonymous SWI dict tags are representation-only:

_{a:1,b:_{c:2}}

must normalize deterministically to the same closed canonical value on every call. A genuinely variable dict value, list member, compound argument, key-bearing semantic field, or executable field must still fail closed.

Named dict tags remain semantic and must be preserved.

Scope

Audit and fix every deterministic identity/normalization boundary that handles closed runtime data, especially current failures in:

  • authority operation fingerprints;
  • durable effect request/options/identity;
  • Spec/assertion/evidence identity;
  • prompt/compiler fingerprints;
  • evolution candidate/config normalization;
  • any shared tool/chain/runtime canonicalizer using the same pattern.

Prefer one small shared helper if it reduces duplicated security-sensitive normalization without creating a generic untyped fact layer. Otherwise apply the same explicit rule at each owning module boundary.

TDD / acceptance

  • same anonymous-tag operation produces byte-identical authority fingerprint across repeated calls;
  • correlation-only differences remain excluded where already specified;
  • nested anonymous dict request/semantics data normalizes as closed effect data;
  • named dict tags remain preserved and identity-relevant where currently intended;
  • genuine variables inside values still fail closed;
  • cyclic values still fail closed;
  • recursive-plan #135 behavior remains correct;
  • focused authority/effect/spec/compiler/evolution regressions pass;
  • restored aggregate swipl -q -s test/run_tests.pl is the merge oracle and cannot be replaced by the focused async runner;
  • do not weaken or delete failing tests to obtain green.

Coordination

Base remediation on the #152 runner-integrity head until #152 lands, so failures are measured through the real aggregate gate. Keep #149 ownership untouched.

Discovered during the post-false-green audit of work merged after #60.

## Failure Restoring the real aggregate PlUnit runner in #151/#152 exposed a shared deterministic-normalization defect across multiple merged runtime surfaces. SWI anonymous dict syntax such as `_{a:1}` carries a variable dict tag. Several core canonicalizers preserve that representation-only variable tag or reject the entire otherwise-ground payload as nonground. This makes logically identical values unstable or invalid across repeated calls. Concrete evidence from the restored suite includes: - `rlm_authority`: two calls to `rlm_operation_fingerprint/3` over the same operation produce different SHA-256 fingerprints; - authority hardening: incidental-correlation equivalence fingerprints differ; - `rlm_effect`: otherwise-ground requests/options containing anonymous nested dicts fail as nonground/instantiation errors; - completion/spec/evolution/compiler tests show the same family of failures. This is the same representation issue already fixed narrowly for recursive-plan fingerprints in #135, where `canonical_recursive_dict_tag/2` maps a variable dict tag to the stable sentinel `rlm_anonymous_dict`. ## Root cause pattern Canonicalizers currently do variants of: ```prolog dict_pairs(Value, Tag, Pairs0), ... dict_pairs(Canonical, Tag, Pairs). ``` or apply `ground/1` to the whole dict term before treating an anonymous tag as representation-only. A variable anonymous tag must not become semantic identity and must not make a closed dict payload fail deterministic normalization. ## Required invariant For closed data APIs, anonymous SWI dict tags are representation-only: ```text _{a:1,b:_{c:2}} ``` must normalize deterministically to the same closed canonical value on every call. A genuinely variable dict value, list member, compound argument, key-bearing semantic field, or executable field must still fail closed. Named dict tags remain semantic and must be preserved. ## Scope Audit and fix every deterministic identity/normalization boundary that handles closed runtime data, especially current failures in: - authority operation fingerprints; - durable effect request/options/identity; - Spec/assertion/evidence identity; - prompt/compiler fingerprints; - evolution candidate/config normalization; - any shared tool/chain/runtime canonicalizer using the same pattern. Prefer one small shared helper if it reduces duplicated security-sensitive normalization without creating a generic untyped fact layer. Otherwise apply the same explicit rule at each owning module boundary. ## TDD / acceptance - [ ] same anonymous-tag operation produces byte-identical authority fingerprint across repeated calls; - [ ] correlation-only differences remain excluded where already specified; - [ ] nested anonymous dict request/semantics data normalizes as closed effect data; - [ ] named dict tags remain preserved and identity-relevant where currently intended; - [ ] genuine variables inside values still fail closed; - [ ] cyclic values still fail closed; - [ ] recursive-plan #135 behavior remains correct; - [ ] focused authority/effect/spec/compiler/evolution regressions pass; - [ ] restored aggregate `swipl -q -s test/run_tests.pl` is the merge oracle and cannot be replaced by the focused async runner; - [ ] do not weaken or delete failing tests to obtain green. ## Coordination Base remediation on the #152 runner-integrity head until #152 lands, so failures are measured through the real aggregate gate. Keep #149 ownership untouched. Discovered during the post-false-green audit of work merged after #60.
lost-rob0t commented 2026-08-24 08:05:38 +00:00 (Migrated from github.com)

Completed on current main through the integrated closed-data boundary in #177. Exact current-main focused verification passed 136/136 across closed-data, authority/effect identity, Spec, prompt compiler, and evolution; full aggregate passed 762/762. PR #155 was closed as superseded.

Completed on current main through the integrated closed-data boundary in #177. Exact current-main focused verification passed 136/136 across closed-data, authority/effect identity, Spec, prompt compiler, and evolution; full aggregate passed 762/762. PR #155 was closed as superseded.
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#154
No description provided.