Phase 5: selectors module with multi-strategy fallbacks#7
Conversation
X (Twitter) часто переименовывает data-testid атрибуты, а content_script
завязан на них в 6+ местах. После очередного редизайна расширение тихо
ломается — пользователь видит пустые ответы вместо ошибки.
- Добавлен src-like модуль selectors.js: window.TTASelectors с функциями
findTweetText, findTweetAnchor, findAuthorLink, findAccountSwitcher,
findProfileLink, findComposeBox, findDmComposers. Каждая идёт по
цепочке стратегий: testid → семантика (ARIA/lang/dir) → структура.
- Каждый успешный/проваленный поиск пишется в ring-buffer счётчика
selector health (chrome.storage.local.tta_selector_health). Если l1
стабильно проваливается — это сигнал что X сменил DOM. UI-баннер
оставлен на следующую итерацию; диагностика читается из storage.
- manifest content_scripts.js: selectors.js загружается перед
content_script.js, поэтому TTASelectors доступен сразу.
- content_script.js: getTweetText, getAuthorId, detectActiveHandle,
insertIntoComposer и scan() переведены на TTASelectors.*. Старый
inline querySelector('[data-testid="tweetText"]') в attachToTweet
заменён на fallback-chain (нужно было отфильтровать quoted-блок).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 086daa6893
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| el = $(r, 'textarea'); | ||
| if (el) { record('composeBox', 'l3'); return el; } |
There was a problem hiding this comment.
Avoid matching TweAI's own textarea as the X composer
When the native reply composer has not mounted synchronously after article.querySelector('[data-testid="reply"]')?.click(), this generic textarea fallback can match the .tta-compose-input textarea that buildBlock() always inserts inside the same article. Because insertIntoComposer() treats that as success, it skips quickInsert(), so the generated reply is written into the extension prompt box instead of the X reply composer in that timing case.
Useful? React with 👍 / 👎.
Summary
X часто переименовывает
data-testidатрибуты, content_script завязан на них в 6+ местах. После каждого редизайна расширение тихо ломается: пустые ответы, неработающий compose.Введён
selectors.js—window.TTASelectorsс цепочками fallback-стратегий + ring-buffer счётчиком успеха каждого уровня.Что добавлено
selectors.js—TTASelectors.{findTweetText, findTweetAnchor, findAuthorLink, findAccountSwitcher, findProfileLink, findComposeBox, findDmComposers}. Каждая идёт по цепочке: testid → семантика (ARIA/lang/dir) → структура.chrome.storage.local.tta_selector_health. Если уровень 1 стабильно проваливается — это сигнал что X сменил DOM. UI-баннер на эту диагностику оставлен на следующую итерацию (PR-8).selectors.jsгрузится передcontent_script.js(один isolated world, top-level вижен).getTweetText,getAuthorId,detectActiveHandle,insertIntoComposer,scan()теперь черезTTASelectors.*. Inline-querySelector вattachToTweet(где нужно отфильтровать quoted-блок) переведён на fallback-chain руками.Test plan
chrome.storage.local.get('tta_selector_health', console.log)→ видны счётчики l1/l2/l3/miss.data-testidу одного твита → fallback-стратегия 2 находит текст →tweetText.l2инкрементируется.findDmComposersнаходит элементы по testid или по aria-label).findAccountSwitcherилиfindProfileLink).🤖 Generated with Claude Code