#162: spec — the flat layout cannot carry the siblings file safely
Summary
found building Task 9. A flat row writes to /data, which every flat row on the box shares, so two flat hosts wanting a siblings file want the same path and the loser reads another account's pair key. The writer refuses both and decides per directory; the residual hole (a flat row receiving a neighbour's path) is a contract on the reading app, which must check the file's host field.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
1 file changed,
+23
−0
docs/superpowers/specs/2026-09-21-replica-placements-design.md+23 −0
CI passed — run details
diff --git a/docs/superpowers/specs/2026-09-21-replica-placements-design.md b/docs/superpowers/specs/2026-09-21-replica-placements-design.md| index 986ad702f..b2b2d7ed7 100644 |
| --- a/docs/superpowers/specs/2026-09-21-replica-placements-design.md |
| +++ b/docs/superpowers/specs/2026-09-21-replica-placements-design.md |
| @@ -467,6 +467,29 @@ is **omitted** rather than written with an empty `addr`, and the file is |
| written for a home even when its `replicas` list is empty, so the app can |
| tell "no replicas" from "no file" **(fable B-6)**. |
| +**The flat layout cannot carry this file safely** (found in implementation, |
| +Task 9). A nested row writes to `/data/instances/<id>`, which is its own; |
| +a FLAT row writes to `/data`, which every flat row on the box shares. Two |
| +flat hosts that both want a siblings file want the same path, and the |
| +loser's app would read a key minted for another account's pair — and sign |
| +a lease call with it, which that pair's sibling would accept. So: |
| + |
| +- the writer refuses **both** when two flat hosts on a box would share one |
| + directory, logs once naming them, and removes any stale file there; |
| +- the write and the removal decision are made **per directory**, never per |
| + host, or removing one host's file would delete a flat neighbour's; |
| +- the residual hole is not the writer's to close: a flat row with no |
| + replicas of its own still receives `CARLOS_SIBLINGS_FILE=/data/siblings.json`, |
| + which may be a neighbour's file. **The reading app MUST check the file's |
| + `host` field against its own host and ignore a file that names another.** |
| + That is a contract on titogo, stated here and on #162. |
| +- Replica pairs want the nested layout. A deployment that puts a replica |
| + on a flat row gets no file and a log line, which is the fail-closed |
| + direction. |
| + |
| +**No mesh key, no file.** A file whose `keys` list is empty reads as |
| +"armed but unsignable"; the pass writes nothing until the edge has a key. |
| + |
| **The keys** are per *pair*: `HMAC(meshKey, "replica/" + account + "/" + |
| homeHost + "/" + replicaHost)` **(fable 5, adapted)**. Round 1 proposed |
| per-instance keys the home derives itself; the home cannot, because it must |