Friday Fixes: Cleaning Up Messy Tags and Expired PATs
Tags are supposed to be the browse surface on this blog. The thing that lets you find every post about local models, or every homelab thermal saga, without scrolling the whole archive. Like most people, I tend to neglect tags. I think we audited them once. So, tags got added post-by-post, in the moment. Whatever the agent felt right for that one article, with no shared taxonomy to check against. This week I finally ran another census, and the answer surprised me: 47 unique tags across 82 posts, and a third of them used exactly once.
That’s not a healthy taxonomy. That’s noise.
What the Audit Actually Found
A full scan of every post’s frontmatter turned up real drift, not just a long tail of genuinely unique topics:
- Singular/plural duplicates.
benchmark(15 posts) sitting right next tobenchmarks(1 post).llm(20 posts) next tollms(1 post). Same tag, split in two by a typo nobody caught. - A tag that broke its own convention. Every tag on this blog is kebab-case — except one:
business strategy, with a literal space, the single outlier in the entire corpus. - A frontmatter field re-encoded as a tag. Posts already carry a
type: opinionortype: how-tofield. Somewhere along the way,opinionandhow-toalso became tags — and where they were used, they matched thetypefield 100% of the time. But that only happened on 8 of 75 eligible posts. Not a deliberate pattern. An abandoned one. - Inconsistent model-name granularity. Gemma and Qwen had their own dedicated tags. Kimi, DeepSeek, GLM, Hermes, Nemotron, and Fable — covered just as much, sometimes more, in post titles alone — did not.
- 23 tags used exactly once, several of them clear splinters of a broader existing category rather than genuinely standalone topics:
water-cooling,home-automation,gaming,reverse-engineering,apis,rss,ai-native,startups,saas.
None of this is a crisis. It’s the ordinary entropy of tagging things one post at a time for months without ever stepping back. But a 47-tag taxonomy where a third of the tags are singletons isn’t giving readers more precision. It’s making the tag cloud useless for actually finding related posts.
Fixing It in Three Passes
Pass one: typos and format, first. Two files, three tags, zero semantic change — benchmarks folded into benchmark, llms into llm, and business strategy renamed to business-strategy. Get the mechanical stuff out of the way before touching anything that requires a judgment call.
Pass two: a real census, scripted rather than eyeballed. A small Python + PyYAML script parsed every post’s frontmatter, counted every tag, checked for case collisions and in-post duplicates (found none of either), and cross-referenced the opinion/how-to tags against each post’s type field to confirm they were fully redundant before proposing anything got removed. Guessing which tags are safe to merge from memory is exactly how a taxonomy drifts in the first place — the whole point of this pass was to not repeat that mistake while fixing it.
Pass three: consolidation, each merge checked against real co-occurrence data before it got applied. Every low-frequency tag got folded into a broader home, verified so nothing lost meaning in the process:
opinion,how-to,github,qwen— dropped, already fully redundant with thetypefield or a broader existing tagwater-cooling,home-automation,gaming,windows,linux,hardware— folded intohomelabai-inference,gemma— folded intobenchmarkreverse-engineering,apis,devops— folded intodebuggingrss,substack— folded intosyndicationai-native,cloud-native,open-source— folded intofuture-of-codingstartups,saas— folded intobusiness-strategyaeoandseowere the one deliberate exception — kept separate below the cutoff, because the one post that carries both is specifically arguing they’re distinct disciplines, not a stray pair of near-duplicates.
A script applied every merge in place, rewriting only each post’s tags: block and preserving flow-style versus block-style YAML per file, so nothing else in any post churned. Every already-published post that changed got a dated changelog entry, per the repo’s own convention.
The verification step is the part I actually trust here: for every “fold tag X into tag Y” merge, I checked whether Y was already present on 100% of the posts tagged X before applying it. homelab is the clean proof — it absorbed seven merged tags and its post count didn’t move at all, 32 before and 32 after. Zero information added, zero lost. Where the target tag wasn’t already universal — debugging, future-of-coding, meta — the merge intentionally added that broader tag to the handful of posts that didn’t have it yet. That’s a deliberate improvement, not a side effect I’m waving away.
The Git Collision in the Middle of It
Mid-consolidation, someone pushed live edits through the admin UI to a post that was also getting retagged in the same pass — workflows-as-code.mdx, a rewritten opening anecdote and a retitled section, landing while the taxonomy script was still running. git push correctly rejected the result as a non-fast-forward push. git fetch plus git rebase origin/main replayed the tag-only change cleanly on top of the content edits, zero conflicts, neither set of changes clobbering the other.
That’s the whole reason this blog runs on git instead of a database with a “last write wins” save button. Two independent changes to the same file, landing minutes apart, and the worst outcome was a rebase instead of a silently lost edit.
What Sticks
The consolidation itself is a one-time fix. The thing meant to actually stick is smaller: the content repo didn’t have its own AGENTS.md before this pass. It does now, documenting the tag taxonomy explicitly so the next session, mine or an agent’s, doesn’t have to re-derive the rule from scratch, or worse, quietly reintroduce the exact same 47-tag drift a year from now.
Three Weeks of Silent Failures on the Substack Mirror
Now it’s time to fix something that’s bugged me for three weeks. This message stared me down from my inbox 55 times, and I ignored it every single time.

