ouroboros/tests/test_extract_trailing_json_object.py
Anton Razzhigaev 3b05f321a2 fix: final-wave batch — superseded replay refuses, basis-scoped throttle, global-scope evaluate, whole-text parser contract
Dispositions of the final codex+fable pair on the triad-fixed head (both
lanes ran executable probes):

- The superseded-run paid-identity replay had a hole on the CLEAN side
  (sol MAJOR, probe-reproduced accepted decision; fable traced the same
  scenario to an inconsistent ledger — ACCEPTED decision beside superseded
  trace rows the delivery binding can never match): a clean-PASS panel
  superseded by an evidence revision re-authorized on an identical
  resubmission through the clean-pass branch, which runs before the reused
  refusal. A superseded replay now ALWAYS lands in the typed
  identical_acceptance_refused terminal — its verdict predates the
  evidence change; nothing stale is re-authorized, and the decision stays
  consistent with the superseded rows. Pinned with a superseded clean-PASS
  scenario.
- The density writer's throttle was basis-blind (sol MAJOR,
  probe-reproduced): a fresh RAW row at the same numeric density
  suppressed the FIRST bounded_proxy witness as 'no drift', leaving the
  bounded-only main resolver cold for the whole freshness window on an
  upgraded store. The memo key and the newest-row comparison are now
  basis-scoped; pinned with a same-density cross-basis sequence.
- The bounded evaluate used DIRECT eval (sol MINOR + both fable lanes):
  user code saw the wrapper's lexical __obo_result binding (TDZ
  ReferenceError on 'typeof __obo_result') and var/function declarations
  no longer persisted across evaluate calls. Now '(0, eval)' — indirect,
  global scope, exactly the driver's global.eval: cross-call persistence
  and zero lexical exposure verified by node probe; wrapper pin updated.
- The parser returned a TRUNCATED prefix with parsed=None when a
  structurally balanced tail failed json.loads (fable finding — a
  single-quoted pseudo-JSON tail): both current callers were safe, but the
  contract said non-directive text returns whole. It now does; only a
  duplicate-key rejection keeps the prefix/tail split (that tail IS a
  strict-parser-refused directive shape and protocol-repair needs the
  boundary). Pinned.

Disclosed, not changed (fable Info): custody._iter_rows swallows a
mid-iteration OSError and yields the partial row set — a race-window
truncated read could omit a disposition row without the typed marker;
narrow window, tracked with the projection follow-up.

Suites: 11778 parallel + 618 serial green; ratchet 5 passed vs base;
ruff -F clean.

Co-authored-by: Ouroboros <311266734+ouroboros-agent@users.noreply.github.com>
2026-08-31 06:59:35 +00:00

129 lines
5.3 KiB
Python

