# AI Master Plan — cg.cx Refinement Pass ## 1. Current Repo Understanding ### Architecture - **10-crate Rust workspace** (`cgcx-core`, `cgcx-config`, `cgcx-crypto`, `cgcx-db`, `cgcx-storage`, `cgcx-content-typing`, `cgcx-file-pipeline`, `cgcx-moderation`, `cgcx-bot`, `cgcx-server`) - **SQLite** database with WAL mode, 7 migrations already applied (`001_init` through `007_hash_blacklist`) - **Svelte 5** SPA frontend (`frontend/`), Vite build, served as static files by Axum fallback - **Teloxide** bot (standalone binary) + **Axum** server (standalone binary), both share DB and config - Content encrypted with XChaCha20-Poly1305, per-file CEKs wrapped with AES-KW under a master key - BLAKE3 plaintext hashes stored for deduplication and hash-blacklist enforcement ### Already Implemented (verified in code) | Task | Status | Location | |------|--------|----------| | D — GLOBAL_BAN config | ✅ | `config/default.toml` `[groups] global_ban`; `propagate_punishment()` in bot | | F — Approval message with media batches | ✅ | `handle_forward_callback` "approve" — decrypts files, batches up to 10, appends caption to last batch | | G — Review group media | ✅ | `finalize_upload` — decrypts and sends media batches to review group, appends review text to last batch | | H — Review buttons (Ban, Blackl., Ban/BL u.) | ✅ | Inline keyboard in `finalize_upload` and handlers in `handle_forward_callback` | | K — Show/Hide Author toggle | ✅ | `UploadOptions.show_author`, `toggle_author` callback, `show_author` DB column (migration 005) | | L — File list metadata | ✅ | `ViewContent.svelte` shows `created_at`, `total_size`, `author` (username hyperlink + ID) | | M — Deduplication | ✅ | `FilePipeline::ingest_file` checks `find_active_by_plaintext_hash`, increments `ref_count` | | N — Hash blacklist | ✅ | `HashBlacklistRepo`, migration 007, blocked-hash rejection in pipeline | | O — Username change tracking | ✅ | `UserRepo::ensure_exists` logs changes to `data/uname_changes.json` (configurable path in config) | | Partial A — Misc report UI | ✅ | `Home.svelte` already has "Report Content via Telegram" link + "Report Content directly" input/button | | Partial Q — Homepage bot link | ✅ | `Home.svelte` already has `t.me/{BOT_USERNAME}` link, but in wrong DOM order and styling needs tweak | ### Actual Bugs / Gaps to Fix | Task | Root Cause | Fix Strategy | |------|-----------|--------------| | **B — /get_id** | Admin commands gated behind `msg.chat.is_group() \|\| msg.chat.is_supergroup()`, **excluding channels**. Also, HTML parse errors in logs come from unescaped `` tokens in `/help`, but `/get_id` must also be hardened for channels where `msg.from` / admin visibility differs. | Add `msg.chat.is_channel()` to admin command scope. Ensure `handle_get_id_search` gracefully handles channels (`get_chat_administrators` works in channels too if bot is admin). | | **C — /help** | `help_text` raw string contains literal ``, `<@username>`, ``, ``, ``, ``. Telegram HTML parse mode rejects unsupported tags like ``. | Escape all argument placeholders: replace `` with `<arg>` or `[arg]`. Minimally invasive: keep the rest of the formatting intact. | | **E — blacklist_uid / whitelist_uid** | Commands are technically restricted to `admin_group_ids` inside the handler, but the outer command dispatch allows them in any group for admins, producing a confusing "only available in admin group" message. Missing-parameter handling exists but UX is inconsistent with other admin commands. | Move the admin-group check into the command dispatch so non-admin-group chats get a clear "Unauthorized" response. Ensure missing-parameter usage info is returned **before** the admin-group gate when possible, so users in the admin group see usage info immediately. | | **I — Password + auto-destroy 410** | `serve_file` increments `view_count` for **HEAD requests** because `is_conditional` only checks `If-None-Match`, not request method. Some browsers/proxies/link previews issue HEAD before GET, consuming the view and causing the subsequent GET to hit `view_count >= max_views` → 410. | Add `Method` extractor to `serve_file` and skip view increment when `method == Method::HEAD`. Also skip increment for any non-GET method as defense-in-depth. | | **J — Password field UX** | `Home.svelte` `submit()` calls `fetchMetadata(cxid)` **without password first**. For password-protected content this returns 401, throws, and the catch block sets a raw JSON error string. `needsPassword` is **never set to true**, so the password field never appears on the home page. Users cannot access password content from the home page at all. | Restructure `submit()`: on 401 from `fetchMetadata`, explicitly check if the error is auth-related and set `needsPassword = true` instead of treating it as a generic error. Ensure password verification only runs on explicit submit/Enter, not on keystrokes. | | **A — Misc report (complete)** | Frontend UI exists but the "direct" report still opens a Telegram deep link instead of submitting via the web backend. The hardcoded `harmfulmeowbot` username is wrong; should use `BOT_USERNAME` from `api.js`. | Add `POST /api/report` endpoint to the server (it has access to `config.telegram.bot_token`). Server inserts report into DB and forwards a notification to configured review groups via direct Bot API HTTP calls. Update frontend to call the API instead of opening Telegram. | | **Q — Homepage bot link** | Bot link is present in `Home.svelte` but **DOM order is wrong** (currently above Content ID label; should be between Content ID field and "-- cannibal girls --"). Styling says underline + very dark green/blackish green; current color is `var(--retro-green)` which may need to be `var(--retro-accent)` or a darker custom value. | Reorder elements in `Home.svelte`. Adjust CSS to match spec. Keep `BOT_USERNAME` dynamic import. | ## 2. Locked Implementation Rules - **No broad rewrites.** Fix only the targeted bugs and gaps. - **No redesign of working flows.** The upload pipeline, encryption, submission forward system, and moderation engine are working — do not touch them except where task I requires the HEAD-request guard. - **Preserve existing frontend style and behavior.** Keep retro theme, fonts, colors, and animations. Only adjust the specific elements requested in A, J, Q. - **No cleanup-only changes.** Do not refactor unrelated code, rename variables, or change formatting. - **4-agent cycle mandatory** for implementation batches. - **SQLite schema is frozen** except if a new migration is absolutely required. Tasks A–Q do not need new DB tables (report endpoint can reuse existing `reports` table with `reporter_user_id = 0` for web reports). ## 3. Exact Batch Order for This Refinement Pass ### Batch 1: Security + Stability (Agent 1) - **B** — /get_id channel support and robustness - **C** — /help HTML escaping fix - **E** — blacklist_uid/whitelist_uid command behavior refinement - **I** — HEAD request view-count bugfix in `serve_file` ### Batch 2: Telegram Bot + Permissions (Agent 2) - Verify Batch 1 bot changes compile and pass basic smoke tests - **A** backend — Add `POST /api/report` endpoint to server (reuse `reports` table, forward to Telegram review groups via reqwest HTTP call to Bot API) - **O** verification — Confirm username tracking writes correctly in channels/groups - **D** verification — Confirm global_ban propagation logic works with recent schema ### Batch 3: Content Delivery + Rendering (Agent 3) - **A** frontend — Wire "Report Content directly" to call `POST /api/report` instead of Telegram deep link - **J** — Fix home page password flow (needsPassword trigger on 401) - **Q** — Reorder bot link, adjust underline/dark-green styling - **L** verification — Ensure metadata bar renders correctly after Batch 1 server changes ### Batch 4: Docs + QA + Regression (Agent 4) - **P** — Update `docs/COMMANDS.md`, `docs/API.md`, `docs/MODERATION.md`, `README.md` to reflect all changes - Regression test checklist: /get_id in group + channel, /help output, blacklist_uid usage, password+auto-destroy content loads on first GET, home page password flow, report submission API, bot link styling - Run `cargo check --workspace` and `cargo test --workspace` - Run frontend build (`cd frontend && npm run build`) and verify no new warnings ## 4. Key Risks | Risk | Mitigation | |------|-----------| | Adding `Method` extractor to `serve_file` changes its signature and could break route registration if not matched exactly. | Use `extract::Method` in the handler signature; Axum `get()` accepts handlers with extra extractors. | | `POST /api/report` needs to send Telegram messages from the server, which currently has no Telegram client. | Use `reqwest` (already transitive via Axum) to make direct HTTPS POSTs to `https://api.telegram.org/bot/sendMessage`. Add `reqwest` explicitly to `cgcx-server/Cargo.toml`. | | Channel admin command handling may behave differently because `msg.from` in channels can be the channel itself or anonymous. | Use `msg.sender_chat` or check `msg.from` carefully; `is_admin` still works with the bot's own admin check. | | Frontend `fetchMetadata` 401 handling change in J must not break non-password flows. | Only set `needsPassword = true` when `err.status === 401`. Keep existing catch behavior for other errors. | ## 5. Exact 4-Agent Loop ``` Batch N assigned to 4 subagents -> execute in parallel -> wait for all 4 -> brief review -> update AI_CHECKPOINT.md -> continue to Batch N+1 ``` Agent definitions (always use these exact names): 1. **Security + Stability** — Server-side hardening, HTML escaping, view-count logic, command permission gates 2. **Telegram Bot + Permissions** — Bot command behavior, channel support, global_ban, backend API wiring 3. **Content Delivery + Rendering** — Frontend UX, Svelte components, API integration, styling 4. **Docs + QA + Regression** — Documentation updates, end-to-end verification, build checks, regression checklist ## 6. Resume Rules - On any resume, **read this file first**, then `AI_CHECKPOINT.md`, then `AI_RESUME_PROMPT.md`. - Do not skip batches. Do not merge batches. - If a batch fails review, re-run that batch before advancing. - Update `AI_CHECKPOINT.md` after every batch completes. - Preserve all existing working behavior not explicitly listed for change.