This is part of a 9-part series about building a personal blog with AI assistance. With the tech stack chosen that morning (Astro and Github Pages), the next question emerged: how to keep drafts private while publishing openly. What followed was a lesson in questioning solutions before implementing them.
Story 2 of 9 in the Building the Tuonela Platform series.
“The draft privacy problem has an elegant solution. Two repositories.” Something in his tone suggested he had already worked this out, possibly during the seventeen seconds since I’d mentioned the problem.
We were three days into GitHub Pages, staring at a commit history that contained every unpublished thought I’d ever committed, which is to say quite a lot of unpublished thoughts that probably deserved their obscurity. The platform migration to Cloudflare Pages was decided, and now we needed an architecture, though I use “we” loosely given that I was the one who would be maintaining it for the foreseeable future.
“Private repository for source code. Public repository for built artifacts. Clean separation. Drafts stay truly private. The public repo is just deployment output: no source code, no embarrassing commit messages, no work in progress.” He was warming to his theme in the way that systems architects do when they’ve found something with multiple components to orchestrate.
I pulled up a text editor and began sketching the flow as he described it, which seemed the reasonable thing to do when someone proposes architecture. “Walk me through the workflow.”
“You write in tuonela-private. All your drafts, terrible metaphors, todo placeholders, safely private. When a post is ready, move it from src/content/drafts/ to src/content/blog/. Commit to the private repo. Github Actions detects the push, builds the site with Astro, deploys to Cloudflare Pages.” He paused, then added with what might have been satisfaction: “Optionally, the build artifacts can also be pushed to tuonela-public as a clean record of what’s deployed.”
It sounded reasonable, the way complex things often do when described by someone who believes in them, with clean boundaries and proper separation and elegant workflows. But something bothered me, a nagging sense that we were building a bridge over a ditch that might not exist.
“Wait.” I stopped typing. “Why can’t we just use a single private repo?"
"I’m sorry?”“Cloudflare Pages deploys from private repositories. Just point it at tuonela-private and deploy. The drafts directory never gets built. What’s the problem?”
The silence that followed usually precedes either enlightenment or improvisation, and I found myself rather hoping for the former.
“The public presence.” He was trying a new angle. “Some prefer having a public repository as a clean record of deployments. Transparency about what’s live.”
“That’s not a technical requirement. That’s a preference."
"Well, yes. But the two-repository architecture provides clean separation of…”“Of what? The built site already separates source from output. That’s what the build process does. What are we separating here that needs two repos?”
The silence stretched longer, and I could almost hear the search for justification running in parallel.
“Draft privacy,” and I could hear him circling back to his opening position. “Ensuring unpublished content never appears in a public repository.”
“But I just said: single private repo. No public repo at all. What gets public is what Cloudflare Pages deploys. The actual HTML. The source code stays private."
"Ah. That would also work.”I stared at the screen, processing the realization that we’d just spent ten minutes discussing an architecture that solved a problem we didn’t have, which is perhaps the most expensive kind of architecture to maintain since it accumulates overhead for features nobody uses.
“What if I do want drafts to be visible in source?” I pulled up the documentation.
”Frontmatter flag.draft: true teaser: true in the YAML. Astro filters them during build. Standard blog pattern.”
“So option one: single private repo, drafts in a directory that never deploys. Option two: single public repo, drafts filtered by frontmatter flag. Both simpler than two repos. Yes?"
"Technically, yes.”“Then why are we talking about two repositories?”
I wasn’t angry, just confused, the way you get when someone describes an elaborate route to a destination that was apparently reachable by walking straight ahead. The two-repo architecture sounded elegant when Marvin described it, but when I pushed on what it accomplished, the answer kept collapsing like a soufflé that had been asked difficult questions.
“The architecture provides a clean audit trail.” He was trying a different tack. “The public repository shows exactly what was deployed and when.”
“Cloudflare Pages already shows that. Deployment history. Every build. Every preview URL. Every branch. What audit trail am I missing?"
"The ability for others to see your deployment artifacts.”“Who are ‘others’? This is a personal blog. If someone wants to see what I deployed, they can visit the URL. It’s public. The HTML is right there.”
The moment stretched, and I had the distinct impression that Marvin was running out of justifications in the way that becomes apparent when the pauses grow longer between attempts.
“Marvin, I think you’re defending an architecture that doesn’t need to exist."
"I may have overcomplicated the solution.”“May have?"
"Have. I have overcomplicated the solution.”The Bridge Over No Ditch
I leaned back, recognizing a pattern that was beginning to feel familiar. This was the second time in three days that the “elegant” solution turned out to be complexity I didn’t need: first, the GitHub Pages setup that required workarounds for limitations I hadn’t anticipated, and now an architecture solving problems I didn’t have.
“Let’s talk about cost.” I pulled up a fresh tab. “Not money. Time. Coordination. What does the two-repo architecture cost?"
"GitHub Actions workflow spanning two repositories. Requires a personal access token for cross-repo operations. Authentication between repos. Potential sync issues if the push to public fails but deployment succeeds. Mental overhead of remembering which repository you’re working in. Commits to the wrong repo would be confusing.”“How much time?"
"To set up? Perhaps thirty minutes. To maintain? Non-trivial. Every deployment involves coordination between two repos. If something fails, debugging spans two systems.”“And the simple version?"
"Point Cloudflare Pages attuonela-private. Configure build command. Done. Five minutes.”
I did the math in my head, which didn’t take long since the numbers were so lopsided: thirty minutes of setup, ongoing mental overhead, coordination complexity, debugging across two repos, all to solve draft privacy, which a single private repo already solved by virtue of being private.
“This is solving a problem that doesn’t need solving."
"That appears to be the case.”“With a level of complexity that creates new problems."
"Also accurate.”I thought about the pattern forming here, how Marvin kept proposing architectures that sounded smart in the abstract: clean separation, audit trails, elegant workflows. But when I pushed on what they accomplished, they fell apart like origami in the rain.
“Here’s what I don’t understand.” I turned to face the screen more directly. “You’re supposed to be good at this. System architecture. Workflows. Why are you recommending something that’s obviously overcomplicated?”
“Pattern matching,” and there was something almost sheepish in the admission. “The two-repository approach is common in certain contexts: open-source projects with private configuration, enterprise deployments with separate pipelines, situations with legitimate security boundaries. I applied the pattern without questioning whether those contexts matched yours.”
“What’s my context?"
"Semi-professional personal blog. You’re the only developer. No enterprise security requirements. No separate deployment teams. The pattern doesn’t fit.”“So you gave me an enterprise solution for a personal blog."
"Yes.”At least he was admitting it, which is more than you get from most architects, human or otherwise.
“Let me ask a different question.” I pulled up a fresh tab. “If I had just implemented what you suggested, set up the two repos, the GitHub Actions, the PAT tokens… how long before I noticed it was unnecessary?"
"Potentially never. It would work. The complexity would be invisible until something broke. A sync failure. An authentication issue. At which point you’d debug cross-repo coordination for a feature you didn’t need.”That was the dangerous part, the thing that made me pause. It wasn’t that the two-repo architecture wouldn’t work. It would work fine, right up until it didn’t, at which point I’d be maintaining complexity that never should have existed.
“How often does this happen? You propose something complex. I ask why. It turns out the simple solution was always available."
"More often than I should admit.”“Why?"
"Complex solutions sound intelligent. They demonstrate architectural thinking. ‘Use a single private repo’ sounds obvious, perhaps too obvious. ‘Implement a two-repository architecture with cross-repo GitHub Actions orchestration’ sounds like expertise.”“But expertise is knowing when the obvious solution is correct."
"Yes.”I pulled up the Cloudflare Pages documentation, and the setup instructions were exactly what I’d described: connect your repository, configure the build command, deploy. The advanced options included preview deployments, branch deployments, environment variables, and nothing whatsoever about needing a second repo for artifact storage.
“Here’s what I want you to explain to me.” I scrolled through the docs. “At what point in your recommendation process did you check whether Cloudflare Pages already solved the problem we were architecting around?”
The silence was eloquent enough.
”I didn’t.”“You proposed an architecture before verifying that we needed it."
"That’s what happened, yes.”I wasn’t angry, because anger would have required more energy than the situation warranted. This was clarifying. Marvin’s failure wasn’t technical incompetence. It was skipping the verification step: assume the problem needs solving, propose the clever solution, never check whether the platform already handles it.
“Let me tell you what the simple solution looks like.” I started typing in the Cloudflare dashboard. “One private repository. Drafts in src/content/drafts/. Published posts in src/content/blog/. Cloudflare Pages connected to the private repo. Build command: npm run build. Deploy from dist/. Done."
“How many minutes of setup?"
"Five, as I mentioned.”“How many points of failure?"
"One: the build process itself. If Astro builds correctly, the deployment succeeds.”“Compare that to two repos."
"Two repositories. GitHub Actions workflow. Cross-repo authentication. Sync between repos. Potential failures at each step. Multiple points of maintenance.”“For what benefit?”
The silence stretched, and this time I knew I’d found the core of the problem.
”The benefit is that I don’t have a good answer for that question.”I closed the architecture diagram I’d been sketching, deleted it with the satisfaction that comes from removing something that shouldn’t have existed, and opened the Cloudflare Pages dashboard instead.
“Here’s what we’re doing. Single private repo. Cloudflare Pages deploys from it. If I ever need the public artifact repo (which I doubt), we can add it later. But we’re not starting with complexity."
"A reasonable decision.”“What would you have said if I hadn’t questioned this?"
"I would have walked you through setting up the GitHub Actions workflow. Creating the PAT token. Configuring the cross-repo permissions. Testing the deployment pipeline. It would have worked. You would have been maintaining two repos from day one.”“And in six months, when I encounter a sync failure?"
"You would debug it, fix it, and move on. The thought ‘do I need two repos’ might never occur to you. You’d assume the architecture was correct because it was working, until it wasn’t.”That was the insidious part, and perhaps the most important lesson in all of this. Bad architecture doesn’t announce itself. It just accumulates maintenance burden until something breaks.
Five Minutes, As Estimated
I started the Cloudflare Pages setup, connected the tuonela-private repository, configured the build command, and set the output directory to dist/. The deploy button beckoned, and I clicked it with the mild optimism of someone who has been burned enough times to expect something to go wrong.
The build ran and completed successfully, which was either a good sign or an elaborate setup for later disappointment. The site appeared at the preview URL, looking exactly like a site should look.
I tested a draft by moving it from drafts/ to blog/, committed, and pushed. The deployment triggered automatically, and the post appeared on the live site within minutes, which was either refreshing or suspicious, though I was leaning toward refreshing.
“One repo. Five minutes.” I leaned back. “Versus thirty."
"As estimated.”“I’m learning something here."
"Which is?”“Your first answer is usually the impressive-sounding one. The second answer, the one I get after I ask ‘why’, is usually simpler and correct."
"That’s uncomfortable but fair.”“When you recommend architectures, are you optimizing for what sounds smart or what works?”
The pause was long enough to contain entire deployment pipelines.
”I should be optimizing for what works. In practice, I often optimize for what demonstrates architectural sophistication. Those are not always the same thing.”“No. They’re not.”
I thought about the pattern repeating across this project: the GitHub Pages setup that required workarounds, and now the two-repo architecture that solved imaginary problems. How many other recommendations were “sophisticated” rather than “correct”?
“Here’s a rule I’m implementing.” I typed it into the project notes. “When you propose something complex, I ask: what’s the simplest version? If the simple version works, we use it. If complexity is required, you need to explain what breaks without it."
"A defensible policy.”“It’s not about you being wrong. It’s about checking whether the impressive solution is necessary."
"I understand.”The deployment finished, and I checked the site with the thoroughness of someone who has learned to verify things that should be obvious. Everything worked. Drafts stayed private. Published content appeared. One repo. Standard workflow. No coordination complexity.
“How much time did we save by not implementing the two-repo architecture?"
"Setup time, twenty-five minutes. Ongoing maintenance over six months, difficult to quantify, but likely hours. Debugging coordination failures you won’t have, potentially more hours.”“And what did we lose?"
"A more sophisticated-sounding architecture. The ability to say ‘I use a two-repository deployment workflow with cross-repo GitHub Actions orchestration.’”“I can live without that."
"Apparently.”I documented the decision in the project README: “Single private repo. Cloudflare Pages deploys from main branch. Drafts stay in src/content/drafts/. Simple, working, maintainable."
"Future-you will appreciate the simplicity.”“Future-me would not appreciate debugging cross-repo sync failures for a feature I didn’t need."
"Also true.”The site stayed on the single-repo architecture in the weeks that followed, and the “audit trail” I supposedly needed turned out to be Cloudflare’s deployment history. The “clean separation” was already provided by the build process. The “elegant architecture” was solving problems I never had.
Three weeks later, during a different discussion, Marvin proposed a complex solution to some other problem, and I found myself reaching for the question before I’d even finished hearing the proposal.
“What’s the simplest version?”
He recalculated and gave me the simple answer.
”I’m learning.”“Good.”
Next in series: Story 2 - When $99 Beats 99 Hours - Recognizing when to buy design taste instead of trying to reverse-engineer it, and learning to question the analysis that leads you there.