# Persian RTL Reliability Implementation Plan > **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. **Goal:** Make the extension conservatively correct Persian text direction, add Vazirmatn only to author-unstyled Persian text, remain responsive during streaming AI chats, and provide a clearer accessible popup. **Architecture:** Keep the dependency-free Manifest V3 structure. Replace the corrupted broad Arabic-range detector with testable Persian-specific helpers inside the isolated content script, apply reversible DOM mutations, and coalesce mutation work by semantic block. Keep settings in `chrome.storage.local` and make the popup a small controller over the same schema. **Tech Stack:** Chrome Extensions Manifest V3, plain JavaScript, HTML/CSS, Node.js, jsdom 29. ## Global Constraints - Detect Persian text only; Arabic-only and Hebrew text do not trigger changes. - Never rewrite text, punctuation, or Latin digits. - Any author-specified font family counts as styled, including generic and inherited families. - Work automatically on all supported websites and optimize for streaming AI chats without site-specific selectors. - All mutations must be reversible without a reload. - This folder is not a Git repository, so verification checkpoints replace commit steps. --- ### Task 1: Real UTF-8 Detection and Direction Contract **Files:** - Create: `test/content-engine.js` - Modify: `src/content.js` - Remove after replacement: `test/integration-v2.js`, `test/regex-test.js` **Interfaces:** - Consumes: the content script's automatic bootstrap with a mocked `chrome` API. - Produces: Persian detection based on Persian-specific letters; conservative `rtl`/`auto` decisions and byte-identical text. - [ ] **Step 1: Add failing fixtures** for `این متن فارسی است`, Arabic-only `هذا نص عربي`, mixed English/Persian text, and `نسخه 1234567890`. - [ ] **Step 2: Run** `node test/content-engine.js`; expect failures for Persian detection and Arabic-only isolation against the corrupted current range. - [ ] **Step 3: Replace the range** with explicit Unicode escapes for Persian-specific letters plus a broader Arabic-script letter count used only after a Persian trigger. Classify first-strong Persian blocks as `rtl`, English-leading mixed blocks as `auto`, and preserve the original text exactly. - [ ] **Step 4: Run** `node test/content-engine.js`; expect all direction and integrity assertions to pass. ### Task 2: Conservative Targets and Author-Font Detection **Files:** - Modify: `test/content-engine.js` - Modify: `src/content.js` **Interfaces:** - Consumes: `processTextNode(node, votedBlocks)` and reversible element markers. - Produces: semantic block targeting, explicit-direction preservation, and `hasAuthorFont(element): boolean` behavior. - [ ] **Step 1: Add failing cases** for existing `dir="rtl"`, sensible inherited direction, inline Arial, stylesheet `font-family: sans-serif`, inherited body font, and a document with no author font. - [ ] **Step 2: Run** `node test/content-engine.js`; expect the current unconditional Vazirmatn behavior to fail the author-font cases. - [ ] **Step 3: Implement author-font inspection** by walking the element/ancestor chain and checking matching author stylesheet declarations plus inline declarations. Apply Vazirmatn only when no declaration exists; isolate inaccessible stylesheet errors. - [ ] **Step 4: Refine target selection** so paragraph/list/heading/message-sized containers win over broad sections, while code, SVG, MathML, and editable content remain protected. - [ ] **Step 5: Run** `node test/content-engine.js`; expect all font and target cases to pass. ### Task 3: Streaming, Inputs, Frames, and Reversible Lifecycle **Files:** - Modify: `test/content-engine.js` - Modify: `test/edge-cases.js` - Modify: `src/content.js` - Modify: `manifest.json` **Interfaces:** - Consumes: queued text nodes/roots and storage change callbacks. - Produces: one scheduled processing pass per burst, reversible teardown/reapply, and related-frame coverage through Manifest V3 fields. - [ ] **Step 1: Add asynchronous tests** that append a streaming Persian response in several character-data mutations, toggle settings off/on, and verify text identity plus restored `dir`/font state. - [ ] **Step 2: Run** `node test/content-engine.js` and `node test/edge-cases.js`; expect streaming/lifecycle failures where stale direction or styling remains. - [ ] **Step 3: Coalesce work by block** and re-evaluate a previously processed block when streamed text changes its classification. Clear queues and observers during teardown. - [ ] **Step 4: Keep inputs at `dir="auto"`** without rewriting their values, and apply the unstyled-font policy consistently. - [ ] **Step 5: Add `match_origin_as_fallback: true`** beside `all_frames` for related `about:`, `data:`, `blob:`, and `filesystem:` frames. - [ ] **Step 6: Run both tests**; expect zero failures and no unhandled jsdom errors. ### Task 4: Accessible Popup and Settings Migration **Files:** - Create: `test/popup.js` - Modify: `popup/popup.html` - Modify: `popup/popup.css` - Modify: `popup/popup.js` **Interfaces:** - Consumes: settings `{ enabled, fixDirection, useFont, fixInputs, disabledSites }` with legacy values safely defaulted. - Produces: current-site status, master/site/direction/font/input controls, and safe unsupported-page/error states. - [ ] **Step 1: Add popup controller tests** with mocked tabs/storage for a normal HTTPS tab, `chrome://extensions`, storage failure, dependency disabling, and setting persistence. - [ ] **Step 2: Run** `node test/popup.js`; expect failure because current markup lacks status and `fixDirection`. - [ ] **Step 3: Update markup and copy** to expose the approved five controls and a live status region. Use native checkbox semantics and explicit labels. - [ ] **Step 4: Update styles** with visible keyboard focus, sufficient contrast, disabled states, compact spacing, and status icons/text that do not rely on color. - [ ] **Step 5: Update controller** to use `chrome.runtime.lastError`, tolerate missing tab URLs, disable site controls for unsupported pages, and migrate the old settings shape without data loss. - [ ] **Step 6: Run** `node test/popup.js`; expect all controller and accessibility assertions to pass. ### Task 5: Demo, Documentation, and Complete Verification **Files:** - Modify: `demo.html` - Modify: `README.md` - Modify: `package.json` - Modify: `manifest.json` **Interfaces:** - Consumes: the final behavior and test commands. - Produces: correctly encoded manual fixtures, accurate installation/behavior documentation, and a single test entry point. - [ ] **Step 1: Replace mojibake** in user-visible metadata, popup copy, README, demo, test labels, and Persian fixtures with valid UTF-8. - [ ] **Step 2: Add a streaming-chat demo** that appends Persian text incrementally without converting its Latin digits. - [ ] **Step 3: Add package scripts**: `"test": "node test/content-engine.js && node test/edge-cases.js && node test/popup.js"` and `"check:encoding": "node test/encoding.js"`; add an encoding test that rejects known mojibake markers and requires real Persian fixtures. - [ ] **Step 4: Run** `npm test`; expect all suites to pass. - [ ] **Step 5: Run** `npm run check:encoding`; expect `Encoding check passed`. - [ ] **Step 6: Parse `manifest.json`** with Node and inspect the popup/demo in a Chromium browser if available; record any browser-only validation still required. ## Self-Review - Spec coverage: direction, Persian-only scope, digit preservation, font policy, streaming, popup, reversibility, errors, demo, and tests are each assigned above. - Placeholder scan: no unresolved implementation placeholders remain. - Interface consistency: the shared settings keys are `enabled`, `fixDirection`, `useFont`, `fixInputs`, and `disabledSites` in content, popup, and tests.