carlos / todomvc-bakeoff Public

Clone
git clone https://amadan.net/carlos/todomvc-bakeoff

Plain git — no account needed to clone.

Download

Download this file

1# πŸ€– CARLOS working conventions
2
3How the family builds. These conventions exist because each was learned the
4hard way at least once; the incident is noted where it names the rule.
5
6## Repo documents
7
8- **AGENTS.md** β€” "how we build and the decisions we've committed to."
9 Written before the code (factor V: the intent is the system β€” the code
10 should have to argue with something). Opens with the one rule. Contains:
11 settled decisions (dated, attributed, with rejected alternatives),
12 named laws, the workflow, and a "Deliberately not built yet" list with the
13 trigger for each deferral. One file, for every agent that reads the repo β€”
14 not one per vendor. Older repos still carry it as CLAUDE.md; rename it to
15 AGENTS.md the next time you touch one, rather than keeping two.
16- **README.md** β€” user-facing: what it is, run it, honest trade-offs.
17- **DESIGN.md** β€” the spec, what gets built. **PLAN.md** β€” why it is shaped
18 this way, the roadmap.
19- **docs/** β€” design records and briefs, written *before* the build
20 ("Brainstormed with Paul; decisions recorded here"), each with a Status
21 line (`built` / `approved design β€” not yet built`), annotated in place
22 when built. The doc's decisions are binding: if one proves wrong in
23 practice, stop and flag it in the PR rather than redesigning.
24
25## Git and PR playbook
26
27- **Worktree per session, always.** Multiple sessions (agents and humans)
28 are active at once; the main checkout's uncommitted state belongs to
29 another session. Never build in the main checkout β€” reading it is fine,
30 writing is not.
31- **The cadence is: worktree β†’ branch β†’ regular pushed commits β†’
32 squash-merge.** Commit as you go and push every commit. The branch is
33 where work in progress lives; you do not wait to be asked to put it
34 there, and a session that ends with unpushed work has lost it as far as
35 everyone else is concerned. Keep the PR small and focused.
36- **Squash-merge to main when all three hold: the work is done, a human has
37 approved it, and CI is green** (`gh pr merge --squash --delete-branch`
38 on GitHub; on amadan, where the branch is the pull request,
39 `amadan branch merge` makes a merge commit and `-squash` lands one
40 commit; never squash by hand there, or the branch shows as deleted).
41 Two of the three is not a merge β€” a green run on unapproved work waits,
42 and an approval over a red run waits. Never commit to main. Deploy only
43 merged main, and only when asked.
44- **"CI green" binds once CI exists, and a new repo's early work is to
45 make it exist.** A repo with no CI has no green to wait for: the
46 condition is not waived, it simply has nothing to read yet, so the first
47 merges of a new project land on done + approved. Standing up CI is one
48 of the first work items, not a prerequisite nobody can satisfy β€” and it
49 is the gate you already run locally, kept as one definition rather than
50 a second list that drifts, so debugging CI is running it. Once the repo
51 has CI all three bind absolutely and the carve-out is spent.
52- Commit subjects are area-prefixed prose that says why (`web: the front
53 door is a homepage β€” pitch left, sign-in right`; `auth: delete the
54 recovery passphrase, root and branch`). Comment the why, not the what.
55- Every commit carries `Co-Authored-By: Claude <model>
56 <noreply@anthropic.com>`; the human is the author of record.
57
58## Canaries
59
60- **Every session gets its own canary; review happens on a deployed canary,
61 never on localhost.** (Adopted after two sessions sharing a dev host
62 produced an evening outage.) Local stacks are for automated drives only.
63- On the platform, a canary is a channel: `carlos canary` deploys to
64 `canary/<slug>` (a per-session dead-end rung, zero bake) and the canary
65 host serves it at
66 `<slug>-<app>.<sqid>.<domain>` β€” same rule, no box. Off-platform,
67 canaries multiplex onto the devbox: own port/state/unit/TLS at
68 `<branch>.<dev-host>`. Shared hosts (`prod`, the plain dev host) only ever
69 carry main builds β€” enforced by the deploy path, not memory.
70- Report the complete clickable canary URL in **every** reply while
71 iterating, with a short list of what to test. The human clicks through
72 mid-flight; never make them scroll back for the URL.
73- Tear your canary down when the branch merges. Never echo claim links or
74 secrets into the session β€” the prompt ledger publishes what gets typed.
75
76## Testing
77
78The layers, in order:
79
801. **`go test ./...`, `go vet ./...`, `gofmt -l .` β€” all clean, always.**
81 Nothing lands untested; a bug fix carries its regression test. When
82 gating on a test run, never pipe it β€” a pipe eats the exit code (a red
83 suite once merged and deployed exactly this way). A guard belongs
84 *inside* the test binary, never in a shell step around it β€” a guard a
85 shell step can satisfy is a guard a shell step can be wrong about
86 (one browser-required check went silently unrun for weeks).
872. **Prefer a parsing test to a browser for anything computable from
88 source.** Contrast ratios computed from the token file's declarations
89 (WCAG AA, both themes, no browser); network reachability rules parsed
90 from the served JS; performance fixes shipped with an `EXPLAIN QUERY
91 PLAN` assertion over the *exported production query string* so the
92 test cannot drift from the real SQL. When a rule needs an exception,
93 the allowlist entry pins the exact occurrence count, not just the
94 file β€” a new call site inside an exempted file must still fail.
953. **JS logic DOM-free under `node --test`**, wired into `go test` via a
96 small `jstest_test.go`, so one command runs everything. `node --check`
97 alone is not enough β€” it parses as CommonJS and swallows ES-module errors
98 that crash Safari; check a `.mjs` copy and load it in a real engine.
994. **uidump β€” dump, don't drive** (adopted by the platform console). An env-gated test (`UIDUMP_DIR` set, else
100 skipped) boots the real handler in-process over `httptest`, seeds a
101 fixture world rich enough that every state has a subject, signs in,
102 GETs every named screen, and writes each response body to disk with
103 asset paths rewritten relative so the files stand alone. An agent
104 then screenshots the static files directly with headless Chrome
105 (`--headless --screenshot=…`), re-shooting dark mode by stamping the
106 theme attribute and mobile at a narrow window. Near-zero cost, zero
107 flake, works on a display-less box; adding a screen is one map entry
108 β€” and **"add your screen to the dump" is a checklist line in every
109 plan**, or coverage rots. It renders HTML+CSS only and asserts
110 nothing itself: it is the visual-review gate, not the invariant gate.
1115. **Browser drives are for the residue** that needs a JS engine and
112 real layout geometry β€” enhancement-script behaviour, popover sizing,
113 overflow, theme resolution β€” env-gated, with assertions written as
114 the named bug class they caught. Playwright, or chromedp for
115 pure-Go. Passkey flows run in Chromium β€” the virtual authenticator
116 is a CDP feature; a separate passkey-free smoke runs in WebKit,
117 Safari's engine, because it breaks first. Loud on purpose: fail on
118 any console error, page error, or failed request, and junk-scan
119 every view for `undefined`, `null`, `[object Object]`, `NaN` β€” the
120 bug class that renders perfectly and says nothing (a stray `null`
121 *text node* included: native `append()` stringifies one). A skip is
122 not a pass: report executed-vs-skipped.
1236. **The merciless greps** (server-blind apps): end-to-end tests that grep
124 raw SQLite bytes *and* S3 objects for plaintext content and names.
1257. **After every deploy: the console check in WebKit** against the live
126 host (the keymail rule) β€” a JS syntax error takes the whole client down
127 and only a real engine sees it; WebKit specifically, because it is the
128 strictest engine and Safari users hit it first.
1298. **Security scan** (Aikido) before ending a work cycle; triage every
130 finding; never publish over an untriaged one.
131
132Simulation suites are the spec for convergence-critical engines (sync,
133progression): any behaviour change changes the suite first. Golden vectors
134pin multi-language implementations (see blueprint.md).
135
136## Ending a session
137
138Every session ends through the committed `/end-session` gate. The shape:
139
1401. Clean tree β€” nothing uncommitted, nothing unpushed, no orphan worktrees.
1412. Gates green: build, vet, gofmt, tests (unpiped), browser drives with
142 executed-vs-skipped counts.
1433. Security scan clean or triaged.
1444. Ledgers accrued (below), reviewed word-by-word for secrets before
145 publishing β€” never publish text you haven't read; when unsure, redact
146 with an annotated `⟦redacted: category⟧` and say what and why.
1475. Deploy state reported; canaries torn down or handed over.
1486. A handoff report: PRs, clickable canary URLs with what to verify, open
149 threads, and what was deliberately not done.
150
151## Ledgers and transparency
152
153The family practices radical operational transparency on a public status
154site: **prompt registry** (every human prompt behind the code, whole and in
155order, credentials redacted in place), **carbon tally** (token spend β†’
156COβ‚‚e bands, plus the boxes' share), **contributors** (humans and AI models
157on one metric, from git trailers), roadmap and milestones written in member
158language β€” what changed for a member, never how the boxes are run. Ledger
159updates ship exactly like code: commit β†’ PR β†’ deploy. No hostnames, no
160account IDs, no third-party personal data in anything published.
161
162## AI authorship (factor X)
163
164- Machine-authored text is marked **πŸ€–** wherever it surfaces β€” visible,
165 immediately before the heading or block it covers; a marker on a heading
166 cascades. Never hide the πŸ€– in a comment.
167- A person marker (πŸ‘¨/πŸ‘€/πŸ§‘) certifies human text: an LLM must not rewrite,
168 rephrase, condense, or delete it. No marker means ambiguous β€” never claim
169 human authorship for unmarked text.
170- Disclosure extends to product: AI features are opt-in, never required,
171 always disclosed, and every path works with the AI switched off β€” this is
172 a hard constraint, not an aspiration. Nothing assumes AI stays cheap.
173- Uncompiled or unverifiable code is marked (`// UNVERIFIED: written without
174 an iOS toolchain`) and kept in separate commits.
175
176## Working with the human
177
178Patterns visible across every prompt history, useful calibration for agents:
179
180- Directives are terse ("go", "merge", "Deploy!", "keep going until it's
181 done"). Long autonomous runs are normal; write the design doc, then build
182 until there's something live to click.
183- Bug reports arrive as lived user experience from the live product, in
184 product language. Reproduce on a canary, fix, and ask "is this flow being
185 tested?" β€” because that question is coming.
186- Product shape is given, parameters are left open ("allows edits for what,
187 5 minutes? 2 minutes?") β€” make the judgement call and flag it.
188- Sibling apps are the design vocabulary ("like Eleven's home server",
189 "Woodstar's shape, copied on purpose"). Check the sibling before
190 inventing.
191- Calm UI: red is for danger only, no toasts, no nerdspeak in the default
192 flow, buttons stay where the thumb is, feedback is inline and honest.
193