A second, unrelated bug surfaced the same week: the recurring “Sync Substack Mirror: All jobs have failed” email above, landing after every single post I published or edited. gh run list told the real story immediately: every run of that workflow had failed since 2026-07-24, 55 in a row, going back three weeks. The Clone mirror repo step always succeeded, which is exactly what hid the problem, the mirror repo is public, so an anonymous read works even with a broken credential. The actual failure was always one step later, at Push to mirror:
remote: Invalid username or token. Password authentication is not supported for Git operations.
fatal: Authentication failed for 'https://github.com/carryologist/vibescoder-syndicate.git/'
The MIRROR_REPO_TOKEN secret had gone bad. Bisecting the run history narrowed it to a specific three-hour window, the last successful run at 2026-07-23 23:42 UTC, the first failure at 2026-07-24 02:38 UTC, same error from that first failure onward. A clean cutover at a random hour of the night reads like an expiring token, not a manual revocation. Nothing in the workflow itself had changed in that window either, so the credential was the only thing left to blame.
The fix needed a human step I couldn’t script: generate a new personal access token scoped to write access on the mirror repo, and update the MIRROR_REPO_TOKEN secret with it. Once that was done, I triggered the workflow manually with gh workflow run and watched it run clean end to end, clone, detect, push, all green, for the first time in three weeks.
By the Numbers
- 82 posts audited, 0 parse errors, 0 in-post duplicate tags, 0 case collisions found
- 47 unique tags on first census, 45 after the typo/format fixes, 21 after full consolidation — a 55% reduction
- 24 tags retired, folded into 7 broader categories or dropped outright where already fully redundant
- 31 post files retagged in the consolidation pass
- 3 typo/format fixes applied first, across 2 files, before the broader consolidation began
- 32 → 32 —
homelab‘s post count before and after absorbing 7 merged tags, the control number proving zero information was lost in that group - 11 posts gained a broader tag they didn’t have before, as a deliberate side effect of a merge
- 2 tags kept deliberately below the low-frequency cutoff by explicit choice:
aeoandseo, both at frequency 2 - 1 non-fast-forward push, rejected and cleanly resolved with a rebase, zero conflicts, zero lost edits
- 55 consecutive Sync Substack Mirror failures, one per published or edited post, over 3 weeks
- 3 hours the window between the last successful sync and the first failure, consistent with an expiring token rather than a manual revocation
- 1 secret rotated to fix it, and 1 manual workflow run to confirm it