Commit graph

3 commits

Author SHA1 Message Date
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
Anton Razzhigaev
1a50e7a2c7 fix: triad-wave batch — Playwright-parity evaluate, starvation-free cursor, supersession replay, basis-gated density
Dispositions of the multi-model triad + scope wave (grok-4.6, fable-5,
gpt-5.6-sol; scope sol-xhigh), severity order:

- _evaluate_bounded lost Playwright's function-invocation semantics
  (unanimous MAJOR, confirmed against the installed driver: UtilityScript
  eval()s a raw-string expression and INVOKES a function-valued result
  when isFunction is unset). page.evaluate(_MARKDOWN_JS), the health
  snapshot and every '() =>' user evaluate serialized the uninvoked
  function to undefined. The wrapper now evals and invokes exactly as the
  driver does; the wrapper-shape test pins both halves.
- The settled-refresh cursor pinned its byte offset on the earliest
  SETTLED row of a still-RUNNING task (grok/sol MAJOR): each tick re-read
  the same 5MB window behind one long-lived parent and permanently starved
  every later terminal-boundary settlement past the cap — the exact class
  the cursor exists to heal. The offset now always advances; deferred
  tasks ride a durable bounded map retried every tick (oldest-evicted at
  500, disclosed), pinned by a starvation test.
- A superseded-by-revision acceptance run was excluded from the prior-run
  lookup even on an identical paid identity (sol MAJOR): the resubmission
  fell through to the wallet's binding_dispatch_already_claimed and
  recorded a synthetic DEGRADED panel instead of the typed
  identical_acceptance_refused terminal. Identity-matched superseded runs
  now replay for free with a replayed_from_superseded disclosure —
  evidence revision stays stale-detection, never a paid-cycle mint
  (owner decision 5=A). Moved _prior_acceptance_run to
  acceptance_dialogue.py (loop.py byte debt is shrink-only).
- The trailing-JSON scanner missed a real directive after an unmatched
  brace/quote in the prose prefix (sol MAJOR with executed repro; fable
  MINOR): the forced rail then leaked the raw protocol JSON — the original
  O4 defect resurfacing on one input class. On primary-scan failure the
  parser now retries from the last few line-start '{' anchors (bounded,
  string-aware); the inline-after-unbalanced-prose case stays a disclosed
  prose-degrade, pinned. The scope wave's fence-peel O(n*k) shortfall is
  also fixed (no slicing per peel, 4-fence cap) and ARCHITECTURE's parser
  description synced to the final implementation.
- Legacy/raw-basis density rows stayed authoritative for their 14-day TTL
  after an upgrade (sol MAJOR, probe-confirmed): resolve_main_token_density
  now calibrates ONLY on bounded_proxy rows (review/aggregate resolvers
  keep all rows — their text-heavy witnesses measure the same on either
  basis); a poisoned 0.55 image-route witness falls back to the neutral
  1.0 instead of under-admitting by 45%. Tests seeding the main resolver
  updated to the modern producer shape (the observer stamps the basis).
- acceptance_patch_dispositions computed the unreviewed_delegated_apply
  headline AFTER truncation (fable MAJOR): a delegated apply among the
  25-cap-omitted oldest rows false-negatived the one fact the attest
  decision (4=A) exists to surface. Headline now derives from the complete
  row set; pinned with a mixed-row scenario.
- write_patch_verdict treated custody.emit's False return as success
  (grok/fable/sol): a lost attestation row was invisible — the packet's
  empty section read as 'nothing recorded'. Both the exception AND the
  False-return paths now disclose custody_row_write_failed on the verdict
  artifact, and the row lands on the canonical custody root.
- find_child_tasks overlay test now pins CONTENT restoration (cost,
  result, artifacts), not just the id (grok MINOR).

Also: reservation test keeps the read-surface pin with the offline
rationale (a cost-equality behavioral pin honestly returns None without a
live pricing route — fable m5 disposition); scope-wave (a)-items verified
against the ratified record (tools_on_path=11=A, salvage-rail in the O4
verdict, dialogue-history=R2, cycle accounting=O11 seams) — prompt gaps,
not drift.

Suites: 11775 parallel + 618 serial + 694 web green; ruff -F clean;
size-ratchet regenerated (loop.py net-shrinks further).

Co-authored-by: Ouroboros <311266734+ouroboros-agent@users.noreply.github.com>
2026-08-31 06:35:17 +00:00
Anton Razzhigaev
0c32bd73c1 fix(delivery,browser): trailing protocol JSON never leaks or drops its directive; browser actions honor real timeouts
Phase O-C of the harness-health sprint:

- utils.extract_trailing_json_object: one SSOT for splitting prose from a
  TRAILING JSON object (raw_decode anchored from the last brace; the tail
  may be only whitespace/one closing fence; duplicate keys invalidate with
  the caller's protocol-key flag preserved). Deliberately no key-scanning
  — an answer QUOTING the protocol mid-prose stays prose (the
  review_verdict_extraction D19 lesson).
- loop._parse_delivery_control_object delegates to it: a final answer of
  'prose... {"delivery_control": ...}' previously shipped the raw JSON to
  the owner AND silently dropped the directive before verb dispatch (a
  replace lost its full_answer with no degraded stamp — the exact
  invariant ARCHITECTURE declares). Armed/forced paths now dispatch the
  extracted control; the two unarmed gates ship the prose without the
  trailing object, control flow unchanged. loop.py net-shrinks one byte
  (BYTE_DEBT is shrink-only; manifest regenerated).
- observability.latest_llm_response_text (the supervisor hard-kill
  salvage rail) applies the same trailing-strip: prose salvages, the
  machine directive never reaches the owner's terminal result;
  whole-body suppression unchanged.
- browser: page.set_default_timeout plumbs the caller timeout into the
  default-honoring calls (screenshot/inner_text/content/health probes,
  floored so the 5s action default cannot strangle the 30s capture), and
  _evaluate_bounded wraps every previously unbounded evaluate site
  (evaluate + IIFE retry, markdown extraction, health snapshot, scroll)
  in an in-page Promise.race — honest about its limit: an async hang is
  bounded, a synchronous block still rides the outer tool timeout.

Co-authored-by: Ouroboros <311266734+ouroboros-agent@users.noreply.github.com>
2026-08-30 20:41:05 +00:00