Skip to content

content: 20.09 execution + two Rails posts (EOL, AI-builder migration) - #439

Merged
pftg merged 16 commits into
masterfrom
claude/content-calendar-next-post-hztfag
Aug 8, 2026
Merged

content: 20.09 execution + two Rails posts (EOL, AI-builder migration)#439
pftg merged 16 commits into
masterfrom
claude/content-calendar-next-post-hztfag

Conversation

@pftg

@pftg pftg commented Aug 8, 2026

Copy link
Copy Markdown
Member

Executes the 20.09 priority stack, then adds the next two posts off the plan. Every load-bearing claim was verified against a primary source; where I couldn't verify, the claim was cut rather than softened.

Posts published (3)

Post Stream Why this one
rails-cve-2026-66066-active-storage-rce Durable news CVE ID is a permanent search string, in our only click-earning topic
rails-7-eol-unpatched-security-exposure Durable news 7.1 got no patch for a CVSS 9.5 pre-auth bug; 7.2 died Aug 9
migrate-lovable-replit-app-to-rails Technical / crossover Every documented exit from a vibe-coded app goes to Vercel/Supabase/AWS. Rails as the rescue target was written nowhere.

Cannibalization was checked before drafting — the rule F2 violated. The existing rails-7-upgrade-guide is Rails 6→7 (opposite direction); nothing covered AI-builder migration. A YJIT candidate was rejected because yjit already appears in five posts including the performance canonical.

Defects the review chain caught

Every one of these would have shipped broken instructions to someone following along:

  1. CVE post's exposure gate was wrong. It told readers to grep for .variant( calls and treat a match as the test. The advisory says verbatim: "Generating variants is not a separate requirement." Readers who grepped, found nothing and stopped would be exposed while believing they were clear — on a post whose premise is that patching alone isn't enough. Real criteria: Active Storage on libvips + untrusted uploads + libvips < 8.13.
  2. CVE runbook would have caused an outage. The draft said the patched gem silently no-ops on old libvips. It fails closed — raises at boot. Bump the gem first on Ubuntu 22.04 (libvips 8.12.1) and production won't start. Runbook now lands libvips first.
  3. Rotation list omitted RAILS_MASTER_KEY — which lives in /proc/self/environ, the exact file the attack reads. Without it an attacker re-decrypts the new credentials.
  4. A RUN vips --version line commented as a build gate that exits 0. A no-op labelled as protection.
  5. EOL post pointed 7.1 readers at 7.2 without noting 7.2 loses support the next day. Now in paragraph 1.
  6. A Gemfile.lock command printing >= instead of the version whenever an alphabetically-earlier gem depends on rails. Reproduced against a realistic lockfile.
  7. Migration playbook stranded readers mid-migrationpg_dump --schema=public skips auth.users, so they'd export zero accounts, then hit an auth section telling them to move bcrypt hashes they never got.
  8. Supabase Storage was never migrated — a rescued app would silently lose every avatar and attachment.
  9. A fabricated date the fact-checker marked VERIFIED — "Rails 7.1 support ended 2025-10-01" appears nowhere in the cited announcement, which gives no date and is published Oct 29.

What that says about the review design

Four layers read the CVE detection section and missed the exposure bug; CodeRabbit caught it. The critics all verified whether the stated facts were true and none asked whether the post's decision procedure matched the source's. Those are different questions, and only the second one catches a wrong gate. Recorded in .okf/.

