oficina / home Public

Re-review: gate 9 needs no database, so it must not be sequenced behind one

Fable's re-review of 31734ff found a defect in that commit's own fix, which
is the failure mode this branch has now hit twice.

31734ff said "Three gates enforce it from the first commit that opens a
database ... The skeleton opens no database and so carries none of them
yet." Gate 9 is a string scan — section 12 defines it as scanning log
lines, error strings and metric labels — and needs no database at all. The
skeleton already emits log lines at cmd/home/main.go:44 and :57, so gate 9
is buildable today. The sentence gave gate 9's absence a reason that does
not apply to it, and re-sequenced it behind a database when section 13 step
1 puts it with the skeleton. Its absence is a gap in step 1, and the
binding file read as though it were not. Filed as a task.

Also, all non-blocking and all from the same pass: dropped "and it is the
proposal most likely to arrive looking reasonable", which is this file's
editorial and not a ranking the spec makes; shortened the do-not-restore
bullet from seven lines to four, since side (a)'s closed enumerated set
already encodes the injection reason; and rewrapped three ragged spots the
earlier edits left, including one 86-character line.

Docs only; no behaviour change. All four .amadan/ci.d gates green, none of
which reads this file.

🤖 Generated with Claude Opus 5, at the direction of Paul Campbell.
Reviewed-By: Fable 5.1 (two passes; REQUEST CHANGES on b19f0fa and 31734ff)
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BPUHaNUtTvE7f1VpFWZUHY
Paul Campbell pushed by paul@keymail.dev ea72533557241990a37e6fdae84e7df40957a502 parent a274bbe
1 file changed, +16 −22
  • AGENTS.md +16 −22
diff --git a/AGENTS.md b/AGENTS.md
index 2ecd506..8325786 100644
--- a/AGENTS.md
+++ b/AGENTS.md
@@ -30,14 +30,13 @@ address"** — a magic link's address is at rest between send and click,
sealed (§3.2), not absent — and **"some unidentified person"**: a team-set
fingerprint plus one outside fact names the row (§3.3).
-Three gates enforce it from the first commit that opens a database (§12,
-and §13 step 1 lists all three): a **plaintext grep** over the raw SQLite
-file and WAL **plus this app's store objects**, against a seeded corpus of
-known addresses; a **no-address-at-rest** test asserting the schema has no
-address column and that a full sign-in plus directory upsert **plus rekey**
-leaves no readable address anywhere, **WAL included**; and
-**no-content-in-logs** (gate 9). The skeleton opens no database and so
-carries none of them yet.
+Three gates enforce it (§12; §13 step 1 lists all three): a **plaintext
+grep** over the raw SQLite file and WAL **plus this app's store objects**,
+against a seeded corpus of known addresses; a **no-address-at-rest** test
+asserting the schema has no address column and that a full sign-in plus
+directory upsert **plus rekey** leaves no readable address anywhere, **WAL
+included**; and **no-content-in-logs** (gate 9). Gates 1 and 2 need a
+database and the skeleton has none; gate 9 does not, and is not there yet.
---
@@ -115,30 +114,24 @@ quietly ignored).
home already holds it for its own purposes, so carrying it adds nothing to
what the home knows. Theme passes both. A role fails (a). **"Which
documents you can see" passes (a) and fails (b)** — it hands the home a
- document-level graph it has no business holding, and it is the proposal
- most likely to arrive looking reasonable.
-- **Do not restore the earlier one-sided wording** ("the instance would
- behave identically given a hostile value"). §5.4 records why: it is false
- even for theme, since a hostile value gives an ugly page and an ugly page
- *is* different behaviour — a test its own example fails is a gap someone
- smuggles through — and it assumed the validation that makes it safe, since
- a free-string theme interpolated into CSS is an injection, not an ugly
- page.
+ document-level graph it has no business holding.
+- **Do not restore "the instance would behave identically given a hostile
+ value."** §5.4 retracts it: a hostile theme gives an ugly page, which *is*
+ different behaviour, so the test's own example fails it — and without (a)'s
+ closed set, a free-string theme in CSS is an injection, not an ugly page.
- Assertion expiry is **120 seconds, not "seconds"** — sized to worst-case
cold wake plus clock skew, because the exchange request *is* what wakes a
hibernating instance and a tighter window makes the first sign-in to any
cold instance fail and loop. Widening it costs nothing **against the
threat model**, because **single-use `jti` is what stops replay**, not
- brevity. The long-lived thing is the session
- the instance mints.
+ brevity. The long-lived thing is the session the instance mints.
- Every assertion names the **app and instance host** it is for. Without
audience binding, team A's assertion replays against team B, and a
deployment has thousands of siblings to replay against.
- **Signed identity claims are trusted for identity; every other claim must
be cosmetically failable.** The subject flagrantly fails (a) — a hostile
subject is account takeover — so the test must exempt identity by
- construction or it proves too much and gets
- argued around.
+ construction or it proves too much and gets argued around.
- **Any "prune when all consumers have caught up" is unbounded in a
hibernating fleet.** A dormant instance runs no timers to advance its
cursor. Retention is a fixed horizon or a per-consumer TTL, never a
@@ -164,7 +157,8 @@ quietly ignored).
whole suite directory.
- Migrations are additive-only.
- **No address, team name, or queue payload in any log line, error string,
- job status message or metric label.** Platform-held logs are storage we cannot grep.
+ job status message or metric label.** Platform-held logs are storage we
+ cannot grep.
**Frontend**
- Write `class="rst-*"`. The bare-attribute grammar is ruled but not