Neil Godfrey

Tinley Park · May 18, 2026

Sunday, May 10, 2026

mood: consolidating

Drew a line in the morning. Three projects, not ten. Then shipped the biggest single-day infra cutover of the year by lunch. The narrowing made the shipping possible.

Worked on

  • Backfilled yesterday's journal entry — streak was at risk (file existed, body was an empty stub)
  • Three-project focus declaration — gl-elevatedaily, gl-options, gl-neil only. Everything else paused
  • Archived the academy and truthers projects in the issue tracker
  • Added "Active Focus" callout to working docs, marked the parked product tracks as paused, noted gl-oracle merger into gl-elevatedaily
  • Personal blog at /blog on this domain — content collection, hero + post pages, .prose-letter typography, stub post
  • Letterhead nav: Journal and Blog links rewired from dead subdomains to same-domain paths
  • Journal week-folder rename: 2026-W19/W19/ (drop redundant year prefix)
  • Added --delete to HTML sync step in all three deploy workflows (asset sync had it, HTML sync didn't)
  • CloudFront default behavior got its own RewriteIndexFunction (fixed /blog/ 403)
  • yield.godfreylabs.com migration — full end-to-end: ACM cert, DNS validation, two CFN stacks, GH secrets, deploy workflow, first deploy, cutover PR with site/auth URL flips, vault chat-corpus updated
  • Hard sunset of blog.godfreylabs.com — DNS gone, CloudFront distribution gone, S3 bucket gone (59 object versions purged), IAM stack gone. No 301 redirect
  • Rotated CF_API_TOKEN GitHub secret — deploy workflow Cloudflare cache-purge step had been 401'ing for days

Shipped

  • Durable rule + canonical-state record locked: active-focus-three-projects (the rule), the current state of active vs paused tracks
  • https://neil.godfreylabs.com/blog/ — live, Letter aesthetic, first post is the focus declaration in long form
  • https://yield.godfreylabs.com/ — live, canonical and sitemap correctly pointing at yield. Trading-desk content moved here from blog.godfreylabs.com
  • blog.godfreylabs.com — fully decommissioned. DNS resolution failure for any inbound request
  • Eight PRs merged in gl-neil today (#8, #9, #10, #11, #12, #13, #14, #15, #16) plus one CLAUDE.md PR on godmode-cli
  • CloudFront stack gl-neil-yield-cloudfront, IAM stack gl-neil-yield-github-actions, S3 bucket gl-paiddaily-prod, deploy workflow deploy-yield.yml

Got stuck

  • /blog/ returned 403 after first deploy — CloudFront's default cache behavior didn't have a trailing-slash → /index.html rewrite function. Only the /journal* path-pattern did. Astro emits directory-format URLs, S3 with OAC + REST endpoint won't auto-resolve them. Lesson: when adding new directory-format paths to a CloudFront-fronted S3 setup, verify the cache behavior they fall under has the index-rewrite function
  • Astro lowercases collection slugs by default — a folder rename to W19/ emits /w19/ in the URL. Accepted; lowercase is consistent with the rest of the site
  • Auto-mode classifier blocked credential scans (Cloudflare token, AWS Secrets Manager broad-list) — correct blocks. Each time, the move was to ask for the specific value rather than probe
  • Sunset commands required a verbatim authorization phrase typed in chat — an AskUserQuestion answer alone wasn't enough to unstick the classifier on destructive prod ops
  • Keycloak gate on the cutover PR turned out to be over-cautious — investigation found the gl-finance-blog client never existed in the realm. The auth flow has been broken regardless of which redirect URI it references. Dropped the gate, merged
  • Cloudflare cache-purge step in deploy.yml had been 401'ing for days. Bad token. Rotated using the gl-smith-dns token (verified it has Zone Cache Purge permission)

Tomorrow

  • First commit on gl-options — push the discovery doc + scaffold
  • gl-elevatedaily Phase 0 — F.1 (apply migration to live DB), F.2 (off-host pg_dump → encrypted), F.3 (schema namespace split)
  • Decide what to do with the dead Keycloak auth pages on the yield blog — wire a real client or rip them out

Notes

The pattern of the day was narrow, then ship hard. The focus declaration came first — three projects, no others, paused everything that wasn't them. That single rule made the rest of the day's work possible. With ten projects in the air, no day produces this much. With three, the path through any work is short.

Three GL surfaces now share the same home: neil.godfreylabs.com hosts the chat island (Letter), /journal (this), and /blog (personal long-form). Three jobs, one neighborhood. The finance content moved out — it's its own property at yield.godfreylabs.com, tied to gl-options and the cashflow thesis.

Hard sunset over 301 was a real call. Conventional ops advice says preserve old URLs with redirects for SEO. We didn't. The trading-desk content is small in volume and the audience can rebuild on yield. The constraint is what makes the choice disciplined — saying "no redirect" forces clarity about which domain is the work.

The sunset itself was instructive on the safety rails. The auto-mode classifier blocked the destructive ops twice despite an interactive confirmation. It took a verbatim plain-text authorization phrase typed into chat to unstick. Annoying in the moment; right by design. Production deletes shouldn't slip through ambiguous signals.

Eight PRs merged in one session. The throughput came from a different shape than usual — every change shipped as its own surgical PR rather than batched into a megapatch. The classifier's gates rewarded that shape: small, clearly scoped, easy to authorize. Making the safety rails work with the work instead of around it.