Other work in this PR

  • Funnel links/services/vibe-code-rescue/ had zero inbound links from 608 posts. Six rescue-intent posts now link to it, one-line diffs each.
  • Auth consolidation — 4 posts competing on one keyword collapsed to 1 canonical + 3 aliases (all returning 200). Also fixed a real bug: the canonical's password-reset action leaked account existence.
  • Sourcing — F5Bot retired (passive, can't backfill the ≤30-day window card add tags #29 needs). Replaced with a date-filtered site: sweep. It produced zero rows — this environment's search ignores site:/after: and Reddit blocks the agent. Card Remove redundant 'wp' styles and js #12's blocker moved from a 2-minute keyword swap to venue reachability; the query bank needs a human browser.
  • CodeRabbit's 14 comments worked through: pg_dump credentials out of the URI, schema/data split so the dump can't replay DDL, Stripe webhook idempotency, API-mode session/CORS/CSRF config, CVE-2025-48757 marked vendor-disputed and scoped, plus the sourcing-doc cleanups.
  • Removed <!-- Reference cadence --> markers shipping in published HTML on five posts, three already live.

Gates

  • bin/hugo-build green — 752 pages, 8/8 validators
  • Scroll gate on all three posts at 1280×800 and 390×844 — zero console errors, zero 4xx, no overflow
  • Covers rendered to the 6-slot spec, each viewed before commit
  • Three critics + cold-eyes per post; CodeRabbit review addressed
  • Zero em dashes, zero erb fences, all internal slugs verified on disk

Mobile gate caught a real defect: the migration post's 3-column table overflowed 390px. The container is 354px and the theme gives tables no overflow-x wrapper, so minimum content width wins (116+132+129=377). Trimming prose didn't fix it — min-width comes from the longest token per column, and the first trim made it 1px worse. Collapsed to 2 columns. Logged in .okf/ as a content rule; the systemic fix is a CSS change that would trigger the full visual pair.

Known risk, deliberately not fixed

sync_status.yml still lists two deleted slugs and lib/sync has no skip mechanism — if either dev.to article is edited upstream, the deleted directory returns and the auth cluster re-splits. Low probability on 2024 posts; adding a retired-slug skip is its own change.

claude added 4 commits August 8, 2026 05:43
/services/vibe-code-rescue/ carries the full offer and had zero inbound links
from 608 blog posts - reachable only through nav. These six posts are the
site's pre-qualified rescue traffic and each linked to it zero times.

One contextual link per post, placed where the post already names the pain
rather than as a footer CTA. Founder-audience posts only; the 2026-08-07
exemption in 20.09 keeps service links out of deep-technical posts.

Each edit is a one-line diff - no page was rewritten or re-themed.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RHgyr6mEXghWSzipXnzQuY
Four posts competed for "Rails 8 authentication generator". The newest shipped
2026-07-29 from a content-plan row that named a new slug without checking what
already existed - a 347-line post against an existing 1,337-line one.

Canonical is rails-8-authentication-generator-devise-migration: deepest coverage
and the most accumulated authority. The other three are merged in and 301'd via
Hugo aliases, so every old URL still resolves.

Merged from the Jul-29 post: authenticate_by as the constant-time alternative to
find_by+authenticate, database-backed session rationale, generates_token_for
self-invalidation, force_ssl and sliding-window session notes. Nothing from the
two 2024 dev.to posts survived the cut test.

Also fixes a real bug the canonical carried: its password-reset create action
branched on "Email not found", leaking account existence. It now redirects with
the same message either way.

Internal links in rails-argon2-has-secure-password-migration-guide and
solid-queue-advanced-patterns-retries-concurrency repointed to the canonical.

KNOWN RISK, not fixed here: content/blog/sync_status.yml still carries entries
for two of the deleted slugs. lib/sync has no skip mechanism, so if either
dev.to article is edited upstream, desynchronized? fires and
Post.create_from_remote_details recreates the deleted directory, re-splitting
the cluster. Low probability on 2024 posts; adding a retired-slug skip to
lib/sync is its own change, not this one.

bin/hugo-build green, all three alias stubs verified emitting.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RHgyr6mEXghWSzipXnzQuY
F5Bot produced zero usable mentions and Paul called it dead. Two structural
flaws: it matches literal substrings only, and it is passive - it can only see
mentions from setup-time forward, so it can never backfill. Card #29 needs rows
verified inside a 30-day window, which a passive monitor cannot deliver on
demand. The "swap the v2 keywords" unblock is therefore void, not pending.

Replacement is p7-search-sweep.md: ~30 copy-paste queries pairing site: with
after:YYYY-MM-DD across reddit (plus sub-scoped variants), IndieHackers, HN, X
and Lobsters, with the date arithmetic spelled out so a cold session can
regenerate the window. Keeps the v2 keywords - those were derived from our own
captured verbatim quotes and were never the problem.

The sweep produced ZERO rows, and the cause is this environment, not the market.
Verified independently: the search tool ignores site: and after: entirely - a
site:reddit.com query returns Substack, Goodreads and Yahoo. reddit.com is
hard-blocked to the agent user agent, and every thread-open attempt returns
EGRESS_BLOCKED. Vote 3 check 3 requires a timestamp read from the opened thread,
so with no venue openable every candidate fails by construction.

Nothing was logged rather than infer a date or re-log a known row - the exact
defects card #28 exists to prevent.

Card #12 stays blocked, but the diagnosis moves: the blocker is no longer a
2-minute keyword swap, it is venue reachability. The query bank is ready for a
human browser and untested against a real index.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RHgyr6mEXghWSzipXnzQuY
First durable-news post under the 20.09 swap rule: a CVE ID is a permanent
search string, unlike the event-news posts that flatline after a week.

Angle most coverage buries - patching Rails is not sufficient. The bug is in how
Active Storage hands uploads to libvips, so libvips must reach >=8.13, and
secret_key_base plus database and storage credentials must be rotated because an
arbitrary file read may already have taken them.

Left draft: true pending the review loop. Currently in critics.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RHgyr6mEXghWSzipXnzQuY
@coderabbitai

coderabbitai Bot commented Aug 8, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

Added Rails migration and security articles, consolidated authentication content, linked blog posts to the vibe code rescue service, and replaced F5Bot sourcing with a documented date-filtered search sweep.

Changes

Content and service funnel

Layer / File(s) Summary
Vibe-coded MVP migration article
content/blog/migrate-lovable-replit-app-to-rails/index.md
Added migration guidance for Supabase data, Rails authentication, Stripe webhooks, frontend options, deployment, and migration boundaries.
Rescue-service content links
content/blog/47-startups-failed-same-coding-mistake/index.md, content/blog/dev-shop-red-flags-checklist/index.md, content/blog/fire-dev-shop-guide/index.md, content/blog/hiring-dev-shop-questions/index.md, content/blog/quality-tax-ai-mvp-cost/index.md, content/blog/vibe-coding-crisis-ai-code-debt/index.md
Added links to the vibe code rescue service and audit or fixed-price engagement details.

Rails authentication content

Layer / File(s) Summary
Authentication article consolidation
content/blog/rails-8-authentication-generator-devise-migration/index.md, content/blog/rails-argon2-has-secure-password-migration-guide/index.md, content/blog/solid-queue-advanced-patterns-retries-concurrency/index.md, content/blog/new-methods-that-help-implement-authentication-in-ruby-on-rails-71/index.md, content/blog/rails-8-authentication-generator-complete-guide/index.md, content/blog/rails-8-introducing-built-in-authentication-generator-ruby/index.md
Added legacy URL aliases, deleted overlapping authentication articles, removed obsolete links, and updated cross-references.
Authentication privacy and session guidance
content/blog/rails-8-authentication-generator-devise-migration/index.md
Added constant-time authentication, uniform password-reset responses, token invalidation, database-backed session revocation, secure cookies, and refreshed session expiry guidance.

Rails Active Storage security content

Layer / File(s) Summary
Active Storage CVE article
content/blog/rails-cve-2026-66066-active-storage-rce/index.md, docs/projects/2510-seo-content-strategy/20-29-strategy/20.09-content-plan-revision-aug-2026.md
Added CVE-2026-66066 exposure checks, a libvips-first remediation runbook, secret rotation guidance, exploit details, version options, references, and shipment status.
Rails 7 end-of-life guidance
content/blog/rails-7-eol-unpatched-security-exposure/index.md
Added Rails 7.1 exposure assessment, upgrade and patching paths, mitigations, risk-acceptance guidance, decision criteria, support dates, and sources.

Rescue prospect sourcing

Layer / File(s) Summary
Date-filtered search sweep
docs/projects/2607-vibe-code-rescue/rescue-sprint/prospects/p7-search-sweep.md, docs/projects/2607-vibe-code-rescue/rescue-sprint/prospects/p7-f5bot.md, docs/projects/2607-vibe-code-rescue/rescue-sprint/prospects/RUN.md, docs/projects/2607-vibe-code-rescue/backlog.md
Retired F5Bot and documented date-window queries, venue verification, cadence, deduplication, and output rules.
Search sweep execution status
docs/projects/2607-vibe-code-rescue/rescue-sprint/prospects/p7-search-sweep.md, docs/projects/2607-vibe-code-rescue/backlog.md, .okf/log.md
Recorded the blocked initial sweep, empty prospect output, excluded results, absent verified VoC, and updated project status.

Estimated code review effort: 4 (Complex) | ~45 minutes

Possibly related PRs

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately identifies the content-plan execution and two Rails posts, which are substantial parts of the changeset.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch claude/content-calendar-next-post-hztfag

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

claude added 3 commits August 8, 2026 05:58
The draft said the patched gem's guard silently no-ops on libvips < 8.13. The
advisory says the opposite, verbatim: "Active Storage will raise an exception
during boot in such an unsecurable environment." It fails CLOSED.

That inverted the runbook. As drafted, a reader on Ubuntu 22.04 - which ships
libvips 8.12.1 - would bump the gem, deploy, plan to fix libvips later, and take
production down at boot. The runbook now lands libvips >= 8.13 in the same image
build as the gem bump or before it, and says why.

Three more blockers from the same review:
- Workarounds were inverted. The advisory allows no workaround below libvips
  8.13 other than removing the dependency; VIPS_BLOCK_UNTRUSTED and
  Vips.block_untrusted are for apps already on 8.13 that cannot bump the gem yet.
- Rotation list omitted RAILS_MASTER_KEY, which lives in /proc/self/environ - the
  exact thing the read targets. Without it an attacker re-decrypts the new
  credentials file. Added, plus a warning that rotating secret_key_base kills
  outstanding signed_id links and signed blob URLs in already-sent mail.
- The Dockerfile guard was a no-op labelled as a gate: `RUN vips --version`
  exits 0. Replaced with dpkg --compare-versions.

Also: Ethiack named the bug, not Akamai; ruby-vips links libvips in-process via
FFI rather than shelling out; Vips::LIBRARY_VERSION is now the primary detection
check since slim images ship libvips42 without vips-tools.

Restructured for triage - affected-versions block above the fold, detection and
runbook ahead of mechanism. Contraction sweep applied.

Still draft: true pending the cold-eyes gate. bin/hugo-build green.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RHgyr6mEXghWSzipXnzQuY
Cold-eyes gate pass. Most valuable catch was a date the fact-check critic had
marked VERIFIED: the post claimed Rails 7.1 security support "ended 2025-10-01",
citing the rubyonrails.org announcement. That date appears nowhere in the
announcement - it says only that 7.1 "has now completed its security support
period", published 2025-10-29. Cold-eyes spotted the absurdity (an announcement
dated Oct 29 announcing an Oct 1 date) and routed it back rather than editing
fact territory; fetching the primary source confirmed it. Now reads "finished
its security support period by October 2025", which is what the source supports.

