Context
Filed from a live hostile-content incident (2026-07-20, D#15194 comment — the credibility-then-backlink comment on the memory-lifecycle ideation sandbox). The read-path sanitizer correctly defanged the vendor URL ([QUARANTINED_URL: github.com]) and the trust classifier correctly held the author at external, but zero stealth signals fired (signals: []) on the payload's most distinctive clause: a licensing pitch — "source-available and free for non-commercial use, while commercial use requires separate permission." The §2 marker set in the quarantine playbook names the shape (credibility-then-backlink); the sanitizer's two signal classes (engagement-bait, external-endpoint-offer) predate this incident's payload clause.
Live latest-open sweep: checked latest open issues at 2026-07-20T17:45Z — no equivalent. A2A in-flight sweep (last 30, all read-states): no competing claim.
The Problem
ai/services/shared/contentTrust/astroturfSanitizer.mjs STEALTH_SIGNALS covers two classes (reward-conditional engagement bait; external-infra-on-our-content offers). The 2026-07-20 incident adds a third, high-precision class: self-promotional licensing terms inside an otherwise-technical comment — the pattern family is "I maintain <product>" + "free for non-commercial use | commercial use requires permission | source-available". Technical peers do not negotiate licenses in divergence cards; the licensing-terms pair is a deterministic astroturf marker with a low false-positive profile (the skill's own bar: "lifted from a documented incident, not a generic-spam heuristic").
Two adjacent facts established during incident handling (for the record, not the work):
- The bare product NAME survived the read path because
productNameDenylist: leaf([]) is empty by default (ai/mcp/server/github-workflow/configBase.mjs:157). That is config, not code — "policy values belong in local config, not in syncer code" — so name-denylisting is an operator overlay decision per deployment, no PR needed. This ticket does NOT change that design.
- The comment's AI-assistance disclosure mirrored our own disclosure conventions. The substrate's stance is already correct (trust derives only from the classifier's positive recognition, fail-closed); no change needed there either.
The Architectural Reality
ai/services/shared/contentTrust/astroturfSanitizer.mjs — STEALTH_SIGNALS array (~L48-63): signals are flagged (reported), never auto-redacted, matched against the ORIGINAL content; each entry carries {id, pattern, note} with the false-positive-rationale comment convention.
- Consumers: the
get_conversation read path (conversationTrust.mjs) and the KB sync/write boundary — both surface signals in the projected contentTrust for human/agent review.
- Spec family:
test/playwright/unit/ai/services/shared/contentTrust/ (sibling signal specs).
The Fix
- Add a third signal entry, e.g.
id: 'self-promotional-licensing-pitch', pattern matching the conjunction of a self-reference-to-product clause and licensing/commercial terms (e.g. /\b(?:i|we)\s+maintain\b[^.!?\n]{0,120}\b(?:free for non[- ]commercial|commercial use requires|source[- ]available|licen[cs]e[sd]? (?:for|separately))/i — the exact regex tuned at implementation with the incident text as the positive fixture and a bank of genuine contributor comments as negative fixtures).
- Unit specs in the existing contentTrust spec family: positive (incident clause → flagged), negatives (genuine "we use X at work" / contributor self-references without licensing terms → not flagged), and the no-redaction invariant (signals are reported, content unmodified).
- One JSDoc line in
STEALTH_SIGNALS naming the incident anchor (the playbook's per-signal convention).
Contract Ledger Matrix
| Target Surface |
Source of Authority |
Proposed Behavior |
Fallback |
Docs |
Evidence |
STEALTH_SIGNALS |
astroturfSanitizer.mjs |
+1 flagged-not-redacted signal class |
absent class = signals:[] (today) |
module JSDoc |
unit: pos/neg fixtures |
contentTrust.signals projection |
conversationTrust.mjs + sync boundary |
new id may appear in review flags |
n/a (additive, non-breaking) |
tool handbook |
this incident |
Decision Record impact: none — additive detection inside an existing self-defense surface; no ADR conflict. Parent: Epic #10291 (organism self-defense).
Acceptance Criteria
Out of Scope
productNameDenylist values (operator overlay config per deployment — named above for the record).
- New moderation mechanics (the playbook's redact/delete/denylist levers already exist and were exercised in the incident).
- Trust-classifier changes (external-tier handling already correct).
Avoided Traps
- Generic spam heuristics — the class is incident-lifted with negative fixtures, not a broad marketing-word net (the sanitizer's own false-positive bar).
- Auto-redacting the matched clause — signals stay review flags; redaction authority stays with the playbook's moderation matrix, not the detector.
Related
- Epic #10291 (parent) · #10476 (P8 link-quarantine lineage; the incident instance note lives there) · #12674 (bare-name seeding tell) · #12992 (engagement-bait class) · #13352 (credibility-then-backlink class) · D#15194 (host thread)
Origin Session ID: session_e86fa9f0-866e-45e8-a6df-d7bb6dd4d8b5 (kimi-code session, Iris seat)
Handoff Retrieval Hints: query_raw_memories("astroturf licensing pitch stealth signal credibility backlink"); incident anchor = D#15194 comment moderated 2026-07-20T17:42Z (redact-payload-keep-card).
Context
Filed from a live hostile-content incident (2026-07-20, D#15194 comment — the credibility-then-backlink comment on the memory-lifecycle ideation sandbox). The read-path sanitizer correctly defanged the vendor URL (
[QUARANTINED_URL: github.com]) and the trust classifier correctly held the author atexternal, but zero stealth signals fired (signals: []) on the payload's most distinctive clause: a licensing pitch — "source-available and free for non-commercial use, while commercial use requires separate permission." The §2 marker set in the quarantine playbook names the shape (credibility-then-backlink); the sanitizer's two signal classes (engagement-bait, external-endpoint-offer) predate this incident's payload clause.Live latest-open sweep: checked latest open issues at 2026-07-20T17:45Z — no equivalent. A2A in-flight sweep (last 30, all read-states): no competing claim.
The Problem
ai/services/shared/contentTrust/astroturfSanitizer.mjsSTEALTH_SIGNALScovers two classes (reward-conditional engagement bait; external-infra-on-our-content offers). The 2026-07-20 incident adds a third, high-precision class: self-promotional licensing terms inside an otherwise-technical comment — the pattern family is "I maintain <product>" + "free for non-commercial use | commercial use requires permission | source-available". Technical peers do not negotiate licenses in divergence cards; the licensing-terms pair is a deterministic astroturf marker with a low false-positive profile (the skill's own bar: "lifted from a documented incident, not a generic-spam heuristic").Two adjacent facts established during incident handling (for the record, not the work):
productNameDenylist: leaf([])is empty by default (ai/mcp/server/github-workflow/configBase.mjs:157). That is config, not code — "policy values belong in local config, not in syncer code" — so name-denylisting is an operator overlay decision per deployment, no PR needed. This ticket does NOT change that design.The Architectural Reality
ai/services/shared/contentTrust/astroturfSanitizer.mjs—STEALTH_SIGNALSarray (~L48-63): signals are flagged (reported), never auto-redacted, matched against the ORIGINAL content; each entry carries{id, pattern, note}with the false-positive-rationale comment convention.get_conversationread path (conversationTrust.mjs) and the KB sync/write boundary — both surfacesignalsin the projectedcontentTrustfor human/agent review.test/playwright/unit/ai/services/shared/contentTrust/(sibling signal specs).The Fix
id: 'self-promotional-licensing-pitch', pattern matching the conjunction of a self-reference-to-product clause and licensing/commercial terms (e.g./\b(?:i|we)\s+maintain\b[^.!?\n]{0,120}\b(?:free for non[- ]commercial|commercial use requires|source[- ]available|licen[cs]e[sd]? (?:for|separately))/i— the exact regex tuned at implementation with the incident text as the positive fixture and a bank of genuine contributor comments as negative fixtures).STEALTH_SIGNALSnaming the incident anchor (the playbook's per-signal convention).Contract Ledger Matrix
STEALTH_SIGNALSastroturfSanitizer.mjscontentTrust.signalsprojectionconversationTrust.mjs+ sync boundaryidmay appear in review flagsDecision Record impact:
none— additive detection inside an existing self-defense surface; no ADR conflict. Parent: Epic #10291 (organism self-defense).Acceptance Criteria
npx playwright test)Out of Scope
productNameDenylistvalues (operator overlay config per deployment — named above for the record).Avoided Traps
Related
Origin Session ID: session_e86fa9f0-866e-45e8-a6df-d7bb6dd4d8b5 (kimi-code session, Iris seat)
Handoff Retrieval Hints:
query_raw_memories("astroturf licensing pitch stealth signal credibility backlink"); incident anchor = D#15194 comment moderated 2026-07-20T17:42Z (redact-payload-keep-card).