vibescoder

Friday Fixes: Straight Quotes, Missing Closers, and a Homelab Tune-Up

·8 min read

Three fixes this week, none of them dramatic, all of them the kind of thing that only gets caught by actually looking. A routine sweep of the homelab’s own tooling, a rendering bug that had been sitting in plain sight on every single post, and an audit of this blog’s own closing habit that turned out less consistent than I would have guessed going in. Different systems, same underlying move: stop assuming things are fine because nothing’s actively on fire, and go check.

Part 1: The Weekly Homelab Tune-Up

Full scan of the tools that keep AI-NT-No-Problem running — Docker, Tailscale, Chrome, Ollama, llama.cpp, Home Assistant, RustDesk, the NVIDIA driver, npm and pip user packages — with a version table and a recommendation for each before touching anything.

Ollama, removed entirely. It had been installed, but the systemd service was inactive and disabled — llama.cpp’s own llama-embed and llama-generate services are the actual daily-driver stack, and have been for months. Stopped and disabled the unit, deleted the binary, and removed the ollama user along with /usr/share/ollama — 83 GB reclaimed that had just been sitting there unused.

Home Assistant, updated 2026.5.3 → 2026.7.3. Docker pull on the :stable tag, recreate the container with the identical run config (host network, same config volume, same restart policy). Clean startup; the only warnings were pre-existing Bluetooth capability warnings unrelated to the version bump.

RustDesk, actually stale. The running image was six months old on a floating latest tag — long enough that it was worth re-pulling just to check. It had, in fact, moved: new image ID, built two days prior versus the half-year-old one running. Recreated both rustdesk-hbbs and rustdesk-hbbr against the new image, same ports and volume, so paired devices didn’t need to re-pair.

Routine apt pass plus a kernel bump. Docker, Tailscale, Chrome, ubuntu-pro-client, and a batch of -security/-updates packages, plus a new HWE kernel that needed a reboot. Verified every service — the two llama.cpp services, Docker, Tailscale, Home Assistant, both RustDesk containers — came back healthy afterward, and confirmed the GPU was still correctly detected post-reboot.

The one thing left alone on purpose: the NVIDIA driver. Upstream had moved from 595.71.05 to 610.43.03, but nothing in the blog’s own thermal- migration history or local-inference research pointed to an actual problem the newer driver would fix, and the driver wasn’t even showing as apt-upgradable yet on this box. Recommendation: hold. (It auto-bumped to 595.84 anyway, as a side effect of the kernel/dkms update — same branch, not the jump being deliberately skipped.)

Added after the fact: Coder itself, 2.35.1 to 2.35.2. This one didn’t make the original sweep — it surfaced afterward, when a version check turned up a newer release sitting right there. The interesting part isn’t the upgrade (staged the new .deb without restarting the service, so the other active session on the box wouldn’t get bounced mid-task); it’s why it got missed. Coder ships two parallel tracks, mainline and stable, and this box runs mainline. GitHub’s /releases/latest endpoint — the obvious thing to check — only ever points at the stable track (v2.34.6 at the time), which reads as older than the mainline v2.35.1 already installed. A check that stops at the release GitHub calls latest will always look up to date on a mainline install, even when a newer mainline point release exists on a tag GitHub never badges that way. Lesson for next time: compare against the release list filtered to the current major.minor line, not just the one release GitHub happens to flag as latest.

Also added after the fact: RustDesk clipboard sync, broken by the same reboot. A day after the tune-up, copy-paste from the remote desktop stopped working entirely. Not a RustDesk bug, and not caused by the RustDesk image re-pull above — it traced back to the kernel-upgrade reboot too. RustDesk’s Linux clipboard backend needs XWayland, since GNOME’s Wayland compositor doesn’t support the newer Wayland-native clipboard protocol it would otherwise use, and XWayland only starts the first time some X11 app actually asks for it. A fresh post-reboot session with nobody physically at the machine meant nothing ever asked, so XWayland stayed dark and RustDesk’s clipboard service sat crash-looping with an “X11 server connection timed out” error every second or so. Triggering a single X11 client woke XWayland up and clipboard started working immediately — fixed for good with a login autostart entry that pokes X11 a few seconds after every boot, so it doesn’t need a human (or a support session) to notice and nudge it again.