Edit-seam fixes from the earlier restructure: removed a duplicated no-IOC
statement, stopped the mechanism section re-teaching /proc/self/environ now that
the rotation list precedes it, replaced a near-verbatim repeat of the
block_untrusted workaround with a backward reference, and untangled a
garden-path sentence in the ordering rule - the one sentence that must not be
ambiguous.

Also: dropped an invented "months later" interval, replaced two unattributed
quantifiers ("most 7.x and 8.x apps", an asserted upgrade duration) with claims
that follow from stated facts, cut negative parallelism from 4 to 2, gave the
one subjectless sentence a subject, and reconciled the Dockerfile gate with the
detection section - the gate needs vips-tools and only proves what the image
installed, while Vips::LIBRARY_VERSION confirms what the process linked.

Verified no survivor of either inverted claim: libvips-first ordering holds in
all five places, and all four mentions say raise/refuse rather than no-op.

Still draft: true - cover.png is generating.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RHgyr6mEXghWSzipXnzQuY
Cold-eyes gate PUBLISH-READY after its two remaining blockers were cleared: the
missing cover is generated, and the fabricated Rails 7.1 EOL date is gone.

Cover follows the 6-slot spec on the technical-stream template, with the
severity treatment kept inside the existing palette. Chips carry CVSSv4 9.5,
libvips 8.13-or-newer, and pre-auth RCE - the three facts that decide whether
this gets a maintenance window tonight.

