~bigbes/sr-ht-spec

5d3d94414bf7dfcc83ca765822b436167914fdae — bigbes 27 days ago 305bb09
docs: pin URL grammar, document addressing, and the attachment gap

The read plane specified both that /~user/space/path.md renders and that
.md returns raw source, which cannot both hold for one URL. Extensions are
format selectors, so a document's own address carries none.

Adds the addressing rule for documents whose id is absent or duplicated,
which skip-validation makes reachable on the approved branch. A duplicated
id resolves to neither document: picking one silently would aim links and
search results at a document nobody chose, with no visible sign.

Records that cross-space id resolution cannot live in the read layer,
since an archive is one space at one revision; the global hop needs the
registry and therefore belongs in service/.

Promotes attachments from a hypothetical to a measured gap: the git layer
walks and accepts .md only, so embeds have nothing to resolve against.
1 files changed, 33 insertions(+), 6 deletions(-)

M docs/DESIGN.md
M docs/DESIGN.md => docs/DESIGN.md +33 -6
@@ 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.