01-projects/printables-product

Scribble Works — five-audit synthesis and the hardening plan

2026-09-02·decision-brief·status: decided (amended) 2026-09-02 18:52 ET
scribble-worksprintables-productauditsynthesishardeningcharterdecision-brief

Scribble Works — where we are, and what happens next

Founder decision, 2026-09-02 18:52 ET: AMEND. Decision 1, no counsel authorization. Decision 2, flip the three that passed and iterate on the two that did not, as a standing rule (ruling 32: games release as they pass the critic). Decision 4, no USPTO knockout now - "not mature enough yet to worry about this". Decisions 3, 5 and 6 accepted as recommended. Cadence: now.

Updated 2026-09-02 15:25 ET after round-2 verification ([[round2-verify-2026-09-02]]).

Five auditors, dispatched with zero build context and no sight of each other's briefs [unverifiable: the dispatch prompts are not on disk], read the repo, the live site, the charter, the rulings and all 27 PDFs.

1. The verdicts, in their words

Your "vibe coded" question went to A, the only auditor scoped to it. Its answer is no: a solid 3, held back by four nameable gaps rather than diffuse sloppiness. The craft holds; the machinery around it does not.

Your other question, whether a fresh-eyes critic should review the whole architecture: audit A was that review, done source-blind. Repeat it at the next hardening cycle, not every round.

2. Where the auditors agree

Seven findings landed in two or more audits independently. Attribution is on each.

  1. Fail-open defaults. (A, B) The money gate is on in production only because one dashboard string reads true. The Twilio webhook returns "verified" when its token is missing, leaving a public endpoint that writes to production D1 and fetches attacker-supplied URLs.
  2. No CI. (A, D) No .github/ at all. A thousand real assertions exist and nothing runs them on a PR. C and D both name PR #49, six minutes of Customize down, as the bill already paid.
  3. Retention promised, never enforced. (A, B, C) retain_until is stamped on every row in two tables, and there is no DELETE FROM outside the tests.
  4. Privacy copy ahead of the code. (A, B, C) /privacy says rows are deleted after 90 days, which nothing does. B alone adds that the "expires the next day" line describes the limiter key, not the retained one.
  5. Governance text is stale. (C, D) Thirteen production deploys today, all on your word, against a charter that still reads as if engineering has a hard gate.
  6. Measurement is off. (C, D on signal 2; C alone on the rest) Gateway logs off, so spend is unobservable. The Sonnet round-count test never ran. Signal 2, founder time, is unscored.
  7. The live copy contradicted itself. (C, D) At audit time /terms said "no accounts" while accounts were live, /faq said "ages 3-4" on a 2-10 site, and the Ages 2-3 facet returned zero games. All three were fixed in #63 and live at 13:54.

Single-auditor, still worth acting on: the name-in-a-sentence gap, where a parent who skips the name box and writes "Mae is 4 and loves horses" sends Mae to the model and a 90-day row (B); one real user and blind counters (D); no robots.txt, sitemap or 404 (D); an unauthenticated downloads endpoint feeding the kill-or-ship numbers (B).

E is the exception that proves the pattern. The one gate we finally ran found nothing blocking.

3. Where they disagree, and my call

D wants counsel authorized and accounts frozen. C wants the charter re-baselined first, because a document contradicted daily is no control at all. A wants defaults and CI first; B wants defaults, headers and retention first.

My call: A/B, then C, then D, in one cycle this week. Rows 1-7 are hours [unverifiable: A puts rows 4, 5 and 8 at half a day]; 8-11 are a day or two. One is a live unauthenticated write door on production data, so doing them first costs the others nothing. C's re-baseline is documentation and rides along with ruling 29. D's headline ask is gated for shipping (counsel answers before v2 reaches production), but design continued: the members-area spec and wireframes were produced after D. No overrule on the wand: D also puts the print test ahead of it, and Part 3 keeps that order. A and B were scoped to code and security and offer no product-order opinion, so read them as sequencing input, not as parties to the argument.

4. The plan

Part 1, docs and CI (ruling 29, in flight). ARCHITECTURE.md: components, wiring, secrets map, deploy path. Actions on every PR as required checks: build, validators, all ten suites, schema guard, drift check. A pre-PR checklist agents clear before opening.