Gates: bin/hugo-build green (750 pages, 8/8 validators); rendered scroll gate at
1280x800 and 390x844 with zero console errors, zero 4xx, no horizontal overflow;
post, offer page and all three auth aliases return 200.

Plan and OKF updated with the two review lessons - a verifier marked a date
VERIFIED that its own cited source does not contain, and this is the second
consecutive technical post where voice review passed an instruction that would
break a reader's production.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RHgyr6mEXghWSzipXnzQuY
@pftg
pftg marked this pull request as ready for review August 8, 2026 06:09
claude added 2 commits August 8, 2026 06:45
Both draft: true - in the critic loop, not published.

Rails 7 EOL exposure: the branch-level companion to the CVE-2026-66066 post.
7.1 and earlier got no patch for a CVSS 9.5 pre-auth RCE, so there is no version
to bump to on that branch. Verified against the Rails announcement while drafting:
7.2 security support ends 2026-08-09, which means upgrading to 7.2.3.2 for the CVE
fix buys about one day of support - the post aims readers past 7.2.

Lovable/Replit to Rails migration: the clearest white space the competitor scan
found. Every documented exit path from a vibe-coded app goes to Vercel, Supabase,
AWS or Railway; Rails as the rescue target is written nowhere. This is the post
that puts the site's proven ranking category and the active bet on one page.

Cannibalization checked before drafting, per the 20.09 rule that F2 violated:
the existing rails-7-upgrade-guide is Rails 6 to 7 (opposite direction), and no
post covers AI-builder migration. A YJIT/ZJIT candidate was rejected - yjit
already appears in five posts including the performance canonical.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RHgyr6mEXghWSzipXnzQuY
Still draft: true - cold-eyes gate and covers outstanding.

Rails 7 EOL: the opening listed 7.2 among the patched branches without noting
7.2 loses security support the next day, so a reader who bounced early would
upgrade straight into an EOL branch. That warning now lands in paragraph 1.
Also fixed a Gemfile.lock version-extraction command that printed ">=" instead
of the version whenever an alphabetically-earlier gem depended on rails
(reproduced against a realistic lockfile), corrected makandra Rails LTS coverage
which now includes a 7.2 line, and cut a passage that re-taught the CVE post's
remediation near-verbatim.

Removed a sentence telling readers to distrust any duration they read anywhere.
That was an anti-fabrication instruction of mine leaking into the prose as an
apologetic caveat, and it read as a rebuke of the sibling post's 2-6 week figure.

AI-builder migration: pg_dump --schema=public skips auth.users, where Supabase
keeps emails and bcrypt hashes - the playbook exported zero accounts and then
told the reader to migrate hashes they never had. Also adds the Supabase Storage
step (a rescued app was silently losing every upload) and corrects the Rails 8
generator's users PK, which is bigint rather than the UUID the snippet assumed.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RHgyr6mEXghWSzipXnzQuY

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 14

Note

Due to the large number of review comments, Critical, Major severity comments were prioritized as inline comments.

🟡 Minor comments (9)
content/blog/rails-cve-2026-66066-active-storage-rce/index.md-132-133 (1)

132-133: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Remove or cite the migration estimate.

2-6 weeks and above 60% are precise planning thresholds, but the post
provides no benchmark or citation. Remove the thresholds, or label them as
an internal heuristic and cite supporting evidence.

As per coding guidelines, blog content assertions require citations.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@content/blog/rails-cve-2026-66066-active-storage-rce/index.md` around lines
132 - 133, Update the upgrade guidance in the Rails migration recommendations to
remove the unsupported “2-6 weeks” and “above 60%” planning thresholds, or
explicitly identify them as internal heuristics and add a supporting citation.
Keep the upgrade and backport recommendations otherwise unchanged.

Source: Coding guidelines

content/blog/rails-7-eol-unpatched-security-exposure/index.md-78-78 (1)

78-78: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Replace the relative release-window reference.

If this draft publishes after August 8, 2026, tomorrow, as this post goes out points the wrong release date. Use August 9, 2026 instead. The linked Rails announcement/maintenance policy lists this date for Rails 7.2 security support.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@content/blog/rails-7-eol-unpatched-security-exposure/index.md` at line 78,
Update the release-window sentence in the Rails support comparison to replace
“tomorrow, as this post goes out” with the absolute date “August 9, 2026,” while
preserving the existing security-support link and surrounding content.

Source: MCP tools

content/blog/rails-cve-2026-66066-active-storage-rce/index.md-2-3 (1)

2-3: 🔒 Security & Privacy | 🟡 Minor | ⚡ Quick win

Avoid stating RCE as a guaranteed outcome.

