Skip to content

Sprint C1 + C2.1 + C0.1: kill criterion, de-fabricated claims, idea-first drafts, blog exhibits - #477

Merged
pftg merged 14 commits into
masterfrom
sprint-c1-arrival-2026-08-20
Aug 20, 2026
Merged

pftg merged 14 commits into
masterfrom
sprint-c1-arrival-2026-08-20

Conversation

@pftg

@pftg pftg commented Aug 20, 2026

Copy link
Copy Markdown
Member

Sprint C1 from the groomed queue (50.03), plus the parallel-safe C0.1. Executed by four agents under WIP-disjoint file ownership, with independent review gates.

The headline finding

The LinkedIn campaign had no stop condition. metrics-ledger.md asserted "each lane's plan has a 2-week kill criterion" — neither plan had one, only steering Decision rules. The campaign could not fail, only continue. A 3-lens panel (growth / lean-validation / ICP) set the real one; reasoning and both split calls are in 50.04.

Unanimous: post-count units (a calendar window at 2-3 posts/wk measures Paul's availability, not the market), 3 icp_replies (anchored to the plan's existing 3-signal ICP-update bar), a reach guard, and a kill kills the channel, never the ICP.

My two calls where lenses split:

  • n=10, not 6 or 8. Lean showed the arithmetic — zero in 6 only excludes p>50%, which cannot retire a channel; 10 excludes p>26%. ICP's 6 becomes a mandatory no-kill review rather than being discarded.
  • Absolute, not comparative; override, not veto. I verified the ICP lens's evidence and corrected it (actual harvest: 14 IH / 13 Reddit / 3 LI / 1 X, not "27 with 2"). The proportion holds, but you cannot gate a decision on a comparator that has published zero posts — the comparison survives as the kill action. And an arrival veto firing on baseline profile traffic would make the campaign unkillable again, which is the bug being fixed.

Commits

C1.2 Four dangling-story claims de-fabricated. Three were owner-approved; a fourth (salvage-vs-rebuild) came from the cluster grep — it cited "the founder in the opening story" on a page with no opening story, plus an invented $7,500.
C1.3 Campaign-read scaffold + ledger rows for every scheduled/posted draft.
C1.1 Three course-lane drafts revised to idea-first, then fixed against two independent critics.
Ledger icp_replies made countable (SELF + ARTIFACT + NON-SUPPLIER); added dms / icp_profile_views / reply_protocol_run — the plan named DMs a primary metric and the ledger had nowhere to put them.
C0.1 Marketing ratchet now reads built HTML, catching the line-wrapped and partial-only defects source matching is blind to.

Why the cold-eyes gate paid for itself

The implementer's self-review passed all three drafts. An independent critic found the Monday post's attached image still rendering the banned lines its own notes claimed were removed — "A compliment isn't demand" (negative parallelism) and a definitional-cadence subtitle — plus Tuesday's payload, in 30px type above the fold where the body text isn't. The board serves a PNG, so fixing only the SVG would still have shipped it; both were regenerated and render-verified.