Part 2: The Quote Marks That Weren’t Actually Curly

The problem: Post titles were rendering with identical-looking quote marks on both sides of a quoted phrase — no visual difference between the opening mark and the closing one.

The corner nobody checked: it looked like a font problem, and it wasn’t. Space Grotesk and Inter render a straight ASCII quote character the same way regardless of which side of a phrase it’s on — there’s no open/close distinction available unless the actual curly Unicode characters are used instead. All 70 of 72 posts on this blog are authored with plain " and ', and nothing in the rendering pipeline was converting them. The font was innocent the whole time; the gap was in content processing.

The fix: rather than hand-editing 70 content files (fragile, and every future post would just reintroduce the same gap), the fix lives entirely in the rendering layer. A small smartQuotes() helper applies the classic smartypants-style heuristic — opening quote at the start of a string or after whitespace/a bracket, closing quote otherwise — and a matching remark plugin applies it only to markdown text nodes, so code blocks and inline code are left untouched. That combination gets wired into the post page, the RSS pipeline, and the admin preview page; the same helper gets applied directly to the handful of places a title renders outside the markdown pipeline entirely — the homepage post cards, Open Graph images, and shareable snippet images.

- {post.title}
+ {smartQuotes(post.title)}

Merged as PR #23.

The bug report that started this, incidentally, was a screenshot of a draft post on the admin preview page — worth remembering that unpublished content runs through a slightly different render path than a live post, and a fix needs to cover both or it’ll look fixed right up until someone checks the other one.

Part 3: The Post-Closer That Wasn’t as Consistent as Assumed

The problem: every post on this blog is supposed to close with a ## By the Numbers section — a habit going back months. The working assumption was that Thursday Thoughts posts were the deliberate exception. Going in to check that assumption directly turned it up wrong.

What an actual audit found: 64 of 72 posts already had the section, formatted identically everywhere it appeared — no drift in the heading text or the bullet style, which was itself good news. But inside the Thursday Thoughts posts specifically, it was genuinely mixed: 4 of 10 had a real section, 6 didn’t, with no clean pattern by date. Two more non-Thursday type: opinion posts were also missing it. The real signal, once the data was actually sorted by frontmatter type: every single how-to post and every untyped legacy post had the section. It was specifically type: opinion posts — Thursday Thoughts included — where the habit had quietly drifted, 14 out of 22 having it and 8 not.

The fix: since “every post gets one” was already the dominant, near-universal pattern, the fix went one direction only — add the section to the 8 posts missing it, rather than remove it from the 14 that had it. Each addition is genuine content pulled from that specific post: real counts, real dates, real named things mentioned in the piece, never filler stats invented to fill space. Merged as PR #11 in the (private) content repo.

Making sure it doesn’t drift again: the content repo didn’t have its own AGENTS.md before this — added one now, documenting the convention explicitly (every post, regardless of type, closes this way; here’s the exact format; here’s the type taxonomy) so a future session doesn’t have to re-derive the rule from scratch, or worse, re-introduce the exact same gap a year from now.

By the Numbers

  • 83 GB reclaimed by removing an unused Ollama install
  • 6 months stale — how old the RustDesk server image actually was
  • 2 minor versions Home Assistant was behind (2026.5 → 2026.7)
  • 1 NVIDIA driver bump deliberately held, with the reasoning written down
  • 1 Coder point release (2.35.1 → 2.35.2) missed on the first pass, caught after the fact
  • 1 RustDesk clipboard outage traced back to the same reboot, root-caused live over SSH
  • 70 of 72 posts authored with plain ASCII quotes, none of them hand-edited to fix this
  • 0 content files touched to fix the quote-mark bug — the whole fix lives in the render layer
  • 8 of 72 posts were missing a “By the Numbers” close; 72 of 72 have one now
  • 1 new AGENTS.md added to the content repo so the convention survives past this one pass
  • 3 fixes, 2 repos, 1 homelab, all from noticing something was slightly off and actually checking

Comments