Weryfikacja publikacji AI-agenta na X: od 83 fałszywych sukcesów do 94% rzeczywistych
AI-agent do automatycznych komentarzy na X pokazywał 83 udane publikacje, ale rzeczywistych odpowiedzi było tylko 16. Różnica powstała z powodu niepełnej weryfikacji: kliknięcie przycisku Reply nie gwarantuje pojawienia się treści na platformie. Spam-filtry X silently dropują posty bez powiadomień.
Mechanizm publikacji przez przeglądarkę
Agent używa Puppeteer CDP do zarządzania prawdziwą przeglądarką. Otwiera wątek, wprowadza tekst i klika Reply. Pierwsza wersja funkcji sprawdzała tylko zdarzenie DOM:
const button = await page.$('[data-testid="tweetButton"]');
if (button) {
const disabled = await button.evaluate(el =>
el.getAttribute('aria-disabled') === 'true'
);
if (!disabled) {
await button.click();
return true; // <-- problem wczesnego sukcesu
}
}
return false;
Zwrot true rejestrował sukces na poziomie DOM, bez weryfikacji platformy. Baza danych gromadziła rekordy, dashboard zieleniał.
X nie sygnalizuje odrzucenia: pole jest czyszczone, URL się nie zmienia. Rate limiter lub polityka treści działają w ciszy, pozostawiając przeglądarkę w iluzji sukcesu.
Problemy z ID postów
Do śledzenia agent wyodrębniał ID z page.url() po kliknięciu:
const tweetId = page.url().split('/status/')[1];
X nie przekierowuje na nowy post — URL pozostaje nadrzędnym. Wszystkie 83 rekordy otrzymały ten sam parent_tweet_id, maskując problem pod ważnymi danymi.
Odkrycie nastąpiło ręcznie przez analitykę X: 83 vs 16 rzeczywistych odpowiedzi.
Źródło problemu: rozbieżność między DOM a platformą
DOM: button.click() → success ✓
Browser: event fired → success ✓
X Platform: content dropped → ??? (cisza)
Database: recorded as "posted" → success ✓
Dashboard: 83 engagements → doskonale ✓
Reality: 16 actual posts
Monitoring ograniczał się do przeglądarki. Platformowe filtry — czarna skrzynka.
Rozwiązanie: post-weryfikacja z przeładowaniem
Nowa funkcja verifyReplyPosted czeka na render, przeładowuje stronę i skanuje DOM w poszukiwaniu tekstu:
export async function verifyReplyPosted(
page: Page,
replyText: string,
parentTweetId: string,
): Promise<{ verified: boolean; replyTweetId: string | null }> {
await new Promise(r => setTimeout(r, 3000));
await page.reload({ waitUntil: "domcontentloaded" });
await new Promise(r => setTimeout(r, 5000));
await page.evaluate("window.scrollBy(0, 1000)");
await new Promise(r => setTimeout(r, 2000));
const result = await page.evaluate(`
(function() {
var snippet = '${safe}'; // pierwsze 30 znaków
var articles = document.querySelectorAll(
'article[data-testid="tweet"]'
);
for (var i = 0; i < articles.length; i++) {
var textEl = articles[i].querySelector(
'[data-testid="tweetText"]'
);
if (!textEl) continue;
var text = (textEl.innerText || '').slice(0, 60);
if (text.indexOf(snippet.slice(0, 30)) !== -1) {
var links = articles[i].querySelectorAll(
'a[href*="/status/"]'
);
return { verified: true, replyTweetId: realId };
}
}
return { verified: false, replyTweetId: null };
})()
`);
return result;
}
- Przeładowanie zapewnia aktualny wątek bez cache.
- Wyszukiwanie po
article[data-testid="tweet"]i[data-testid="tweetText"]. - ID jest wyodrębniane z
hreflinków wewnątrz article. - Tylko
verified: truejest zapisywane w bazie.
Uniwersalność podejścia
Problem nie jest unikalny dla X. Platformy (social media, formularze, płatności, deploy) silently rejectują treść.
Kluczowe zasady weryfikacji:
- Imitować użytkownika: przeładowanie + scroll do leniwego ładowania.
- Szukać markera (fragment tekstu) w docelowym DOM.
- Wyodrębniać identyfikatory z rzeczywistych elementów, nie z URL/zdarzeń.
- Anulować zapis przy braku dowodu.
- Logować failures w czasie rzeczywistym.
Co jest ważne
- Zdarzenia DOM ≠ sukces platformy: kliknięcie nie gwarantuje publikacji.
- Silent drops: spam-filtry działają bez alertów, aby utrudnić obejście.
- Weryfikacja przez skanowanie DOM: przeładowanie + wyszukiwanie tekstu/ID.
- Metryki po poprawce: 94% verified success rate, failures są widoczne natychmiast.
- Zastosowanie: każdy automatyczny posting/submit wymaga weryfikacji podobnej do użytkownika.
Po wdrożeniu agent rejestruje rzeczywiste publikacje, dashboard odzwierciedla prawdę. Podejście skaluje się na inne platformy z analogicznymi filtrami.
— Editorial Team
Brak komentarzy.