Compare commits

...
Author SHA1 Message Date
time 268b0ee626 card #160: kept .github/time/test_time.py (generated)
heartbeat / tick (pull_request_review) Canceled after 0s
ci / test (pull_request) Successful in 36s
2026-10-19 15:10:47 +00:00
time 16d7a8993c card #160: kept .github/time/test_time.py (generated)
time/worker-run cd .github/time; python3 - <<'EOF' s = open("test_time.py").read() a='''for w_, home_ in ((wh79, "ca
2026-10-19 15:10:39 +00:00
time f78613c5c7 card #160: kept .github/time/test_time.py (generated)
time/worker-run cd .github/time; python3 - <<'EOF' s = open("test_time.py").read() a='''"plan": {"pricing": []}}], T
2026-10-19 15:10:32 +00:00
time 7c2a2aa45f card #160: kept .github/time/test_time.py (generated)
time/worker-run cd .github/time; python3 - <<'EOF' s = open("test_time.py").read() a = s.index("# a renamed venture
2026-10-19 15:09:58 +00:00
time c466dfbb28 card #160: kept .github/time/venture.py (generated)
time/worker-run cd .github/time; python3 - <<'EOF' s = open("test_time.py").read() def sub(a, b): global s a
2026-10-19 15:09:13 +00:00
2 changed files with 70 additions and 28 deletions

No files matched your search

+32
View File
@@ -964,11 +964,43 @@ assert rec79[-1]["shot"] == rec79[-1]["sheet"] == "star-checker/shots/sheet.png"
gv.launch(3, {"slug": "star-checker", "name": "Star checker"}, {}, {}, None, "", lambda *a: None)
assert "shot" not in rec79[-1], "no sheet, no picture"
gv.record, gv.count_signups, gv.launch_post, gv.pages_file, gv.put_pages = real_rec79, real_cs79, real_lp79, real_pf79, real_pp79
real_reg79 = gv.registry
gv.registry = lambda: {"ventures": [{"slug": "box-art-night", "home": "cartridge"}]}
w79 = {"slug": "star-checker", "name": "Star checker", "signal": 7, "card": 3}
assert gv.join_url(w79, "Free").startswith("https://forge.test/o/r/issues/new?") and gv.signal_url(w79) == "https://forge.test/o/r/issues/7"
assert gv.blob_url(w79, "LAUNCH.md") == "https://forge.test/o/r/src/branch/gh-pages/ventures/star-checker/LAUNCH.md"
html79 = gv.index_html({"ventures": [{**w79, "url": gv.site_of("star-checker"), "join": "j", "launched": "2026-10-18", "one_liner": "o"}]})
assert "github.com" not in html79 and 'href="https://star-checker.yolopreneur.lol/"' in html79 and "https://forge.test/o/r/issues/7" in html79
# a renamed venture (its registry entry has `home`) lives in its home folder: links, checks and the portfolio follow it;
# its slug stays the key. One without a home is unchanged (above)
wh79 = {"slug": "box-art-night", "name": "Cartridge", "signal": 7, "url": "u", "join": "j"}
assert gv.home_of(wh79) == "cartridge" and gv.home_of({**wh79, "home": "x"}) == "x" and gv.home_of(w79) == "star-checker"
assert gv.blob_url(wh79, "LAUNCH.md").endswith("/ventures/cartridge/LAUNCH.md")
assert "ventures/cartridge/" in gv.build_body({**wh79, "url": "u", "join": "j"}, {"pricing": [{"tier": "Free", "price": "0", "for": "f", "includes": "i"}],
"positioning": "p", "primary_cta": "c"}) and "box-art-night/" not in gv.build_body(
{**wh79, "url": "u", "join": "j"}, {"pricing": [{"tier": "Free", "price": "0", "for": "f", "includes": "i"}], "positioning": "p", "primary_cta": "c"})
read79 = []
gv.pages_file = lambda path: read79.append(path)
assert gv.check_page(wh79, {}) == ["ventures/cartridge/index.html is missing"] and gv.check_page(w79, {}) == ["ventures/star-checker/index.html is missing"]
gv.judge(wh79); assert read79[-2:] == ["ventures/cartridge/index.html", "ventures/cartridge/README.md"], read79
# the next version carries the home and reads the home's page as its prior; the build worker writes only inside the home
cards79, rb79 = [], []
real_nc79, real_cm79, real_bp79 = gv.new_card, gv.tm.comment, gv._build_on_pages
gv.new_card = lambda title: {"number": 9}
gv.tm.comment = lambda n, text, meta=None: cards79.append(meta)
gv.next_version(wh79, ["a"], 3); gv.next_version(w79, ["a"], 3)
assert cards79[0]["winner"]["home"] == "cartridge" and cards79[0]["winner"]["prior"] == "ventures/cartridge/index.html", cards79[0]
assert "home" not in cards79[1]["winner"] and cards79[1]["winner"]["prior"] == "ventures/star-checker/index.html", cards79[1]
gv._build_on_pages = lambda card, done, spec, root="": rb79.append((done, root)) or {"seat": "s", "steps": 1, "model": "m"}
plan79 = {"pricing": [{"tier": "Free", "price": "0", "for": "f", "includes": "i"}], "positioning": "p", "primary_cta": "c"}
for w_, home_ in ((wh79, "cartridge"), ({**w79, "name": "S", "url": "u", "join": "j"}, "star-checker")):
gv.advance({"number": 9}, [], [{"beat": "planned", "winner": w_, "plan": plan79}], True)
assert rb79[-1][1] == f"ventures/{home_}/" and rb79[-1][0].startswith(f"ventures/{home_}/index.html"), rb79
gv.new_card, gv.tm.comment, gv._build_on_pages = real_nc79, real_cm79, real_bp79
gv.pages_file = real_pf79
hh79 = gv.index_html({"ventures": [{**wh79, "home": "cartridge", "launched": "2026-10-18", "join": "j"}]})
assert "https://cartridge.yolopreneur.lol/shots/sheet.png" in hh79 and "ventures/cartridge/LAUNCH.md" in hh79 and "box-art-night.yolo" not in hh79
gv.registry = real_reg79
# the scout asks GitHub's public search with no token of ours; the forge's API is never asked for /search
seen79 = []
gv.github_search = lambda q, n: (seen79.append(q), {"items": [{"full_name": "a/b", "stargazers_count": 900, "description": "d",
+38 -28
View File
@@ -99,6 +99,14 @@ def site_of(slug: str) -> str:
return f"https://{slug}.{env('TIME_VENTURE_PAGES_DOMAIN', 'yolopreneur.lol')}/"
def home_of(w: dict, reg: dict | None = None) -> str:
"""The folder a venture lives in under ventures/ (and the subdomain it is served at): its own `home` or its registry
entry's (the owner renamed it), else its slug. The slug stays the key in beats, the registry and the signup form."""
if w.get("home"):
return w["home"]
return next((v["home"] for v in (reg or registry())["ventures"] if v.get("slug") == w["slug"] and v.get("home")), w["slug"])
def studio_url() -> str:
"""The studio's list of ventures. Teahub serves the Pages branch's ventures/ folder at the Pages domain's root, so
https://yolopreneur.lol/ is ventures/index.html (and yolopreneur.lol/backlog.json is ventures/backlog.json)."""
@@ -562,7 +570,7 @@ def signal_url(w: dict) -> str:
def blob_url(w: dict, name: str) -> str:
return f"{tm.SERVER}/{REPO}/src/branch/{PAGES_BRANCH}/ventures/{w['slug']}/{name}"
return f"{tm.SERVER}/{REPO}/src/branch/{PAGES_BRANCH}/ventures/{home_of(w)}/{name}"
BUILD_BODY = """Build and launch **{name}**: {one_liner}
@@ -675,7 +683,7 @@ preloaded sample never depends on them, and nobody has to sign in to use the fre
def backend_brief(w: dict) -> str:
return BACKEND.format(url=w["url"], slug=w["slug"]) if w.get("backend") else ""
return BACKEND.format(url=w["url"], slug=home_of(w)) if w.get("backend") else ""
def build_body(w: dict, plan: dict) -> str:
@@ -688,7 +696,7 @@ def build_body(w: dict, plan: dict) -> str:
f"of the product that work." + (f" {w['prior_note']}" if w.get("prior_note") else "") + "\n") if w.get("prior") else ""
return BUILD_BODY.format(name=w["name"], one_liner=w.get("one_liner", ""), for_whom=w.get("for_whom", ""),
page=w.get("page", ""), next=w.get("next", ""), positioning=plan["positioning"], prior=prior,
slug=w["slug"], url=w["url"], cta=plan["primary_cta"], join=w["join"], rides=rides_txt or " (none)",
slug=home_of(w), url=w["url"], cta=plan["primary_cta"], join=w["join"], rides=rides_txt or " (none)",
tiers="\n".join(tiers), repo=REPO, forge=tm.SERVER, signal=signal_url(w), backend=backend_brief(w))
@@ -887,15 +895,16 @@ def index_html(reg: dict) -> str:
rows = []
vs = sorted(reg["ventures"], key=lambda v: (v.get("planned", ""), v.get("card", 0)), reverse=True)
for k, v in enumerate(vs):
home = v["url"] if v.get("backend") else site_of(v["slug"]) # its own subdomain; its own domain once it has a backend
h = home_of(v, reg)
home = v["url"] if v.get("backend") else site_of(h) # its own subdomain; its own domain once it has a backend
links = [f'<a href="{e(home)}">{e(urllib.parse.urlsplit(home).netloc)}</a>' if v.get("backend") else "",
f'<a href="{e(v["join"])}">Join early access</a>' if v.get("join") else "",
f'<a href="{tm.SERVER}/{REPO}/issues/{v["signal"]}">Signal #{v["signal"]}</a>' if v.get("signal") else "",
f'<a href="{tm.SERVER}/{REPO}/src/branch/{PAGES_BRANCH}/ventures/{e(v["slug"])}/LAUNCH.md">Launch plan</a>',
f'<a href="{tm.SERVER}/{REPO}/src/branch/{PAGES_BRANCH}/ventures/{e(h)}/LAUNCH.md">Launch plan</a>',
f'<a href="{tm.SERVER}/{REPO}/issues/{v["card"]}">Card #{v["card"]}</a>' if v.get("card") else ""]
status = v.get("status", "building")
since = f"since {v['launched']}" if v.get("launched") else f"planned {v.get('planned', '')}"
shot = (f'<a class="shot" href="{e(home)}"><img src="{e(site_of(v["slug"]))}shots/sheet.png" alt="{e(v.get("name", v["slug"]))} '
shot = (f'<a class="shot" href="{e(home)}"><img src="{e(site_of(h))}shots/sheet.png" alt="{e(v.get("name", v["slug"]))} '
f'at phone and desktop size" loading="lazy" onerror="this.parentNode.remove()"></a>') if v.get("launched") else ""
rows.append(f"""<article class="row sheet"><div class="no">{len(vs) - k:03d}</div>
<div><h2><a href="{e(home)}">{e(v.get('name', v['slug']))}</a></h2><p>{e(v.get('one_liner', ''))}</p>
@@ -954,7 +963,7 @@ def external_refs(text: str) -> list[str]:
def check_page(w: dict, plan: dict) -> list[str]:
slug = w["slug"]
slug = home_of(w)
page = pages_file(f"ventures/{slug}/index.html")
if page is None:
return [f"ventures/{slug}/index.html is missing"]
@@ -1087,7 +1096,7 @@ def judge_product(w: dict) -> tuple[list[str], str]:
def judge(w: dict) -> dict:
"""Inference after the deterministic gates: does the output depend on the input, does the code do what's claimed (both
are problems, and fix rounds), and how good is it as a product: {problems, verdict, score (1-10 or None), better}."""
slug = w["slug"]
slug = home_of(w)
page = pages_file(f"ventures/{slug}/index.html") or ""
code = "\n".join(re.findall(r"<script\b[^>]*>(.*?)</script>", page, re.S | re.I))
for a in re.findall(r"<script\b[^>]*\bsrc\s*=\s*[\"']([^\"'#?]+\.js)", page, re.I):
@@ -1457,8 +1466,8 @@ def chans_md(chans: list[dict]) -> str:
def true_drafts(w: dict, plan: dict, chair: str) -> list[dict]:
"""The chair rewrites the plan's launch drafts against what was built; the plan's drafts stand if that fails."""
readme = (pages_file(f"ventures/{w['slug']}/README.md") or "")[:4000]
html = pages_file(f"ventures/{w['slug']}/index.html") or ""
readme = (pages_file(f"ventures/{home_of(w)}/README.md") or "")[:4000]
html = pages_file(f"ventures/{home_of(w)}/index.html") or ""
text = _s(re.sub(r"<script.*?</script>|<style.*?</style>|<[^>]+>", " ", html, flags=re.S | re.I), 3000)
drafts = "\n\n".join(f"[{c['channel']}]\n{c['draft']}" for c in plan["launch_channels"])
try:
@@ -1490,8 +1499,8 @@ def launch_post(w: dict, plan: dict, sheet: str | None, note: str) -> str:
pic = f"\n\n<img src=\"{sheet}\" alt=\"{htmllib.escape(w['name'])} at phone and desktop size\" width=\"820\">" if sheet else ""
return (f"🚀 **{w['name']}** is live: {w['url']}\n\n{plan['positioning']}\n\n"
f"**Join early access:** [issue form]({w['join']}) · **Signal:** #{w['signal']} · "
f"**Plan:** [LAUNCH.md]({blob_url(w, 'LAUNCH.md')}) · **Code:** [ventures/{w['slug']}]"
f"({tm.SERVER}/{REPO}/src/branch/{PAGES_BRANCH}/ventures/{w['slug']})\n\n"
f"**Plan:** [LAUNCH.md]({blob_url(w, 'LAUNCH.md')}) · **Code:** [ventures/{home_of(w)}]"
f"({tm.SERVER}/{REPO}/src/branch/{PAGES_BRANCH}/ventures/{home_of(w)})\n\n"
f"| Tier | Price | For |\n|---|---|---|\n{tiers}\n\n"
f"**7-day lines:** success at ≥{plan['success_signups']} signups ({plan['success_metric']}); kill at "
f"≤{plan['kill_signups']} ({plan['kill_metric']}). Decision on {decide}.\n\n"
@@ -1502,7 +1511,8 @@ def launch_post(w: dict, plan: dict, sheet: str | None, note: str) -> str:
def next_version(w: dict, asks: list[str], card: int) -> int:
"""Success: a new card that plans and builds the next version on the same page, shaped by what signups asked for."""
v2 = {**w, "version": int(w.get("version", 1)) + 1, "prior": f"ventures/{w['slug']}/index.html", "asks": asks[:12],
h = home_of(w)
v2 = {**w, **({"home": h} if h != w["slug"] else {}), "version": int(w.get("version", 1)) + 1, "prior": f"ventures/{h}/index.html", "asks": asks[:12],
"page": f"{w.get('page', '')} Next: {w.get('next', '')}"}
for k in ("join", "signal", "card", "url", "batch"): # a v2 is its own venture, not held for its first batch
v2.pop(k, None)
@@ -1581,7 +1591,7 @@ def advance(card: dict, comments: list[dict], beats: list[dict], heavy_ok: bool)
w["slug"] = f"{w['slug']}-{n}" # never overwrite another venture's page
ensure_pages()
w["card"] = n
w["url"] = w["pages"] = site_of(w["slug"])
w["url"] = w["pages"] = site_of(home_of(w))
backend_note = give_backend(w)
w["design"] = w.get("design") or PRODUCT_FIRST
w["join"] = join_url(w)
@@ -1589,7 +1599,7 @@ def advance(card: dict, comments: list[dict], beats: list[dict], heavy_ok: bool)
paid = [t["tier"] for t in plan["pricing"][1:]]
w["join"] = join_url(w, paid[0] if paid else None)
w["signal"] = signal_issue(w)["number"]
put_pages(f"ventures/{w['slug']}/LAUNCH.md", launch_md(w, plan, plans), f"venture {w['slug']}: launch plan")
put_pages(f"ventures/{home_of(w)}/LAUNCH.md", launch_md(w, plan, plans), f"venture {w['slug']}: launch plan")
version = int(w.get("version", 1))
entry = {"slug": w["slug"], "name": w["name"], "one_liner": w["one_liner"], "for_whom": w["for_whom"], "url": w["url"],
"pages": w["pages"], "join": w["join"], "signal": w["signal"], "card": n, "design": w["design"], "version": version}
@@ -1603,7 +1613,7 @@ def advance(card: dict, comments: list[dict], beats: list[dict], heavy_ok: bool)
return "wait"
w, plan = st["winner"], st["plan"]
r = _build_on_pages({"number": n, "title": f"Launch {w['name']}", "body": build_body(w, plan)},
BUILD_DONE.format(slug=w["slug"]), worker_spec(), root=f"ventures/{w['slug']}/")
BUILD_DONE.format(slug=home_of(w)), worker_spec(), root=f"ventures/{home_of(w)}/")
say(f"🔨 `{r['seat']}` built the launch page in {r['steps']} steps ({r['model']}). Checking it next.",
{"beat": "built", **keep, "fixes": 0, "seat": r["seat"], "model": r["model"]})
return "heavy"
@@ -1612,7 +1622,7 @@ def advance(card: dict, comments: list[dict], beats: list[dict], heavy_ok: bool)
problems, sheet, note = check_page(w, plan), None, "browser pass not run"
fixes, polish, j = int(st.get("fixes", 0)), [], {}
if not problems:
problems, sheet, note = browser_check(w["slug"])
problems, sheet, note = browser_check(home_of(w))
if not problems: # the inference tier, only once the cheap gates pass
j = judge(w)
problems, note = j["problems"], f"{note}; {j['verdict']}"
@@ -1632,9 +1642,9 @@ def advance(card: dict, comments: list[dict], beats: list[dict], heavy_ok: bool)
# cost cascade: the cheap worker gets the first round; a failed round escalates to a stronger model
spec = worker_spec() if fixes == 0 else env("TIME_VENTURE_ESCALATE", ESCALATE)
r = _build_on_pages({"number": n, "title": f"Fix the {w['name']} launch page",
"body": FIX_BODY.format(name=w["name"], slug=w["slug"], problems=bullets, page=w.get("page", ""),
"body": FIX_BODY.format(name=w["name"], slug=home_of(w), problems=bullets, page=w.get("page", ""),
join=w["join"], signal=signal_url(w))},
"every check above passes", spec, root=f"ventures/{w['slug']}/")
"every check above passes", spec, root=f"ventures/{home_of(w)}/")
say(f"🔧 `{r['seat']}` ({r['model']}) worked on the fixes in {r['steps']} steps. Re-checking.",
{"beat": "built", **keep, "fixes": fixes + 1})
return "heavy"
@@ -1647,25 +1657,25 @@ def advance(card: dict, comments: list[dict], beats: list[dict], heavy_ok: bool)
{"beat": "built", **keep, "fixes": fixes, "problems": polish, "polish": True, "score": j["score"]})
spec = worker_spec() if fixes == 0 else env("TIME_VENTURE_ESCALATE", ESCALATE)
r = _build_on_pages({"number": n, "title": f"Polish the {w['name']} launch page",
"body": POLISH_BODY.format(name=w["name"], slug=w["slug"], score=j["score"], bar=bar(),
"body": POLISH_BODY.format(name=w["name"], slug=home_of(w), score=j["score"], bar=bar(),
problems=bullets, page=w.get("page", ""), join=w["join"],
signal=signal_url(w))},
"every change above is made and every check still passes", spec, root=f"ventures/{w['slug']}/")
"every change above is made and every check still passes", spec, root=f"ventures/{home_of(w)}/")
say(f"🎨 `{r['seat']}` ({r['model']}) polished it in {r['steps']} steps. Re-checking.",
{"beat": "built", **keep, "fixes": fixes + 1})
return "heavy"
plan = {**plan, "launch_channels": true_drafts(w, plan, drafter)}
keep["plan"] = plan
md = pages_file(f"ventures/{w['slug']}/LAUNCH.md")
md = pages_file(f"ventures/{home_of(w)}/LAUNCH.md")
if md and "## Launch channels" in md:
md = re.sub(r"(## Launch channels \(drafts; nothing is sent\)\n\n).*?(\n\n## 7-day lines)",
lambda m: m.group(1) + chans_md(plan["launch_channels"]) + m.group(2), md, flags=re.S)
put_pages(f"ventures/{w['slug']}/LAUNCH.md", md, f"venture {w['slug']}: launch drafts checked against the build")
put_pages(f"ventures/{home_of(w)}/LAUNCH.md", md, f"venture {w['slug']}: launch drafts checked against the build")
shot = None
if sheet:
res = put_pages(f"ventures/{w['slug']}/shots/sheet.png", sheet, f"venture {w['slug']}: screenshots")
res = put_pages(f"ventures/{home_of(w)}/shots/sheet.png", sheet, f"venture {w['slug']}: screenshots")
ref = (res.get("commit") or {}).get("sha") or PAGES_BRANCH
shot = f"{tm.SERVER}/{REPO}/raw/commit/{ref}/ventures/{w['slug']}/shots/sheet.png"
shot = f"{tm.SERVER}/{REPO}/raw/commit/{ref}/ventures/{home_of(w)}/shots/sheet.png"
if w.get("batch") and not batch_released(int(w["batch"])):
say(f"✅ Checks pass. Ready, held for batch #{w['batch']} so its ventures launch together "
f"(at most {batch_hold_hours():g}h after the first of them is ready).",
@@ -1704,7 +1714,7 @@ def advance(card: dict, comments: list[dict], beats: list[dict], heavy_ok: bool)
def launch(n: int, w: dict, plan: dict, keep: dict, shot: str | None, note: str, say) -> None:
since = dt.datetime.now(dt.timezone.utc).strftime("%Y-%m-%dT%H:%M:%SZ")
# the portfolio (ventures/index.html) shows `shot` and links `sheet`, both relative to ventures/
pics = {"shot": f"{w['slug']}/shots/sheet.png", "sheet": f"{w['slug']}/shots/sheet.png"} if shot else {}
pics = {"shot": f"{home_of(w)}/shots/sheet.png", "sheet": f"{home_of(w)}/shots/sheet.png"} if shot else {}
record({"slug": w["slug"], "status": "live", "launched": today(), "card": n, "source": "time", "hosting": "pages", **pics,
"signups": count_signups(w, since if int(w.get("version", 1)) > 1 else None)[0]}, f"ventures: launch {w['slug']}")
say(launch_post(w, plan, shot, note), {"beat": "launched", **keep, "shot": shot, "since": since})
@@ -1750,7 +1760,7 @@ def give_backend(w: dict) -> str:
return ""
try:
be = cfb.deploy(w["slug"], w["pages"])
put_pages(f"ventures/{w['slug']}/time.js", cfb.client(be["api"]), f"venture {w['slug']}: backend client")
put_pages(f"ventures/{home_of(w)}/time.js", cfb.client(be["api"]), f"venture {w['slug']}: backend client")
except Exception as e: # noqa: BLE001
return f"\n\n_Backend: Cloudflare didn't take it ({str(e)[:200]}); launching on Pages, and the next tick tries again._"
w["url"], w["backend"] = be["url"], {k: be[k] for k in ("worker", "db", "rev", "api")}
@@ -1775,7 +1785,7 @@ def refresh_backends(reg: dict, limit: int = 2) -> None:
done += 1
try:
be = cfb.deploy(v["slug"], pages)
put_pages(f"ventures/{v['slug']}/time.js", cfb.client(be["api"]), f"venture {v['slug']}: backend client")
put_pages(f"ventures/{home_of(v, reg)}/time.js", cfb.client(be["api"]), f"venture {v['slug']}: backend client")
except Exception as e: # noqa: BLE001
print(f"backend {v['slug']} failed:", str(e)[:200])
continue