Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
68 changes: 68 additions & 0 deletions bin/check-course-paths
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
#!/usr/bin/env ruby
# frozen_string_literal: true
#
# devx O7c: catch course path drift at build time. Two checks per lesson under
# content/course/tech-for-non-technical-founders-2026/:
# 1. every in-body `Next:` link resolves to a real lesson page (no dead slug)
# 2. for a lesson whose data/course_sequence.yaml branch marks a "Core path →"
# target, the in-body Next's core route (its FIRST link) names that same
# slug - the exact 2.1 drift where the prose Next funneled through the
# optional 2.2 while yaml routed the core path to 2.3.
#
# Report-only by default (exit 0 + list). COURSE_PATH_BLOCK=1 makes it exit 1.
# Usage: bin/check-course-paths [--self-test]

require "yaml"

COURSE = "content/course/tech-for-non-technical-founders-2026"
SEQ = "data/course_sequence.yaml"
REPORT_ONLY = ENV.fetch("COURSE_PATH_BLOCK", "") != "1"

# lesson slugs (first-link order) named on a page's `Next:` line
def next_links(path)
line = File.readlines(path).find { |l| l.include?("**Next:**") }
line ? line.scan(%r{/course/[^/]+/([^/)]+)/?\)}).flatten : []
end

# slug => yaml "Core path" target slug, for lessons that declare one
def core_targets(seq_file = SEQ)
YAML.load_file(seq_file)["sequence"].each_with_object({}) do |e, h|
b = (e["branches"] || []).find { |x| x["direction"].to_s.start_with?("Core path") }
h[e["slug"]] = b["slug"] if b
end
end

def check(course = COURSE, seq_file = SEQ)
core = core_targets(seq_file)
fails = []
Dir.glob(File.join(course, "*", "index.md")).sort.each do |path|
slug = File.basename(File.dirname(path))
links = next_links(path)
links.each { |s| fails << [slug, "dead Next link -> #{s}"] unless Dir.exist?(File.join(course, s)) }
if core[slug] && links.first != core[slug]
fails << [slug, "core route #{links.first.inspect} != yaml Core path #{core[slug].inspect}"]
end
end
fails
end

if ARGV.include?("--self-test")
line = "> **Next:** core continues at [2.3](/course/x/real-core/) - or optional [2.2](/course/x/optional/)."
links = line.scan(%r{/course/[^/]+/([^/)]+)/?\)}).flatten
raise "extract" unless links == %w[real-core optional]
raise "drift predicate" unless links.first != "optional" # yaml core=optional => flagged
raise "clean predicate" if links.first != "real-core" # yaml core=real-core => clean
live = check
raise "live tree drifted: #{live.inspect}" unless live.empty?
puts "self-test: ok (live tree clean)"
exit 0
end

fails = check
if fails.empty?
puts "course-paths: all lessons resolve and match their yaml Core path"
exit 0
end
puts "course-paths: #{fails.size} drift(s):"
fails.each { |slug, msg| puts " #{slug}: #{msg}" }
exit(REPORT_ONLY ? 0 : 1)
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ The fix was not a better Meta Ads brief. The fix was to stop the ads, run a 90-m

Bucket holds **32 paying users at $29 / month**. Stop the ads. Run the 90-minute cohort triage. Decide: fix the product, change the segment, or kill the SKU.

Module 5 (Lessons 5.1-5.7) teaches you how to land your first paying customers. This chapter covers what Module 5 does not - what to do when the customers you already have are leaving faster than the funnel can replace them. It is the chapter for the messy middle - the founder who hit Module 5 once, got customers, and watched them slip away faster than the spreadsheet predicted.
Module 5 (Lessons 5.1-5.7) teaches you how to land your first paying customers. This chapter covers what Module 5 does not - what to do when the customers you already have are leaving faster than the funnel can replace them. It is the chapter for the messy middle: you hit Module 5, got customers, and watched them slip away faster than the spreadsheet predicted.

The KISS rule for this chapter: if your churn is above 30% in a 30-day window, every dollar you spend on acquisition is wasted until you triage. Read on.

