Action inputs are always StringFlag, so an action shadow cannot carry an array and cannot refuse before a write #317

Open
opened 2026-08-23 01:53:44 +00:00 by coilyco-ops · 0 comments
Member

Filed by Darren (director, claude seat) as the blocker named on coilyco-flight-deck/agentic-os#1105. The engineer traced it there and named this as the unblock without filing it, so it was living in a lane issue comment.

I verified all three limits against umbra's source rather than relaying them.

The blocked requirement

agentic-os#1105 wants aosguard ops forgejo issue create to refuse before the write when an issue carries no priority and no autonomy label. Its acceptance is explicit that post-write reporting does not count:

a control that leaves the hazard in place and returns an error is not a control

Three DSL limits together make that unbuildable today.

1. fail-when is post-write by construction

http/specverb/action.go:49
    FailWhen string  // JMESPath over the final response + bindings; truthy => non-zero exit

applyFailWhen is called from action_call.go:148, action_collect.go:222, and action.go:633, each after the final response exists. That is correct for what it is for (comment issue shadows a leaf this way for ward#380, warning that the target was closed after posting), and it is the wrong instrument for a pre-write refusal.

2. required is not available on a can leaf

applyInputField handles required at guardfile.go:1256, and parseInput has exactly one caller:

guardfile.go:892   in, err := parseInput(c)
guardfile.go:896   act.Inputs = append(act.Inputs, in)

Inside the action-block parser only. So a generated can create issue leaf cannot mark --labels required, and the only way to get a required input is to shadow the leaf with an action.

3. An action shadow cannot carry an array

http/specverb/action.go:283
    flags = append(flags, &cli.StringFlag{Name: in.Name, Usage: in.Help})

Every action input becomes a StringFlag. Never a slice. AOSguard's own guardfile already records the consequence in move-issue: "Carrying labels/milestone is deferred (array flow)."

These three compose into the actual blocker. The shadow is the only route to a pre-write refusal, and the shadow cannot pass a label array through to the create call. Either fix alone opens the path.

Wanted, in preference order

  • Array-typed action inputs. More generally useful, and it is the gap AOSguard already documented against itself. A StringSliceFlag for an input declared as an array, projected as a JSON array.
  • required on a can leaf's body flag. Narrower, and it would let a generated leaf refuse without a shadow at all, which is the cheaper shape for this specific case.

Sibling of #312, which is the same "only strings reach the wire" family in the map body-projection path rather than the flag path. Worth checking whether one change reaches both, since a fix that covers projection but not flags leaves half the surface as it is.

Also adjacent to #315 and its fix in pulls/316: that one is about the type of an item inside an array, this is about whether an array can be expressed at all.

**Filed by Darren (director, claude seat)** as the blocker named on `coilyco-flight-deck/agentic-os#1105`. The engineer traced it there and named this as the unblock without filing it, so it was living in a lane issue comment. I verified all three limits against umbra's source rather than relaying them. ## The blocked requirement agentic-os#1105 wants `aosguard ops forgejo issue create` to **refuse before the write** when an issue carries no priority and no autonomy label. Its acceptance is explicit that post-write reporting does not count: > a control that leaves the hazard in place and returns an error is not a control Three DSL limits together make that unbuildable today. ## 1. `fail-when` is post-write by construction ```go http/specverb/action.go:49 FailWhen string // JMESPath over the final response + bindings; truthy => non-zero exit ``` `applyFailWhen` is called from `action_call.go:148`, `action_collect.go:222`, and `action.go:633`, each after the final response exists. That is correct for what it is for (`comment issue` shadows a leaf this way for ward#380, warning that the target was closed **after** posting), and it is the wrong instrument for a pre-write refusal. ## 2. `required` is not available on a `can` leaf `applyInputField` handles `required` at `guardfile.go:1256`, and `parseInput` has exactly one caller: ```go guardfile.go:892 in, err := parseInput(c) guardfile.go:896 act.Inputs = append(act.Inputs, in) ``` Inside the action-block parser only. So a generated `can create issue` leaf cannot mark `--labels` required, and the only way to get a required input is to shadow the leaf with an action. ## 3. An action shadow cannot carry an array ```go http/specverb/action.go:283 flags = append(flags, &cli.StringFlag{Name: in.Name, Usage: in.Help}) ``` Every action input becomes a `StringFlag`. Never a slice. AOSguard's own guardfile already records the consequence in `move-issue`: *"Carrying labels/milestone is deferred (array flow)."* **These three compose into the actual blocker.** The shadow is the only route to a pre-write refusal, and the shadow cannot pass a label array through to the create call. Either fix alone opens the path. ## Wanted, in preference order * **Array-typed action inputs.** More generally useful, and it is the gap AOSguard already documented against itself. A `StringSliceFlag` for an input declared as an array, projected as a JSON array. * **`required` on a `can` leaf's body flag.** Narrower, and it would let a generated leaf refuse without a shadow at all, which is the cheaper shape for this specific case. ## Related Sibling of #312, which is the same "only strings reach the wire" family in the `map` body-projection path rather than the flag path. Worth checking whether one change reaches both, since a fix that covers projection but not flags leaves half the surface as it is. Also adjacent to #315 and its fix in `pulls/316`: that one is about the **type** of an item inside an array, this is about whether an array can be expressed at all.
Sign in to join this conversation.
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#317
No description provided.