@@ 161,6 161,23 @@ tags: [storage, review]
resolve by ID, comment anchors reference IDs, and bots pin to IDs. The service
enforces **global** ID uniqueness via a registry table.
+**Addressing when `id:` is absent or duplicated.** Because
+`--push-option=skip-validation` exists, both states are reachable on the approved
+branch, and the read plane still has to name such a document. The rule, mirroring
+what the merge already does:
+
+- valid and unique in its space → the document is addressed by its ID;
+- absent or malformed → addressed by its path minus the extension;
+- **duplicated → the ID resolves to neither document.** Refusing to guess is the
+ only safe option: silently picking one would make links and search results
+ point at a document the author did not mean, and the ambiguity is invisible.
+
+**Cross-space ID resolution belongs to `service/`, not the read layer.** A
+rendered archive is one space at one revision, so `[[SPEC-0007]]` can only be
+resolved space-locally there. The global hop needs the `document_id` registry,
+which means the link resolver is layered: `doc/` resolves within the space and
+reports misses; `service/` resolves the misses against the registry.
+
**"Approved" is a property of the branch, not of the frontmatter.** A document
reachable from the approved ref is approved; that is the whole definition. Had
`approved` stayed in the `status` enum, either the approved branch would
@@ 326,8 343,14 @@ a volume question, not an architectural one (see the reuse inventory).
### 1. Read plane (anonymous-capable, cached)
-`GET /~user/space/path.md` renders. Content negotiation gives `.md` raw,
-`.json` metadata+body, `?rev=<sha>` pinned to an immutable revision.
+`GET /~user/space/specs/0007-storage` renders. Content negotiation gives
+`.md` raw, `.json` metadata+body, `?rev=<sha>` pinned to an immutable revision.
+
+**URL grammar, pinned.** An earlier draft wrote both "`GET /~user/space/path.md`
+renders" and "`.md` gives raw" — which cannot both be true of one URL. The
+extension is a *format selector*, so the document's own address carries **no**
+extension: `/~user/space/specs/0007-storage` renders, `+ .md` is raw source,
+`+ .json` is metadata plus body.
**Reads default to the approved revision**, with a visible "draft is 3 changes
ahead" affordance. This is the plane bots consume; it must be boring and
@@ 1143,10 1166,14 @@ degrading, which is the point of listing them.
mangles whichever language it was not chosen for. Options: detect language at
index time and write to `ru`/`en` fields, querying both; or accept degraded
stemming on the minority language.
-- **Attachments and binaries.** Diagrams and images in specs mean binary blobs in
- git: no useful diff, unbounded repo growth, and a size-cap decision. Mermaid in
- fenced blocks stays text and diffs properly — possibly worth *preferring* by
- convention over checked-in images.
+- **Attachments and binaries — now a concrete gap, not a hypothetical.** The
+ Space section says a space holds "markdown documents, plus attachments", but
+ the git layer enumerates and accepts **`.md` only**, so `![[diagram.png]]` has
+ nothing to resolve against and renders as visibly missing. Closing it needs a
+ `WalkBlobs`-shaped addition to `gitx` plus an asset index in `doc/`. Deliberately
+ not faked: an invented href would be worse than an honest missing link. The
+ cheaper answer may be to **prefer Mermaid in fenced blocks by convention** —
+ it stays text, diffs properly, and needs none of the above.
- **Agent token distribution.** How a Claude Code session actually acquires a
scoped token — long-lived value in the environment, or minted per session.
Per-session is better for provenance and revocation but needs an issuing flow.