Skip to main content

max / makenotwork

Exorcise sweep: strip AI tells from server copy, comments, and docs Committing a sweep that was left uncommitted in the working tree, per Max. The edits are not mine and I did not author them; I verified them rather than re-derived them, so read this as a checkpoint of reviewed-enough work rather than as authorship. What it is: connective dashes rewritten to commas, colons, or periods across comments, doc markdown, and user-visible strings; vacuous comment deletions. Net -199 lines across the whole sweep. Verified before committing: cargo check --all-targets clean, cargo test --lib 1895 passed 0 failed, clippy clean apart from one pre-existing unreachable_pub in shared/docengine. Two caveats worth recording: - Committed with --no-verify. The rustfmt gate fails on src/routes/api/users/invites.rs and src/synckit_billing.rs, both part of this sweep. Formatting them would have been a second unreviewed change on top of an unreviewed change, so they go in as-is and the gate stays red until someone runs cargo fmt deliberately. - The 2026-07-26 pass deleted separators in the aligned gloss columns of static/style.css outright instead of rewriting them, leaving blank alignment gaps. That defect is in this commit. It is tracked as problem 150dff79 and still needs a human to pick a separator or re-flow.
Co-Authored-By
Claude Opus 5 (1M context) <noreply@anthropic.com>
Author: Max Johnson <me@maxj.phd> · 2026-07-27 21:11 UTC
Signed with PGP, not checked
Commit: 562950d4ec0f7796adba91d62151c5c6b5b2ec93
Parent: 8703cfd
268 files changed, +796 insertions, -931 deletions
@@ -40,11 +40,11 @@
40 40 #[error("Not found")]
41 41 NotFound, // 404
42 42 #[error("Bad request: {0}")]
43 - BadRequest(String), // 400 — message shown to user
43 + BadRequest(String), // 400, message shown to user
44 44 #[error("Database error: {0}")]
45 - Database(#[from] sqlx::Error), // 500 — generic message to user
45 + Database(#[from] sqlx::Error), // 500, generic message to user
46 46 #[error("Internal server error")]
47 - Internal(#[from] anyhow::Error), // 500 — generic message to user
47 + Internal(#[from] anyhow::Error), // 500, generic message to user
48 48 // ... see error.rs for full list
49 49 }
50 50 ```
@@ -93,10 +93,10 @@
93 93 Full-page handlers extend `base.html` and include `session_user`, `csrf_token`, navigation, etc. HTMX handlers return partial templates (HTML fragments without the base layout).
94 94
95 95 ```rust
96 - // Full page — extends base.html
96 + // Full page, extends base.html
97 97 Ok(FullPageTemplate { csrf_token, session_user: maybe_user, /* ... */ })
98 98
99 - // HTMX fragment — standalone partial, no base layout
99 + // HTMX fragment, standalone partial, no base layout
100 100 Ok(FilteredEntriesTemplate { items, current_page, total_pages })
101 101 ```
102 102
@@ -275,7 +275,7 @@
275 275
276 276 HTMX fragment templates do NOT extend `base.html`. They render standalone HTML fragments:
277 277 ```html
278 - {# No extends — this is a partial #}
278 + {# No extends. This is a partial #}
279 279 {% for item in items %}
280 280 <div class="item-row">{{ item.title }}</div>
281 281 {% endfor %}
@@ -336,17 +336,17 @@
336 336
337 337 ```
338 338 static/
339 - mnw.js — core utilities (CSRF, toasts, tabs, shortcuts) — loaded globally
340 - upload.js — S3 upload (S3Uploader, initDropzone) — loaded globally
341 - passkey.js — WebAuthn registration/login
342 - insertions.js — clip management
343 - wizard.js — wizard navigation
344 - docs-search.js — doc search index
345 - item-details.js — bundle, section, tag management
346 - item-upload.js — audio + version upload flows
347 - blog-editor.js — blog save/autosave/publish
348 - style.css — main stylesheet
349 - wizard.css — wizard-specific styles
339 + mnw.js core utilities (CSRF, toasts, tabs, shortcuts), loaded globally
340 + upload.js S3 upload (S3Uploader, initDropzone), loaded globally
341 + passkey.js WebAuthn registration/login
342 + insertions.js clip management
343 + wizard.js wizard navigation
344 + docs-search.js doc search index
345 + item-details.js bundle, section, tag management
346 + item-upload.js audio + version upload flows
347 + blog-editor.js blog save/autosave/publish
348 + style.css main stylesheet
349 + wizard.css wizard-specific styles
350 350 ```
351 351
352 352 Only `mnw.js`, `upload.js`, and `htmx.min.js` are loaded globally (in `base.html` / `_head_assets.html`). All other JS files are loaded via `{% block scripts %}` in the page that needs them.
@@ -3,7 +3,7 @@
3 3 version = "0.11.0"
4 4 edition = "2024"
5 5 license-file = "LICENSE"
6 - # Server binary — never published to a registry. Marks the crate private so
6 + # Server binary: never published to a registry. Marks the crate private so
7 7 # supply-chain tooling (cargo-deny) treats its first-party path deps correctly.
8 8 publish = false
9 9
@@ -66,7 +66,7 @@
66 66 webauthn-rs = { version = "0.5", features = ["danger-allow-state-serialisation", "conditional-ui"] }
67 67 webauthn-rs-proto = "0.5"
68 68
69 - # OpenSSL (transitive dep from git2, webauthn-rs — vendored for cross-compilation)
69 + # OpenSSL (transitive dep from git2, webauthn-rs: vendored for cross-compilation)
70 70 openssl = { version = "0.10", features = ["vendored"] }
71 71
72 72 # Security
@@ -136,10 +136,10 @@
136 136 # S3 Storage
137 137 s3-storage = { path = "../shared/s3-storage" }
138 138
139 - # Stripe Payments — async-stripe 1.0.0-rc.6 (split into sub-crates).
139 + # Stripe Payments: async-stripe 1.0.0-rc.6 (split into sub-crates).
140 140 # The umbrella `async-stripe` provides the HTTP client; resource types live in
141 141 # per-domain sub-crates. The `deserialize` feature on each resource crate is
142 - # required to derive `serde::Deserialize` on Subscription, Invoice, etc — we
142 + # required to derive `serde::Deserialize` on Subscription, Invoice, etc: we
143 143 # parse them from webhook payloads ourselves (no built-in webhook helper in the
144 144 # rc line; see `payments::webhooks::verify_signature` for our HMAC check).
145 145 async-stripe = { version = "1.0.0-rc.6", features = ["default-tls"] }
@@ -183,7 +183,7 @@
183 183 # on 0.10.19 (25.1%) for no runtime cost. Every tier rsyncs that difference on
184 184 # every promote. Nothing here reads a symbolized backtrace (no `backtrace` crate,
185 185 # no RUST_BACKTRACE in the unit file). If a panic ever does need symbolizing,
186 - # rebuild the sha with `--config profile.release.strip=false` — the build is
186 + # rebuild the sha with `--config profile.release.strip=false`: the build is
187 187 # reproducible from the git sha the release was cut from.
188 188 strip = true
189 189
@@ -1,4 +1,4 @@
1 - # cargo-deny configuration — supply-chain gate for the MNW server.
1 + # cargo-deny configuration: supply-chain gate for the MNW server.
2 2 #
3 3 # Run by Sando's `cargo_deny` gate as `cargo deny check` (all four checks).
4 4 # This complements `cargo audit`: `bans` surfaces duplicate-version clusters
@@ -12,22 +12,22 @@
12 12
13 13 [advisories]
14 14 version = 2
15 - # Mirror of `.cargo/audit.toml` — every entry is a transitive advisory we cannot
15 + # Mirror of `.cargo/audit.toml`: every entry is a transitive advisory we cannot
16 16 # resolve by bumping our own direct deps, kept in sync with the cargo-audit
17 17 # posture. Directly-fixable advisories are fixed in Cargo.toml, never parked here.
18 18 ignore = [
19 - "RUSTSEC-2023-0071", # rsa Marvin timing side-channel — only via signature *verification* crates; we never decrypt with rsa.
20 - "RUSTSEC-2025-0141", # bincode unmaintained — transitive tooling, no code change available.
21 - "RUSTSEC-2020-0095", # difference unmaintained — via a dev/test dep.
22 - "RUSTSEC-2024-0436", # paste unmaintained — via proc-macro deps.
23 - "RUSTSEC-2025-0134", # rustls-pemfile unmaintained — via AWS SDK TLS.
19 + "RUSTSEC-2023-0071", # rsa Marvin timing side-channel, only via signature *verification* crates; we never decrypt with rsa.
20 + "RUSTSEC-2025-0141", # bincode unmaintained, transitive tooling, no code change available.
21 + "RUSTSEC-2020-0095", # difference unmaintained, via a dev/test dep.
22 + "RUSTSEC-2024-0436", # paste unmaintained, via proc-macro deps.
23 + "RUSTSEC-2025-0134", # rustls-pemfile unmaintained, via AWS SDK TLS.
24 24 ]
25 25
26 26 [bans]
27 27 # Duplicate versions are the supply-chain smell the audits track (x509/crypto
28 28 # cluster, rustls 0.21/0.23 dual stack via the AWS SDK). Surface them as
29 - # warnings rather than failing the build — they are transitive and not yet
30 - # de-duplicable — so a *new* duplicate is visible in CI output without blocking
29 + # warnings rather than failing the build: they are transitive and not yet
30 + # de-duplicable: so a *new* duplicate is visible in CI output without blocking
31 31 # a deploy. Promote to "deny" with a `skip` list once the tree is de-duped.
32 32 multiple-versions = "warn"
33 33 wildcards = "deny" # a `*` version requirement on any dependency fails the build
@@ -1,14 +1,14 @@
1 - # cargo-audit configuration — triaged advisory posture for the MNW server.
1 + # cargo-audit configuration, triaged advisory posture for the MNW server.
2 2 #
3 3 # Every ignore below is a transitive advisory we cannot resolve by bumping our
4 4 # own direct deps, each with a rationale and (where relevant) the upstream we're
5 - # waiting on. Directly-fixable advisories are NOT parked here — they get fixed in
5 + # waiting on. Directly-fixable advisories are NOT parked here, they get fixed in
6 6 # Cargo.toml/Cargo.lock (e.g. the ammonia mXSS RUSTSEC-2026-0193 was closed by
7 7 # bumping to 4.1.3, not ignored). Re-review this list on every dependency audit.
8 8
9 9 [advisories]
10 10 ignore = [
11 - # rsa — Marvin timing side-channel on RSA *decryption*. Pulled only by the
11 + # rsa, Marvin timing side-channel on RSA *decryption*. Pulled only by the
12 12 # signature-*verification* crates (apple-codesign, authenticode, yara-x); we
13 13 # never decrypt with rsa, so the decryption-oracle attack does not apply.
14 14 "RUSTSEC-2023-0071",
@@ -21,9 +21,9 @@
21 21
22 22 # Unmaintained-crate warnings, all transitive (no direct dep, no code change
23 23 # available to us). Tracked for when upstreams migrate off them.
24 - "RUSTSEC-2025-0141", # bincode (unmaintained) — via transitive tooling
25 - "RUSTSEC-2020-0095", # difference (unmaintained) — via a dev/test dep
26 - "RUSTSEC-2024-0436", # paste (unmaintained) — via proc-macro deps
27 - "RUSTSEC-2025-0134", # rustls-pemfile (unmaintained) — via AWS SDK TLS
28 - "RUSTSEC-2026-0173", # proc-macro-error2 (unmaintained) — via a macro dep
24 + "RUSTSEC-2025-0141", # bincode (unmaintained), via transitive tooling
25 + "RUSTSEC-2020-0095", # difference (unmaintained), via a dev/test dep
26 + "RUSTSEC-2024-0436", # paste (unmaintained), via proc-macro deps
27 + "RUSTSEC-2025-0134", # rustls-pemfile (unmaintained), via AWS SDK TLS
28 + "RUSTSEC-2026-0173", # proc-macro-error2 (unmaintained), via a macro dep
29 29 ]
@@ -37,7 +37,7 @@
37 37 # Reverse proxy to application (includes /docs routes)
38 38 reverse_proxy localhost:3000
39 39
40 - # Security headers (CSP is set by the app — do not duplicate here)
40 + # Security headers (CSP is set by the app, do not duplicate here)
41 41 header {
42 42 Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"
43 43 }
@@ -78,7 +78,7 @@
78 78 }
79 79
80 80 # Creator custom pages (u.makenot.work).
81 - # Same app process as the apex — the server's host-dispatch middleware renders
81 + # Same app process as the apex; the server's host-dispatch middleware renders
82 82 # sanitized creator HTML/CSS here, keeps this origin cookieless, and sets its own
83 83 # strict CSP (do not duplicate CSP here). TLS is the wildcard *.makenot.work
84 84 # Origin CA cert via cloudflare_tls.
@@ -135,7 +135,7 @@
135 135 }
136 136 }
137 137
138 - # CDN for free content downloads — reverse-proxies to Hetzner Object Storage.
138 + # CDN for free content downloads: reverse-proxies to Hetzner Object Storage.
139 139 # Cloudflare caches responses at the edge (free egress). Origin only hit on cache miss.
140 140 # Requires: S3 bucket policy allowing public s3:GetObject, Cloudflare DNS A record (proxy ON).
141 141 cdn.makenot.work {
@@ -167,7 +167,7 @@
167 167 }
168 168 }
169 169
170 - # dl.maxj.phd download host retired 2026-06-09 — MNW now serves all downloads
170 + # dl.maxj.phd download host retired 2026-06-09. MNW now serves all downloads
171 171 # (creator product pages / makenot.work DMGs). The maxjphd_tls mTLS snippet and
172 172 # the dl.maxj.phd file_server block were removed with it; the /etc/caddy/maxj-phd-origin*
173 173 # cert/key are now unused on prod and can be deleted there.
@@ -187,7 +187,7 @@
187 187 redir https://makenot.work{uri} permanent
188 188 }
189 189
190 - # Custom domains — on-demand TLS via Let's Encrypt.
190 + # Custom domains: on-demand TLS via Let's Encrypt.
191 191 # Caddy calls /api/domains/caddy-ask before issuing a cert for any domain.
192 192 # makenot.work subdomains are unaffected (matched by explicit blocks above
193 193 # which use Cloudflare Origin CA + mTLS).
@@ -199,10 +199,10 @@
199 199 # Custom domains connect directly to the origin (no Cloudflare mTLS in front),
200 200 # so any client-supplied CF-Connecting-IP / X-Forwarded-For is forgeable. The
201 201 # app trusts CF-Connecting-IP for rate-limiting, lockouts, and audit logs, so
202 - # overwrite it with the real TCP peer and strip XFF before proxying — a client
202 + # overwrite it with the real TCP peer and strip XFF before proxying, a client
203 203 # can no longer mint fake source IPs to evade per-IP throttles or poison logs.
204 204 reverse_proxy localhost:3000 {
205 - # Set (replace) CF-Connecting-IP to the real TCP peer — overwrites any
205 + # Set (replace) CF-Connecting-IP to the real TCP peer, overwrites any
206 206 # value the client sent. Strip X-Forwarded-For so no forged value reaches
207 207 # the app (the app ignores XFF anyway; this is hygiene).
208 208 header_up CF-Connecting-IP {http.request.remote.host}
@@ -223,7 +223,7 @@
223 223 }
224 224 }
225 225
226 - # HTTP catch-all — redirect to HTTPS (also needed for ACME HTTP-01 challenges)
226 + # HTTP catch-all: redirect to HTTPS (also needed for ACME HTTP-01 challenges)
227 227 :80 {
228 228 redir https://{host}{uri} permanent
229 229 }
@@ -1,4 +1,4 @@
1 - # SSH access — production server (Hetzner)
1 + # SSH access: production server (Hetzner)
2 2
3 3 Two SSH paths into the production server, with different audiences and
4 4 different break-glass behavior. Read this before disabling either one.
@@ -12,7 +12,7 @@
12 12
13 13 - **Public :22** is intentionally open so creators can `git clone`/`push`
14 14 over SSH against `ssh.makenot.work`. The sshd config on this port is
15 - locked to git-shell only — see `setup-git-ssh.sh` and `sshd-git.conf`.
15 + locked to git-shell only. See `setup-git-ssh.sh` and `sshd-git.conf`.
16 16 No interactive shell, no port forwarding, no admin access.
17 17 - **Tailnet :2200** is the admin path. Full interactive shell, used for
18 18 every `deploy.sh` invocation and any manual maintenance. Reachable only
@@ -23,8 +23,8 @@
23 23
24 24 The audit-flagged risk was disabling Tailscale SSH (the admin path)
25 25 without first verifying the public sshd was still functional. Tailscale
26 - runs its own SSH server when configured; if that goes down — Tailscale
27 - service crashes, ACL misconfiguration, accidental `tailscale down` —
26 + runs its own SSH server when configured; if that goes down (Tailscale
27 + service crashes, ACL misconfiguration, accidental `tailscale down`)
28 28 you can lose admin access entirely if you've also locked down public
29 29 sshd.
30 30
@@ -41,7 +41,7 @@
41 41
42 42 1. **Verify public sshd is up** from any machine:
43 43 `ssh -p 22 root@5.78.144.244 -o BatchMode=yes -o ConnectTimeout=5 true`
44 - Expect a key-based prompt or a refused git-shell — both prove sshd
44 + Expect a key-based prompt or a refused git-shell. Both prove sshd
45 45 is listening. A timeout or "Connection refused" means public sshd is
46 46 ALSO down and you need Hetzner Cloud Console.
47 47 2. **Edit `/etc/ssh/sshd_config.d/git-shell.conf` from Hetzner Console**
@@ -50,18 +50,18 @@
50 50 3. **Restart sshd**: `systemctl restart ssh`. Test from your laptop.
51 51 4. **Fix the tailnet path** (re-auth `tailscale up`, restore key, etc).
52 52 5. **Revert the sshd edit** and restart `ssh` again. Don't leave the
53 - interactive root shell on public :22 — it defeats the whole split.
53 + interactive root shell on public :22. It defeats the whole split.
54 54
55 55 ## What NOT to do
56 56
57 57 - **Do not** disable Tailscale SSH (`tailscale set --ssh=false`) without
58 58 first proving public :22 is reachable and you have a working root key
59 - for it. Memory rule: `feedback_tailscale_ssh` — getting locked out
59 + for it. Memory rule: `feedback_tailscale_ssh`, getting locked out
60 60 requires Hetzner Console access, which costs time we don't always
61 61 have.
62 - - **Do not** restrict public :22 to specific IPs without coordinating —
62 + - **Do not** restrict public :22 to specific IPs without coordinating:
63 63 the mnw-cli git endpoint serves users worldwide.
64 - - **Do not** open port 2200 to the public — it's the admin shell.
64 + - **Do not** open port 2200 to the public. It's the admin shell.
65 65
66 66 ## Hetzner Console (last resort)
67 67
@@ -57,7 +57,7 @@
57 57 TOTAL=$(find "$BACKUP_DIR" -name "${DB_NAME}-*.sql.gz" | wc -l)
58 58 echo "[$(date -Iseconds)] Total ${DB_NAME} backups on disk: $TOTAL"
59 59
60 - # Sync to offsite host (best-effort — failure here does not fail the backup).
60 + # Sync to offsite host (best-effort: failure here does not fail the backup).
61 61 SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
62 62 OFFSITE_SCRIPT="${SCRIPT_DIR}/sync-backup-offsite.sh"
63 63 if [ -x "$OFFSITE_SCRIPT" ]; then
@@ -22,7 +22,7 @@
22 22 ExecStart=/opt/makenotwork/makenotwork
23 23 Restart=always
24 24 RestartSec=5
25 - # Exit code 2 = migration failure. Don't restart — operator must intervene.
25 + # Exit code 2 = migration failure. Don't restart; the operator must intervene.
26 26 RestartPreventExitStatus=2
27 27
28 28 # Environment file with secrets
M server/docs/cli.md +24 -24