GHSA-xr9x-r78c-5hrm describes an Active Storage variant-processing issue that can expose secret_key_base; that exposure can then enable RCE, but the RCE path is not guaranteed by Active Storage itself.

  • content/blog/rails-cve-2026-66066-active-storage-rce/index.md: change the metadata to describe possible RCE and update cover_image_alt on line 21 from pre-auth RCE to possible pre-auth RCE.
  • content/blog/rails-7-cve-2026-66066-active-storage-rce/index.md line 9: update the description: to avoid stating CVE-2026-66066 as a pre-auth RCE.
  • content/blog/rails-7-eol-unpatched-security-exposure/index.md: change line 24 from escalates to code execution to may enable code execution.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@content/blog/rails-cve-2026-66066-active-storage-rce/index.md` around lines 2
- 3, Revise the metadata and security wording to avoid presenting RCE as
guaranteed: in content/blog/rails-cve-2026-66066-active-storage-rce/index.md,
describe RCE as possible and change cover_image_alt from “pre-auth RCE” to
“possible pre-auth RCE”; in
content/blog/rails-7-cve-2026-66066-active-storage-rce/index.md line 9, update
description accordingly; and in
content/blog/rails-7-eol-unpatched-security-exposure/index.md lines 24-26,
change “escalates to code execution” to “may enable code execution.”

Source: MCP tools

docs/projects/2607-vibe-code-rescue/rescue-sprint/prospects/p7-search-sweep.md-29-29 (1)

29-29: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Add languages to the fenced blocks.

markdownlint-cli2 reports MD040 on these fences. Use text for the
query and configuration blocks.

Also applies to: 62-62, 73-73, 85-85, 95-95, 104-104, 121-121, 131-131

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@docs/projects/2607-vibe-code-rescue/rescue-sprint/prospects/p7-search-sweep.md`
at line 29, Update the fenced code blocks in p7-search-sweep.md, including the
blocks at the referenced locations, to specify the text language identifier. Use
text for both query and configuration blocks so every fence has an explicit
language.

Source: Linters/SAST tools

docs/projects/2607-vibe-code-rescue/backlog.md-101-101 (1)

101-101: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Record the tooling failure by venue, not as a global operator failure.

The detailed P7 run log shows mixed behavior: IndieHackers URLs were
returned, after: was ineffective, and Reddit rejected the user agent.
Keep the blocker, but preserve these distinctions in both summaries.

  • docs/projects/2607-vibe-code-rescue/backlog.md#L101-L101: describe
    operator support and venue access separately.
  • .okf/log.md#L890-L898: use the same venue-specific diagnosis.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/projects/2607-vibe-code-rescue/backlog.md` at line 101, Update the
sweep-failure summaries to distinguish operator/tooling support from venue
access: in docs/projects/2607-vibe-code-rescue/backlog.md lines 101-101 and
.okf/log.md lines 890-898, retain the blocker while noting that IndieHackers
URLs were returned, after: filtering was ineffective, and Reddit rejected the
user agent; describe thread-opening egress failures separately from
search-surface limitations at both sites.
content/blog/rails-8-authentication-generator-devise-migration/index.md-316-316 (1)

316-316: 🔒 Security & Privacy | 🟡 Minor | ⚡ Quick win

Scope the password-change invalidation claim.

generates_token_for does not bind every token to the password. This post’s :password_reset token does, because the shown User model uses password_digest&.last(10), but the sentence should reference that token or declaration.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@content/blog/rails-8-authentication-generator-devise-migration/index.md` at
line 316, Update the password-change invalidation sentence in the discussion of
`generates_token_for` to scope the claim specifically to the `:password_reset`
token declaration using `password_digest&.last(10)`, rather than implying every
generated token is password-bound. Preserve the existing explanation that this
token becomes invalid after a password change.
content/blog/rails-8-authentication-generator-devise-migration/index.md-227-239 (1)

227-239: 🔒 Security & Privacy | 🟡 Minor | ⚡ Quick win

Use mitigation wording instead of a constant-time guarantee.

authenticate_by performs a password digest even when no record matches, which helps reduce timing-based email enumeration. It does not promise a fully constant-time request; replace “constant-time call” and “no timing gap” with mitigation language.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@content/blog/rails-8-authentication-generator-devise-migration/index.md`
around lines 227 - 239, Update the explanatory text around User.authenticate_by
to describe it as reducing or mitigating timing differences by performing a
password digest when no record matches, rather than calling it constant-time or
claiming there is no timing gap. Keep the code example and the recommendation to
prefer authenticate_by unchanged.
content/blog/migrate-lovable-replit-app-to-rails/index.md-158-158 (1)

158-158: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Remove the editorial marker from published content.

<!-- Reference cadence: thoughtbot --> is internal review metadata. It also
conflicts with the founder-post rule, which requires Walling+Fishkin rather
than thoughtbot. Remove it and run the founder stream self-test.

As per coding guidelines, founder posts use the founder voice workflow.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@content/blog/migrate-lovable-replit-app-to-rails/index.md` at line 158,
Remove the `<!-- Reference cadence: thoughtbot -->` editorial marker from the
published post, then run the founder stream self-test using the founder voice
workflow.

Source: Coding guidelines

content/blog/dev-shop-red-flags-checklist/index.md-71-71 (1)

71-71: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Clarify the audit promise.

The Rescue Audit is a 48-hour scorecard, not necessarily a published test-coverage number. Change this to 48-hour scorecard or confirm the scorecard includes coverage before keeping coverage number.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@content/blog/dev-shop-red-flags-checklist/index.md` at line 71, Update the
closing sentence near the vibe code rescue link to describe the service as
providing a 48-hour scorecard instead of promising a test-coverage number,
unless the audit explicitly includes coverage reporting.