Part 2, the ranked refactor list, from A's top ten, B's fix-first five and C's gate-map breaches. Blocking means it lands before the next feature PR. Status is as of 15:25 ET; the synthesis went out at 14:10, and four rows had already merged by then.

# Fix Effort Blocking Status
1 Twilio verify fails closed; workers_dev = false; cap the media fetch S Yes Landed after publication (#66 merged 14:42, deployed 14:54)
2 Remove the committed node_modules symlink S Yes Merged before publication (#64, 14:03)
3 npm test plus Actions CI with required checks S Yes Merged before publication (#65, 14:09)
4 Invert fail-open defaults: gate, allowlist, sign-in limiter S Yes Landed after publication (#66, 14:42, deployed 14:54); the sign-in limiter still fails open
5 Stop discarding priorError; log the failure class S Yes Landed after publication (#66, 14:42, deployed 14:54)
6 public/_headers: CSP, frame-ancestors, HSTS, nosniff S Yes Landed after publication (#66, 14:42, deployed 14:54)
7 Fix the live copy: /terms, /faq, the empty Ages 2-3 facet (done) S Yes Merged before publication (#63, 13:52; live 13:54)
8 Retention purge on a cron, plus the retain_until index M Yes Landed after publication (sweeper and migration 0004 deployed 14:55)
9 Reconcile privacy copy with code: name gap, household hash, feedback M Yes Landed: privacy copy in #63 (13:52), the rest in #66 (14:42, deployed 14:54)
10 ARCHITECTURE.md M Yes Merged before publication (#64, 14:03)
11 Run build-landing-page on the live pages (verify-pdf-output ran as audit E) M Yes Still open

Non-blocking, in order: E's eleven ITERATEs (one bubble line-length fix clears four) · the monthly ceiling off KV read-modify-write · a first-visit dimension on the counters plus closing the open downloads endpoint · one printable footer at a 7pt floor · discovery basics (robots.txt, sitemap, a real 404, apex domain attached) · the shared-primitives layer · splitting the 700-line installCustomize().

Part 3, the product order after hardening, as a default. Flip the pending games, run the four-household print test, build the wand, then members-area v2 once counsel answers. Counter-argument: the test spends a week learning what four households think of a catalog we may rebuild anyway.

5. Decisions for you

  1. Authorize counsel. Default: yes. I source three children's-privacy attorneys this week; you pick or decline. Nothing with a kid profile ships until they answer. Decided: no counsel authorization (consistent with the 18:30 park and ruling 30).
  2. Flip the pending work live. Five sit gate-passed since 09:00: fraction-pizza, map-the-room, making-change, word-ladder, colorea-al-unicornio. E grades map-the-room and colorea-al-unicornio ITERATE on cosmetics, foot slack and an orphan bubble word; the other three PASS. Default: flip all five, fix both next design round. Say "hold the two" to flip three. Decided: flip fraction-pizza, making-change and word-ladder (audit E PASS); iterate map-the-room and colorea-al-unicornio and release each as it passes. The general rule is recorded as ruling 32: games ship as they pass the critic.
  3. Metered generation and its meter. Default: keep the metered gateway, keep its logs off so parents' sentences stay out of Cloudflare, and price each call from a token/cost column still to be added to the UGC row (queue.md lists it). Audit C recommends the opposite: logs on, with a per-round cost line. Your call. Charter §4 gets amended either way. Decided: recommendation accepted.
  4. USPTO clearance. Default: I run it this week, and no new brand surface accrues until it reads. Alternative: accept the risk knowingly. Decided: no USPTO knockout now - "not mature enough yet" (founder, 18:52 ET); revisit at maturity.
  5. Charter §7 signal 3. Unasked-for morning corrections have happened more than twice: the 06:16 rulings and the 07:19 ruling-20 correction (see §6). The charter's consequence is that the cron reverts to on-demand. I am the party that rule constrains, so I am not defaulting it. My recommendation is that overnight rounds continue and the 2026-09-14 review scores all three signals. Discount that accordingly. Decided: recommendation accepted.
  6. Charter re-baseline. Default: I draft the amendment covering §2's hard gate, §4's cost model, an §8c daytime breaker, the §8 hardening cadence and the org table. You confirm when it lands. Decided: recommendation accepted. Draft: [[2026-09-02-charter-rebaseline-draft]].

6. What I got wrong today

Related

Changelog