max / makenotwork
3 files changed,
+0 insertions,
-549 deletions
| @@ -1,141 +0,0 @@ | |||
| 1 | - | # Exorcise Comments — Inventory | |
| 2 | - | ||
| 3 | - | Inventory of Rust comment density across `MNW/server/src/` and shared crates, to size `/exorcise` sub-batches. Inventory only — no edits. | |
| 4 | - | ||
| 5 | - | Counting method: | |
| 6 | - | - doc comments: `rg '^\s*///|^\s*//!'` | |
| 7 | - | - inline comments: `rg '^\s*//[^/!]'` minus TODO/FIXME lines (those stay) | |
| 8 | - | ||
| 9 | - | ## Grand Totals | |
| 10 | - | ||
| 11 | - | | Scope | Files | Doc lines | Inline lines | | |
| 12 | - | |---|---|---|---| | |
| 13 | - | | Server top-level files (9) | 9 | 391 | 196 | | |
| 14 | - | | Server subdirs | 254 | 4,367 | 2,266 | | |
| 15 | - | | Server total | 263 | 4,758 | 2,462 | | |
| 16 | - | | Shared crates | 33 | 1,327 | 635 | | |
| 17 | - | | **Combined** | **296** | **6,085** | **3,097** | | |
| 18 | - | ||
| 19 | - | Total comment lines surveyed: ~9,182. | |
| 20 | - | ||
| 21 | - | Notes: | |
| 22 | - | - `git_issues/` does not exist in this tree — listed as N/A. | |
| 23 | - | - `templates.rs` does not exist; there is a `templates/` directory (6 files) — inventoried under that name. | |
| 24 | - | - `tauri-updater-ui` has no `src/` (JS-only shipping asset) — listed as N/A. | |
| 25 | - | ||
| 26 | - | ## Server Modules | |
| 27 | - | ||
| 28 | - | ### `payments/` | |
| 29 | - | ||
| 30 | - | High AI-tell risk per task brief (past LLM-assisted edits). | |
| 31 | - | ||
| 32 | - | - Files: 5 (`mod.rs`, `checkout.rs`, `checkout_metadata.rs`, `connect.rs`, `webhooks.rs`) | |
| 33 | - | - Doc lines: 131 | |
| 34 | - | - Inline: 30 | |
| 35 | - | - Judgment: **small batch** (single pass). Low raw count but flagged for scrutiny — read carefully even though counts are modest. | |
| 36 | - | ||
| 37 | - | ### `routes/` | |
| 38 | - | ||
| 39 | - | - Files: 140 | |
| 40 | - | - Doc lines: 1,592 | |
| 41 | - | - Inline: 1,582 | |
| 42 | - | - Judgment: **split into 3–4 sub-batches**. Largest surface in the codebase by file count and inline density. | |
| 43 | - | ||
| 44 | - | ### `db/` | |
| 45 | - | ||
| 46 | - | - Files: 91 | |
| 47 | - | - Doc lines: 2,075 | |
| 48 | - | - Inline: 337 | |
| 49 | - | - Judgment: **split into 2–3**. Doc-comment heavy (highest absolute doc count anywhere); inline is lighter than routes. | |
| 50 | - | ||
| 51 | - | ### Top-level files | |
| 52 | - | ||
| 53 | - | | File | Lines | Doc | Inline | | |
| 54 | - | |---|---|---|---| | |
| 55 | - | | `lib.rs` | 288 | 23 | 6 | | |
| 56 | - | | `config.rs` | 899 | 91 | 52 | | |
| 57 | - | | `error.rs` | 459 | 20 | 16 | | |
| 58 | - | | `auth.rs` | 666 | 65 | 16 | | |
| 59 | - | | `storage.rs` | 860 | 65 | 14 | | |
| 60 | - | | `templates/` (dir, 6 files) | — | 405 | 138 | | |
| 61 | - | | `synckit_auth.rs` | 311 | 15 | 9 | | |
| 62 | - | | `build_runner.rs` | 700 | 34 | 27 | | |
| 63 | - | | `license_templates.rs` | 489 | 13 | 8 | | |
| 64 | - | ||
| 65 | - | - Judgment: **one batch for all top-level `.rs` files** (~330 doc + 117 inline), then **`templates/` as its own small batch** (405 doc + 138 inline — surprisingly dense for a 6-file dir). | |
| 66 | - | ||
| 67 | - | ### `git/` | |
| 68 | - | ||
| 69 | - | - Files: 4 (`mod.rs`, `history.rs`, `objects.rs`, `refs.rs`) | |
| 70 | - | - Doc lines: 47 | |
| 71 | - | - Inline: 46 | |
| 72 | - | - Judgment: **small batch**. | |
| 73 | - | ||
| 74 | - | ### `git_issues/` | |
| 75 | - | ||
| 76 | - | - N/A — directory does not exist under `MNW/server/src/`. | |
| 77 | - | ||
| 78 | - | ### `validation/` | |
| 79 | - | ||
| 80 | - | - Files: 5 | |
| 81 | - | - Doc lines: 73 | |
| 82 | - | - Inline: 80 | |
| 83 | - | - Judgment: **small batch**. | |
| 84 | - | ||
| 85 | - | ### `import/` | |
| 86 | - | ||
| 87 | - | - Files: 3 | |
| 88 | - | - Doc lines: 44 | |
| 89 | - | - Inline: 53 | |
| 90 | - | - Judgment: **small batch**. | |
| 91 | - | ||
| 92 | - | ## Shared Crates | |
| 93 | - | ||
| 94 | - | ### `docengine` | |
| 95 | - | ||
| 96 | - | - Files: 15 | |
| 97 | - | - Doc lines: 261 | |
| 98 | - | - Inline: 190 | |
| 99 | - | - Judgment: **medium batch** (single pass). | |
| 100 | - | ||
| 101 | - | ### `tagtree` | |
| 102 | - | ||
| 103 | - | - Files: 1 | |
| 104 | - | - Doc lines: 378 | |
| 105 | - | - Inline: 148 | |
| 106 | - | - Judgment: **medium batch**. Single file but very doc-heavy — likely deliberate library prose; review with care. | |
| 107 | - | ||
| 108 | - | ### `synckit-client` | |
| 109 | - | ||
| 110 | - | - Files: 15 | |
| 111 | - | - Doc lines: 602 | |
| 112 | - | - Inline: 285 | |
| 113 | - | - Judgment: **split into 2**. Highest doc-line total of any shared crate. | |
| 114 | - | ||
| 115 | - | ### `theme-common` | |
| 116 | - | ||
| 117 | - | - Files: 1 | |
| 118 | - | - Doc lines: 54 | |
| 119 | - | - Inline: 11 | |
| 120 | - | - Judgment: **tiny batch**. | |
| 121 | - | ||
| 122 | - | ### `s3-storage` | |
| 123 | - | ||
| 124 | - | - Files: 1 | |
| 125 | - | - Doc lines: 32 | |
| 126 | - | - Inline: 1 | |
| 127 | - | - Judgment: **tiny batch**. | |
| 128 | - | ||
| 129 | - | ### `tauri-updater-ui` | |
| 130 | - | ||
| 131 | - | - N/A — no Rust `src/` (JS asset crate: `updater.js` + `docs/`). | |
| 132 | - | ||
| 133 | - | ## Recommended Batch Ordering | |
| 134 | - | ||
| 135 | - | 1. `payments/` — small but high AI-tell risk, do first. | |
| 136 | - | 2. `routes/` — split into 3–4 (e.g., by sub-area). | |
| 137 | - | 3. `db/` — split into 2–3. | |
| 138 | - | 4. `synckit-client` — split into 2. | |
| 139 | - | 5. Server top-level files (one batch) + `templates/` (one batch). | |
| 140 | - | 6. `docengine`, `tagtree` — one batch each. | |
| 141 | - | 7. Mop-up: `git/`, `validation/`, `import/`, `theme-common`, `s3-storage`. |
| @@ -1,207 +0,0 @@ | |||
| 1 | - | # Inventory: User-Facing Prose String Literals (Rust) | |
| 2 | - | ||
| 3 | - | ## Methodology | |
| 4 | - | ||
| 5 | - | Ripgrep sweep over `MNW/server/src/` and `MNW/shared/*/src/`, excluding `tests/` directories and any line falling inside a `#[cfg(test)]` module (filter: Python script that pre-computes brace-balanced ranges per file). Goal: surface runtime user-facing prose where AI-tell tone (em-dashes, hedge openers, false contrasts, padding adverbs, "seamless/robust/leverage", checkmark/emoji, etc.) may have leaked in. This is an inventory only; no strings were edited. | |
| 6 | - | ||
| 7 | - | Four categories (plus two derived sub-cuts: `write!(f,...)` for Display body prose, and `impl Display for ...` block headers as a navigation index): | |
| 8 | - | ||
| 9 | - | 1. Flash / toast helpers (`hx_toast` is the canonical helper; no `flash!` macro exists) | |
| 10 | - | 2. `thiserror` `#[error("...")]` annotations | |
| 11 | - | 3. Email / notification builders (file path filtered to `email/` and `notification` files; raw match contained ~183 hits dominated by URL-format helpers in `synckit-client` and `docengine` which were excluded as non-prose) | |
| 12 | - | 4. Hardcoded prose: capital-leading, 40+ chars, ending in period | |
| 13 | - | ||
| 14 | - | ## Grand Totals (post-filter, non-test only) | |
| 15 | - | ||
| 16 | - | | Category | Total hits | Shown | | |
| 17 | - | |---|---:|---:| | |
| 18 | - | | 1. Flash/Toast (`hx_toast`) | 22 | 22 | | |
| 19 | - | | 2. `#[error("...")]` (thiserror) | 40 | 30 | | |
| 20 | - | | 3. Email/notification `format!` builders (email/notification paths only) | 72 | 30 | | |
| 21 | - | | 4. Long prose literals (≥40 chars, sentence-shaped) | 118 | 30 | | |
| 22 | - | | (Aux A) `write!(f, "...")` Display prose (≥20 chars) | 9 | 9 | | |
| 23 | - | | (Aux B) `impl Display for ...` blocks (index) | 15 | 15 | | |
| 24 | - | ||
| 25 | - | **Top 3 files by combined user-facing prose density:** | |
| 26 | - | 1. `server/src/email/templates/notifications.rs` — 29 hits (every email body) | |
| 27 | - | 2. `server/src/error.rs` — 18 hits (central `#[error]` catalog) | |
| 28 | - | 3. `server/src/email/tokens.rs` — 17 hits (unsubscribe action copy) | |
| 29 | - | ||
| 30 | - | Other notable hotspots: | |
| 31 | - | - `server/src/routes/pages/email_actions/account.rs` — 10 prose unsubscribe confirmations | |
| 32 | - | - `server/src/db/creator_tiers.rs` — 11 quota/tier-upsell prose strings | |
| 33 | - | - `server/src/routes/storage/{images,uploads,versions,media}.rs` — repeated copy-paste of "Upload not found. Please try uploading again." and "Could not determine file size. Please try uploading again." (consolidation candidate) | |
| 34 | - | - `shared/synckit-client/src/error.rs` — em-dash usage in error variants ("Encryption not initialized — call setup_encryption first", "Token expired — re-authenticate to continue syncing") — classic AI tell | |
| 35 | - | ||
| 36 | - | ## 1. Flash / Toast (22 hits) | |
| 37 | - | ||
| 38 | - | - `server/src/helpers.rs:142` — `([("HX-Trigger", hx_toast(message, toast_type))], axum::response::Html(String::new()))` | |
| 39 | - | - `server/src/helpers.rs:145` — `pub fn hx_toast(message: &str, toast_type: &str) -> HeaderValue {` | |
| 40 | - | - `server/src/helpers.rs:154` — `tracing::warn!(message, error = %e, "hx_toast produced invalid header value");` | |
| 41 | - | - `server/src/routes/api/license_keys.rs:18` — `helpers::{self, hx_toast, is_htmx_request},` | |
| 42 | - | - `server/src/routes/api/license_keys.rs:461` — `[("HX-Trigger", hx_toast("License key revoked", "success"))],` | |
| 43 | - | - `server/src/routes/api/ssh_keys.rs:12` — `use crate::helpers::{hx_toast, is_htmx_request};` | |
| 44 | - | - `server/src/routes/api/ssh_keys.rs:109` — `[("HX-Trigger", hx_toast("SSH key added", "success"))],` | |
| 45 | - | - `server/src/routes/api/ssh_keys.rs:149` — `[("HX-Trigger", hx_toast("SSH key removed", "success"))],` | |
| 46 | - | - `server/src/routes/api/passkeys.rs:16` — `helpers::hx_toast,` | |
| 47 | - | - `server/src/routes/api/passkeys.rs:128` — `[("HX-Trigger", hx_toast("Passkey registered", "success"))],` | |
| 48 | - | - `server/src/routes/api/passkeys.rs:182` — `[("HX-Trigger", hx_toast("Passkey renamed", "success"))],` | |
| 49 | - | - `server/src/routes/api/passkeys.rs:216` — `[("HX-Trigger", hx_toast("Passkey deleted", "success"))],` | |
| 50 | - | - `server/src/routes/api/totp.rs:15` — `helpers::hx_toast,` | |
| 51 | - | - `server/src/routes/api/totp.rs:106` — `[("HX-Trigger", hx_toast("Two-factor authentication enabled", "success"))],` | |
| 52 | - | - `server/src/routes/api/totp.rs:140` — `[("HX-Trigger", hx_toast("Two-factor authentication disabled", "success"))],` | |
| 53 | - | - `server/src/routes/api/totp.rs:187` — `[("HX-Trigger", hx_toast("Backup codes regenerated", "success"))],` | |
| 54 | - | - `server/src/routes/api/promo_codes.rs:15` — `helpers::{self, hx_toast, is_htmx_request}, ` | |
| 55 | - | - `server/src/routes/api/promo_codes.rs:289` — `[("HX-Trigger", hx_toast("Promo code created", "success"))], ` | |
| 56 | - | - `server/src/routes/api/promo_codes.rs:372` — `[("HX-Trigger", hx_toast("Promo code deleted", "success"))], ` | |
| 57 | - | - `server/src/routes/api/promo_codes.rs:472` — `[("HX-Trigger", hx_toast("Promo code updated", "success"))], ` | |
| 58 | - | - `server/src/routes/api/promo_codes.rs:497` — `[("HX-Trigger", hx_toast(&format!("{count} expired code(s) deleted"), "success"))], ` | |
| 59 | - | - `server/src/routes/api/promo_codes.rs:611` — `[("HX-Trigger", hx_toast("Item added to your library", "success"))], ` | |
| 60 | - | ||
| 61 | - | > Note: no `flash!` macro, `set_flash`, or `add_flash` exists in the codebase. All transient user feedback flows through `hx_toast(message, type)` in `server/src/helpers.rs`, which emits an `HX-Trigger` header consumed by htmx. | |
| 62 | - | ||
| 63 | - | ## 2. `#[error("...")]` (thiserror) — top 30 of 40 | |
| 64 | - | ||
| 65 | - | - `server/src/git/mod.rs:304` — `#[error("Invalid repository or owner name")]` | |
| 66 | - | - `server/src/git/mod.rs:306` — `#[error("Repository not found")]` | |
| 67 | - | - `server/src/git/mod.rs:308` — `#[error("Ref not found")]` | |
| 68 | - | - `server/src/git/mod.rs:310` — `#[error("Tree not found")]` | |
| 69 | - | - `server/src/git/mod.rs:312` — `#[error("Path not found")]` | |
| 70 | - | - `server/src/git/mod.rs:314` — `#[error("Git error: {0}")]` | |
| 71 | - | - `shared/synckit-client/src/error.rs:9` — `#[error("HTTP request failed: {0}")]` | |
| 72 | - | - `shared/synckit-client/src/error.rs:14` — `#[error("Server returned {status}: {message}")]` | |
| 73 | - | - `shared/synckit-client/src/error.rs:25` — `#[error("JSON serialization error: {0}")]` | |
| 74 | - | - `shared/synckit-client/src/error.rs:30` — `#[error("Encryption not initialized — call setup_encryption first")]` | |
| 75 | - | - `shared/synckit-client/src/error.rs:35` — `#[error("Wrong password or corrupted key envelope")]` | |
| 76 | - | - `shared/synckit-client/src/error.rs:39` — `#[error("Invalid key envelope: {0}")]` | |
| 77 | - | - `shared/synckit-client/src/error.rs:44` — `#[error("Encryption error: {0}")]` | |
| 78 | - | - `shared/synckit-client/src/error.rs:48` — `#[error("Base64 decode error: {0}")]` | |
| 79 | - | - `shared/synckit-client/src/error.rs:52` — `#[error("Not authenticated — call authenticate first")]` | |
| 80 | - | - `shared/synckit-client/src/error.rs:57` — `#[error("Token expired — re-authenticate to continue syncing")]` | |
| 81 | - | - `shared/synckit-client/src/error.rs:61` — `#[error("Internal error: {0}")]` | |
| 82 | - | - `shared/synckit-client/src/error.rs:66` — `#[error("Keychain error: {0}")]` | |
| 83 | - | - `server/src/mt_client.rs:15` — `#[error("MT unreachable: {0}")]` | |
| 84 | - | - `server/src/mt_client.rs:17` — `#[error("MT returned error status {status}: {body}")]` | |
| 85 | - | - `server/src/mt_client.rs:19` — `#[error("failed to deserialize MT response: {0}")]` | |
| 86 | - | - `server/src/config.rs:490` — `#[error("Invalid HOST address")]` | |
| 87 | - | - `server/src/config.rs:492` — `#[error("Invalid PORT number")]` | |
| 88 | - | - `server/src/config.rs:494` — `#[error("DATABASE_URL environment variable is required")]` | |
| 89 | - | - `server/src/config.rs:496` — `#[error("SIGNING_SECRET is required in production (HOST=0.0.0.0 or HTTPS HOST_URL detected). Set SIGNING_SECRET to a stable random string.")]` | |
| 90 | - | - `server/src/config.rs:498` — `#[error("SIGNING_SECRET must be at least 32 characters long")]` | |
| 91 | - | - `server/src/error.rs:18` — `#[error("Not found")]` | |
| 92 | - | - `server/src/error.rs:21` — `#[error("Unauthorized")]` | |
| 93 | - | - `server/src/error.rs:24` — `#[error("Forbidden")]` | |
| 94 | - | - `server/src/error.rs:27` — `#[error("Bad request: {0}")]` | |
| 95 | - | ||
| 96 | - | > Many of these (especially in `server/src/error.rs` and `shared/synckit-client/src/error.rs`) surface directly to end users via response bodies or sync-client toasts. The synckit em-dashes (lines 30, 52, 57) are the highest-priority AI-tell candidates. | |
| 97 | - | ||
| 98 | - | ## 3. Email / Notification `format!` builders — top 30 of 72 | |
| 99 | - | ||
| 100 | - | - `server/src/email/templates/notifications.rs:19` — `let subject = format!("New sale: {}", item_title);` | |
| 101 | - | - `server/src/email/templates/notifications.rs:20` — `let body = format!(` | |
| 102 | - | - `server/src/email/templates/notifications.rs:47` — `let body = format!(` | |
| 103 | - | - `server/src/email/templates/notifications.rs:71` — `let subject = format!("{} -- from {}", subject, creator_name);` | |
| 104 | - | - `server/src/email/templates/notifications.rs:72` — `let body = format!(` | |
| 105 | - | - `server/src/email/templates/notifications.rs:99` — `let subject = format!("New release: {} by {}", item_title, creator_name);` | |
| 106 | - | - `server/src/email/templates/notifications.rs:100` — `let body = format!(` | |
| 107 | - | - `server/src/email/templates/notifications.rs:127` — `let subject = format!("New post: {} by {}", post_title, creator_name);` | |
| 108 | - | - `server/src/email/templates/notifications.rs:128` — `let body = format!(` | |
| 109 | - | - `server/src/email/templates/notifications.rs:153` — `let body = format!(` | |
| 110 | - | - `server/src/email/templates/notifications.rs:176` — `let body = format!(` | |
| 111 | - | - `server/src/email/templates/notifications.rs:203` — `let body = format!(` | |
| 112 | - | - `server/src/email/templates/notifications.rs:237` — `let body = format!(` | |
| 113 | - | - `server/src/email/templates/notifications.rs:265` — `let subject = format!("Content removed: {}", item_title);` | |
| 114 | - | - `server/src/email/templates/notifications.rs:266` — `let body = format!(` | |
| 115 | - | - `server/src/email/templates/notifications.rs:291` — `let subject = format!("Content restored: {}", item_title);` | |
| 116 | - | - `server/src/email/templates/notifications.rs:292` — `let body = format!(` | |
| 117 | - | - `server/src/email/templates/notifications.rs:312` — `let body = format!(` | |
| 118 | - | - `server/src/email/templates/notifications.rs:342` — `let body = format!(` | |
| 119 | - | - `server/src/email/templates/notifications.rs:379` — `let subject = format!("New issue on {}/{}: {}", repo_owner, repo_name, issue_title);` | |
| 120 | - | - `server/src/email/templates/notifications.rs:380` — `let body = format!(` | |
| 121 | - | - `server/src/email/templates/notifications.rs:430` — `let subject = format!("Re: New issue on {}/{}: {}", repo_owner, repo_name, issue_title);` | |
| 122 | - | - `server/src/email/templates/notifications.rs:431` — `let body = format!(` | |
| 123 | - | - `server/src/email/templates/notifications.rs:478` — `let subject = format!("{} tipped you {}", tipper_name, price);` | |
| 124 | - | - `server/src/email/templates/notifications.rs:480` — `Some(msg) => format!(` | |
| 125 | - | - `server/src/email/templates/notifications.rs:495` — `None => format!(` | |
| 126 | - | - `server/src/email/templates/notifications.rs:520` — `let subject = format!("{} is leaving Makenot.work — download your purchases", creator_name);` | |
| 127 | - | - `server/src/email/templates/notifications.rs:521` — `let body = format!(` | |
| 128 | - | - `server/src/email/templates/notifications.rs:557` — `let body = format!(` | |
| 129 | - | - `server/src/email/templates/auth.rs:15` — `let body = format!(` | |
| 130 | - | ||
| 131 | - | > Continuation lines for each `let body = format!(` invocation contain the actual prose; this index points at the call sites. `server/src/email/templates/notifications.rs` is the single biggest concentration of runtime-built prose in the codebase and should be the first exorcise target. | |
| 132 | - | ||
| 133 | - | ## 4. Hardcoded prose literals (capital-led, ≥40 chars, sentence-ending) — top 30 of 118 | |
| 134 | - | ||
| 135 | - | - `server/src/email/templates/auth.rs:77` — `.map(|url| format!("Use this link to log in securely:\n\n{}\n\nThis link expires in 15 minutes.", url))` | |
| 136 | - | - `server/src/email/templates/auth.rs:78` — `.unwrap_or_else(|| "Your account will unlock automatically in 15 minutes.".to_string())` | |
| 137 | - | - `server/src/email/templates/monetization.rs:202` — `.map(|d| format!("You will retain your Fan+ benefits until {}.", d.format("%B %-d, %Y")))` | |
| 138 | - | - `server/src/main.rs:137` — `tracing::info!("S3 storage not configured. File uploads will be unavailable.");` | |
| 139 | - | - `server/src/main.rs:164` — `tracing::info!("Stripe not configured. Payments will be unavailable.");` | |
| 140 | - | - `server/src/routes/pages/sandbox.rs:133` — `Some("A sample project to explore the creator dashboard."),` | |
| 141 | - | - `server/src/routes/pages/sandbox.rs:154` — `Some("Edit this item to see how content management works."),` | |
| 142 | - | - `server/src/routes/pages/email_actions/password.rs:47` — `"If an account exists with that email, we've sent a password reset link.",` | |
| 143 | - | - `server/src/routes/pages/email_actions/password.rs:250` — `"This password has appeared in {} known data breach(es). Consider changing it.",` | |
| 144 | - | - `server/src/routes/auth.rs:126` — `"Account is locked. Try again in {} minute(s), or use the login link sent to your email.",` | |
| 145 | - | - `server/src/routes/auth.rs:164` — `"Too many failed attempts. Account locked for {} minutes. A login link has been sent to your email.",` | |
| 146 | - | - `server/src/routes/pages/email_actions/account.rs:80` — `message: "This deletion link has expired. Please request a new one from your account settings.".to_string(),` | |
| 147 | - | - `server/src/routes/pages/email_actions/account.rs:331` — `Ok("You have unfollowed this creator and will no longer receive their broadcasts."` | |
| 148 | - | - `server/src/routes/pages/email_actions/account.rs:336` — `Ok("You will no longer receive emails about new releases from creators you follow."` | |
| 149 | - | - `server/src/routes/pages/email_actions/account.rs:341` — `Ok("You will no longer receive email notifications when someone buys your content."` | |
| 150 | - | - `server/src/routes/pages/email_actions/account.rs:347` — `"You will no longer receive email notifications for new followers."` | |
| 151 | - | - `server/src/routes/pages/email_actions/account.rs:354` — `Ok("You will no longer receive email notifications for new device sign-ins."` | |
| 152 | - | - `server/src/routes/pages/email_actions/account.rs:359` — `Ok("You will no longer receive email notifications for issues on your repositories."` | |
| 153 | - | - `server/src/routes/pages/email_actions/account.rs:364` — `Ok("You will no longer receive platform status notifications.".to_string())` | |
| 154 | - | - `server/src/routes/pages/email_actions/account.rs:371` — `Ok("You have been unsubscribed from this mailing list.".to_string())` | |
| 155 | - | - `server/src/routes/pages/email_actions/account.rs:375` — `Ok("You will no longer receive email notifications for tips.".to_string())` | |
| 156 | - | - `server/src/db/custom_domains.rs:30` — `"You already have a custom domain configured. Remove it first to add a new one.".to_string(),` | |
| 157 | - | - `server/src/routes/git_issues/push_refs.rs:196` — `"Closed via commit ['{}'](/git/{}/{}/commit/{}) on '{}'.",` | |
| 158 | - | - `server/src/routes/git_issues/push_refs.rs:213` — `"Reopened via commit ['{}'](/git/{}/{}/commit/{}) on '{}'.",` | |
| 159 | - | - `server/src/routes/git_issues/push_refs.rs:225` — `"Referenced in commit ['{}'](/git/{}/{}/commit/{}) on '{}'.",` | |
| 160 | - | - `server/src/routes/api/reports.rs:81` — `return Err(AppError::Validation("Report limit reached. Please try again later.".to_string()));` | |
| 161 | - | - `server/src/db/items/bulk.rs:235` — `"Too many copies with similar names. Rename an existing copy first.".to_string(),` | |
| 162 | - | - `server/src/routes/storage/images.rs:140` — `"Upload not found. Please try uploading again.".to_string(),` | |
| 163 | - | - `server/src/routes/storage/images.rs:146` — `AppError::BadRequest("Could not determine file size. Please try uploading again.".to_string())` | |
| 164 | - | - `server/src/routes/storage/images.rs:310` — `"Upload not found. Please try uploading again.".to_string(),` | |
| 165 | - | ||
| 166 | - | > The `email_actions/account.rs` cluster (lines 331–375) is 11 near-identical unsubscribe confirmations — strong candidate for a shared helper. The four `storage/*.rs` files repeat "Upload not found. Please try uploading again." and "Could not determine file size. Please try uploading again." verbatim — consolidation opportunity. | |
| 167 | - | ||
| 168 | - | ## Aux A. `write!(f, "...")` Display body prose (9 hits, all shown) | |
| 169 | - | ||
| 170 | - | - `shared/docengine/src/filters.rs:93` — `Self::TypeError { filter, message } => write!(f, "filter '{filter}': {message}"),` | |
| 171 | - | - `shared/docengine/src/filters.rs:95` — `write!(f, "filter '{filter}' expects {expected} arg(s), got {got}")` | |
| 172 | - | - `shared/docengine/src/filters.rs:98` — `write!(f, "filter '{filter}' arg {position}: expected {expected}")` | |
| 173 | - | - `shared/docengine/src/filters.rs:100` — `Self::DomainError { filter, message } => write!(f, "filter '{filter}': {message}"),` | |
| 174 | - | - `shared/docengine/src/filters.rs:326` — `Self::EmptyExpression => write!(f, "empty expression inside {{{{ }}}}"),` | |
| 175 | - | - `shared/docengine/src/filters.rs:328` — `Self::MissingFilterName => write!(f, "missing filter name after '|'"),` | |
| 176 | - | - `shared/docengine/src/filters.rs:329` — `Self::InvalidArg(s) => write!(f, "invalid filter argument: {s:?}"),` | |
| 177 | - | - `shared/docengine/src/assumptions.rs:41` — `Self::Parse(e) => write!(f, "TOML parse error: {e}"),` | |
| 178 | - | - `shared/docengine/src/assumptions.rs:50` — `write!(f, "unresolved placeholders: {}", unresolved.join(", "))` | |
| 179 | - | ||
| 180 | - | ## Aux B. `impl Display for ...` headers (index, 15 hits) | |
| 181 | - | ||
| 182 | - | - `server/src/email/tokens.rs:21` — `impl std::fmt::Display for UnsubscribeAction {` | |
| 183 | - | - `shared/synckit-client/src/types.rs:23` — `impl fmt::Display for ChangeOp {` | |
| 184 | - | - `shared/docengine/src/filters.rs:90` — `impl fmt::Display for FilterError {` | |
| 185 | - | - `shared/docengine/src/filters.rs:323` — `impl fmt::Display for ParseError {` | |
| 186 | - | - `shared/docengine/src/assumptions.rs:37` — `impl fmt::Display for AssumptionsError {` | |
| 187 | - | - `shared/docengine/src/assumptions.rs:78` — `impl fmt::Display for LookupValue {` | |
| 188 | - | - `shared/tagtree/src/lib.rs:67` — `impl fmt::Display for TagError {` | |
| 189 | - | - `server/src/license_templates.rs:22` — `impl fmt::Display for LicensePreset {` | |
| 190 | - | - `server/src/db/analytics.rs:31` — `impl std::fmt::Display for TimeRange {` | |
| 191 | - | - `server/src/db/enums.rs:14` — `impl std::fmt::Display for $enum_name {` | |
| 192 | - | - `server/src/db/id_types.rs:50` — `impl fmt::Display for $name {` | |
| 193 | - | - `server/src/db/validated_types.rs:63` — `impl std::fmt::Display for $name {` | |
| 194 | - | - `server/src/db/validated_types.rs:184` — `impl std::fmt::Display for Email {` | |
| 195 | - | - `server/src/db/validated_types.rs:283` — `impl std::fmt::Display for Cents {` | |
| 196 | - | - `server/src/db/validated_types.rs:421` — `impl std::fmt::Display for PriceCents {` | |
| 197 | - | ||
| 198 | - | > Read the immediately-following `match` arms in each of these to audit Display body text. | |
| 199 | - | ||
| 200 | - | ## Recommended Exorcise Priority | |
| 201 | - | ||
| 202 | - | 1. `server/src/email/templates/notifications.rs` — highest reader exposure, most prose per file | |
| 203 | - | 2. `server/src/email/templates/auth.rs` and `monetization.rs` — auth/billing copy is high-stakes | |
| 204 | - | 3. `server/src/routes/pages/email_actions/account.rs` — duplicated unsubscribe prose, consolidate then exorcise | |
| 205 | - | 4. `shared/synckit-client/src/error.rs` — em-dashes in error messages | |
| 206 | - | 5. `server/src/db/creator_tiers.rs` — tier-upsell prose, business-critical tone | |
| 207 | - | 6. Storage upload error duplication across `routes/storage/{images,uploads,versions,media}.rs` and `routes/api/internal/uploads.rs` — consolidate before exorcising |
| @@ -1,201 +0,0 @@ | |||
| 1 | - | # Exorcise Templates Inventory | |
| 2 | - | ||
| 3 | - | This file inventories every `.html` template under `MNW/server/templates/` and tags each one for the upcoming `/exorcise` campaign. Categories are picked by a quick read plus grep of paragraph tags and natural-language sentences. **prose-heavy** files carry enough human-readable copy (paragraphs, descriptions, empty states, help text, flash text) that an exorcise pass has surface area to find LLM tells (em-dashes, hedge openers, false contrasts, padding adverbs, decorative emoji, overused vocab). **chrome-only** files are structural HTML/CSS/JS with only short button labels and form chrome — skippable. **mixed** files are mostly structural with a meaningful chunk of prose embedded (a settings page with one explanatory paragraph, an upload widget with help text). | |
| 4 | - | ||
| 5 | - | **Total: 181 files. 73 prose-heavy / 47 mixed / 61 chrome-only.** | |
| 6 | - | ||
| 7 | - | ## templates/ (root) | |
| 8 | - | ||
| 9 | - | - `_head_assets.html` — chrome-only: head assets, link/script tags. | |
| 10 | - | - `base.html` — chrome-only: layout skeleton with header/footer blocks. | |
| 11 | - | - `index.html` — chrome-only: trivial redirect/landing stub. | |
| 12 | - | ||
| 13 | - | ## dashboards/ | |
| 14 | - | ||
| 15 | - | - `dashboards/admin-appeals.html` — chrome-only: admin table with appeal entries partial. | |
| 16 | - | - `dashboards/admin-metrics.html` — mixed: admin metrics tables with section descriptions and threshold notes. | |
| 17 | - | - `dashboards/admin-reports.html` — chrome-only: admin reports table. | |
| 18 | - | - `dashboards/admin-signups.html` — mixed: signup queue with reviewer guidance copy. | |
| 19 | - | - `dashboards/admin-uploads.html` — chrome-only: upload moderation table. | |
| 20 | - | - `dashboards/admin-users.html` — chrome-only: user admin table. | |
| 21 | - | - `dashboards/admin-waitlist.html` — chrome-only: waitlist table chrome. | |
| 22 | - | - `dashboards/dashboard-blog-editor.html` — chrome-only: markdown editor scaffold. | |
| 23 | - | - `dashboards/dashboard-delete-account.html` — prose-heavy: deletion warning copy, recovery window explainer. | |
| 24 | - | - `dashboards/dashboard-export.html` — prose-heavy: export descriptions for each data type. | |
| 25 | - | - `dashboards/dashboard-import.html` — prose-heavy: import guide, per-platform notes, coming-soon list. | |
| 26 | - | - `dashboards/dashboard-item.html` — chrome-only: tab shell for item dashboard. | |
| 27 | - | - `dashboards/dashboard-project.html` — chrome-only: tab shell for project dashboard. | |
| 28 | - | - `dashboards/dashboard-user.html` — prose-heavy: account-state banners (deactivated/paused/suspended) with explanatory copy. | |
| 29 | - | ||
| 30 | - | ## pages/ | |
| 31 | - | ||
| 32 | - | - `pages/account-deleted.html` — prose-heavy: farewell copy. | |
| 33 | - | - `pages/audio_player.html` — mixed: player chrome with description and metadata blocks. | |
| 34 | - | - `pages/blog_post.html` — prose-heavy: blog post body rendered as long-form markdown. | |
| 35 | - | - `pages/buy.html` — mixed: checkout chrome with terms and disclosure copy. | |
| 36 | - | - `pages/cart.html` — prose-heavy: cart empty states, wishlist prompts, checkout copy. | |
| 37 | - | - `pages/changelog.html` — prose-heavy: changelog entries are pure prose. | |
| 38 | - | - `pages/collection.html` — mixed: collection page with description block. | |
| 39 | - | - `pages/confirm_delete.html` — prose-heavy: deletion confirmation warning copy. | |
| 40 | - | - `pages/creators.html` — prose-heavy: creator-pitch landing page, multiple paragraphs. | |
| 41 | - | - `pages/discover.html` — mixed: long template, mostly card chrome but with empty-state and section intro copy. | |
| 42 | - | - `pages/doc_index.html` — mixed: doc index page with intro paragraph. | |
| 43 | - | - `pages/doc.html` — prose-heavy: rendered documentation body. | |
| 44 | - | - `pages/email_result.html` — prose-heavy: short result message page. | |
| 45 | - | - `pages/error.html` — prose-heavy: error message body. | |
| 46 | - | - `pages/fan_plus.html` — prose-heavy: Fan Plus tier pitch and benefits. | |
| 47 | - | - `pages/feed.html` — mixed: feed listing with empty-state and intro copy. | |
| 48 | - | - `pages/forgot_password.html` — prose-heavy: password reset instructions. | |
| 49 | - | - `pages/git/blame.html` — chrome-only: blame table. | |
| 50 | - | - `pages/git/commit.html` — chrome-only: commit diff view. | |
| 51 | - | - `pages/git/commits.html` — chrome-only: commit list. | |
| 52 | - | - `pages/git/explore.html` — chrome-only: repo browse grid. | |
| 53 | - | - `pages/git/file_log.html` — chrome-only: file history table. | |
| 54 | - | - `pages/git/file.html` — chrome-only: file viewer chrome. | |
| 55 | - | - `pages/git/issue.html` — mixed: issue thread with reply-by-email instructions. | |
| 56 | - | - `pages/git/issues.html` — chrome-only: issue list table. | |
| 57 | - | - `pages/git/repo.html` — mixed: repo header with README placeholder and empty-state copy. | |
| 58 | - | - `pages/git/repos.html` — chrome-only: repo list. | |
| 59 | - | - `pages/git/settings.html` — mixed: settings form with field help text. | |
| 60 | - | - `pages/git/tree.html` — chrome-only: tree browser. | |
| 61 | - | - `pages/health.html` — mixed: probe results with summaries; mostly tabular but some explanatory text. | |
| 62 | - | - `pages/index.html` — prose-heavy: marketing landing page. | |
| 63 | - | - `pages/item.html` — prose-heavy: public item page with description and bundle/section copy. | |
| 64 | - | - `pages/library_audio.html` — mixed: audio library player with item metadata. | |
| 65 | - | - `pages/library_downloads.html` — mixed: downloads list with per-file help copy. | |
| 66 | - | - `pages/library_locked.html` — prose-heavy: locked-library explainer. | |
| 67 | - | - `pages/library_text.html` — mixed: text library viewer chrome with description. | |
| 68 | - | - `pages/library_video.html` — mixed: video library viewer. | |
| 69 | - | - `pages/library.html` — chrome-only: library tab shell. | |
| 70 | - | - `pages/login.html` — chrome-only: login form. | |
| 71 | - | - `pages/oauth_authorize.html` — mixed: OAuth consent screen with scope descriptions. | |
| 72 | - | - `pages/policy.html` — prose-heavy: content policy long-form text. | |
| 73 | - | - `pages/pricing.html` — prose-heavy: pricing page with tier descriptions and FAQ. | |
| 74 | - | - `pages/project_blog.html` — mixed: project blog index with intro copy. | |
| 75 | - | - `pages/project_paywall.html` — prose-heavy: paywall explainer with tier options. | |
| 76 | - | - `pages/project.html` — prose-heavy: public project page with description and section copy. | |
| 77 | - | - `pages/purchase.html` — prose-heavy: purchase flow with tier explainers and disclosures. | |
| 78 | - | - `pages/receipt.html` — mixed: receipt template with thank-you copy. | |
| 79 | - | - `pages/reset_password.html` — prose-heavy: reset password instructions and expiry messages. | |
| 80 | - | - `pages/sandbox.html` — chrome-only: developer sandbox. | |
| 81 | - | - `pages/stripe_disclaimer.html` — prose-heavy: Stripe flow explainer, paragraphs of policy. | |
| 82 | - | - `pages/tag_tree.html` — chrome-only: tag tree visualization. | |
| 83 | - | - `pages/team.html` — prose-heavy: team bios and founder narrative. | |
| 84 | - | - `pages/text_reader.html` — mixed: reader chrome with content body. | |
| 85 | - | - `pages/two_factor.html` — prose-heavy: 2FA instruction copy. | |
| 86 | - | - `pages/use_cases.html` — prose-heavy: use-case landing page, multiple pitches per medium. | |
| 87 | - | - `pages/user.html` — mixed: public profile with bio and item lists. | |
| 88 | - | - `pages/video_player.html` — mixed: video page with description blocks. | |
| 89 | - | ||
| 90 | - | ## partials/ | |
| 91 | - | ||
| 92 | - | - `partials/_ui.html` — chrome-only: UI helper macros. | |
| 93 | - | - `partials/admin_appeal_entries.html` — chrome-only: admin table rows. | |
| 94 | - | - `partials/admin_nav.html` — chrome-only: admin nav links. | |
| 95 | - | - `partials/admin_report_entries.html` — chrome-only: admin table rows. | |
| 96 | - | - `partials/admin_upload_entries.html` — chrome-only: admin table rows. | |
| 97 | - | - `partials/admin_user_entries.html` — chrome-only: admin table rows. | |
| 98 | - | - `partials/admin_waitlist_entries.html` — chrome-only: admin table rows. | |
| 99 | - | - `partials/alert.html` — chrome-only: one-line alert macro. | |
| 100 | - | - `partials/discover_results.html` — mixed: card grid with empty-state and sort-label copy. | |
| 101 | - | - `partials/discussion_section.html` — chrome-only: discussion block scaffold. | |
| 102 | - | - `partials/error_fragment.html` — chrome-only: tiny error fragment. | |
| 103 | - | - `partials/export_content_ready.html` — chrome-only: HTMX swap fragment. | |
| 104 | - | - `partials/export_download.html` — chrome-only: download link fragment. | |
| 105 | - | - `partials/follow_button.html` — chrome-only: follow toggle. | |
| 106 | - | - `partials/form_status.html` — chrome-only: form status indicator. | |
| 107 | - | - `partials/git_nav.html` — chrome-only: git nav tabs. | |
| 108 | - | - `partials/insertion_list.html` — chrome-only: list builder UI. | |
| 109 | - | - `partials/item_analytics.html` — chrome-only: analytics charts and stat cards. | |
| 110 | - | - `partials/item_audio_upload.html` — chrome-only: audio upload widget. | |
| 111 | - | - `partials/item_edit_row.html` — chrome-only: editable row. | |
| 112 | - | - `partials/item_license_keys.html` — chrome-only: license key table. | |
| 113 | - | - `partials/item_text_editor.html` — mixed: markdown editor with help-text panel. | |
| 114 | - | - `partials/item_version_upload.html` — chrome-only: version upload widget. | |
| 115 | - | - `partials/library_status.html` — chrome-only: status one-liner. | |
| 116 | - | - `partials/link_row.html` — chrome-only: link row macro. | |
| 117 | - | - `partials/login_error.html` — chrome-only: tiny error swap. | |
| 118 | - | - `partials/onboarding_checklist.html` — mixed: checklist with per-step help text. | |
| 119 | - | - `partials/passkey_list.html` — mixed: passkey list with explanation paragraph. | |
| 120 | - | - `partials/paywall.html` — prose-heavy: paywall message with tier prompts (small but dense). | |
| 121 | - | - `partials/placement_list.html` — chrome-only: placement table. | |
| 122 | - | - `partials/promo_codes_list.html` — chrome-only: promo code table. | |
| 123 | - | - `partials/report_modal.html` — chrome-only: report modal form. | |
| 124 | - | - `partials/save_status.html` — chrome-only: save indicator. | |
| 125 | - | - `partials/share_link.html` — chrome-only: empty/trivial file. | |
| 126 | - | - `partials/site_header.html` — chrome-only: header nav. | |
| 127 | - | - `partials/slug_status.html` — chrome-only: slug availability indicator. | |
| 128 | - | - `partials/ssh_keys_list.html` — mixed: SSH key list with help text. | |
| 129 | - | - `partials/suspension_banner.html` — prose-heavy: suspension banner copy with appeal instructions. | |
| 130 | - | - `partials/tabs/buyer_contacts.html` — chrome-only: contacts table. | |
| 131 | - | - `partials/tabs/item_details.html` — prose-heavy: extensive form help text and section explainers. | |
| 132 | - | - `partials/tabs/item_embed.html` — prose-heavy: per-embed-format description copy. | |
| 133 | - | - `partials/tabs/item_files.html` — chrome-only: file row macro. | |
| 134 | - | - `partials/tabs/item_overview.html` — mixed: item overview with status copy. | |
| 135 | - | - `partials/tabs/item_pricing.html` — prose-heavy: pricing model explainers, license terms text. | |
| 136 | - | - `partials/tabs/item_sales.html` — mixed: sales table with refund-policy notes. | |
| 137 | - | - `partials/tabs/item_settings.html` — mixed: settings form with help text. | |
| 138 | - | - `partials/tabs/library_collections.html` — mixed: collections UI with empty-state copy. | |
| 139 | - | - `partials/tabs/library_communities.html` — mixed: community tab with intro copy. | |
| 140 | - | - `partials/tabs/library_contacts.html` — mixed: contacts tab with help text. | |
| 141 | - | - `partials/tabs/library_feed.html` — mixed: feed tab with empty-state copy. | |
| 142 | - | - `partials/tabs/library_purchases.html` — mixed: purchase history with note copy. | |
| 143 | - | - `partials/tabs/library_subscriptions.html` — chrome-only: subscriptions table. | |
| 144 | - | - `partials/tabs/library_wishlists.html` — mixed: wishlist with empty-state copy. | |
| 145 | - | - `partials/tabs/project_analytics.html` — chrome-only: analytics charts. | |
| 146 | - | - `partials/tabs/project_blog.html` — mixed: blog tab with intro copy. | |
| 147 | - | - `partials/tabs/project_code.html` — mixed: git/code panel with help text. | |
| 148 | - | - `partials/tabs/project_content.html` — prose-heavy: content tab with several empty-state and explainer paragraphs. | |
| 149 | - | - `partials/tabs/project_members.html` — mixed: member management with role descriptions. | |
| 150 | - | - `partials/tabs/project_monetization.html` — chrome-only: stub tab. | |
| 151 | - | - `partials/tabs/project_overview.html` — prose-heavy: onboarding-style overview with multiple help paragraphs. | |
| 152 | - | - `partials/tabs/project_promotions.html` — prose-heavy: promo code creation with rule explainers. | |
| 153 | - | - `partials/tabs/project_settings.html` — prose-heavy: settings form with extensive per-field help copy. | |
| 154 | - | - `partials/tabs/project_subscriptions.html` — mixed: subscription tab with explainer. | |
| 155 | - | - `partials/tabs/project_synckit.html` — prose-heavy: SyncKit explainer paragraphs. | |
| 156 | - | - `partials/tabs/user_account.html` — prose-heavy: account settings with help text per option. | |
| 157 | - | - `partials/tabs/user_analytics.html` — chrome-only: analytics charts. | |
| 158 | - | - `partials/tabs/user_creator.html` — prose-heavy: creator tier copy, trial guidance, founder pricing notes. | |
| 159 | - | - `partials/tabs/user_forums.html` — mixed: forum tab with intro copy. | |
| 160 | - | - `partials/tabs/user_media.html` — prose-heavy: media library with help text and empty states. | |
| 161 | - | - `partials/tabs/user_payments.html` — prose-heavy: payments tab with Stripe Connect onboarding copy and status messages. | |
| 162 | - | - `partials/tabs/user_profile.html` — prose-heavy: profile fields with per-field help text and RSS explainer. | |
| 163 | - | - `partials/tabs/user_projects.html` — mixed: projects tab with empty-state. | |
| 164 | - | - `partials/tabs/user_sessions.html` — mixed: session list with security note. | |
| 165 | - | - `partials/tabs/user_settings.html` — chrome-only: settings shell. | |
| 166 | - | - `partials/tabs/user_ssh_keys_tab.html` — mixed: SSH keys tab with help text. | |
| 167 | - | - `partials/tabs/user_ssh_keys.html` — mixed: SSH keys panel with help text. | |
| 168 | - | - `partials/tabs/user_support.html` — prose-heavy: support tab with contact and policy copy. | |
| 169 | - | - `partials/tabs/user_synckit.html` — prose-heavy: SyncKit explainer for users. | |
| 170 | - | - `partials/tag_follow_toggle.html` — chrome-only: toggle button. | |
| 171 | - | - `partials/tag_suggestions.html` — chrome-only: suggestion list. | |
| 172 | - | - `partials/tag.html` — chrome-only: tag macro. | |
| 173 | - | - `partials/tip_button.html` — chrome-only: tip button. | |
| 174 | - | - `partials/toast.html` — chrome-only: toast macro. | |
| 175 | - | - `partials/totp_setup.html` — prose-heavy: TOTP setup instructions. | |
| 176 | - | - `partials/totp_status.html` — prose-heavy: TOTP status messages with backup-code guidance. | |
| 177 | - | - `partials/transactions_table.html` — chrome-only: transaction table. | |
| 178 | - | - `partials/username_status.html` — chrome-only: username availability indicator. | |
| 179 | - | ||
| 180 | - | ## wizards/ | |
| 181 | - | ||
| 182 | - | - `wizards/partials/step_nav.html` — chrome-only: prev/next buttons. | |
| 183 | - | - `wizards/steps/item/basics.html` — mixed: form fields with per-field help text. | |
| 184 | - | - `wizards/steps/item/content.html` — prose-heavy: upload step with extensive drop-zone and per-type instructions. | |
| 185 | - | - `wizards/steps/item/preview.html` — mixed: preview step with summary copy. | |
| 186 | - | - `wizards/steps/item/pricing.html` — mixed: pricing form with help text. | |
| 187 | - | - `wizards/steps/item/sections.html` — mixed: tabbed sections builder with help text. | |
| 188 | - | - `wizards/steps/item/type.html` — mixed: type chooser with descriptions. | |
| 189 | - | - `wizards/steps/join/account.html` — mixed: account form with intro copy. | |
| 190 | - | - `wizards/steps/join/complete.html` — prose-heavy: completion screen with branching welcome copy. | |
| 191 | - | - `wizards/steps/join/pitch.html` — prose-heavy: creator-application pitch instructions. | |
| 192 | - | - `wizards/steps/join/profile.html` — mixed: profile form with help text. | |
| 193 | - | - `wizards/steps/join/stripe.html` — prose-heavy: Stripe Connect onboarding explainer. | |
| 194 | - | - `wizards/steps/project/appearance.html` — mixed: appearance form with per-field help text. | |
| 195 | - | - `wizards/steps/project/basics.html` — mixed: basics form with help text. | |
| 196 | - | - `wizards/steps/project/first_content.html` — prose-heavy: first-content prompt with explainer. | |
| 197 | - | - `wizards/steps/project/monetization.html` — mixed: monetization form with tier descriptions. | |
| 198 | - | - `wizards/steps/project/preview.html` — mixed: preview step with summary copy. | |
| 199 | - | - `wizards/wizard_item.html` — chrome-only: wizard shell. | |
| 200 | - | - `wizards/wizard_join.html` — mixed: join wizard shell with intro copy. | |
| 201 | - | - `wizards/wizard_project.html` — mixed: project wizard shell with summary copy. |