Skip to content

Commit 71207c8

Browse files
committed
docs(empty-values): sharpen why the server cannot just copy the rule
The section claiming a CLI rule cannot reach API callers had the mechanism wrong. It implied its examples were empty values arriving at the server. They are not: in 162 of the 166 cases an empty value and an absent flag produce an identical payload, so nothing empty ever reaches the server and there is nothing there for it to reject. That is why the server's half is a different rule rather than a mirror of the CLI's. The three examples are now a table, one per kind, with whose problem each payload is in its own column - the CLI's, the server's, or neither. Two of them were being read as the four combinations where an empty value differs from omitting the flag; they are not, they are drawn from the 162 where it does not, which is the whole point of citing them. Dropped "a record the server cannot read back is not one it should accept". The included-environments 500 is a plain defect that will be fixed regardless, and stating it as a rule here prescribed one of two possible fixes - refusing the write, or tolerating the read - which is not this document's call. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
1 parent ccc3cd1 commit 71207c8

1 file changed

Lines changed: 19 additions & 25 deletions

File tree

‎docs/handover/2026-08-13-empty-value-decision.md‎

Lines changed: 19 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -137,31 +137,25 @@ Not every request arrives through the CLI. A customer calling the API directly
137137
keeps all of this, and the warnings in steps 1 and 2 will never see them, so the
138138
measurement they produce covers CLI traffic only.
139139

140-
The findings split by where the behaviour actually lives. Reading the payloads
141-
the CLI sends with `--debug` says which is which.
142-
143-
Some are the CLI's own doing, and a CLI rule genuinely settles them:
144-
145-
- `kosli attest generic --fingerprint ""` sends no fingerprint, to the
146-
trail-scoped endpoint `/attestations/{org}/{flow}/trail/{trail}/generic`. The
147-
CLI picked that endpoint. Someone calling the API chooses the artifact endpoint
148-
or the trail endpoint deliberately, and is not misled.
149-
- `--template-file ""` reading as "no template given" is the CLI's file handling.
150-
151-
Others are the server accepting something it should not, and a direct caller
152-
reaches them just as easily:
153-
154-
- `--included-environments ""` sends a logical environment with **no**
155-
`included_environments` field at all. The server returns 201 and then cannot
156-
read the record back. Any client can send that payload.
157-
- `create environment` sends `"description": ""` when no `--description` was
158-
passed, and the server writes it over whatever was there. The CLI should not
159-
send it, and the server should not treat an empty string as "erase this".
160-
161-
So the two halves want different fixes, and the server half is the one that
162-
covers every client. That makes the server work in step 2 more than a
163-
precondition for the CLI change: it is the part that closes the hole for
164-
everyone.
140+
The server cannot close that gap by copying the rule, because it mostly never
141+
sees an empty value. When an empty value produces the same request as omitting
142+
the flag - which is 162 of the 166 - the server receives an identical payload
143+
either way, and there is nothing empty in it to reject.
144+
145+
Those 162 fall into three kinds, by whose problem the payload turns out to be.
146+
One of each, read with `--debug`:
147+
148+
| Command | What reaches the server | Whose problem |
149+
|---|---|---|
150+
| `kosli attest generic --fingerprint ""` | no fingerprint at all, sent to the trail-scoped endpoint `/attestations/{org}/{flow}/trail/{trail}/generic` | the CLI's. It picked that endpoint. Someone calling the API chooses the artifact endpoint or the trail endpoint deliberately, and is not misled. The rule settles this one |
151+
| `kosli create environment --included-environments ""` | a logical environment with **no** `included_environments` field, which the server accepts with a 201 and then cannot read back. Omitting the flag sends the same thing | neither's, for this decision. It is a plain defect, being fixed on its own account |
152+
| `kosli create environment` | `"description": ""`, whether or not `--description` was passed | the server's. By the time it arrives this is not about empty values at all: it is a request meaning "nothing was specified", treated as an instruction to erase. A direct caller sends the same thing and gets the same result |
153+
154+
So the server's half of this is one rule, and not a mirror of ours: **an absent
155+
or empty field is not an instruction to erase what is stored.** That covers every
156+
client, including the ones the warnings cannot see, which makes the server work in
157+
step 2 more than a precondition for the CLI change - it is the part that closes
158+
the hole for everyone.
165159

166160
## What refusing an empty value would cost
167161

0 commit comments

Comments
 (0)