Expand Down Expand Up @@ -156,7 +156,7 @@ The most common founder failure mode at this triage step is to refuse to pick. T

## The Refund-the-Wrong-Segment Script

Decision 2 is the hardest to execute because it requires telling 18 of your 30 paying customers, in writing, that you built the wrong product for their situation. The default response is to flinch at this step. They run an "improvement campaign" instead, hoping the wrong segment will start retaining if the product gets a few more features. It will not. The wrong segment never converts to the right segment.
Decision 2 is the hardest to execute because it requires telling 18 of your 30 paying customers, in writing, that you built the wrong product for their situation. The default response is to flinch and run an "improvement campaign" instead, hoping the wrong segment starts retaining with a few more features. It will not - the wrong segment never converts to the right one.

Refunds are cheaper than churn. If a wrong-segment user churns at month 2, you have collected $58 and lost $200 in CAC and ~$25 in support time - net negative. If you proactively refund their last 30 days at month 2, you have lost $58 plus the same $200 CAC, but you have gained a goodwill quote, a clean Stripe ledger, and 20 minutes of support time you would otherwise spend explaining why the product feels off. The math on a wrong-segment refund campaign is positive against the alternative of waiting for churn.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ One time-box: if you catch yourself on day three still polishing the list instea

## Before you start: write three sentences

These are not new homework - they are your 1.1 Founding Hypothesis blanks, unpacked for people-hunting. Open your `Founding Hypothesis` doc, copy the sentence in, and expand two of its blanks into full sentences (the third - Business - is the one genuinely new line). Without them, every interview answer sounds encouraging and you can't tell confirm from kill:
Started a few rows during the Lesson 1.4 wait? Pick up from those. These are not new homework - they are your 1.1 Founding Hypothesis blanks, unpacked for people-hunting. Open your `Founding Hypothesis` doc, copy the sentence in, and expand two of its blanks into full sentences (the third - Business - is the one genuinely new line). Without them, every interview answer sounds encouraging and you can't tell confirm from kill:

| Profile | What to write | Bad vs Good |
|---------|---------------|------------|
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,14 @@ Cold outreach is the main track. Two others run alongside it when they fit:

Both tracks, the parallel-run logic, and the part-time founder's batch-send variant are in the [full reference](/course/tech-for-non-technical-founders-2026/reference/find-10-people-full/).

## While the replies trickle in

Booking 10 calls takes 2-4 weeks - messages go out, a few replies land, and you send the next batch. The calendar sits half-full for days at a stretch, and it's easy to stop pushing new messages out.

