Skip to content

Decode embedded-encoding strings by one shared policy in both body-diff engines - #94

Open
iemyashasvi wants to merge 2 commits into
mainfrom
work/embedded-string-canon
Open

iemyashasvi wants to merge 2 commits into
mainfrom
work/embedded-string-canon

Conversation

@iemyashasvi

Copy link
Copy Markdown
Collaborator

What happened

Replay rp-sbx-97ed6d68b9-1788270827951761795-0901144939416 failed with 17 BodyMismatches while the report rendered "0 response fields differ" beside them. Main has two body-diff engines since 6a0e2dc: the kernel's diff_json (writes body_diff, decodes embedded-JSON strings and form-pair strings) and the scorer's order-canonical recompute (decides the verdict, read strings as bytes). Prism's rawConnectorRequest echo — an embedded JSON string whose headers map serializes in per-process HashMap order, carrying a form-encoded body whose pair order is random too — passed one engine and blocked the other, on every response, for identical behavior.

The fix

WHAT a string carries is now the kernel's decoding policy, stated once and imported by both engines:

  • embedded_json_documents (pub, hoisted from diff_json's own arm): both sides must parse to an object or array — scalars keep byte semantics, prose stays opaque, a document on one side only is a real difference.
  • parse_form_pairs / diff_form_pairs (now pub): the strict form qualifier and the pair-order policy (distinct keys order-insensitive, repeated keys keep relative order, values stay percent-encoded).

HOW a decoded document is compared stays each engine's own recursion: inside an embedded string the recompute's array canon applies exactly as outside one, and nested encodings (the echo's form body) re-enter the arm on recursion. Seeing through the encoding is not tolerance — a genuinely changed inner value still blocks, at its inner path. The tape is never touched: this normalizes judgment, not evidence.

Verification

  • All 18 recorded/replayed body pairs from the failing run are equivalent under the shared policy (checked against the run's captured http-diffs; the test fixture is that literal shape with synthesized credentials).
  • New tests: the measured echo reduces to no difference; a real inner change reports at its inner path; an array inside an embedded document uses the array canon; prose strings keep byte semantics.
  • Full suites green: deja-kernel 34, deja-orchestrator 405.

@iemyashasvi
iemyashasvi force-pushed the work/embedded-string-canon branch from ae4b4cd to f084853 Compare September 2, 2026 13:47
@maverox maverox assigned maverox and iemyashasvi and unassigned maverox Sep 2, 2026
…ff engines

The scorer's order-canonical body recompute (the engine whose rows decide
BodyMismatch) read strings as bytes while the kernel's diff_json decoded
them — so prism's rawConnectorRequest echo, an embedded JSON string whose
headers map serializes in per-process HashMap order, produced zero kernel
rows and 17 blocking recompute leaves on the same replay, and the report
said '0 response fields differ' beside a body-mismatch verdict.

WHAT a string carries is now the kernel's decoding policy, stated once and
imported: embedded_json_documents (both sides parse to an object or array)
and the strict form-pair qualifier become pub. HOW a decoded document is
compared stays each engine's own recursion — inside an embedded string the
recompute's array canon applies exactly as outside one, and the echo's
form-encoded body string re-enters the arm on recursion. Seeing through the
encoding is not tolerance: a genuinely changed inner value still blocks, at
its inner path.

Verified against the measured run: all 18 recorded/replayed body pairs from
rp-sbx-97ed6d68b9-1788270827951761795-0901144939416 are equivalent under the
shared policy; the fixture in the tests is that shape with synthesized
credentials.
…and pin the incident it exists for

Two things changed under this branch in the thirteen days it sat unmerged.

rustfmt wants the `else if let (Some(bp), Some(cp))` tuple broken across
lines; that was the whole of the failing `rust` check.

Main now absorbs a pure permutation by the default rule (`canon_absorbed`,
`ClauseSource::Default`) instead of counting it as one blocking ordering
fact, so `an_array_inside_an_embedded_document_uses_the_array_canon` asserted
the old rule. Its own doc string already said an array inside a document must
behave exactly as one outside it, so the test now asserts what the outside
does: not blocking, absorbed at `$.doc.tags`, no `order_only_paths`.

And the incident that motivates the arm is pinned as a test of its own: a
system echoes the connector request it built as a serialized document whose
`headers` object comes from a hash map, so its key order is seeded per
process. Byte-different, the same JSON value, and therefore not a difference
at all — no rows, nothing to absorb, nothing blocking. Without this arm the
deployed recompute compares the two strings as scalars and blocks three of
three correlations on a body the kernel scores as identical.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants