← 1.0.0 scope SAPE-9

Name collision: decide whether namespaces exist — the deliverable is the decision

Status
To do
Component
server
Priority
High — unrecoverable after the tag either way
Blocked by
Blocks

Description

Decide whether operation names are namespaced, and write the decision down with its reasoning. There are two answers and this ticket is done when one of them is chosen: namespaces exist, or names are flat forever and the collision behaviour is documented as intended. This ticket is not an instruction to build namespaces. It is an instruction to stop the question being open at tag time.

Why now

Naming is the flat-out worst thing to leave undecided across a 1.0 boundary. Adding namespaces later changes what an existing name means, and every operation anybody declared is addressed by one. Deciding "no namespaces" later is equally impossible if somebody has already been given a way to write a qualified name. Both doors close at the tag; this ticket picks which one closes.

Measured 2026-09-20. There is no namespace. Searching every .go file for namespace finds two hits, both in sapedb_test.go (lines 32 and 34) and both about Go's own package scope, not about operation names. The collision behaviour is in internal/store/ops.go:367, DeclareOperation: operation.Version = 1, then if found { operation.Version = latest.Version + 1 }. Declaring a name that already exists does not fail and does not warn — it creates version N+1 of the existing name, keeps the older versions, and returns success. Two unrelated authors choosing orders.list produce one operation with two versions, and the second author's declaration silently becomes the one Invoke reaches, because Invoke takes the newest.

pipelines/tasks/0071 adds a reason this decision cannot wait for the external-operations group to land first: the recommended v1 shape for an external operation is an OperationBundle — one or more store.Operations declared under a signature — and every operation inside a bundle is still just a name in the same flat table DeclareOperation already writes to. A stranger's bundle and a name already declared on the target server collide exactly the way two unrelated authors do in the blockquote above, silently, by this ticket's own measurement — there is nothing about "external" that changes the collision rule. Whichever way this ticket decides, that decision is what an OperationBundle author has to be told before they publish one.

Acceptance criteria

  1. A written decision exists, naming which of the two answers was chosen and why. A ticket closed with neither answer written down is not closed.
  2. The behaviour in the blockquote is covered by a test that asserts it deliberately, whichever way the decision goes — so the current silent-versioning is either proved intentional or proved changed.
  3. If the decision is "no namespaces": the flat-name rule and the collision consequence are on the documentation page that tells people how to name an operation, in the place they read before choosing a name rather than after.
  4. If the decision is "namespaces": every existing unqualified name still resolves, proved by declaring an operation the old way and invoking it by its old name. The migration for zero deployed databases is free, and the test is what proves it stayed free.
  5. Either way, the decision is cited from SAPE-2's policy document under declaration semantics, since that is the surface it freezes.

Out of scope