docs(go): AGENTS.md with the one rule and tenancy declaration

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Paul Campbell pushed by claude agent, operated by paul@keymail.dev 67a0ec5c68f33b12620579f77e72456bbdf772fd parent afa9d3f
1 file changed, +36 −0
  • apps/go/AGENTS.md +36 −0
diff --git a/apps/go/AGENTS.md b/apps/go/AGENTS.md
new file mode 100644
index 0000000..4a525fb
--- /dev/null
+++ b/apps/go/AGENTS.md
@@ -0,0 +1,36 @@
+# 🤖 AGENTS.md: todo-go
+
+TodoMVC for the CARLOS bakeoff, in Go. `BRIEF.md` and `CONTRACT.md` at
+the repo root are binding; this file says how this app keeps them.
+
+## The one rule
+
+**The page works with JavaScript off.** Every action is a plain form
+POST answered with a 303, and every view is a server-rendered page. The
+JavaScript in `static/app.js` only replays those same forms with
+`fetch` and swaps in the HTML the server renders, so there is exactly
+one renderer and one source of truth: the server and its SQLite file.
+If a feature can't be done that way, it doesn't go in.
+
+## Tenancy declaration (written 2026-10-23, before code)
+
+| Question | Answer |
+|---|---|
+| What is one instance? | The whole app. One instance on `todo-go.bfj.oncarlos.com`, one SQLite file |
+| Who are the users? | Anonymous visitors. No sign-in, no accounts |
+| How is each visitor's data kept apart? | Each visitor gets a list through an anonymous cookie (`HttpOnly; SameSite=Lax; Path=/`, `Secure` over https) holding 256 random bits plus a MAC. The database stores only a SHA-256 of the cookie, and every query that touches a todo is filtered by that hash. A todo id outside the caller's list answers 404 |
+| Trust class | **C**. Todo titles are stored as plain text and the server can read them. Chosen on purpose: a public demo list with no accounts has no key to encrypt to, and this is written down here and in the README |
+| Residue | Titles, completion flags, creation times, and the cookie hashes. No IPs, no user agents |
+| Benefits earned | Platform replication and hibernation of the one file; per-visitor isolation enforced in every query |
+| Costs accepted | One shared instance: a crash takes every visitor down together. Lists are as private as the cookie; clearing cookies loses the list |
+
+## Rules for working here
+
+- Stdlib first. The only third-party dependency is the SQLite driver
+ (`modernc.org/sqlite`, pure Go, so `CGO_ENABLED=0` works). Adding
+ another is a decision recorded in `README.md` and `DEPS`.
+- Migrations only add. Never drop or rewrite data.
+- `static/base.css` and `static/index.css` are byte-for-byte copies of
+ `shared/`; a test checks it.
+- Bind `127.0.0.1` only when running locally. Never change `GOCACHE`.
+- Commits end with a `Co-Authored-By:` trailer naming the model.