oficina / sheets Public

AGENTS.md, and the review rule

Paul's call, 2026-08-30, both parts.

AGENTS.md rather than CLAUDE.md, carrying the one rule verbatim as
CARLOS requires โ€” sealed at rest, the bucket never holds a plaintext
cell โ€” plus the mechanical rules that are enforced by tests rather than
remembered, and the spec as the authority it defers to.

And the review rule: every spec and every branch is reviewed by the
highest-capability model available before it is approved or merged.
Cheaper models draft, the most capable one available reviews, and a
review by a weaker model than the author is not a review. The reviewing
model is recorded, because a review nobody can attribute is a review
nobody can check โ€” and the model is discovered rather than hardcoded,
since naming today's flagship in a file is how the rule would go stale
without anyone noticing.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01APtNStXDZ5H2fAc1ZuGqtS
Paul Campbell 7297e0a8c323b74dacebf20070b08cb5be67c4f5 parent eafee26
2 files changed, +148 −2
  • AGENTS.md +126 −0
  • docs/superpowers/specs/2026-08-30-sheets-design.md +22 −2
diff --git a/AGENTS.md b/AGENTS.md
new file mode 100644
index 0000000..3636d66
--- /dev/null
+++ b/AGENTS.md
@@ -0,0 +1,126 @@
+# ๐Ÿค– Sheets
+
+A CARLOS spreadsheet. One instance per team.
+
+This file is binding. Where it disagrees with a general skill, this file
+wins. Where it disagrees with the design spec, the spec wins and this file
+is wrong โ€” fix it in the same commit.
+
+**The design:** `docs/superpowers/specs/2026-08-30-sheets-design.md`. Its
+ยง1 is the settled-decisions table: dated, attributed, with the rejected
+alternative beside each. Don't relitigate one in a drive-by.
+
+---
+
+## The one rule
+
+> **A sheet's contents are sealed at rest. The bucket never holds a
+> plaintext cell.**
+
+The instance holds the key while it runs, so the server *can* read a sheet
+it has open. That is a deliberate softening, not an accident, and the spec's
+ยง2 names every leak it produces. What the rule forbids absolutely is a
+plaintext value reaching the replicated SQLite file or object storage.
+
+A test greps raw SQLite bytes and bucket objects for plaintext from the
+first commit. `plaintextExempt` starts empty; any entry is dated, justified,
+and listed in the README.
+
+**We never claim "we can't read your data."** A compromised live host can
+read any open sheet. The README says so and the UI never implies otherwise.
+
+---
+
+## Review โ€” RULED 2026-08-30 by Paul
+
+**Every spec and every branch is reviewed by the highest-capability model
+available before it is approved or merged.**
+
+Not the model that happened to write it, and not whichever model the
+session started on. Cheaper models draft; the most capable one available
+reviews. A review by a weaker model than the author is not a review.
+
+Mechanically:
+
+- **Specs** โ€” a review pass before the spec is presented for human approval,
+ and again after any material change to a settled decision.
+- **Branches** โ€” a review pass before the PR is opened, and again after any
+ force-push that changes more than a rebase.
+- **Record which model reviewed**, in the PR body or the spec's status line.
+ A review nobody can attribute is a review nobody can check.
+
+**The highest-capability model is discovered, not hardcoded.** At the time
+of writing that is Opus; naming a model here without saying how to re-derive
+it is how this rule goes stale silently. The check is: what is the most
+capable model this session can actually reach right now. If a session cannot
+reach one at least as capable as the author's, it says so and waits rather
+than passing a weaker review off as done.
+
+This is a floor, not a ceiling โ€” an extra pair of eyes, human or model, is
+always welcome on top.
+
+---
+
+## Intent before code
+
+CARLOS's first principle: the design doc precedes the build, and its
+decisions are taken. If one proves wrong, **stop and flag it** rather than
+quietly redesigning around it.
+
+Keep the spec's "Deliberately not built yet" table honest. Every deferred
+thing has a written trigger. A thing deferred without a trigger is a thing
+forgotten.
+
+---
+
+## Mechanical rules
+
+Rules here are enforced by tests, not by memory. If you find yourself
+relying on remembering one, make it a test instead.
+
+**Data**
+- Every query touching user-owned rows goes through `scope.Owned(g, uid)` โ€”
+ reads *and* writes, inside transactions too. Scope `tx`, never the outer
+ handle, or the one-connection writer pool deadlocks.
+- A row that isn't yours **404s, never 403s**.
+- Never bind a request body onto a GORM model. Explicit `map[string]any`
+ plus a `.Select` allowlist.
+- Read the viewer with `auth.From(r)` or `sessions.Current(r)`. **Never
+ `sessions.UserID`** โ€” it returns `(0, false)` for an email Subject, and
+ dropping that `ok` scopes every query to uid 0.
+- Migrations are additive-only. New code over an old DB is always safe.
+ Never delete data to update.
+- A float never touches an amount. The formula evaluator's IEEE arithmetic
+ is a bounded exception that stops at the storage boundary.
+
+**Frontend**
+- No build step. Jspreadsheet CE is vendored as a static asset, not fetched
+ from a CDN and not bundled.
+- Write the rastrillo **attribute** grammar (`rst-btn="primary compact"`),
+ never the `class="rst-*"` vocabulary โ€” it is mid-migration and the classes
+ are the losing spelling.
+- **Re-copy `static/tokens.css` on every rastrillo upgrade.** It is frozen
+ at scaffold time while partials upgrade with the module. Adopt
+ `rastrillo doctor` the day it lands and delete this step.
+- Don't build on `.rst-page-header::after` โ€” the rake line is retired in
+ favour of `--rst-header-rule`.
+- 300-line JS module cap, test-enforced, ratchet-down only. The vendored
+ Jspreadsheet blob is exempt and named as such; nothing we write is.
+- Every drag-only affordance has a menu equivalent.
+
+**Deploys**
+- One binary, `CGO_ENABLED=0`, cgo-free SQLite. A cgo driver sneaking in is
+ a bug.
+- Review on a deployed canary, never localhost.
+- A 200 is not a deploy verification. Only `X-Carlos-Version` on the
+ canonical host, after the watch, is proof.
+- A promote is not a deploy. Until the process cycles, the old binary
+ serves.
+
+---
+
+## Authorship
+
+๐Ÿค– / ๐Ÿ‘จ markers, `Co-Authored-By: Claude โ€ฆ` trailers, published prompt and
+carbon ledgers. AI is a guest with a name tag: opt-in, disclosed, and every
+path works with it switched off.
diff --git a/docs/superpowers/specs/2026-08-30-sheets-design.md b/docs/superpowers/specs/2026-08-30-sheets-design.md
index f1878e2..397dc6b 100644
--- a/docs/superpowers/specs/2026-08-30-sheets-design.md
+++ b/docs/superpowers/specs/2026-08-30-sheets-design.md
@@ -21,7 +21,7 @@ rule forbids absolutely is a plaintext value reaching the replicated SQLite
file or object storage, and a test greps the raw bytes for exactly that from
the first commit.
-`CLAUDE.md` opens with this rule verbatim, and is written before any code.
+`AGENTS.md` opens with this rule verbatim, and is written before any code.
---
@@ -577,6 +577,26 @@ From the first commit, not a later hardening pass:
8. **Module-size cap** on JS, test-enforced, ratchet-down only. The vendored
Jspreadsheet blob is exempt and named as such; nothing we write is.
+### 12.1 Review โ€” RULED 2026-08-30 by Paul
+
+**Every spec and every branch is reviewed by the highest-capability model
+available before it is approved or merged.** Cheaper models draft; the most
+capable one available reviews. A review by a weaker model than the author is
+not a review.
+
+Specs get a pass before human approval and again after any material change
+to a settled decision. Branches get one before the PR opens and again after
+any force-push bigger than a rebase. **The reviewing model is recorded** in
+the PR body or the spec's status line โ€” a review nobody can attribute is a
+review nobody can check.
+
+The highest-capability model is **discovered, not hardcoded**; naming one
+here without saying how to re-derive it is how the rule goes stale silently.
+A session that cannot reach a model at least as capable as the author's says
+so and waits, rather than passing a weaker review off as done.
+
+Full wording in `AGENTS.md`.
+
Review happens on a deployed canary, never localhost. Verify a deploy with
`X-Carlos-Version` on the canonical host after the watch โ€” never a 200.
@@ -584,7 +604,7 @@ Review happens on a deployed canary, never localhost. Verify a deploy with
## 13. Sequencing
-1. Skeleton, `CLAUDE.md`, auth
+1. Skeleton, `AGENTS.md`, auth
2. Storage and sealing (gate 1 live from here)
3. Formula engine
4. Grid