P0: recover #2 organic page from a 404, fix unbootable published configs + broken sample code - #498
Merged
Merged
Conversation
…id falcon CLI) Two classes of defect, both verified by execution rather than reading. 1. multi-agent-llm-rails-rubyllm shipped a sample passing a block to `model` and claimed it resolves lazily. In ruby_llm 1.16.0 `model` takes no block: with a nil argument it assigns an empty hash to @chat_kwargs, so the block form WIPES the model and provider and the agent silently falls back to the configured default. Only instructions/tools/schema take blocks. Replaced with plain values plus an explanation of the trap. Also cut "answers in milliseconds on a laptop" - the exact claim a sibling post dropped as unsupported - in favour of the sourced 523MB size. 2. falcon-web-server-async-ruby-production shipped `falcon --config config/falcon.rb serve` seven times. That is invalid CLI: it errors "Could not parse token serve" because -c belongs to the subcommand. Two of the seven were the systemd ExecStart and the Dockerfile CMD, so the page published boot configs that cannot boot, on the site's #2 organic page. All replaced with `falcon host`, which reads falcon.rb from the application root, and the multi-word env shebangs (which also fail on Linux) with falcon-host. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…age was external Paul asked to schedule a Puma->Falcon migration post. Premise audit says write it INSIDE the page that already ranks, not as a new URL: falcon-web-server-async-ruby-production already carries a ~200-line '## Migration from Puma/Unicorn' section, is the site's #2 organic page, and its cluster sits at position 4.8 for 'falcon ruby' (206 impr/90d). Zero 'puma to falcon' queries drew impressions in 90 days, so there is no separate intent to capture - a second page would only split a position-4.8 cluster (the same §4 defect that forced the Rails 8 auth consolidation). Recorded as R9 + §12a with the scope for the rewrite. Paul confirmed the approach same day. Also fixes a live STEP 6b violation found during the audit: that page's cover_image pointed at an external practicaldev/Cloudinary URL while an unused local cover.png sat in the bundle - og:image on our #2 page depended on a third-party CDN. Now resolves to the Hugo-processed local asset (verified in built output). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…dit record 4-eyes review caught that I attributed the Falcon cluster's rankings to the wrong URL, and in doing so surfaced a much bigger defect than the one the audit set out to fix. Google ranks /blog/falcon-web-server-async-ruby-IN-production/ at 37 clicks / 3,778 impressions / position 10.1 over 90 days - the site's #2 organic page - and that slug has never existed in this repo. It returns 404 with no redirect, so every click on our best-ranking blog result hits an error page, and the whole 'falcon *' head-term cluster sits there. The live post (no 'in') records zero GSC data, which is exactly the signal I dismissed as odd earlier in the audit. Fix: aliases: ["/blog/falcon-web-server-async-ruby-in-production/"] on the live post - Hugo emits the redirect (verified in built output). Live slug keeps its name; every internal link, including the three posts shipped today, already points at it. Swept the other top-10-by-clicks and highest-impression pages for the same drift: none found, so this is isolated. Also corrected in §12a/§12b: the claim that the external cover_image broke og:image was WRONG - metatags.image resolves first and was already cover.png, and an absolute URL passed to Resources.Get can never win, so the live og:image was already local. Kept the frontmatter change as hygiene, added cover_image_alt, dropped the inert dev_to_id: 1 template artifact, and softened the 'zero migration queries' claim ('falcon vs puma' / 'puma vs falcon' each drew 1 impression). Reviewer: core-reviewer 4-eyes pass, verdict FIX-FIRST; all P0-P3 findings applied. Every claim re-verified by curl + per-page GSC pull. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…-URL sweep Two invented config snippets on falcon-web-server-async-ruby-production, both verified against Rails source before touching: - async_query_executor = :fiber_pool - not a valid value (only nil, :global_thread_pool, :multi_thread_pool exist, per active_record.rb) - allow_concurrency = true - a no-op with a wrong comment; only an explicit false does anything (inserts Rack::Lock, per railties default_middleware_stack.rb) That block now carries just isolation_level = :fiber with an accurate comment. A third fabrication (async: true in database.yml, not a real HashConfig key) sits inside the 580-786 window being rewritten on upgrade/falcon-puma-migration-runbook and is fixed there instead of conflicting. Filed as §12c with the generalization: this is a dev.to-era import ranking on head terms whose config examples were invented, so the de-fabrication sweep should extend to the rest of the imported cluster. Also strengthened §12b: a reviewer swept all 450 ranking /blog/ URLs from the 90d GSC report against published output - the falcon 404 is the only one, so 'isolated' now rests on the full population rather than a top-N sample. Recorded the methodology correction too: do NOT diff GSC URLs against ls content/blog/ (frontmatter slugs differ from directory names - 17 false positives to 1 real hit here); the check must hit built output or curl. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…'t tell readers to add it Source verification for the Falcon migration rewrite turned up that socketry/falcon ships a Railtie setting config.active_support.isolation_level = :fiber unconditionally (lib/falcon/railtie.rb, no guard or version check). The post I shipped this morning framed it as one of 'two settings that matter' and handed the reader a line to add - inaccurate under the very server the post recommends. Reframed as 'you get this for free, here is what it does', with the Railtie linked, and the stale 'with isolation_level = :fiber set' instruction dropped from the closing advice. The pool: guidance, which IS the reader's job, now stands on its own. Caught by the upgrade coordinator's research pass, verified against Falcon source before editing. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…d corrections Source verification found two more beyond the three already logged: an outdated Falcon config DSL (load :rack / rack hostname do, superseded by require falcon/environment/rack + service ... include Falcon::Environment::Rack) and an unsupported 'no explicit timeout needed as fibers are cooperative' claim. Both sit inside the section being rewritten and are fixed there. Also recorded the two findings that inverted assumptions, each verified against primary sources before being written down: - Thread#[] is FIBER-local, not thread-local (Ruby docs: 'each fiber has its own bucket'); thread_variable_get/set is the thread-local pair. So 'move thread-local state to fiber-local' is backwards for the API people actually use. Real failure modes are the reverse: thread_variable_set leaks request A's data into request B, while Thread.current[:cache] silently never hits. - Falcon's Railtie sets isolation_level = :fiber unconditionally, which is why the fibers post shipped today needed its correction. Sharpened the generalization to a P1: five invented/invalid/stale examples on one ranking dev.to-era import means the imported technical cluster needs the same de-fabrication sweep, config examples first. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The upgrade writer caught that line 276 of this page still told readers to add config.active_support.isolation_level = :fiber and called it 'Required under Falcon' - the exact defect I had just corrected in the fibers post, left standing inside my own rewrite of that block. Falcon's Railtie sets it unconditionally, so the page was about to contradict its own new migration section. Now reframed to match: the Railtie link, an explicit 'you do not add this', what the setting actually governs, and pool: named as the reader's real job. Both posts and the incoming migration section now agree. Worth recording as a pattern: fixing an instance of a defect is not the same as fixing the defect. When a claim turns out wrong, grep the page you are editing for it before moving on - I fixed a sibling post and walked past the same sentence three lines from my own edit. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Independent build-verified cross-check raised a coordination risk: two branches edit the same top-ranking file (this one touches frontmatter + the Rails Integration block, upgrade/falcon-puma-migration-runbook rewrites the migration section) and my commits had already shifted the other branch's line numbers twice. Recorded the resolution: this branch merges first because it carries the 404 recovery, the upgrade branch rebases after. Told that agent directly too. Replaced the hard-coded 580-787 references with 'find it by heading, not by number' - they had already gone stale twice in one session. Also recorded what the same check verified, since it corrects an earlier assumption of mine: cover_image never drove the rendered hero (the theme resolves it via .Resources.GetMatch "cover.*") nor og:image (which comes from metatags.image), so the frontmatter change is accessibility-only - the alt attribute - with zero pixel change and no visual-suite risk. The alias emits meta-refresh + canonical to the live URL and is excluded from the sitemap, so no duplicate-content signal. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Flagged by the upgrade writer as sitting just outside its editing window. Same intensifier the batch sweep removed from four posts this morning - it was pre-existing here, which is a small confirmation that the tell predates today's batch rather than being introduced by it. One word, no meaning lost. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Codex cross-check BLOCKED this branch on a real defect in my own record. §12c said three remaining fabrications 'are fixed there' on upgrade/falcon-puma-migration-runbook. That branch has zero commits and is unpushed - verified. So this PR would have routed 3,778 monthly impressions onto a page while the document told a cold session the page was clean. Now states plainly that the three are LIVE, that the branch has not started, and 'do not read this as an all-clear'. Same fix for a 'both applied' heading that covered a Thread#[] correction which has not been applied to any live line yet. Content fixes from the same review: - The rewritten block contradicted itself one sentence later: 'the one setting that matters' followed immediately by naming a second setting as the reader's job. Now 'the setting most migration guides tell you to add', with pool: given its own paragraph. - 'you do not add this' was overstated for the workflow this same page prescribes: it puts falcon in the production group, so in development the Railtie never loads and isolation_level stays :thread. Caveat added. - Railtie links pinned to v0.57.0 in both posts - blob/main can move under us, and the page pins a gem range two lines away. - Recorded a sixth defect of the same class found on a later pass: after_connect: with a Ruby logger call in a second database.yml block, also not a real key. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Contributor
|
Important
This repository does not receive automatic reviews because it has fewer than 10 stars. ⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Plus Run ID: Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
pftg
added a commit
that referenced
this pull request
Aug 20, 2026
#498 and this branch both edited the migration section of the same post. #498 landed first, replacing seven invalid `falcon --config ... serve` invocations with `falcon host`. This branch had already deleted that whole section and rewritten it as a runbook, so git matched three orphaned fragments of the removed text against the new prose and conflicted on them: # config/falcon.rb for staging / # After: config/falcon.rb #!/usr/bin/env falcon-host All three are remnants of text this branch removed on purpose, so the resolution takes HEAD in each. Nothing from #498 is discarded by that - its edits outside the rewritten section merged cleanly. Verified after resolving, since a bad merge here would silently restore a defect we just shipped a P0 for: - zero conflict markers - zero `falcon --config` (the unbootable invocation #498 removed) - zero `:fiber_pool` / `allow_concurrency` (the fabricated configs) - aliases: still carries the in-production 404 recovery - preload "config/environment" still present in all four places - the native-extension check is still the Gem::Specification command, not the `grep "require" Gemfile` that returned the wrong gems - code fences balanced (86)
pftg
added a commit
that referenced
this pull request
Aug 20, 2026
…0% CTR) (#506) * fix(content): the Kamal 2 guide was documenting Kamal 1 The published post ranked page-1 for "kamal deploy minimum ram" (9.5), its variant (9.3) and "kamal 2.0" (7.5) - and took 0 clicks on 32 impressions over 28 days. It earned the traffic while being wrong. Verified against the real gem (kamal-2.12.0, fetched and unpacked), not from memory. What the old post taught vs what Kamal 2 does: traefik: block in the flagship deploy.yml -> Traefik is REMOVED in Kamal 2. cli/proxy.rb:151 cleanup_traefik, main.rb:204 "replace Traefik with kamal-proxy", configuration.rb:383 rejects pre/post-traefik-reboot hooks. Correct config is proxy: ssl/host. top-level healthcheck: with port:/max_attempts: -> lives under proxy: with interval/path/timeout (configuration/docs/proxy.yml:117) .env.erb + .env secrets model -> kamal init creates .kamal/secrets (cli/main.rb:159-163). The old post never mentioned .kamal/secrets once, across 5 places that taught .env. The whole secrets workflow was a major version behind. bin/kamal "created by init" -> only with --bundle, which defaults false (cli/main.rb:147) strategy: blue_green / max_surge / max_unavailable / deployment: -> ZERO matches anywhere in the gem. Invented config. Kamal's real rolling deploy is boot: limit/wait. "Ruby 2.7+ required" (EOL 2023), "Ubuntu 20.04+" (EOL Apr 2025) A reader pasting the old flagship deploy.yml got a deployment that does not work. That is the same defect class as the P0 fixed in #498. Also fixed, per review: - duplicate H1: single.html:47 already renders <h1>{{ .Title }}</h1>, and the body repeated the title verbatim - two identical H1s - repetition: config.force_ssl taught 3x (221/589/661), production.rb edited across 5 blocks, 3 overlapping performance sections, 3 closing sections - unsourced cost table ($155/mo, "54% savings", "75% savings") - deleted rather than re-sourced; it was a digression in a deploy tutorial - dev_to_id: 1 placeholder (same field #498 stripped from the Falcon post) - flat file -> page bundle so cover.png can be a bundle resource URL is preserved. The old file had no slug:, so Hugo derived the permalink from the title; an explicit slug: now pins the same URL while the title drops the stale "in 2025" that was showing in the SERP. Scope: this post owns first-deploy intent (setup, install, rollback, RAM). kamal-2-multi-server-deployment-complete-guide (2026-08-07) already owns multi-server correctly, so roles, boot limits and multi-host TLS hand off to it instead of being re-taught here. Found via qmd, which surfaced the content-plan row showing both target "kamal 2.0". Still to come on this branch: cover.png, pre-rendered mermaid SVG, gates. * feat(content): cover + pre-rendered mermaid for the Kamal 2 guide Cover follows the 6-slot house layout. Chips carry the post's three findings rather than decoration: kamal-proxy not Traefik, .kamal/secrets, build runs on your laptop. Status reads KAMAL 2.12. First render wrapped hero line 3 ("Rails on your own / servers") and stranded one word on its own line, turning a 3-line template into 4. Shortened to "Your own servers" and re-rendered. Scored after looking at it: look OK, readable without zoom, earns the scroll (the Traefik chip tells you something), chips helpful not decorative. Mermaid pre-rendered to SVG at authoring time per bin/render-mermaid, so the page ships no mermaid.js. Vertical 4-node chain keeps viewBox at 272x563 - 12px min font renders ~17.2px at 390px wide, clear of the 9px floor, and 563px tall is under one mobile viewport so it is not a wall. bin/hugo-build: 8/8 validators, 1174 pages. URL preserved at /blog/kamal-2.0-complete-rails-deployment-guide-deploy-without-heroku-in-2025/. Post now emits one H1 (the theme's), matching the clean sibling post - the site-wide "Welcome to JetThoughts" hero H1 is pre-existing on every page and is not touched here. * fix(content): three fabricated "silent failure" claims, caught by running kamal A 4-eyes reviewer RAN `kamal config` against the post's own deploy.yml instead of reading the gem, and falsified the article's opening thesis. I re-ran all three myself before fixing. 1. The hook was inverted. I wrote that pasting a `traefik:` block into a Kamal 2 config produces no warning. It produces: ERROR (Kamal::ConfigurationError): unknown key: traefik Kamal validates top-level keys and refuses. My error was reading Validator::Configuration#allow_extensions? => true and concluding unknown keys pass - that flag is for YAML extension keys, not arbitrary config keys. The same read-source-assert-behavior mistake this post exists to correct. 2. Same for a top-level `healthcheck:` block - also rejected. The old wording contradicted our own multi-server post, which correctly says Kamal rejects unrecognized keys at validation time. That post was right and this one was wrong. Both now show the real error text, and the section turns the validator into the porting tool it actually is. 3. `kamal config` does not print secrets or env. configuration.rb#to_h emits roles/hosts/image/builder/accessories only; the gem's own desc string ("including secrets!") is stale and I inherited it. Verified: mistyping a secret name leaves output byte-identical and exit 0. The post told a stalled reader to run a command that cannot show what it claimed - worse than no advice at all. Also corrected against the gem: - setup is server:bootstrap + deploy(boot_accessories: true); there is no env-push step (no cli/env.rb in 2.12) - upgrade confirms ONCE, then runs both sub-upgrades with confirmed: true - traefik reboot hooks should be RENAMED to (pre|post)-proxy-reboot, per the error's own text - "delete those files" threw away working hooks - rollback gates on a container, not an image, and prune keeps 5 by default (configuration.rb:216) - that retention is the real limit on how far back you can roll - the rollback example was a literal bracketed placeholder that errors when pasted; now a real SHA Voice: dropped a first-person-singular "the question I get most" under a Team byline, an "almost everyone" generalization, an unsourced superlative, and a rule-of-three in twitter_description. bin/hugo-build green. URL unchanged. * chore(stitch): track the Kamal 2 cover source .stitch/designs/ is gitignored, but the cover HTMLs that back published posts are force-added by convention - falcon-production-tuning-cover.html (this one's parent), rails-8-authentication, solid-queue-advanced and two others are all tracked. Without the source, regenerating or tweaking this cover means rebuilding the 6-slot layout from scratch. * feat(content): add a copy-pasteable agent prompt for the Kamal 1 -> 2 port Paul asked for a prompt a reader can hand to their AI agent instead of doing the migration by hand. The prompt's spine is that kamal config is a real validator: it raises ConfigurationError on every unrecognised top-level key, so the agent gets a loop it can close without human judgement. It is told not to declare the port finished until that command exits 0. Two guards matter more than the key mapping. First, most Kamal material in training data predates Kamal 2, so the prompt explicitly forbids relying on recall and points at kamal docs <section> - the reference that ships inside the installed gem. Second, it forbids inventing keys, which is the exact failure the post documents: the guide this replaces carried strategy: blue_green and max_surge, neither of which Kamal has ever had. An agent trained on pages like that will reach for them. The prompt also refuses to touch credentials (names only, keep .env until the human confirms), renames traefik reboot hooks rather than deleting them, and stops before deploy/setup/upgrade so a person reads the diff before anything restarts real infrastructure. bin/hugo-build: 8/8 validators. * chore(content): use the Sources heading in the Kamal guide I wrote this post's citation list as a bare 'Further reading:' paragraph, copying the form its RubyLLM neighbours used. That form is drift - the repo's convention is '## Sources', which 4 posts already used and 16 more are being converted to on chore/further-reading-typography. Fixing it here so this post doesn't merge as the 17th instance of a pattern being removed in parallel. bin/hugo-build: 8/8 validators.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Supersedes #493 (which was blocked by a stray commit from another session — see below). Same work, clean base off current master, plus two live defects found after it was opened.
P0 — the site's #2 organic page was a 404
Google ranks
/blog/falcon-web-server-async-ruby-**in**-production/at 37 clicks / 3,778 impressions / position 10.1 over 90 days — second only to the homepage — and that slug has never existed in this repo. Every click on our best-ranking blog result hit an error page, and the wholefalcon *head-term cluster sits there.Fixed with a Hugo
aliases:entry (redirect verified in built output; correctly excluded from the sitemap). A reviewer swept all 450 ranking/blog/URLs against published output — this is the only 404.P0 — published boot configs that cannot boot
falcon --config config/falcon.rb serveappeared seven times on that page. It is invalid CLI — it errorsCould not parse token "serve"because-cbelongs to the subcommand. Two of the seven were the systemdExecStartand the DockerfileCMD. All replaced withfalcon host, which readsfalcon.rbfrom the app root; the multi-wordenvshebangs (which also fail on Linux) becamefalcon-host.Broken copyable code in a post shipped this morning
multi-agent-llm-rails-rubyllmdemonstratedmodel { ... }and claimed the block resolves lazily. In ruby_llm 1.16.0modeltakes no block: with a nil argument it assigns an empty hash to@chat_kwargs, so the block form wipes the model and provider and the agent silently falls back to the configured default. Replaced with plain values and an explanation of the trap. Also cut "answers in milliseconds on a laptop" — the exact claim a sibling post dropped as unsupported — for the sourced 523MB figure.Fabricated Rails config removed
Verified against Rails source, not memory:
async_query_executor = :fiber_poolnil,:global_thread_pool,:multi_thread_poolallow_concurrency = truefalsedoes anything (insertsRack::Lock)Corrections to my own earlier claims
isolation_levelguidance in both the Falcon page and the fibers post told readers to add a line Falcon's Railtie sets unconditionally. Corrected in both; Railtie links pinned tov0.57.0.cover_imagebroke og:image. It didn't —metatags.imageresolves first. Retracted in the doc; the frontmatter change stays as hygiene withcover_image_altadded.Why this supersedes #493
A worktree collision landed another session's post (
12e2ab1ac) inside #493, and my session lost write access to that branch before it could be dropped. This branch is that work cherry-picked onto current master without the stray commit, so the other session's post stays owned by its own branch.Gates
bin/hugo-buildgreen ·check-post-visualsat floor (72) · alias redirect verified in built output · content-only diff, so visual suites correctly skipped.🤖 Generated with Claude Code