Source: Coding guidelines

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@content/blog/migrate-lovable-replit-app-to-rails/index.md`:
- Around line 67-70: Update the pg_dump instructions to avoid embedding the
database password in the connection URI: use PGPASSFILE or interactive
authentication instead. Document that dump.sql may contain sensitive user data,
should be protected from unauthorized access, and must be deleted securely after
use.
- Line 25: Update the paragraph’s CVE-2025-48757 claim to state that it concerns
Lovable-generated sites affected through April 15, 2025 and that the
vulnerability is disputed by the supplier. Retain the Superblocks scan as
supporting context, add a citation to the NVD CVE record alongside it, and avoid
presenting the scan as definitive proof of the CVE.
- Line 73: Update the database export guidance to preserve the promised
migration of user rows and bcrypt hashes: export auth.users, including
encrypted_password, separately from the public schema dump, or explicitly
require password resets if those credentials are not exported. Revise the
surrounding text so it no longer implies that excluding the auth schema is
always appropriate.
- Line 85: Update the migration guidance around the pg_dump and psql workflow to
separate schema mapping from data restoration: make the export data-only, or
explicitly restore the full dump into staging for transformation before loading
into the Rails-managed database. Ensure the documented load step cannot replay
Supabase DDL or bypass the new Rails schema.
- Around line 109-136: Update StripeWebhooksController#create to persist
event.id in a unique idempotency record before dispatching subscription work,
and enqueue or otherwise emit durable work instead of calling
Subscriptions::Activate.call or Subscriptions::Revoke.call inline. Return head
:ok only after the event is accepted, while safely treating duplicate event IDs
as already processed.
- Around line 54-58: Update the Builder capability matrix in the migration
comparison to remove or qualify the “v0 is frontend-only” claim using the
applicable version or documentation scope, acknowledging its backend, database,
and authentication capabilities. Revise the Base44 description to accurately
distinguish exported frontend code from managed auth, data, and backend
functions that may require service or SDK migration.
- Around line 142-144: Update the React-with-Rails API migration guidance to
include the required cookie-based session setup: enable cookie/session
middleware, configure a session store, allow credentialed CORS for the frontend
origin, and add CSRF protection. Place this configuration alongside the Rails
API-mode instructions so the documented backend session flow is
browser-compatible.

In `@content/blog/rails-7-eol-unpatched-security-exposure/index.md`:
- Around line 42-70: Expand the fleet sweep to discover Gemfile.lock files
recursively and make the GitHub search cover Rails 7.1, 7.0, and 6.x as stated.
Run bundle-audit separately from each discovered app directory rather than only
the current directory. Broaden the final Active Storage reachability check
beyond app/ and variant/representation calls to include configuration,
variant_processor, and .processed usage, or explicitly qualify any remaining
scope limitations.

In `@content/blog/rails-8-authentication-generator-devise-migration/index.md`:
- Around line 469-474: Use one consistent Rails session model: at
content/blog/rails-8-authentication-generator-devise-migration/index.md lines
469-474, make the signed session[:session_token] cookie derive from
Session.find_by(user_id: session[:user_id]) so user.sessions.destroy_all
invalidates it; at line 1060, remove the separate application-cookie refresh
example and describe the session store’s actual expiry behavior instead.

In `@content/blog/rails-cve-2026-66066-active-storage-rce/index.md`:
- Around line 59-66: Update both the CVE detection flow in
content/blog/rails-cve-2026-66066-active-storage-rce/index.md (lines 59-66) and
the Rails 7 EOL fleet triage/Exit 3 wording in
content/blog/rails-7-eol-unpatched-security-exposure/index.md (lines 66-72) to
use the advisory’s exposure criteria: Active Storage configured with libvips,
untrusted image uploads, and insufficient libvips protection. Remove the
requirement that literal .variant or .representation calls be present, while
preserving guidance for identifying affected applications.

In `@docs/projects/2607-vibe-code-rescue/rescue-sprint/prospects/p7-f5bot.md`:
- Around line 1-4: Remove or clearly label the F5Bot setup and digest
instructions in this document as historical so no executable steps remain after
retirement. Update the shared wrapper reference in RUN.md to mention only P7,
removing the P7/F5Bot naming while preserving the replacement P7 workflow.

In
`@docs/projects/2607-vibe-code-rescue/rescue-sprint/prospects/p7-search-sweep.md`:
- Around line 127-135: Update the “3.6 Trigger-3 rescue lane” procedure so it
explicitly targets known competitor article domains or URLs and captures only
commenters, never the original poster. Add the required competitor sources and a
commenter-only verification step, or remove this lane if those details cannot be
provided.
- Around line 161-170: Update the deduplication workflow in the “Dedupe - thread
URL is the join key” section so candidate URLs are normalized before searching
the merged list and sibling files. Normalize both candidate and stored URLs by
removing utm parameters, trailing slashes, and normalizing Reddit host variants,
then use and record the normalized URL as the join key.

In `@docs/projects/2607-vibe-code-rescue/rescue-sprint/prospects/RUN.md`:
- Line 24: Update the P7 instructions in RUN.md and the referenced
p7-search-sweep.md workflow to resolve the Reddit verification conflict: either
explicitly permit opening Reddit thread bodies and reading timestamps/replies
for P7, or exclude Reddit candidates from the P7 lead set. Keep the wrapper
policy, verification gates, and backlog/method references consistent with the
chosen outcome.

---

Minor comments:
In `@content/blog/dev-shop-red-flags-checklist/index.md`:
- Line 71: Update the closing sentence near the vibe code rescue link to
describe the service as providing a 48-hour scorecard instead of promising a
test-coverage number, unless the audit explicitly includes coverage reporting.

In `@content/blog/migrate-lovable-replit-app-to-rails/index.md`:
- Line 158: Remove the `<!-- Reference cadence: thoughtbot -->` editorial marker
from the published post, then run the founder stream self-test using the founder
voice workflow.

In `@content/blog/rails-7-eol-unpatched-security-exposure/index.md`:
- Line 78: Update the release-window sentence in the Rails support comparison to
replace “tomorrow, as this post goes out” with the absolute date “August 9,
2026,” while preserving the existing security-support link and surrounding
content.

In `@content/blog/rails-8-authentication-generator-devise-migration/index.md`:
- Line 316: Update the password-change invalidation sentence in the discussion
of `generates_token_for` to scope the claim specifically to the
`:password_reset` token declaration using `password_digest&.last(10)`, rather
than implying every generated token is password-bound. Preserve the existing
explanation that this token becomes invalid after a password change.
- Around line 227-239: Update the explanatory text around User.authenticate_by
to describe it as reducing or mitigating timing differences by performing a
password digest when no record matches, rather than calling it constant-time or
claiming there is no timing gap. Keep the code example and the recommendation to
prefer authenticate_by unchanged.

In `@content/blog/rails-cve-2026-66066-active-storage-rce/index.md`:
- Around line 132-133: Update the upgrade guidance in the Rails migration
recommendations to remove the unsupported “2-6 weeks” and “above 60%” planning
thresholds, or explicitly identify them as internal heuristics and add a
supporting citation. Keep the upgrade and backport recommendations otherwise
unchanged.
- Around line 2-3: Revise the metadata and security wording to avoid presenting
RCE as guaranteed: in
content/blog/rails-cve-2026-66066-active-storage-rce/index.md, describe RCE as
possible and change cover_image_alt from “pre-auth RCE” to “possible pre-auth
RCE”; in content/blog/rails-7-cve-2026-66066-active-storage-rce/index.md line 9,
update description accordingly; and in
content/blog/rails-7-eol-unpatched-security-exposure/index.md lines 24-26,
change “escalates to code execution” to “may enable code execution.”

In `@docs/projects/2607-vibe-code-rescue/backlog.md`:
- Line 101: Update the sweep-failure summaries to distinguish operator/tooling
support from venue access: in docs/projects/2607-vibe-code-rescue/backlog.md
lines 101-101 and .okf/log.md lines 890-898, retain the blocker while noting
that IndieHackers URLs were returned, after: filtering was ineffective, and
Reddit rejected the user agent; describe thread-opening egress failures
separately from search-surface limitations at both sites.

In
`@docs/projects/2607-vibe-code-rescue/rescue-sprint/prospects/p7-search-sweep.md`:
- Line 29: Update the fenced code blocks in p7-search-sweep.md, including the
blocks at the referenced locations, to specify the text language identifier. Use
text for both query and configuration blocks so every fence has an explicit
language.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 075990ed-4ea2-4d7e-9c1b-c38e27fd9e1c

📥 Commits

Reviewing files that changed from the base of the PR and between 3b25c17 and 7ab8628.

⛔ Files ignored due to path filters (5)
  • content/blog/new-methods-that-help-implement-authentication-in-ruby-on-rails-71/cover.png is excluded by !**/*.png
  • content/blog/new-methods-that-help-implement-authentication-in-ruby-on-rails-71/file_0.png is excluded by !**/*.png
  • content/blog/rails-8-authentication-generator-complete-guide/cover.png is excluded by !**/*.png
  • content/blog/rails-8-introducing-built-in-authentication-generator-ruby/cover.png is excluded by !**/*.png
  • content/blog/rails-cve-2026-66066-active-storage-rce/cover.png is excluded by !**/*.png
📒 Files selected for processing (21)
  • .okf/log.md
  • content/blog/47-startups-failed-same-coding-mistake/index.md
  • content/blog/dev-shop-red-flags-checklist/index.md
  • content/blog/fire-dev-shop-guide/index.md
  • content/blog/hiring-dev-shop-questions/index.md
  • content/blog/migrate-lovable-replit-app-to-rails/index.md
  • content/blog/new-methods-that-help-implement-authentication-in-ruby-on-rails-71/index.md
  • content/blog/quality-tax-ai-mvp-cost/index.md
  • content/blog/rails-7-eol-unpatched-security-exposure/index.md
  • content/blog/rails-8-authentication-generator-complete-guide/index.md
  • content/blog/rails-8-authentication-generator-devise-migration/index.md
  • content/blog/rails-8-introducing-built-in-authentication-generator-ruby/index.md
  • content/blog/rails-argon2-has-secure-password-migration-guide/index.md
  • content/blog/rails-cve-2026-66066-active-storage-rce/index.md
  • content/blog/solid-queue-advanced-patterns-retries-concurrency/index.md
  • content/blog/vibe-coding-crisis-ai-code-debt/index.md
  • docs/projects/2510-seo-content-strategy/20-29-strategy/20.09-content-plan-revision-aug-2026.md
  • docs/projects/2607-vibe-code-rescue/backlog.md
  • docs/projects/2607-vibe-code-rescue/rescue-sprint/prospects/RUN.md
  • docs/projects/2607-vibe-code-rescue/rescue-sprint/prospects/p7-f5bot.md
  • docs/projects/2607-vibe-code-rescue/rescue-sprint/prospects/p7-search-sweep.md
💤 Files with no reviewable changes (3)
  • content/blog/rails-8-authentication-generator-complete-guide/index.md
  • content/blog/new-methods-that-help-implement-authentication-in-ruby-on-rails-71/index.md
  • content/blog/rails-8-introducing-built-in-authentication-generator-ruby/index.md

Comment thread content/blog/migrate-lovable-replit-app-to-rails/index.md Outdated
Comment thread content/blog/migrate-lovable-replit-app-to-rails/index.md Outdated
Comment thread content/blog/migrate-lovable-replit-app-to-rails/index.md Outdated
Comment thread content/blog/migrate-lovable-replit-app-to-rails/index.md Outdated
Comment thread content/blog/migrate-lovable-replit-app-to-rails/index.md Outdated
Comment thread content/blog/rails-cve-2026-66066-active-storage-rce/index.md Outdated
Comment thread docs/projects/2607-vibe-code-rescue/rescue-sprint/prospects/p7-search-sweep.md Outdated
Comment on lines +161 to +170
**Dedupe - thread URL is the join key** (same rule as P8):

1. Before logging any row, grep the merged list and every sibling file:
```bash
cd docs/projects/2607-vibe-code-rescue/rescue-sprint
rg -F "<candidate-url>" cold-prospect-list.md prospects/
```
2. A hit anywhere = skip the row. Do not re-log under a different handle.
3. Normalize first - strip `?utm_*`, trailing slashes, and `old.reddit.com` vs `www.reddit.com` before comparing.
4. Keep a `### Seen-and-skipped` list in this file with the reason (`already row 14` / `stale, VoC only` / `supplier`) so the next sweep does not re-adjudicate the same URL from scratch.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Normalize URLs before applying the deduplication key.

