Let a grant declare its own value-taking flags #335

Merged
coilyco-ops merged 1 commit from umbra/claude/ee98-valueflag into main 2026-08-29 11:26:08 +00:00
Owner

positionals() consulted one hardcoded table to know that --region us-east-1 is two tokens rather than a flag and a positional. Every entry in it is an AWS CLI global. So for kubectl get pods --context ser8 it returned:

[get pods ser8]

and an argN guard read the flag's value believing it read a resource name.

Nothing is broken today. No kubectl grant carries such a guard, and when on a flag selector never consults the table (flagValue() scans argv directly), which is why the guard in agentic-os#1349 binds correctly. This is the trap laid for whoever writes the next one, and it fails in the direction that does not announce itself.

Two halves, because either alone still permits a silent bind

  • value-flag <name> on a grant, merged over the built-ins, so a guardfile states its own tool's shape instead of inheriting one vendor's.
  • A build-time refusal: a grant guarding argN/any-arg while allowing a long flag that neither the table nor its own list names is rejected when the guardfile parses. The arity cannot be inferred from the flag, and guessing is exactly what produced the silence. Declaring it either way is the fix - as a value-taker so the value is consumed, or to state that it is boolean.

Runtime behavior is unchanged for every guardfile that parses today.

Measured

positionals([get pods --context ser8])              -> [get pods ser8]
positionals([get pods --context ser8], "--context") -> [get pods]

Three tests cover it, including that a flag selector still needs no declaration, so the fix does not tax the guards that were never affected.

docs/execverb.md already predicted this: the table "is one vendor's shape and belongs in the guardfile" (umbra#282). It does now.

Refs coilyco-flight-deck/agentic-os#1351

`positionals()` consulted one hardcoded table to know that `--region us-east-1` is two tokens rather than a flag and a positional. **Every entry in it is an AWS CLI global.** So for `kubectl get pods --context ser8` it returned: ``` [get pods ser8] ``` and an `argN` guard read the flag's *value* believing it read a resource name. Nothing is broken today. No kubectl grant carries such a guard, and `when` on a **flag** selector never consults the table (`flagValue()` scans argv directly), which is why the guard in agentic-os#1349 binds correctly. This is the trap laid for whoever writes the next one, and it fails in the direction that does not announce itself. ## Two halves, because either alone still permits a silent bind * **`value-flag <name>`** on a grant, merged over the built-ins, so a guardfile states its own tool's shape instead of inheriting one vendor's. * **A build-time refusal**: a grant guarding `argN`/`any-arg` while allowing a long flag that neither the table nor its own list names is rejected when the guardfile parses. The arity cannot be inferred from the flag, and guessing is exactly what produced the silence. Declaring it either way is the fix - as a value-taker so the value is consumed, or to state that it is boolean. Runtime behavior is unchanged for every guardfile that parses today. ## Measured ``` positionals([get pods --context ser8]) -> [get pods ser8] positionals([get pods --context ser8], "--context") -> [get pods] ``` Three tests cover it, including that a **flag** selector still needs no declaration, so the fix does not tax the guards that were never affected. `docs/execverb.md` already predicted this: the table "is one vendor's shape and belongs in the guardfile" (umbra#282). It does now. Refs coilyco-flight-deck/agentic-os#1351
feat(execverb): let a grant declare its own value-taking flags
All checks were successful
ci / secrets (pull_request) Successful in 10s
ci / lint (pull_request) Successful in 40s
ci / test (pull_request) Successful in 53s
558aeeb84c
`positionals()` consulted one hardcoded table to know that `--region
us-east-1` is two tokens. Every entry in it is an AWS CLI global, so for
`kubectl get pods --context ser8` it returned ["get","pods","ser8"] and an
`argN` guard read the flag's value believing it read a resource name.

Nothing is broken today: no kubectl grant carries such a guard, and `when`
on a flag selector never consults the table. This is the trap for whoever
writes the next one, and it fails in the direction that says nothing.

Two halves, because either alone still allows a silent bind:

* `value-flag <name>` on a grant, merged over the built-ins, so a guardfile
  states its own tool's shape rather than inheriting one vendor's.
* a grant guarding `argN`/`any-arg` while allowing a long flag neither the
  table nor its own list names is refused when the guardfile parses. The
  arity cannot be inferred, so guessing is what produced the silence.

docs/execverb.md already said the table "is one vendor's shape and belongs
in the guardfile" (umbra#282). It does now.

Refs coilyco-flight-deck/agentic-os#1351

Co-authored-by: Kai Siren <coilysiren@gmail.com>
Co-authored-by: Claude <noreply@anthropic.com>
Agent-Role: platform
coilyco-ops deleted branch umbra/claude/ee98-valueflag 2026-08-29 11:26:08 +00:00
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
coilyco-flight-deck/umbra!335
No description provided.