"""Contract tests for utils.extract_trailing_json_object.
The helper is the shared SSOT behind the loop's delivery-control parse and the
observability salvage rail: prose with one TRAILING protocol object must split
into (prose, object), while an object followed by prose stays quoted material.
"""
from __future__ import annotations
import json
from ouroboros.utils import extract_trailing_json_object
_PROTOCOL_KEYS = ("delivery_control", "full_answer")
def test_whole_text_object_parses_with_empty_prefix():
raw = json.dumps({"delivery_control": "keep"})
prose, parsed, duplicate = extract_trailing_json_object(raw)
assert prose == ""
assert parsed == {"delivery_control": "keep"}
assert duplicate is False
def test_whole_text_object_with_nested_object_still_parses():
# The last "{" belongs to a nested object; the scan must back up to the
# real opening brace instead of rejecting the whole text.
raw = json.dumps({"delivery_control": "replace", "full_answer": "x", "meta": {"a": 1}})
prose, parsed, _duplicate = extract_trailing_json_object(raw)
assert prose == ""
assert parsed is not None and parsed["meta"] == {"a": 1}
def test_prose_plus_trailing_object_splits():
control = json.dumps({"delivery_control": "replace", "full_answer": "THE REAL ANSWER"})
prose, parsed, duplicate = extract_trailing_json_object("Here is the summary.\n\n" + control)
assert prose.rstrip() == "Here is the summary."
assert parsed == {"delivery_control": "replace", "full_answer": "THE REAL ANSWER"}
assert duplicate is False
def test_object_with_prose_after_it_is_not_trailing():
# Quoting the protocol mid-prose must never be mistaken for a directive.
raw = 'prose {"delivery_control": "keep"} more prose'
assert extract_trailing_json_object(raw) == (raw, None, False)
def test_duplicate_protocol_key_invalidates_object_but_flags_intent():
raw = 'prose\n{"delivery_control":"keep","delivery_control":"replace"}'
prose, parsed, duplicate = extract_trailing_json_object(
raw, duplicate_flag_keys=_PROTOCOL_KEYS,
)
assert prose == "prose\n"
assert parsed is None
assert duplicate is True
def test_duplicate_nonflagged_key_invalidates_without_flag():
raw = '{"a":1,"a":2}'
prose, parsed, duplicate = extract_trailing_json_object(
raw, duplicate_flag_keys=_PROTOCOL_KEYS,
)
assert prose == ""
assert parsed is None
assert duplicate is False
def test_fenced_trailing_object_parses_and_trims_dangling_fence():
raw = 'prose\n```json\n{"delivery_control":"keep"}\n```'
prose, parsed, _duplicate = extract_trailing_json_object(raw)
assert prose == "prose"
assert parsed == {"delivery_control": "keep"}
def test_fully_fenced_whole_text_object_has_empty_prefix():
raw = '```json\n{"delivery_control":"keep"}\n```'
prose, parsed, _duplicate = extract_trailing_json_object(raw)
assert prose == ""
assert parsed == {"delivery_control": "keep"}
def test_text_without_object_passes_through():
assert extract_trailing_json_object("just prose, no json at all") == (
"just prose, no json at all", None, False,
)
assert extract_trailing_json_object("") == ("", None, False)
def test_non_dict_json_is_not_extracted():
assert extract_trailing_json_object("[1, 2, 3]") == ("[1, 2, 3]", None, False)
def test_brace_inside_string_value_does_not_break_the_scan():
control = '{"delivery_control":"replace","full_answer":"use {braces} here"}'
prose, parsed, _duplicate = extract_trailing_json_object("lead\n" + control)
assert prose == "lead\n"
assert parsed is not None and parsed["full_answer"] == "use {braces} here"
def test_unbalanced_prose_prefix_still_finds_the_trailing_directive():
"""sol M3 / fable m2: an unmatched brace or quote in the PROSE corrupts the
primary forward scan's state; the bounded line-anchor fallback must still
find the independent trailing object (leaking raw protocol JSON to the
owner was the original O4 defect)."""
prose_brace = "Example: const x = '{';\n{\"delivery_control\": \"keep\"}"
prefix, parsed, dup = extract_trailing_json_object(prose_brace)
assert parsed == {"delivery_control": "keep"}
assert prefix.rstrip().endswith("'{';")
prose_quote = 'He said "unterminated\n{"delivery_control": "replace", "full_answer": "y"}'
_, parsed2, _ = extract_trailing_json_object(prose_quote)
assert parsed2 == {"delivery_control": "replace", "full_answer": "y"}
# An inline object after the unbalanced prose (no line-start anchor) stays
# undetected — disclosed degrade: the answer ships as prose, never a leak
# of a DIFFERENT directive.
inline = "broken { prose {\"delivery_control\": \"keep\"}"
_, parsed3, _ = extract_trailing_json_object(inline)
assert parsed3 is None
def test_unparseable_balanced_tail_returns_the_text_whole():
"""final-lane fable finding: a structurally balanced tail that fails
json.loads (single-quoted pseudo-JSON) is PROSE — the caller gets the
whole text back, never a silently truncated prefix. Only the
duplicate-key case keeps the split (protocol-repair intent)."""
text = "some prose\n{'delivery_control': 'keep'}"
prefix, parsed, dup = extract_trailing_json_object(text)
assert (prefix, parsed, dup) == (text, None, False)