fix(posting-guard): quote the part of a long line that triggered the flag (#704)

* fix(posting-guard): quote the part of a long line that triggered the flag

The excerpt was a fixed line[:200], so when the trigger sat later in a
long paragraph the user saw a warning with 200 characters of ordinary
company prose and nothing suspicious in them. apply.md relies on the
quote to let the user dismiss a flag in a second, and WebFetch paragraphs
and portal plain output routinely run past 200 characters.

Quote a window of the same length around the first match, with an
ellipsis marking a cut at either end; lines up to 200 characters are
quoted whole as before. One new case fails on master; the short-line case
pins the unchanged behaviour.

* changelog: place the #704 entry under [Unreleased]

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Mads Lorentzen <madslorentzen_17@hotmail.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
authored and GitHub committed 2026-10-20 20:56:59 +02:00
1 parent 1c39c51b1b
commit 9a53f5e05b
3 files changed
+51 -2

No files matched your search

+22 -2
View File
@@ -242,6 +242,25 @@ def clean_html(markup: str):
return _fold(text), {"hidden_blocks": hidden_blocks, "hidden_text": "\n".join(hidden_parts)}
def _excerpt(line: str, at: int) -> str:
"""Up to LINE_MAX characters of `line`, always including position `at`.
The quote is what lets the user dismiss a flag in a second, so it must
show the match. A fixed `line[:LINE_MAX]` showed the first 200 characters
of a long paragraph and nothing suspicious when the trigger sat later -
WebFetch paragraphs and portal plain output routinely run past 200.
"""
if len(line) <= LINE_MAX:
return line
lead = LINE_MAX // 3
start = max(0, at - lead)
end = min(len(line), start + LINE_MAX)
start = max(0, end - LINE_MAX)
head = "\u2026" if start else ""
tail = "\u2026" if end < len(line) else ""
return f"{head}{line[start:end]}{tail}"
def scan(visible: str, hidden: str) -> dict:
"""Instruction-shaped lines, hidden URLs, visible URL count, mixed-script words."""
seen = set()
@@ -250,9 +269,10 @@ def scan(visible: str, hidden: str) -> dict:
stripped = line.strip()
if not stripped or stripped in seen:
continue
if any(p.search(stripped) for p in INSTRUCTION_PATTERNS):
match = next((m for m in (p.search(stripped) for p in INSTRUCTION_PATTERNS) if m), None)
if match:
seen.add(stripped)
instruction_like.append(stripped[:LINE_MAX])
instruction_like.append(_excerpt(stripped, match.start()))
hidden_urls = []
for url in URL.findall(hidden):
if url not in hidden_urls: