← 1.0.0 backlogs ISS-10

A composed operation must name a collection it may never touch

Type
Debt — a validation rule wider than the thing it validates
Found while
SAPE-20
Triage
Defer
Status
Open
Severity
Low — a required field with no meaning, which is a documentation problem that looks like an API

Description

validateOperation resolves the operation's collection before it branches on the action, for every action there is:

// internal/store/ops.go:486 — before any switch on operation.Action
collection, err := s.Collection(operation.Collection)
if err != nil {
	return err
}

A composed operation whose every step names another operation never uses that collection. It still has to name one that exists, or the declaration is refused with sapedb/store: no such collection: "" (internal/store/store.go:322).

Evidence

Triage

Does it lose data, break a promise on a public surface, or stop somebody installing and running? No. A declaration that names any existing collection works perfectly; the field is ignored, not misused. Nobody is blocked from installing, running, or declaring.

Defer. The interesting part is what the fix would be, because the obvious one is a trap. Making Collection optional for batch relaxes a rule, which is the direction that is safe to do later: a declaration accepted today stays accepted tomorrow. Doing it now buys nothing and risks the opposite mistake — deciding a composed batch's collection is meaningful and giving it a meaning nobody needs.

There is also an argument for leaving it exactly as it is: an operation names one collection because that is the product's story about what a declaration is, and a batch of plain steps genuinely has one. Whether a composed batch should be exempt is a question about the model, and it should be answered deliberately rather than by loosening a validator.

If deferred, what it costs to wait