@@ 543,12 543,11 @@ who did what.
### Provenance
-Per-space (or per-project) tokens with a role — `reader` / `proposer` /
-`writer` — and a **required agent identity string**. Every commit records it in
-a way that survives clone:
+One agent token (no roles, no per-space scopes — see above) plus a **required
+agent identity string**. Every commit records it in a way that survives clone:
```
-Author: claude-code/spec-writer (for bigbes) <agent@srht.bigb.es>
+Author: claude-code/spec-writer (for bigbes) <agent@spec.srht.bigb.es>
Committer: bigbes <bigbes@gmail.com>
Add storage model section
@@ 560,6 559,31 @@ Committer: bigbes <bigbes@gmail.com>
Git trailers rather than a Postgres-only audit table, so provenance is visible in
plain `git log` on any clone and cannot drift from the content it describes.
+Details settled during implementation, recorded here because the sketch above
+left them open:
+
+- **The agent mailbox is derived, not configured.** `agent@<host of
+ [spec.sr.ht] origin>` — so `agent@spec.srht.bigb.es`. Earlier drafts wrote
+ `agent@srht.bigb.es` (the bare cookie domain) with no stated source. Deriving
+ it from our own origin adds no config key and cannot drift from it.
+- **`X-Agent-Base` is mandatory**, validated as 7–64 lowercase hex. An empty base
+ is a provenance claim with nothing behind it, which would make the trailer
+ decorative rather than auditable — the thing the read-contract decision was
+ supposed to buy. It must be an object name, never a ref name.
+- **Agents transmit identity over `X-Agent` / `X-Agent-Session` request
+ headers**, named after the trailers they become. Deliberately **no**
+ `X-Agent-Base` header: the base is `If-Match`, and a second spelling of one
+ value is exactly how REST and MCP drift apart. The MCP tools map arguments onto
+ the same three values.
+- **A logged-in human who is not the owner resolves to anonymous**, with the
+ cookie name kept for logs only. Single-user makes this correct today; it is the
+ line to revisit if anyone else ever gets an account.
+- **Cookie expiry is not enforceable and is not enforced.** The unified-login
+ cookie carries no service-side TTL, and core-go's own `cookieAuth` uses
+ `DecryptWithoutExpiration`. We match it, so "expired" collapses into "sealed
+ with a key we no longer hold" — i.e. **rotating `[sr.ht] network-key` is the
+ only logout-everywhere lever**, instance-wide.
+
MCP is a **first-class surface, not a wrapper** — it is how agents will actually
consume this: `spec_search`, `spec_read`, `spec_propose`, `spec_comment`,
`spec_status`. warren's `mcpsrv/` is the starting point.