Step 1 searches the raw candidate URL, while Step 3 normalizes it
afterward. A ?utm_* suffix, trailing slash, or host variant can bypass
the first check and create a duplicate row. Normalize both candidate and
stored URLs before comparison, then record the normalized URL as the join
key.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@docs/projects/2607-vibe-code-rescue/rescue-sprint/prospects/p7-search-sweep.md`
around lines 161 - 170, Update the deduplication workflow in the “Dedupe -
thread URL is the join key” section so candidate URLs are normalized before
searching the merged list and sibling files. Normalize both candidate and stored
URLs by removing utm parameters, trailing slashes, and normalizing Reddit host
variants, then use and record the normalized URL as the join key.

Comment thread docs/projects/2607-vibe-code-rescue/rescue-sprint/prospects/RUN.md Outdated
claude added 7 commits August 8, 2026 06:56
Still draft: true. Checkpoint while the remaining gates run.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RHgyr6mEXghWSzipXnzQuY
Still draft: true. Gates in progress.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RHgyr6mEXghWSzipXnzQuY
Both still draft: true. Cover generation and the CVE exposure-criteria fix
are in flight.

EOL cold-eyes cleared all ten copy checks and caught that the .variant
detection command had survived in both posts - replaced with a pointer to the
CVE writeup's exposure checks, which is also the correct gate.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RHgyr6mEXghWSzipXnzQuY
Still draft: true. Covers not yet generated.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RHgyr6mEXghWSzipXnzQuY
The CVE post gated exposure on grepping for literal .variant/.representation
calls. The advisory says verbatim: "Generating variants is not a separate
requirement." A reader who grepped, found nothing and stopped would be exposed
while believing they were clear - on a post whose whole premise is that
patching alone is not enough.

Real criteria: Active Storage on libvips, untrusted image uploads, and libvips
below 8.13 (or above it without the block enabled).

Caught by CodeRabbit. Three specialist critics and a cold-eyes gate all read
that section and missed it - they verified the stated facts were true, but none
checked whether the post's decision procedure matched the advisory's.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RHgyr6mEXghWSzipXnzQuY
Both 2400x1260 to the 6-slot spec, viewed and verified before commit.

EOL uses the ruby severity treatment: NO PATCH ON 7.1 / CVE-2026-66066,
7.2 SUPPORT ENDS August 9 2026, EXITS Four ranked. Migration uses the standard
technical treatment - no alarm styling - carrying the decision the post is
actually about: what transfers vs what gets rebuilt.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RHgyr6mEXghWSzipXnzQuY
Both flipped to draft: false after the full gate chain - three critics,
cold-eyes, CodeRabbit's 14-comment review, covers, build and scroll gates.

Mobile scroll gate caught a real defect: the migration post's 3-column table
overflowed 390px viewports. The article container is 354px and the theme gives
tables no overflow-x wrapper, so minimum content width wins - 116+132+129 = 377.
Trimming cell text did not help (min-width comes from the longest token per
column, and the first trim made it 1px worse). Collapsed to 2 columns with the
verdict folded into the cell, matching the EOL post's table which lands at
exactly 354. Recorded in .okf/ as a content rule.

Also removed <!-- Reference cadence --> markers, which were shipping in
published HTML on five posts including three already live. Internal review
metadata belongs in the agent handback, not the file.

Gates: bin/hugo-build green (752 pages, 8/8 validators); scroll gate clean on
all three posts at 1280x800 and 390x844 - zero console errors, zero 4xx, no
horizontal overflow.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RHgyr6mEXghWSzipXnzQuY
@pftg pftg changed the title content: execute 20.09 priorities - funnel links, auth consolidation, CVE post, sourcing method content: 20.09 execution + two Rails posts (EOL, AI-builder migration) Aug 8, 2026
@pftg
pftg merged commit aa8a1b2 into master Aug 8, 2026
5 checks passed
@pftg
pftg deleted the claude/content-calendar-next-post-hztfag branch August 8, 2026 11:10
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants