matches takes one glob, so a fixed vocabulary cannot be enumerated and a near-miss passes the guard #324

Closed
opened 2026-08-27 04:16:39 +00:00 by coilyco-ops · 0 comments
Owner

Follow-up to #322, filed before the primitive has any consumer, so this is a shape fix rather than a break.

The hole

#322 shipped matches "<glob>" with exactly one glob, and made a second argument a parse error. That was the wrong call in two ways.

It does not match its siblings. Every other glob guard in the DSL is variadic: restrict <param> matches <glob...> at wrap scope, and when/deny-when <sel> matches <glob...> in execverb. A one-glob matches is the odd one out, and the reason it exists is that I did not think about the alternation case rather than a decision.

It forces a wildcard where the vocabulary is fixed, and the wildcard leaks. Constraints stack with AND, so "one of these four" is not expressible and the author has to write autonomy/*. Measured against the real Forgejo endpoint that consumes this, a name outside the vocabulary is dropped silently with a 200:

$ aosguard ops forgejo issue-label add coilyco-flight-deck agentic-os 1310 \
      --body-file <<< '{"labels":["priority/NOPE"]}'
EXIT=0
- name: autonomy/headless      <- the issue's EXISTING labels, echoed back
- name: priority/P4
$ # labels afterwards: unchanged

So under priority/* a typo like priority/p2 or priority/P9 passes the guard, the write proceeds, and nothing is applied. The control reports success over exactly the hazard it exists to prevent, which is the silent-success shape #316 removed for numeric ids and agentic-os#1047 is about.

The change

Make the globs within one constraint alternatives, variadic like restrict:

matches "priority/P[0-4]" message="..."
matches "autonomy/headless" "autonomy/live-collab" "autonomy/async-consult" "autonomy/epic" message="..."

Alternation within a constraint, AND across constraints, so a refusal still names one axis. An enumerated vocabulary then refuses a near-miss before the write instead of passing it to an endpoint that ignores it.

Note

A branch is ready and opens as a PR. agentic-os#1105 is the first consumer and has not landed its guardfile yet, so nothing is pinned to the one-glob form.

Follow-up to #322, filed before the primitive has any consumer, so this is a shape fix rather than a break. ## The hole #322 shipped `matches "<glob>"` with exactly one glob, and made a second argument a parse error. That was the wrong call in two ways. **It does not match its siblings.** Every other glob guard in the DSL is variadic: `restrict <param> matches <glob...>` at wrap scope, and `when`/`deny-when <sel> matches <glob...>` in execverb. A one-glob `matches` is the odd one out, and the reason it exists is that I did not think about the alternation case rather than a decision. **It forces a wildcard where the vocabulary is fixed, and the wildcard leaks.** Constraints stack with AND, so "one of these four" is not expressible and the author has to write `autonomy/*`. Measured against the real Forgejo endpoint that consumes this, a name outside the vocabulary is dropped **silently with a 200**: ``` $ aosguard ops forgejo issue-label add coilyco-flight-deck agentic-os 1310 \ --body-file <<< '{"labels":["priority/NOPE"]}' EXIT=0 - name: autonomy/headless <- the issue's EXISTING labels, echoed back - name: priority/P4 $ # labels afterwards: unchanged ``` So under `priority/*` a typo like `priority/p2` or `priority/P9` passes the guard, the write proceeds, and nothing is applied. The control reports success over exactly the hazard it exists to prevent, which is the silent-success shape #316 removed for numeric ids and agentic-os#1047 is about. ## The change Make the globs within one constraint alternatives, variadic like `restrict`: ```kdl matches "priority/P[0-4]" message="..." matches "autonomy/headless" "autonomy/live-collab" "autonomy/async-consult" "autonomy/epic" message="..." ``` Alternation **within** a constraint, AND **across** constraints, so a refusal still names one axis. An enumerated vocabulary then refuses a near-miss before the write instead of passing it to an endpoint that ignores it. ## Note A branch is ready and opens as a PR. `agentic-os#1105` is the first consumer and has not landed its guardfile yet, so nothing is pinned to the one-glob form.
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#324
No description provided.