From 7fcce1e2f37c7a29b704fc6c0f1c31b36718bb1b Mon Sep 17 00:00:00 2001 From: ciregenz Date: Wed, 5 Aug 2026 00:45:38 -0700 Subject: [PATCH] [eric] browser: prove a send by the payload appearing twice, when the composer never clears --- .../agents/browser/browser_delivery_check.py | 39 +++++++++++ .../agents/browser/browser_send_script.py | 16 +++++ backend/tests/test_receipt_by_occurrence.py | 66 +++++++++++++++++++ 3 files changed, 121 insertions(+) create mode 100644 backend/tests/test_receipt_by_occurrence.py diff --git a/backend/apps/agents/browser/browser_delivery_check.py b/backend/apps/agents/browser/browser_delivery_check.py index bcbc2327..ee9fc086 100644 --- a/backend/apps/agents/browser/browser_delivery_check.py +++ b/backend/apps/agents/browser/browser_delivery_check.py @@ -182,3 +182,42 @@ def unconfirmed_delivery_note(url: str, payload: str) -> str: return (f'I submitted "{clip}" and the composer cleared, but I could NOT confirm it stayed ' f'live: {host} sometimes accepts an automated post and then drops it without an error. ' f'Please check your posts to verify it actually went through before relying on it.') + + +@typechecked +def occurrence_probe_expression(payload: str) -> str: + """JS counting how many times `payload` appears in the page's visible text. + + The count is the whole point. `payload_visible` above is documented "run only AFTER the composer + cleared", and on a site where the composer NEVER clears that makes it useless: one hit could be + the leftover draft or the posted item, and there is no way to tell them apart. Two hits cannot + both be the composer, so the second one is rendered content, which is what "it posted" means. + """ + needle = " ".join((payload or "").split())[:80] + return ("(()=>{try{var n=" + json.dumps(needle) + ";" + "if(!n.length) return {count:0};" + "var t=(document.body&&document.body.innerText)||'';" + "var c=0,i=t.indexOf(n);while(i!==-1){c++;i=t.indexOf(n,i+n.length);}" + "return {count:c};}catch(e){return {count:-1};}})()") + + +@typechecked +async def payload_occurrences( + payload: str, browser_id: str, tab_id: str, execute_tool: ToolRunner +) -> Optional[int]: + """How many times the payload is rendered on the page, or None if we could not look. + + None, never 0, on a failed read: asserting "it is not there" from an observation that never + happened is the same error as claiming a delivery nobody saw, pointed the other way. + """ + try: + r = await asyncio.wait_for(execute_tool( + "BrowserEvaluate", {"expression": occurrence_probe_expression(payload)}, + browser_id, tab_id), timeout=6.0) + except Exception: + return None + v = browser_submit_click.parse_eval_value(r) + if not isinstance(v, dict) or "count" not in v: + return None + n = int(v.get("count") or 0) + return None if n < 0 else n diff --git a/backend/apps/agents/browser/browser_send_script.py b/backend/apps/agents/browser/browser_send_script.py index 53062256..2398eef1 100644 --- a/backend/apps/agents/browser/browser_send_script.py +++ b/backend/apps/agents/browser/browser_send_script.py @@ -189,6 +189,22 @@ async def complete_send( sent = True break p_why = f"payload-still-in-a-textbox (textbox rows={sum(1 for x in state3.splitlines() if '= 2: + sent = True + logger.info(f"[browser-sendscript] receipt via rendered content: the payload appears " + f"{p_n}x on the page, so one of them is not the composer") if not sent: logger.info(f"[browser-sendscript] receipt withheld after {sum(p_waits):.1f}s of polling: {p_why}") # A cleared composer is proof of delivery everywhere EXCEPT the ghost-drop hosts, which clear diff --git a/backend/tests/test_receipt_by_occurrence.py b/backend/tests/test_receipt_by_occurrence.py new file mode 100644 index 00000000..a8e976f1 --- /dev/null +++ b/backend/tests/test_receipt_by_occurrence.py @@ -0,0 +1,66 @@ +"""A cleared composer is not the only proof a post landed. + +Measured on LinkedIn four separate times: the post LANDS, and the composer still holds the text 7.6s +later, so the two-sided receipt ("fill seen committed, then seen gone") reports a successful send as +unverified. An independent read of the activity feed found the post every time. That costs the fast +path (the model goes back to re-verify work that already succeeded, ~60s against ~24s) and it makes +criterion 2 under-report real capability. + +The clear is ABSENCE evidence and some sites never supply it. Presence is the other direction, and +the COUNT is what makes it usable: one hit is ambiguous (a leftover draft or the posted item, no way +to tell them apart), two hits cannot both be the composer, so the second is rendered content. + +Only runs when the clear-poll already failed, so a site whose composer does clear is untouched. +""" + +import json + +from backend.apps.agents.browser import browser_delivery_check as dc + + +def test_the_probe_counts_every_occurrence_not_just_the_first(): + expr = dc.occurrence_probe_expression("canary123") + assert "while(i!==-1)" in expr, "must keep scanning past the first hit" + assert "i+n.length" in expr, "and advance past the match, or it counts forever" + + +def test_the_needle_is_whitespace_normalised_and_capped(): + """innerText collapses whitespace; a payload with a newline would never match verbatim. The cap + keeps a pasted essay from becoming an 80KB expression.""" + expr = dc.occurrence_probe_expression("hello \n world") + assert json.dumps("hello world") in expr + long_expr = dc.occurrence_probe_expression("z" * 300) + assert json.dumps("z" * 80) in long_expr + + +def test_an_empty_payload_counts_nothing_rather_than_everything(): + """indexOf('') returns 0 forever. Without this guard the probe reports an infinite count and + every send would 'verify'.""" + assert "if(!n.length) return {count:0};" in dc.occurrence_probe_expression("") + + +def test_a_page_error_is_reported_as_unreadable_not_as_zero(): + """-1 becomes None upstream. Asserting 'not there' from an observation that never happened is + the same error as claiming a delivery nobody saw, pointed the other way.""" + assert "catch(e){return {count:-1};}" in dc.occurrence_probe_expression("x") + + +def test_the_send_script_requires_TWO_hits_before_it_believes_a_send(): + """One hit is the draft. The threshold is the safety property: at 1 this would call every + unsent draft a delivered post, which is the false-success class the receipt exists to prevent.""" + import inspect + from backend.apps.agents.browser import browser_send_script as ss + src = inspect.getsource(ss) + i = src.index("receipt via rendered content") + block = src[max(0, i - 900):i + 200] + assert "p_n is not None and p_n >= 2" in block, "two hits, and None must not pass" + assert "payload_occurrences" in block + + +def test_it_only_runs_after_the_clear_poll_already_failed(): + """A site whose composer clears must pay nothing for this, and must not get a second opinion + that could disagree with a receipt it already earned honestly.""" + import inspect + from backend.apps.agents.browser import browser_send_script as ss + src = inspect.getsource(ss) + assert 'if not sent and p_why.startswith("payload-still")' in src