You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
fix(empty-flag-audit): measure the 23 combinations it could not
The audit reported 23 command-and-flag combinations where nothing could be said,
and the decision document carried a row admitting the gap. None of them were the
CLI's fault.
Twenty were the evaluate commands, run against deny-no-violations.rego, which is
`allow = false`. No run of those commands could exit 0, so an empty value had
nothing to be compared against. They now use allow-all.rego.
Three were `list environments` asking for every environment in an org the audit
had filled with hundreds of them, and timing out. A page limit keeps the request
small enough to answer, and removes the slowest block of the run with it.
`create environment` now runs last. One of its combinations is the
--included-environments bug that 500s an organization's entire environment
listing, so measuring it early left every later `list environments` unmeasurable.
That is the bug's blast radius reaching the audit itself.
Two harness traps went with them. A run limited by --only wrote a results file
containing only what it ran, silently discarding every other result; it now
merges. And each pass writes its own file, so --ci no longer overwrites the
laptop run.
All 374 measured combinations now yield a result. Refused rises 203 from 190,
let-through 166 from 156, and the document's figures follow.
The release argument changes too. This no longer joins the v3 batch: a customer
whose pipeline breaks should be able to read one release note and know why, and
step 2's warnings say when the moment is right independently of whatever else is
queued for v3.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Copy file name to clipboardExpand all lines: docs/handover/2026-08-13-empty-value-decision.md
+51-33Lines changed: 51 additions & 33 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -59,12 +59,11 @@ It measured 374 of the 653 combinations. Of those:
59
59
60
60
| What happens to an empty value | On a laptop | Inside GitHub Actions |
61
61
|---|---|---|
62
-
| the CLI refuses it |190|188|
62
+
| the CLI refuses it |203|201|
63
63
| the CLI accepts it and the server refuses it | 5 | 7 |
64
-
| nothing refuses it | 156 | 156 |
65
-
| the command did not work with any value, so nothing can be said | 23 | 23 |
64
+
| nothing refuses it | 166 | 166 |
66
65
67
-
Of the 156 that nothing refuses, 152 do exactly what omitting the flag does, so
66
+
Of the 166 that nothing refuses, 162 do exactly what omitting the flag does, so
68
67
an empty value there is merely useless. The rest of this document is about the
69
68
ones where it is not.
70
69
@@ -98,8 +97,8 @@ which is all it takes.
98
97
|`kosli attach-policy P --environment "$VAR"`| the policy is attached to no environment. Anything deployed there is judged without it | changes compliance |
99
98
|`kosli detach-policy P --environment "$VAR"`| the policy is detached from no environment, so it stays in force | changes compliance |
100
99
|`kosli create environment E --type logical --included-environments "$VAR"`| the record cannot be read back, and `list environments` returns HTTP 500 for every environment in the org until it is removed |**outright bug**, written up in `2026-08-13-included-environments-500.md`|
101
-
|`kosli list environments --tag "$VAR"`| answers "No environments were found", identical to a real no-match, exit 0 | wrong answer |
102
100
|`kosli create flow F` with no `--description` at all | wipes the description the flow already had. Same for `begin trail` and `create policy`|**outright bug**, no empty value needed, written up in `2026-08-13-description-wiped-on-upsert.md`|
101
+
|`kosli list environments --tag "$VAR"`| answers "No environments were found", identical to a real no-match, exit 0 | wrong answer |
103
102
104
103
Ten findings, from one slice of one CLI, all of them silent. What the rest of the
105
104
space holds we do not know - and that is the argument. We cannot keep finding
@@ -173,19 +172,35 @@ sharper than usual:
173
172
anything, so "breaking" here means pipelines failing with no change on their
174
173
side.
175
174
176
-
We are on v2.36.5, and #1059 already collects breaking changes for v3, which is
177
-
where this belongs - unless we add `--clear-description` at the same time, which
178
-
would keep the one capability this removes and make that part non-breaking.
175
+
We are on v2.36.5, and #1059 collects breaking changes for v3. This does not have
176
+
to join that batch, and I do not think it should:
177
+
178
+
-**A customer whose pipeline breaks should be able to read one release note and
179
+
know why.** A major version carrying ten unrelated breaks cannot tell them
180
+
that.
181
+
-**The v3 batch has been accumulating for a long time.** Tying this to it means
182
+
the compliance holes above stay open until everything else in it is ready.
183
+
-**The right moment for this one is knowable on its own.** Step 2 reports how
184
+
often empty values actually occur, so we can see when the impact has fallen
185
+
far enough to flip the switch. That signal says nothing about whatever else is
186
+
queued for v3.
187
+
188
+
So: this becomes its own major release, and the changes currently queued for v3
189
+
become the one after. Major versions are cheap; a release note nobody can act on
190
+
is not.
191
+
192
+
If we add `--clear-description` at the same time, the one capability this removes
193
+
comes back, and that part stops being breaking at all.
179
194
180
195
### Proposed: four steps
181
196
182
-
156 combinations changing at once is a lot to ask of customers in one upgrade,
197
+
166 combinations changing at once is a lot to ask of customers in one upgrade,
183
198
so the rule arrives in stages.
184
199
185
200
#### Step 1: somewhere to put a warning, in app.kosli.com
186
201
187
202
Nobody reads warnings in a CI workflow run. A step that only prints one is not a
188
-
migration, it is a delay, and we would arrive at v3 knowing no more than we do
203
+
migration, it is a delay, and we would reach step 3 knowing no more than we do
189
204
now. So before the CLI warns about anything, there has to be somewhere for the
190
205
warning to go.
191
206
@@ -194,7 +209,7 @@ A warning goes to two places, and no more than two:
194
209
1.**The workflow run**, printed as now.
195
210
2.**app.kosli.com, at the org level.** A command that has `--org` and
196
211
`--api-token` can send the warning whatever else it was doing, so this covers
197
-
153 of the 156. The exception is `kosli fingerprint`, which is entirely local
212
+
163 of the 166. The exception is `kosli fingerprint`, which is entirely local
198
213
and needs no credentials.
199
214
200
215
This is work in app.kosli.com: somewhere to receive the warnings, and one place
@@ -207,12 +222,15 @@ Fix the two outright bugs - the description wiping and the
207
222
the flag, and report it. Nothing starts failing, and anyone whose pipeline has an
208
223
unset variable can see it and fix it before it costs them anything.
209
224
210
-
#### Step 3: the warning becomes the error, in v3
225
+
#### Step 3: the warning becomes the error, in a major release of its own
226
+
227
+
One guard, one migration, one release note, and nothing else breaking in the same
228
+
version. Ship `KOSLI_ALLOW_EMPTY_FLAG_VALUES=true` alongside it as an escape
229
+
hatch, so anyone caught out has a one-line unblock while they fix the pipeline,
230
+
and remove it in the next major release.
211
231
212
-
One guard, one migration, one release note. Ship
213
-
`KOSLI_ALLOW_EMPTY_FLAG_VALUES=true` alongside it as an escape hatch, so anyone
214
-
caught out has a one-line unblock while they fix the pipeline, and remove it in
215
-
v4.
232
+
When to ship it is a question step 2 answers: when the reported warnings have
233
+
fallen far enough that the remaining breakage is small and known.
216
234
217
235
#### Step 4: delete what the guard replaced
218
236
@@ -221,12 +239,12 @@ one rule covers every flag. This is the step that is easiest to skip and the
221
239
reason the CLI is inconsistent today, so it belongs in the plan rather than in
222
240
someone's memory.
223
241
224
-
### Why steps 1 and 2 come before v3
242
+
### Why steps 1 and 2 come first
225
243
226
244
Reporting warnings is not only a kindness to customers. It answers the question a
227
-
v3 release note cannot: how much would v3 actually break? Today that is an
228
-
argument. With this, by the time v3 is due, it is a number, per org, and we can
229
-
tell the customers who are affected before it lands rather than after.
245
+
release note cannot: how much would step 3 actually break? Today that is an
246
+
argument. With thisit becomes a number, per org, and we can tell the customers
247
+
who are affected before it lands rather than after.
230
248
231
249
It also reaches where this audit could not. The 279 combinations on commands
232
250
needing AWS, Azure, a git provider and the rest are unmeasured here for want of
@@ -279,15 +297,15 @@ the 152 names are:
279
297
280
298
| What the flag is for, with a few examples | Names | Does an empty value mean anything? | CLI always refuses | Only the server refuses | Refuses on some commands | Never refuses | Not measured |
281
299
|---|---|---|---|---|---|---|---|
282
-
| identity and selection - `--flow`, `--trail`, `--fingerprint`, `--name`| 46 | no. There is no artifact called "" | 12 |2|7|12| 13 |
283
-
| location and input - `--template-file`, `--results-dir`, `--paths`| 26 | no. There is no file called "" |6| 1 | 0 |7| 12 |
0 commit comments