Also caught: "costs them nothing" had become a campaign catchphrase (4 instances, two on consecutive posting days, two inside artwork — now 1, where it's load-bearing), and the Friday post's "This week's posts all came from Module 1" was false by a month given the actual publish dates.

C0.1 findings (data, not fixed here)

40 pre-existing violations, baselined as a ratchet. 25 are one defect syndicated — a content/clients testimonial partial pulled onto all 13 /services/* pages that no source glob covers, exactly the class 20.10 predicted. Runtime 0.58s.

Test plan

  • bin/rake test:unit — 279 runs, 6128 assertions, 0 failures (includes the new ratchet)
  • bin/hugo-build green throughout
  • Ratchet proven by injection: a line-wrapped banned phrase fails the test, then reverts clean
  • Regenerated LinkedIn visual render-verified in browser at 1440px

Needs Paul

  1. Mark contact_cta_click a key event in GA4 (1 click).
  2. Paste the six numbers per post into the ledger — §1 of campaign-read-2026-08.md says where each lives.
  3. Calendar call: the Wednesday poll currently publishes after the Monday post that argues its answer.

🤖 Generated with Claude Code

pftg and others added 7 commits August 20, 2026 12:36
Panel/owner-approved resolutions for the three findings held from the
Aug-20 sweep, plus a fourth found by the cluster grep:

- five-tech-words: dropped 'we shipped for in Q2 2025' (unsourced JT
  client claim); comparison + numbers kept, composite disclaimer added
  to match the same page's L53 precedent.
- sow-reading-guide L138/L176: opener is a second-person hypothetical,
  but both back-refs cited 'the opening-story founder' as a real person.
  De-storied to 'in the scenario above'; $78K stays as the hypothetical
  it always was.
- paid-pilot free-vs-paid-pilot.svg: invented 12%/65% conversion rates
  removed from the ARTWORK (text ratchets can't see exhibits) - bars and
  argument unchanged, now 'most ghost' / 'most convert', basis line and
  alt text updated to say direction-not-rate.
- salvage-vs-rebuild (found by cluster sweep, same defect class): page
  has NO opening story at all, yet cited 'the founder in the opening
  story' + an invented $7,500/three-consultants/nine-weeks. De-storied.
- agency-ai-five-questions: referent EXISTS (illustrative scenario), so
  not a defect - wording aligned to 'the scenario above' for consistency.

Zero residuals: grep for 'opening story|opening-story|we shipped for'
across content/ returns 0. hugo-build green.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ost (C1.3)

The kill-criteria were untestable: the ledger carried one row with every
metric cell empty, 7+ days past its 48-72h logging window.

- metrics-ledger.md: rows for all 3 `scheduled`/`posted` drafts across both
  lanes (derived by grepping frontmatter, every slug verified against a real
  file). Metric cells stay empty - only Paul has LinkedIn access. Row 1's slug
  corrected to the real filename so all rows resolve; slug convention stated.
- campaign-read-2026-08.md (new, AWAITING DATA): the six numbers Paul must
  paste and where to find them, both lanes' decision rules quoted verbatim
  with citations, a blank verdict section with the icp_replies-not-impressions
  rule spelled out, and a "what to reuse" prompt for the next 2-3 drafts.

Neither lane plan uses the phrase "kill criteria" - what exists is each plan's
"Decision rules" list. Quoted as-is rather than invented.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Applies the 2026-08-13 doctrine correction (idea-first, deliver the point)
to the three remaining week1/week2 course-promo drafts, plus a cold-eyes
critic round (AI-feel detector + ICP reader) on the result.

week1-wed-first-move-poll
- Opener was a stacked-clause abstraction carrying two ideas; cut to one
  flat claim ("Your first move on a new idea sets what it costs you to be
  wrong"). ICP reader had to re-read the old line - on a phone that is a
  scroll.
- Dropped the "So:" beat-marker; added "Vote below" per the README poll
  structure; re-synced the cta: field to the new close.
- Para 2 kept verbatim: still no hint at which option is "right", per the
  2026-07-12 ICP-critic finding.

week1-fri-why-i-wrote-it
- Opener led with "Most founders" (zero-tolerance banned generalization)
  behind a 60-word stacked sentence. Replaced with a flat first-person
  history line.
- Cross-post: the opener restated the demand-before-build thesis that
  week1-thu-validate-before-build owns as its whole argument. Cut - this
  post's job is the give-away, not the thesis.
- Module list was four "the <noun>" stems in a 50-word sentence, all
  jargon to the ICP reader. Glossed by mechanic; pulled "you own from day
  one" into its own sentence (the ICP reader's single most relevant line).

week2-mon-friends-politely-lying
- Its tactic was week2-tue's entire payload delivered a day early. Re-angled
  onto its own pillar: WHO you ask, not WHAT you ask. Tuesday keeps the
  past-question script.
- Cut the mom/cooking simile - banned aphoristic-flourish closer, and it
  spent Tuesday's Mom Test reference early.
- "Find that subreddit or forum" was unexecutable for the ICP reader;
  replaced with the actual search move.

All three: revised: idea-first 2026-08-20 added, status: approved kept
(posting stays Paul-gated). Bodies grep clean against the banned list;
bin/hugo-build green (8/8 validators).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…lies countable

Two defects found while defining the missing kill criterion, both verified
against the repo rather than taken on assertion:

1. The validation plan names 'Qualified DMs 2+/week' and 'Profile views from
   ICP roles 20+/week' as PRIMARY metrics, but the ledger had nowhere to
   record either - only a raw 'profile views' column and no dms column at
   all. Added dms, icp_profile_views, and reply_protocol_run (a zero-reply
   window where the 2-hour clarifying reply never ran measures Paul's reply
   latency, not the audience).

2. icp_replies was defined as 'count the ones using ICP language' plus five
   examples - not reproducible. Two readers of the same six-comment thread
   could land anywhere from 0 to 5. Replaced with a three-clause test
   (SELF + ARTIFACT + NON-SUPPLIER), one human counted at most once, and an
   explicit rule for near-misses: ask the clarifying question, count the
   answer.

Thresholds deliberately NOT set here - the kill criterion itself is still
in panel and lands in the plan, not the ledger.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
`marketing_copy_test` globbed source only, so three defect classes were
structurally invisible to it - and all three shipped on 2026-08-14: a false
figure in a partial no glob covered, a banned phrase wrapped across two
template lines, and markup that exists only after compose.

Adds a second pass over the rendered site using the SAME `BANNED` hash - one
list, two inputs, no duplicated canon. It walks blog + course + services under
the suite's own Hugo build (`Hugo.instance`, so it works under rake, bin/test,
qtest and Docker alike rather than assuming someone ran bin/hugo-build first).

Scope decisions:

- dev.to imports excluded, DERIVED from `source: dev_to` frontmatter rather
  than hand-typed. Their stats belong to their original authors and have their
  own ICP gate. Not cosmetic: 94 of those built pages carry a banned word.
- Paginated views (`**/page/N/`) excluded. They only re-print excerpts already
  counted on the source post, and they made the baseline build-dependent - the
  same tree scored 48 under bin/hugo-build and 60 under the test build, which
  emits tag pagination. Without them it is 40 in both.
- Rendered HTML gets its own noise removal instead of source's `scrub`: slugs
  and asset names live in attributes that tag-stripping already removes, so
  dropping <script>/<style> then tags finds the identical 40 hits at 0.9s
  instead of 6.4s over 1,178 pages.

RATCHET, not a cleanup: baseline 40, fails only when the count rises. 25 of
those 40 are one defect syndicated - the deferred `content/clients` excerpts
("to the next level") plus a testimonial saying "seamlessly", pulled onto every
services page by a partial. Clearing them is a content task (20.10 §3b #2) and
is deliberately out of scope here.

Gates: bin/hugo-build green; rake test:unit 279 runs / 0 failures; new pass
0.58s on a warm build. Verified it bites by injecting a line-wrapped
"world-class"/"holistic" into a built services page - 42 > 40, red - then
reverting.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Two independent critics (AI-feel + ICP reader) reviewed what the
implementer shipped. The implementer's own self-review had passed all
three - which is exactly why the gate exists. Blocking findings fixed:

- **The attached VISUAL still shipped the banned lines** the post's own
  notes claimed were removed: 'A compliment isn't demand' (negative
  parallelism) and 'Demand is what they already did about the problem'
  (definitional cadence), plus week2-tue's cost-question payload. The
  image loads above the fold where the body text does not. Regenerated
  the SVG against the post's real payload (who you ask, not what you
  ask) and re-exported the PNG - the board serves the PNG, so an SVG-only
  fix would still have shipped the old text. Same trap logged this
  morning in .okf/log.md: text gates cannot see exhibits.
- 'costs them nothing' had become a campaign catchphrase (4 instances,
  two on consecutive posting days, two inside artwork). Down to 1, in
  week2-tue where the yes/no contrast makes it load-bearing.
- Monday still spent Tuesday's 'have they already paid' proof signal;
  re-ended on the vocabulary payoff instead.
- Friday: rule-of-three template list cut; the ownership line (the ICP
  reader's single most trust-earning sentence) promoted out of a
  prepositional tail into its own paragraph; 'That's the feedback I
  actually need' close crutch removed; unsourced 'last two months' and
  'a dozen calls' de-quantified - the course first landed 2026-07-09, so
  by its Oct 21 slot 'two months' would have been false.
- Friday's 'This week's posts all came from Module 1' DELETED: the
  calendar makes it false (week2 ships 09-17, week1 ships 09-23 and
  10-21) and it retroactively reframed the poll as funnel content.
- Wednesday: subject-less maxim opener replaced with people and
  countable spans; unattributed 'Not what a book says' negation named a
  real behavior instead of a strawman.

Left deliberately: week2-tue's instance (load-bearing), and the poll
publishing after the post that argues its answer - a calendar call for
Paul, flagged in notes.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…us call)

The campaign had no stop condition. metrics-ledger asserted 'each lane's
plan has a 2-week kill criterion'; neither plan had one - only steering
Decision rules. So it could not fail, only continue.

Panel: growth / lean-validation / ICP, briefed independently. Unanimous on
post-count units (a calendar window at 2-3 posts/wk measures Paul's
availability, not the market), on 3 icp_replies (anchored to the plan's
existing 3-signal ICP-update bar), on a reach guard, and that a kill kills
the CHANNEL not the ICP.

Two split calls, both recorded with reasoning in 50.04:
- n=10 not 6 or 8. Lean showed the arithmetic: zero in 6 only excludes
  p>50%, which cannot retire a channel; 10 excludes p>26%. ICP's 6 becomes
  a mandatory no-kill review instead of being discarded. Per lane, not
  campaign-level - the lanes address different people and pooling would let
  course replies mask rescue silence.
- Absolute criterion, not comparative. I verified the ICP lens's own
  evidence and corrected it (actual harvest is 14 IH / 13 Reddit / 3 LI /
  1 X, not the 27-with-2 reported) - the proportion holds, but growth is
  right that you cannot gate a decision on a comparator that has published
  zero posts, and that baking the historical rate in pre-decides H5. The
  comparison survives sequentially as the kill ACTION.
- Arrival veto -> tightened override (>=2 campaign-UTM sessions). A veto
  firing on baseline profile traffic would make the campaign unkillable
  again, which is the exact bug being fixed.

Also: the old Measurement targets are relabelled aspirations, not gates -
sized for 5 posts/wk, they fire 'fail' on post #2 forever. And a
non-execution trigger, the only clause that can fire today: 16 drafts, 3
out, 0 logged.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Aug 20, 2026 •

Copy link
Copy Markdown
Contributor

Important

  • 🔍 Trigger review

This repository does not receive automatic reviews because it has fewer than 10 stars.

⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 19f11358-95e7-4e93-8ad7-63fd65dfd0c0


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.

pftg and others added 7 commits August 20, 2026 13:00
Today's cold-eyes review caught banned constructions still rendering in a
LinkedIn post's artwork after the body was cleaned - three prior readers
missed it because they read markdown and never opened the asset. Worse,
the board and the shipped post serve a PNG export, so an SVG-only fix
renders correctly in review and still ships the old text.

Two binding rules added to house-visual-spec + a dated log entry: grep
artwork whenever a body phrase is banned or changed, and re-export the
PNG (rsvg-convert -w 1440) because the committed artifact, not the
source, is what the reader sees.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ide against real data

Paul: 'you have access to GA' - correct, and I had wrongly parked the
arrival half of the campaign read on him. GA gives the per-post UTM
breakdown directly; only LinkedIn-native counts (impressions, reactions,
comments, DMs) actually need him.

Filled §3b from property 328508492, 2026-08-01..08-19. The one published
campaign post produced 2 campaign-UTM sessions, both landing on the linked
course page via LinkedIn's first-comment link (trk=public_post_comment-text)
- so the click path is wired correctly - but 1 page/session, 0s duration,
1 of 2 engaged. Clicks, not reads. Baseline linkedin.com referral traffic
(5 sessions) correctly excluded by the campaign-UTM filter.

**This falsified the override I shipped hours earlier.** It required '>=2
campaign-UTM sessions'; one post had already hit exactly 2, so it would
have fired at threshold and made the campaign unkillable again - the exact
bug the criterion exists to fix. The panel estimated 3-6 clicks over 8
posts; observed is ~2/post, ~5x higher. Raised to >=3 sessions that are
engaged AND view more than one page, with the correction and its evidence
recorded in 50.04 rather than quietly patched.

Also logged: course funnel moved slightly since Aug-14 (start_course 1->3,
glossary 0->1, still near-floor), and contact_cta_click has no data yet -
it shipped after this window.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
C2.1 post 1 of 4. Hand-drawn SVG (house spec O1) placed right after the
intro, so the first informational visual in the reading order makes "SLA"
concrete before the five requirements start.

Exhibit: severity-reply-clock.svg (720x470, 3 stacked rows). Every number
is already sourced in the body (Atlassian severity scale, Requirement 1
reply windows) - nothing invented inside the artwork. Ruby marks Sev 1 as
the one actionable reading; amber Sev 2; grey Sev 3. Dashes are "-".

Visual gate, both viewports, img.complete awaited before judging:
- 1280x800: 684x447, body scrollWidth 1280 = innerWidth, no overflow
- 390x844 (device emulation): 354x231, scrollWidth 390 = innerWidth,
  basis rung renders 9.83px (>=9px floor), height 0.27x viewport
- console: zero errors/warnings

Scores: (1) great look YES (2) readable without zoom YES
(3) earns the next scroll YES - turns an abstract clause into a
copy-into-the-contract artifact at the earliest content slot
(4) helpful not decorative YES - stacks three deadlines the prose only
states sequentially, pages apart

Skipped the optional mid-body break: requirements 2-5 are each one idea
in two paragraphs, and a second exhibit would restate prose.

bin/hugo-build green (8/8 validators). Content-only class - no
template/CSS touched, so no qtest/dtest.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
C2.1 post 2 of 4. Hand-drawn SVG (house spec O1) in the first content
slot, right after the intro that states the thesis in prose.

Exhibit: assignment-vs-default.svg (720x470, two columns). Ruby column =
the default (anti-pattern per house semantics): invoice paid, no signed
assignment, the developer who typed it keeps the copyright. Purple column
= the alternate path: "hereby assigns" signed, copyright moves the moment
the code exists. Both readings come from the post body and its cited
sources (Circular 30, 17 USC 101, Clause 1); the basis line carries the
not-legal-advice scope. No invented numbers. Dashes are "-".

Visual gate, both viewports, img.complete awaited before judging:
- 1280x800: 684x447, body scrollWidth 1280 = innerWidth, no overflow
- 390x844 (device emulation): 354x231, scrollWidth 390 = innerWidth,
  basis rung 9.83px and step rung 10.32px (>=9px floor), 0.27x viewport
- console: zero errors/warnings

Scores: (1) great look YES (2) readable without zoom YES - two columns
still hold at phone width, no clipping (3) earns the next scroll YES -
the split ending is the whole reason to read five clauses (4) helpful not
decorative YES - the prose states the rule, the exhibit shows both
outcomes at once, which is what a reader checks their own MSA against

Re-render found the outcome pills crowding their right edge under the
cursive fallback; dropped 22px to 21px before wiring.

Skipped a second exhibit: clauses 2-5 are each a single ask, and a
five-row clause map would restate the H2 list.

bin/hugo-build green. Content-only class - no template/CSS touched.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
C2.1 post 3 of 4. Mermaid (pre-rendered via bin/render-mermaid,
mermaid-02a52382.svg committed) rather than hand SVG - the content is a
branch, and posts 1-2 of this wave both shipped card layouts.

Exhibit: flowchart TD, symmetric 2-column fork off one root. Ruby branch =
no senior reader, month four it breaks and you pay a second time. Purple
branch = a senior reads every pull request, the risky change is caught
before it ships. That is the pay-twice cost flow the sprint asked for,
kept QUALITATIVE on purpose: the post carries no sourced rescue-cost
figure, and inventing one inside artwork is exactly what the text gates
cannot see. accTitle/accDescr carry the full reading for screen readers
(mermaid fences take no markdown alt). Dashes are "-".

Visual gate, both viewports, document.fonts.ready + Caveat check awaited:
- 1280x800: 573x510, body scrollWidth 1280 = innerWidth, no overflow
- 390x844 (device emulation): 354x315, scrollWidth 390 = innerWidth,
  node text renders 12.36px (>=9px floor), 0.37x viewport
- data-prerendered confirmed on the host, so no mermaid.js on this page
- console: zero errors/warnings

Scores: (1) great look YES (2) readable without zoom YES
(3) earns the next scroll YES - the fork names the check the next
paragraph teaches (4) helpful not decorative YES - the post's title is a
conditional, and a fork is the only shape that shows both sides at once

First render failed my own gate on two counts and was redrawn before
wiring: labels longer than mermaid's ~200px wrap produced orphan lines
("features", "the", "code"), and a 3-deep left branch against a 2-deep
right one left a hollow bottom-right corner. Merged the two left-hand
consequence nodes into one; orphan SVG deleted, not left behind.

bin/hugo-build green. Content-only class - no template/CSS touched.
bun.lockb churn from bunx mermaid-cli reverted, not committed.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
C2.1 post 4 of 4. Hand-drawn SVG (house spec O1) placed immediately after
the opening scenario, so the hero is a picture of the thing the reader
just recognised in their own sent folder.

Exhibit: blanks-get-filled.svg (720x570). Annotated-artifact shape, not
another card pair: the sent message with its vague phrase highlighted in
amber and labelled "3 words, no moment, no finish line", a ruby arrow
through the mechanism, then the four features that came back. Every
string is the post's own opening paragraph plus the Monday-update line
from the job-story section. Nothing invented; dashes are "-".

Deliberately does NOT reproduce the user-story/job-story blockquote lower
in the post - a visual that duplicates adjacent prose is decorative by
definition, and this one shows the mechanism the prose only asserts.

Visual gate, both viewports, img.complete awaited before judging:
- 1280x800: 684x542, body scrollWidth 1280 = innerWidth, no overflow
- 390x844 (device emulation): 354x280, scrollWidth 390 = innerWidth,
  smallest rung renders 9.83px (>=9px floor), 0.33x viewport
- console: zero errors/warnings

Scores: (1) great look YES (2) readable without zoom YES
(3) earns the next scroll YES - it names the reader's own email and shows
where the money went before the explanation starts (4) helpful not
decorative YES - the highlight plus the mechanism pill are the argument,
and neither exists in the prose

First render left the bottom card's right half hollow against a filled
top card; added the sourced "none of it helps you send Monday's update"
annotation so both cards share one layout language.

bin/hugo-build green. Content-only class - no template/CSS touched.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The house spec requires ONE independent critic on a batch of renders
(per-exhibit self-checklists are author-blind). Dispatched one; it
returned 16 punch-list items. Triaged rather than executed literally -
what landed, and what did not.

APPLIED (correctness first):

1. assignment-vs-default.svg overstated copyright law. It read "the
   developer who typed it keeps the copyright", dropping the employee
   exception the post's own first sentence carries ("unless they are an
   employee of the agency or signed it away"). On a legal-topic post
   that is a wrong takeaway for a reader who trusts the picture over the
   paragraph. Now "whoever typed it may still hold the copyright".

2. blanks-get-filled.svg contradicted its host page in the same eye-line:
   the exhibit labelled "simple admin panel" as "3 words" while the
   paragraph directly below says "those four words" twice. Dropped the
   count from the artwork - the post's prose is out of scope for a
   visual pass, and the exhibit does not need the number.

3. severity-reply-clock.svg had its weight inverted: the Sev badges were
   the loudest marks (26px on filled rects) and the deadlines - the whole
   point - were secondary. Badges 26 to 22, deadlines 23 to 26, and the
   Sev 1 line parallelised to "reply in 2 business hours" so all three
   read as one series. Title moved to an imperative to match.

4. blanks-get-filled.svg alignment: the highlight pill hung 4 units left
   of the quote block it sits inside (x=52 against text at x=56), so the
   quote column jogged 56-62-56. Single left edge now.

5. blanks-get-filled.svg annotation was orphaned - no anchor, no arrow,
   floating beside bullets 2-3 while applying to all four. Anchored with
   an arrow per the retro-summary-annotated exemplar, recoloured amber to
   match its sibling annotation in the top card, and re-pointed at the
   founder's own request ("none of it shows you who signed up") instead
   of forward-referencing a Monday framing the post introduces 20
   paragraphs later.

6. assignment-vs-default.svg pill mismatch: one pill was a description in
   sentence case, its mirror an unmarked contract quote in lower case.
   Now "no signed assignment" against "hereby assigns", signed - one
   capitalisation rule, and the quote reads as a quote.

7. assignment-vs-default.svg hollow connector band: an 82-unit gap held
   open by a 34-unit squiggle that vanished at 390. Arrows lengthened.

8. Batch-level title cadence - the strongest finding. Three of four
   titles were the same machine (definite-article subject + present-tense
   verb + object). Two rewritten to different shapes: an imperative
   ("Put three numbers in the contract") and a negation ("Nobody filled
   your blanks on purpose"). Alt text updated to match on both.

REJECTED, with reasons:

- Add "Basis:" lines to the qualitative exhibits (4 items). Both shipped
  master exemplars - retro-summary-annotated and retro-plus-demo - carry
  no basis line; the v3 grammar's basis rule is for DATA exhibits. Would
  have been bureaucracy on scenario cards.
- Kill the all-caps "YOUR" in the SLA footer. The retro exemplar uses
  exactly this device ("a task on YOUR side"); it is house style.
- De-ruby the spaceship annotation to amber on ruby-for-signal grounds.
  That convention is scoped to the data-viz section; for diagrams the
  rule is red = anti-pattern, and card B IS the anti-pattern outcome.
  (It ended up amber anyway, via class specificity, which is a better
  result for a different reason - it now pairs with the top card's note.)
- Change the mermaid's purple from #f5e9ff to the paper-tone #fbe9ff.
  Every other mermaid on the site uses #f5e9ff; matching the corpus beats
  matching the spec's SVG palette here.
- Give the mermaid a visible in-diagram title, or redraw it as hand SVG.
  No mermaid post in this repo does the former; the latter is a redraw.
  The lead-in sentence carries the takeaway, as on every sibling.
- Redraw assignment-vs-default so it stops rhyming with the mermaid fork.
  Both are red-anti-pattern / purple-alternate because that IS the house
  semantic. Following the grammar consistently is the brand, not a tell.
- Trim the spaceship's bottom card by 22 units for a "dead floor". The
  critic measured to the last BASELINE; measured to the descender the
  padding is 32 top and 32 bottom, already symmetric.

ALSO TRIED AND REVERTED: shortening the mermaid labels to even out node
heights (148/88/88/148/148). It made them LESS uniform - "The risky
change is caught before it ships" dropped to 118, adding a third height -
and degraded the copy. Kept the original labels and the original render;
mermaid-02a52382.svg is byte-identical to the committed one. A metric
gate is not a licence to make the writing worse.

Re-gated all three changed exhibits, both viewports, img.complete awaited:
- 1280x800: all 684 wide, scrollWidth 1280 = innerWidth, no overflow
- 390x844 (device emulation): all 354 wide, scrollWidth 390 = innerWidth,
  smallest rung 9.83px (>=9px floor)
- console: zero errors/warnings across all three pages

bin/hugo-build green. Content-only class - no template/CSS touched.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@pftg pftg changed the title Sprint C1 (arrival) + C0.1 ratchet: kill criterion, de-fabricated claims, idea-first drafts Sprint C1 + C2.1 + C0.1: kill criterion, de-fabricated claims, idea-first drafts, blog exhibits Aug 20, 2026
@pftg
pftg merged commit 464f2f5 into master Aug 20, 2026
5 checks passed
@pftg
pftg deleted the sprint-c1-arrival-2026-08-20 branch August 20, 2026 11:36
pftg added a commit that referenced this pull request Aug 20, 2026
… x Rails cluster (R1, R4, R5) (#488)

* test: catch up stale macos baselines after master copy purges

careers/_overview, nav/use_cases, and mobile/about_us baselines still
showed pre-purge copy (World-Class Training, the 32-clients ratings
line, old mission text) from before the de-cliche/testimonial PRs
(#477/#479/#481). Current renders match master's intentional content;
diffs inspected image-by-image before accepting. Linux legs were
updated by those PRs' CI runs - only the host-only macos set was stale.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* content(refresh): YJIT guide rewritten as Ruby 4.0 YJIT vs ZJIT, fabrications purged

August refresh slot (20.09 §5). Premise audit redirected the slot: the
plan's named candidate (Kamal/Traefik SSL post) had decayed to 4
impressions/pos 20, while ruby-3-4-yjit-performance-guide holds 6,310
impressions at pos 9.5 AND carried fabricated claims - invented Shopify
internal metrics ($2.4M savings), fabricated GitHub results, two fake
JetThoughts client case studies, and a fictional Ruby 3.5/3.6/4.0
roadmap. Full in-place rewrite: every claim now cites a primary source
(ruby-lang 4.0 notes, railsatscale ZJIT launch, speed.ruby-lang.org,
Rails 7.2 announcement, official YJIT docs).

Review loop: 3-critic panel + cold-eyes gate. critic-tech verdict
NEEDS-FIXES -> fixed: the initializer claim was mechanically false
(initializers run for rake tasks too - rewritten as the explicit trap),
ISEQs not methods, 4.1 goal is surpass-not-parity, hedged the prebuilt-
binary claim. critic-slop: PASS 8/10, SEO clean (title 40, desc 152,
5 internal links verified, 6 citations). critic-editor: minor edits,
all applied; diagram redrawn around the CPU-vs-I/O decision. cold-eyes:
PUBLISH-READY after fixing desc flag-count and a fabricated reader
quote. Moved flat file content/blog/2025/*.md into a page bundle (slug
unchanged, URL stable) for local cover + pre-rendered mermaid (18px
labels = 12.7px at 390w, clears the 9px floor). New stitch cover.
check-post-visuals FLOOR ratcheted 78->72 per the script's own report.
Gates: hugo-build green, qtest green, zero console errors/404s.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* content(ai-rails): RubyLLM getting-started + fibers-for-LLM-streaming posts (20.09 §12 R1, R4)

Two new Rails-technical posts from the RubyLLM x Rails queue Paul
directed today. R1 owns 'rubyllm rails' (chat/persistence/tools/
streaming with the real 1.16.0 API, every claim verified against
rubyllm.com + gem source). R4 owns the fibers-vs-threads arithmetic for
LLM streaming (Puma 3-thread default vs 30-60s SSE streams, Falcon/
async, semaphore rate limiting, honest ActionController::Live thread
caveat) and bridges the falcon cluster.

Review loop per post: 3-critic panel + cold-eyes. critic-tech caught 2
majors, both fixed: an unsourced author-stance attribution in R1
(contradicted by the project's own README tagline) and R4's overreach
that Live streams cost only a fiber under Falcon (Live spawns its pool
thread unconditionally - now stated honestly). critic-slop: PASS 8/10
both; cross-post exhibit dedup applied (job snippet lives in R1, R4
links it). critic-editor: minor edits, applied. cold-eyes: PUBLISH-
READY both (one universal-claim fix in R1). Covers from the 6-slot
template; mermaid pre-rendered (R1 272px, R4 675px wide - labels clear
the 9px mobile floor); scroll gate walked desktop+mobile; hugo-build
green; check-post-visuals at floor.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* content(ai-rails): multi-agent RubyLLM pipeline post (20.09 §12 R5) + cluster polish

R5 is the practitioner centerpiece of today's cluster: our production
talent-matching pipeline - eight agents on a 21-line RubyLLM::Agent
base class, a 16-line reduce Workflow, reflector-driven stop loop,
bounded-integer scoring summed in Ruby, and the commit-documented
Aug 16 outage (with_connection held across multi-second LLM calls under
fiber fan-out starved a pool of 10 against 15 fibers). All architecture
facts sourced from the real codebase; gem API cross-checked against
ruby_llm 1.16.

Review loop: critic-tech caught a real BLOCKER - temperature {} blocks
are a silent no-op in ruby_llm 1.16 (only model accepts a block); the
published sketch now declares temperature statically. (Side finding:
the production app's own temperature block is likely a no-op too -
flagged to Paul.) Also fixed: the 'gem rejects out-of-range integers'
claim (no client-side validation exists; the fetch/clamp is the real
enforcement). critic-slop: PASS 8.5/10, the strongest of the four.
critic-editor: minor edits, applied. cold-eyes: PUBLISH-READY after one
universal-claim trim. Cluster-wide polish across all four of today's
posts: 'genuinely' intensifier sweep, 'earns' metaphor thinned,
verbatim phrase dedup, cover alt fixed to describe the actual cover.
Gates: hugo-build green, visuals ratchet at floor, scroll gate walked.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* okf(content): same-day-cluster voice tells + ruby_llm temperature-block gotcha

Four posts in one batch exposed cluster-level fingerprints per-post
review can't see (shared intensifier, shared metaphor family, verbatim
phrase reuse, meta-narration templates, cloned CTA tails) - added the
cross-batch sweep to voice-rules. Logged the ruby_llm 1.16 finding that
only model accepts a block (temperature {} is a silent no-op).
Validated: okf:validate --strict conformant.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* docs(plan): 20.09 §12 execution status - R1/R4/R5 shipped, R3 rescope verdict, R2 caution

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* docs(plan): 20.09 §12 - add R7 (agent evals) and R8 (agent debugging) from Paul's directive

Both grounded in first-hand production material surfaced today
(agent_logs audit trail, VCR matching trap, invariant-test pattern).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* docs(plan): groomed note - Ollama import needs a light banned-phrase refresh

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* content: re-anchor version framing to Rails 8 (Paul: don't lead with Rails 7)

YJIT post now opens its default-check section with 'Every Rails 8 app
has YJIT on out of the box' (7.2 kept only as the cited change-point);
fibers post opens the thread arithmetic with the Rails 8.1 default
('3 threads per worker'), verified against the current rails/rails puma
template (threads ENV.fetch RAILS_MAX_THREADS, 3). R1/R5 were already
version-neutral.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* docs(pipeline): add batch-mode prompt for N-post sprints

Encodes the three practices the 2026-08-20 4-post batch validated on top
of the per-post pipeline: live-GSC premise audit before topic pick,
real-code mining for first-hand material (with sanitization rule),
and the same-day-cluster sweep after the last post. Paste-ready prompt
so future sprints don't reconstruct the orchestration from memory.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* agents: blog-batch-orchestrator + blog-post-coordinator for N-post loops

Outer loop (orchestrator): groomed-queue picks with live-GSC premise
audit, WIP=1 dispatch of one coordinator per post, cluster sweep with
its own 4-eyes pass, plan/OKF sync, one PR, CI watch with flake-rerun.
Inner loop (coordinator): writer packet -> resumable 3-critic panel ->
cold-eyes 9-check gate -> ship gates -> commit, bounded at 2 fix rounds
per gate with SHIPPED/RESCOPE/BLOCKED reporting. blog-pipeline.md batch
section now names the agent form ('Spawn blog-batch-orchestrator, N=4')
with the paste prompt as the registry-free fallback.

4-eyes: agent-def reviewer verdict FIX-FIRST -> all 5 findings applied
(worktree-or-nothing for any second committing coordinator, critic pass
on the sweep diff before the polish commit, dev-server port added to
the dispatch contract, founder-persona note, bounded-iteration cap).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
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.

1 participant