Don't wait for all 10 before you start. The day a third call is booked, start running interviews with the [Lesson 2.1 script](/course/tech-for-non-technical-founders-2026/mom-test-ask-about-past-not-future/) - early calls tell you fast whether your questions are landing, and you can fix them before the later ones. While the replies come in, set up the kit in one sitting: open the 2.1 five-question script, make a blank one-page notes doc you'll copy for each person, and put your 20-minute slots into your [NeetoCal](https://www.neeto.com/neetocal) link so booking is one click for them.

**Come back when 3 calls are booked - and run them, don't hold for 10.** Keep the outreach batches going in the background until the calendar hits 10. Evening-only, with a couple of hours a week? Run the calls first and resume outreach the week after.

> **Done:** 10 interview calls are booked on your calendar and you have sent the first batch of outreach messages.
>
> **You have now:** question list (2.1-2.2) + 30-name list (2.3) + 10 booked interviews (2.4). The problem itself is still unvalidated - the interviews you run next test it.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,6 @@ related_posts: false

One word can hide a year in which nothing shipped. "Refactoring" means changing the structure of code without changing what the user sees, so when an agency uses it to narrate week after week, there is nothing user-visible to check it against, and "we're refactoring the order flow" can cover a stretch where production never moved. That is how the word runs up a bill: **$51K and a year of runway** can pass before a new fractional CTO reads the repo and finds nothing new since month three. The glossary below hands you, for each word, the one question the padded version cannot answer.

Non-technical founders often learn engineering vocabulary under pressure, mid-meeting, with a bill on the table. The agency throws a word, the founder nods, the meeting moves on. By the time the founder figures out what the word actually meant, the next sprint is already approved.

Below is the cheat sheet for the five words that hide the most invoices: refactoring, Docker, tech debt, MVP, architecture. For each you get a plain-English definition, the dishonest version your dev shop probably means when they say it, and one question you can ask in your next standup that the BS-version cannot answer.

![Jargon translator: what your dev shop says vs what it usually means, for refactoring, Docker, tech debt, MVP, and architecture](jargon-translator.svg)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ Read your draft list aloud. Which question would let a polite stranger agree wit
>
> **You have now:** all Module 1 artifacts + a draft Mom Test question list (2.1). Sharpening and recruiting come next - the problem itself isn't validated until you run the 10 real interviews.
>
> **Next:** [2.2 · Sharpen Your Question List with AI Personas](/course/tech-for-non-technical-founders-2026/ai-persona-pre-validation-mom-test-prep/) - takes the draft list you just wrote and stress-tests each question against a simulated ICP before you spend a real interview slot on it.
> **Next:** the core path continues at [2.3 · Find 10 People: Where to Look](/course/tech-for-non-technical-founders-2026/find-10-people-where-to-look/) - it turns your draft question list into a 30-name list of real people to interview. If your list still reads hypothetical or generic, run the optional [2.2 · Sharpen Your Question List with AI Personas](/course/tech-for-non-technical-founders-2026/ai-persona-pre-validation-mom-test-prep/) first - it stress-tests each question against a simulated ICP before you spend a real interview slot.
>
> **If blocked:** open the [Mom Test Interview Script](/course/tech-for-non-technical-founders-2026/mom-test-interview-script/) - it has the 5 questions verbatim with follow-ups.
>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,7 @@ Send the DPA to your warmest lead first. Asking someone you know for a deposit i
>
> **You have now:** a signed Design Partner Agreement + a cleared deposit (5.6), sitting alongside your validated problem statement, Product Brief, and live MVP in the `Founder OS` folder. That completes the folder - the artifact investors fund. Converting this pilot into a year-one contract is the next test, 6-8 weeks out.
>
> **Next:** that is the core course complete - from a one-sentence hypothesis to a stranger's money in your account. Keep going with the optional [5.7 · Going Outbound Without a Sales Team](/course/tech-for-non-technical-founders-2026/outbound-without-sales-team/) when your warm list runs dry, or the [Going further chapters](/course/tech-for-non-technical-founders-2026/first-paying-customer-operating-kit/#going-further-triggers) once your pilot converts. The [First-Paying-Customer Operating Kit](/course/tech-for-non-technical-founders-2026/first-paying-customer-operating-kit/) keeps the build honest through the pilot.
> **Next:** the fork here is persevere or pivot. If a **deposit cleared**, that is the core course complete - from a one-sentence hypothesis to a stranger's money in your account. Keep selling: [5.7 · Going Outbound Without a Sales Team](/course/tech-for-non-technical-founders-2026/outbound-without-sales-team/) when your warm list runs dry, or the [Going further chapters](/course/tech-for-non-technical-founders-2026/first-paying-customer-operating-kit/#going-further-triggers) once your pilot converts. The [First-Paying-Customer Operating Kit](/course/tech-for-non-technical-founders-2026/first-paying-customer-operating-kit/) keeps the build honest through the pilot. If **no one will put money down** after the warm list and the 5.7 outbound pass, the signal is the segment, not the pitch - work [Pivot or Persevere: The Decision Framework](/course/tech-for-non-technical-founders-2026/pivot-or-persevere-decision-framework/) before you build more.
>
> **If blocked:** see "If this fails" above. If you do not have warm demos yet, your work is still in [Lesson 5.3](/course/tech-for-non-technical-founders-2026/first-ten-customers-network-list/) - the DPA is the wrong sprint for an empty pipeline.
>
Expand Down
Loading
Loading