[eric] browser: a post task never fills a comment box, even when it is the only one listed

This commit is contained in:
ciregenz
2026-07-28 16:49:24 -07:00
parent 1056613f80
commit 43cef02b17
3 changed files with 59 additions and 0 deletions
@@ -96,6 +96,29 @@ def looks_signed_out(state_text: str) -> bool:
return bool(P_SIGNIN_AFFORDANCE_RE.search(state_text))
# Creating a POST and commenting on someone else's are different actions on different content.
# LinkedIn's feed carries a comment box on EVERY post, and the capped interactives listing routinely
# starves the real post modal of its own composer, so the only compose-shaped textbox left in the
# list is a stranger's comment box. Filling that is not a slower path to the same place, it is the
# wrong action on the wrong person's content. Measured in a dry-run sweep: linkedin reached its
# composer 1/4, and two of the three misses targeted 'Text editor for creating comment'.
P_POST_INTENT_RE = re.compile(r"\b(post|tweet|publish|share)\b", re.I)
P_COMMENT_INTENT_RE = re.compile(r"\b(comment|reply|respond)\b", re.I)
P_COMMENT_SURFACE_RE = re.compile(r"\b(comment|reply)\b", re.I)
def surface_mismatch(task: str, composer_name: str) -> bool:
"""True when the task asks to create a POST but the composer found is a comment/reply box.
Deliberately one-directional: a task that mentions commenting is left alone, so this can only
ever reject a comment box for a post task, never the reverse. A rejection is cheap (the
structural finder, which does find LinkedIn's real composer, gets its turn instead)."""
t, name = task or "", composer_name or ""
if not P_POST_INTENT_RE.search(t) or P_COMMENT_INTENT_RE.search(t):
return False
return bool(P_COMMENT_SURFACE_RE.search(name))
def is_readonly(text: str) -> bool:
"""A read-only directive ('verify whether', 'do not send') that must decline the scripted
send even with a quoted payload in hand. Keeps the regex private to this file."""
@@ -211,6 +211,12 @@ async def run_send_script(
log: list[dict] = []
composer = browser_send_parse.composer_index_in_state(state_text)
if composer and browser_send_parse.surface_mismatch(task_sans_brief, composer[1]):
# Asked to POST, found a COMMENT box: that is someone else's content, not a slower route to
# ours. Drop it and let the tiers below (opener, then the structural finder, which does find
# LinkedIn's real composer) look properly.
logger.info(f"[browser-sendscript] ignoring {composer[1]!r}: a comment box is not where a post goes")
composer = None
if not composer:
# The staged snapshot is prestage's, frozen the instant it clicked Message; the overlay composer lazy-renders a beat later (r263/r269 declined on exactly this, prestage's LAST step was the Message click). Poll a short window so the overlay has time to appear before we fall back to the opener.
for wait_s in (0.6, 1.2, 1.4):
@@ -67,3 +67,33 @@ def test_empty_and_junk_are_not_readonly():
on a malformed input rather than letting the normal gates decide."""
assert not sp.is_readonly("")
assert not sp.is_readonly(" ")
# --- surface targeting: a post is not a comment ---------------------------------------------
def test_a_post_task_rejects_a_comment_box():
"""Measured: on LinkedIn's feed the capped listing starved the post modal of its own composer,
so the only compose-shaped textbox left was a stranger's comment box. Filling it is the wrong
action on the wrong content, not a slower route to the right one."""
assert sp.surface_mismatch('post this, exactly: "hi"', "Text editor for creating comment")
assert sp.surface_mismatch("start a post saying hi", "Add a comment")
assert sp.surface_mismatch("tweet hello", "Post your reply")
def test_a_comment_task_keeps_its_comment_box():
"""One-directional by design: asking to comment must still land in a comment box."""
assert not sp.surface_mismatch("comment on the first post saying hi", "Text editor for creating comment")
assert not sp.surface_mismatch("reply to that thread with hi", "Add a comment")
assert not sp.surface_mismatch("respond to his post", "Post your reply")
def test_a_post_task_keeps_a_real_post_composer():
assert not sp.surface_mismatch('post this, exactly: "hi"', "Post text")
assert not sp.surface_mismatch("start a post", "Share your thoughts")
assert not sp.surface_mismatch("tweet hello", "What is happening?")
def test_a_task_with_no_post_intent_is_left_alone():
"""Messaging a person is neither posting nor commenting; the guard must not touch it."""
assert not sp.surface_mismatch("text tyler hello", "Write a message")
assert not sp.surface_mismatch("", "Add a comment")