This morning, I finally broke through the first-entry paralysis.
FlipVox HQ has been up for a few days now, but I couldn’t bring myself to publish anything. I spent two days browsing my old Obsidian vault looking for something “worthy” of being the first post. Nothing felt right. Everything was either raw copy-paste material or too messy to share.
The problem wasn’t the content. It was the weight I was putting on “first.” I kept imagining visitors arriving, judging the site by that one note, deciding whether to take me seriously. Classic perfectionism spiral.
A conversation with my local LLM instance (ironically) broke the loop. The first note I publish doesn’t have to be the first thing visitors see. I control the landing page. I can curate later. Why was I treating this like a one-shot decision?
That’s when I decided to stop treating this as a showcase and just turn it into a devlog.
A devlog has built-in permission to be imperfect. It’s dated. It’s a snapshot. It doesn’t have to be my best thinking, just my current thinking.
So here it is. Day 1. Thirty minutes post-coffee, still waking up.
But wait, how do I even spell “DevLog”?
I almost didn’t write anything else today. But then I got stuck on something smaller: what do I name the folder?
devlogdevLogDevLogdev-log
It seems trivial. It’s not.
This is one of those micro-decisions that compounds. Whatever I choose now, I’ll be typing it for months, maybe years. It’ll show up in URLs. It’ll affect how the site’s navigation displays it. And honestly, it’s the kind of thing I’ll quietly regret if I get it “wrong.”
So I fell down the rabbit hole. Here’s what I found.
A primer on casing conventions
If you’ve done any programming, you’ve encountered these. But I’ve rarely seen them all in one place with clear names, so here’s the list:
| Name | Example | Alternative Names | Common Use |
|---|---|---|---|
| flatcase | devlog | URLs, some package names | |
| UPPERFLATCASE | DEVLOG | Rare, legacy systems | |
| camelCase | devLog | lowerCamelCase, dromedaryCase | JavaScript variables, Java methods |
| PascalCase | DevLog | UpperCamelCase, StudlyCase | Classes, React components, C# |
| snake_case | dev_log | underscore_case | Python, Ruby, database columns |
| SCREAMING_SNAKE_CASE | DEV_LOG | MACRO_CASE, CONSTANT_CASE | Constants, environment variables |
| kebab-case | dev-log | dash-case, spinal-case, lisp-case | URLs, CSS classes, filenames |
| SCREAMING-KEBAB-CASE | DEV-LOG | COBOL-CASE, FLAMING-KEBAB-CASE | Legacy systems, some macros |
| Train-Case | Dev-Log | HTTP-Header-Case | HTTP headers |
| Title Case | Dev Log | Headings, UI labels | |
| Sentence case | Dev log | Prose, some UI text |
I have a thing for precise terminology. If a concept has a name, I want to know it. But I must admit, this table makes me rethink my limits.
Why this matters more than you’d think
Here’s where my day job creeps in.
I work in Voice AI, specifically speech recognition (ASR) and text-to-speech (TTS). And in this field, casing is anything but trivial. It’s actually one of the persistent headaches in building robust systems.
The problem with normalization
When training ASR models, you often normalize text to lowercase. It simplifies the vocabulary. “The” and “the” become the same token. Training is cleaner.
But it comes with tradeoffs that ripple downstream. The raw output becomes harder to read. Any system that consumes the ASR output (a summarizer, a search index, a display layer) now has to expect and handle normalized text. If you want readable output for end users, you need a separate truecasing step to restore capitalization, which introduces its own errors.
And yes, a language model can often infer from context whether “polish” means the verb or the nationality. But now you’re relying on that inference instead of preserving information you already had. You’ve traded one complexity (a larger vocabulary) for another (contextual disambiguation and post-processing).
And don’t even get me started on punctuation.
The challenge of truecasing
So we normalize training data to simplify things. But users expect readable output, which means proper capitalization. We want truecased results, but we trained on normalized text.
This means we need to restore casing after the fact, either through a separate truecasing model or as a post-processing step. And that’s where it gets messy.
Consider: “i asked tim at apple about ios and the ceo loved it.”
To restore proper casing, a model needs to know:
- “Tim” is a name
- “Apple” is a company here, not the fruit
- “iOS” has unconventional casing (not “Ios” or “IOS”)
- “CEO” is an acronym that stays all-caps
And this is a relatively clean sentence. Add abbreviations (“dr. smith said…”), ambiguous words (“i love reading”), or domain-specific terms, and you’re relying heavily on context, training data, and luck.
Inverse Text Normalization (ITN)
Truecasing handles capitalization. But spoken language has another layer of mismatch with written text: numbers, dates, currencies, symbols. We don’t say “dollar sign fifty,” we say “fifty dollars.” We don’t say “hashtag,” we say… well, actually, sometimes we do now.
Converting spoken forms back to their written representations is called Inverse Text Normalization:
- “fifty dollars” → “$50”
- “december seventeenth twenty twenty-four” → “December 17, 2024”
- “hashtag dev log” → “#devlog” or “#DevLog”?
Notice that last example. ITN and truecasing intersect. You’re not just deciding how to format “hashtag,” you’re also deciding on the casing of what follows. The problems compound.
Every decision here affects downstream processing. And there’s rarely a single “correct” answer.
”But don’t LLMs already solve all this?”
Yes and no. Modern large language models can handle truecasing and ITN remarkably well. Feed messy text into GPT and it’ll often produce clean, properly formatted output.
But not everyone has the luxury of calling an API for every transcription. Costs add up. Latency matters. Privacy constraints exist. Sometimes you’re working on-device, offline, or in a language that frontier models handle poorly.
When you need to build these systems yourself, the intricacies matter. That’s what I’m trying to surface here: the decisions that disappear behind a clean API, until you have to make them yourself.
The meta-reflection
I started today trying to write a simple “I’m starting a devlog” post. I ended up writing a primer on casing conventions and a mini-essay on truecasing in Voice AI.
This is exactly how a second brain is supposed to work.
One thought leads to another. The folder name question led to the casing rabbit hole. The casing rabbit hole surfaced something from my actual expertise. And now I have a note that’s both a personal log and a potentially useful reference.
Not bad for thirty minutes post-coffee.
So what did I name the folder?
DevLog. PascalCase.
Why? It mirrors how I’d name a component or a class. It’s visually distinct. And since I’ve configured the site to capitalize the first letter in the side explorer anyway, it’ll display consistently whether I’m looking at the filesystem or the published site.
The tags? I’ll keep it consistently lowercase kebabs, thank you very much.
Ask me again in who-knows-how-many-months-this-site-lasts if I regret it.
