← 1.0.0 backlogs ISS-5

A composed operation's rows come back flat and unlabelled

Type
Debt — a wire-contract limit, written down rather than fixed
Found while
SAPE-20
Triage
Defer
Status
Open
Severity
Medium — caps what composition is usable for, and the fix is a compatibility break

Description

A composed operation calls several declared operations and hands back one Result. Every step's rows land in one flat list, in step order, and nothing in that list says which step a row came from.

// internal/store/batch.go:164
into.Rows = append(into.Rows, sub.Rows...)
into.Count = len(into.Rows)

So a caller that composes "the page" and "the total" gets a list and has to tell the two apart by what is in the documents. Two legs over the same collection are indistinguishable.

Evidence

Triage

Does it lose data, break a promise on a public surface, or stop somebody installing and running? No. Nothing is lost — every row is there, in a defined order. Nothing is promised that is not delivered: the limit is documented at the function that causes it and in the CHANGELOG entry for composed operations, so a caller is told before they hit it. Nothing is blocked: the documented use — legs whose shapes differ — works.

Defer, and this is the deferral in this list that deserves the most discomfort, because the reason to fix it in 1.0.0 is not the triage question but the price of waiting. Labelling the answer means changing what Result looks like on the wire, and that is a public surface that freezes at the tag.

It is deferred anyway because the shape of the fix is not decided, and shipping a half-decided wire change is worse than shipping a documented limit. A per-step key, a nested result per leg, and a synthetic column are three different products, and choosing under release pressure is how a compatibility surface acquires a field somebody regrets.

If deferred, what it costs to wait