mirror of
https://github.com/openswarm-ai/openswarm.git
synced 2026-08-24 05:22:22 +02:00
[eric] browser: a comment task must not click Create-new-post
This commit is contained in:
@@ -9,6 +9,7 @@ imports from here, never the reverse.
|
||||
"""
|
||||
|
||||
import re
|
||||
from typing import Optional
|
||||
|
||||
# Double quotes are unambiguous. Single quotes only delimit when the opener is at a word boundary (start/space/colon), so an in-word apostrophe like "chen's" is never mistaken for a payload quote, that mispairing was silently corrupting the canonical "text him '...'" errand.
|
||||
P_QUOTED_DQ_RE = re.compile(r'"([^"]{4,300})"')
|
||||
@@ -249,21 +250,48 @@ def quoted_payload(task: str) -> str:
|
||||
return sq.pop() if len(sq) == 1 else ""
|
||||
|
||||
|
||||
def opener_index_in_state(state_text: str):
|
||||
def opener_index_in_state(state_text: str, task: Optional[str] = None):
|
||||
"""(index, name) of the single composer OPENER, or None.
|
||||
|
||||
An exact name, or a verb+noun compose phrase anywhere in a longer label. The second half is
|
||||
what reaches the openers whose label is a whole sentence, and it keeps the exactness the first
|
||||
half was buying: an upsell ('Send InMail') has the wrong noun and a count ('526 comments') has
|
||||
no verb. Still a SINGLETON, so two candidates stay the model's problem, not a coin flip."""
|
||||
no verb. Still a SINGLETON, so two candidates stay the model's problem, not a coin flip.
|
||||
|
||||
Pass `task` to drop openers that contradict it, which is what keeps a comment task off the
|
||||
'New post' upload button. Optional so existing read-only callers are unaffected."""
|
||||
hits = [(int(m.group(1)), m.group(2)) for m in P_OPENER_ROW_RE.finditer(state_text or "")]
|
||||
if not hits:
|
||||
hits = [(int(m.group(1)), m.group(2))
|
||||
for m in P_CONTROL_ROW_RE.finditer(state_text or "")
|
||||
if P_OPENER_PHRASE_RE.search(m.group(2) or "")]
|
||||
if task is not None:
|
||||
hits = [h for h in hits if not opener_contradicts_task(task, h[1])]
|
||||
return hits[0] if len(hits) == 1 else None
|
||||
|
||||
|
||||
# "New post", "Create", "Compose" open a BLANK thing. Fine when the task is to write something new;
|
||||
# wrong when the task is to respond to something that already exists.
|
||||
P_CREATE_OPENER_RE = re.compile(r"\b(new|create|compose|start a)\b", re.I)
|
||||
|
||||
|
||||
def opener_contradicts_task(task: str, opener_name: str) -> bool:
|
||||
"""True when this opener would take us somewhere the task did not ask to go.
|
||||
|
||||
Measured on instagram 2026-08-04: a "write a comment on the first post" task matched the opener
|
||||
`New post Create`, which is the UPLOAD flow, so the run left the feed for a file picker and
|
||||
never saw a post. Nothing downstream could catch it, because by then the only evidence left was
|
||||
a page with no composer on it.
|
||||
|
||||
Only the create-vs-respond direction, because that is the one with a wrong destination. A
|
||||
respond-shaped opener on a create task is left alone: some sites really do route a new post
|
||||
through a control labelled "Write".
|
||||
"""
|
||||
t, name = task or "", opener_name or ""
|
||||
responding = bool(P_COMMENT_INTENT_RE.search(t))
|
||||
return responding and bool(P_CREATE_OPENER_RE.search(name))
|
||||
|
||||
|
||||
def composer_index_in_state(state_text: str):
|
||||
"""(index, name) of the single compose-shaped textbox, or None. Two
|
||||
candidates = ambiguous = model's problem."""
|
||||
|
||||
@@ -293,7 +293,7 @@ async def run_send_script(
|
||||
p_struct_selector: str = ""
|
||||
if not composer:
|
||||
# Reversible-opener hop: prestage often stops on the profile with the "Message" opener visible (its settle raced the overlay). Opening a composer is the allowed opener class; the irreversible bar is unchanged.
|
||||
opener = browser_send_parse.opener_index_in_state(state_text)
|
||||
opener = browser_send_parse.opener_index_in_state(state_text, task_sans_brief)
|
||||
if opener and browser_send_parse.surface_mismatch(task_sans_brief, opener[1]):
|
||||
# The same wrong-surface rule the composer already enforces, applied one step earlier.
|
||||
# Measured on linkedin.com with "start a post": the only opener listed was 'Comment', so
|
||||
|
||||
@@ -57,3 +57,28 @@ def test_the_exact_rule_is_preferred_over_the_phrase_rule():
|
||||
hit = sp.opener_index_in_state(
|
||||
'[3]<button "Comment">\n[9]<button "Read or add comments 526 comments">')
|
||||
assert hit is not None and hit[0] == 3
|
||||
|
||||
|
||||
def test_a_comment_task_must_not_click_create_new_post():
|
||||
"""Measured live on instagram 2026-08-04, and caused by widening the opener match above.
|
||||
|
||||
"New post Create" contains the phrase "new post", so a task that says "write a comment on the
|
||||
first post" matched Instagram's UPLOAD button. The run left the feed for a file picker and never
|
||||
saw a post, and nothing downstream could catch it: by then the only evidence left was a page
|
||||
with no composer on it, which reads as a missing composer rather than a wrong destination.
|
||||
|
||||
Only the create-vs-respond direction is guarded. A respond-shaped label on a create task is left
|
||||
alone, because some sites really do route a new post through a control labelled "Write"."""
|
||||
ig = '[11]<button "New post Create">'
|
||||
assert sp.opener_index_in_state(ig, "write a comment on the first post") is None
|
||||
# the same button is exactly right when the task IS to create something new
|
||||
assert sp.opener_index_in_state(ig, "create a new post saying hi") is not None
|
||||
# and a genuine comment opener still resolves for the comment task
|
||||
assert sp.opener_index_in_state(
|
||||
'[11]<button "Read or add comments 526 comments">', "write a comment on the first post")
|
||||
|
||||
|
||||
def test_omitting_the_task_leaves_opener_matching_exactly_as_it_was():
|
||||
"""The task argument is optional so read-only callers (the perception summary line) keep their
|
||||
behaviour; a guard that changed what `opener=` reports would corrupt the dryrun report."""
|
||||
assert sp.opener_index_in_state('[11]<button "New post Create">') is not None
|
||||
|
||||
Reference in New Issue
Block a user