fix(ci): make every manual gate default to a value that matches nothing #158

Merged
pat-s merged 1 commit from fix/gate-defaults-match-nothing into main 2026-08-09 15:31:15 +00:00
Owner

Problem

A manual crow pipeline create instantiates every file in .crow/, and a declared variable default is applied even when the run never passed that variable. A gate is therefore only a gate if its default matches nothing.

#155 fixed the three pipelines that had no manual gate at all. It missed that a permissive default leaves a pipeline just as exposed. Demonstrated the expensive way: creating a pipeline with only

--var weekly_audit_missing=alpine-324-amd64

also started build-all-versions — because its gate target_arch defaults to amd64, which matches its own amd64 matrix rows — and process-updates across every row, because that gate defaults to all. The run was killed before any Upload package indexes step produced output and both alpine324 indices were verified unchanged, but build-all-versions uploads binaries and rewrites indexes, so the next one might not be caught in time.

Before:

pipeline gate default fired on an unrelated manual run
build-all-versions target_arch amd64 amd64 rows — builds and uploads
build-all-versions-install-deps target_arch amd64 amd64 rows
weekly-rebuild-missing weekly_rebuild_missing all every row
weekly-audit-missing weekly_audit_missing all every row
process-updates process_cran_updates all every row
repair-built-stamp repair_built_stamp arm64 arm64 rows

archive-missed-packages was the one that behaved, because its gate variable is never declared and so matches nothing. That is the property this restores everywhere.

What this changes

Each of the six gets a none option on its gate variable and defaults to it, so a manual run has to name its target explicitly. The reason is recorded next to the default, where someone would go to change it.

none is used rather than dropping the default so the expression always has a defined value to compare, instead of relying on undefined-variable semantics.

Cron triggers are untouched — they match on the cron: name, not the variable.

Verification

crow lint .crow/ reports all ten configs valid. Auditing every pipeline that accepts a manual event:

archive-missed-packages.yaml:        gate=task                    default=<none>
auto-apply-patches.yaml:             gate=auto_apply_patches      default='false'
build-all-versions-install-deps.yaml gate=target_arch             default=none
build-all-versions.yaml:             gate=target_arch             default=none
process-updates.yaml:                gate=process_cran_updates    default=none
repair-built-stamp.yaml:             gate=repair_built_stamp      default=none
trial-build-registry.yaml:           gate=trial_build_registry    default='false'
weekly-audit-missing.yaml:           gate=weekly_audit_missing    default=none
weekly-patch-proposals.yaml:         gate=weekly_patch_proposals  default='false'
weekly-rebuild-missing.yaml:         gate=weekly_rebuild_missing  default=none

Every gate now defaults to something that matches no matrix row.

## Problem A manual `crow pipeline create` instantiates **every** file in `.crow/`, and a declared variable default is applied even when the run never passed that variable. A gate is therefore only a gate if its default matches nothing. #155 fixed the three pipelines that had no manual gate at all. It missed that a *permissive default* leaves a pipeline just as exposed. Demonstrated the expensive way: creating a pipeline with only ``` --var weekly_audit_missing=alpine-324-amd64 ``` also started `build-all-versions` — because its gate `target_arch` defaults to `amd64`, which matches its own amd64 matrix rows — and `process-updates` across every row, because that gate defaults to `all`. The run was killed before any `Upload package indexes` step produced output and both alpine324 indices were verified unchanged, but `build-all-versions` uploads binaries and rewrites indexes, so the next one might not be caught in time. Before: | pipeline | gate | default | fired on an unrelated manual run | | --- | --- | --- | --- | | `build-all-versions` | `target_arch` | `amd64` | amd64 rows — builds and uploads | | `build-all-versions-install-deps` | `target_arch` | `amd64` | amd64 rows | | `weekly-rebuild-missing` | `weekly_rebuild_missing` | `all` | every row | | `weekly-audit-missing` | `weekly_audit_missing` | `all` | every row | | `process-updates` | `process_cran_updates` | `all` | every row | | `repair-built-stamp` | `repair_built_stamp` | `arm64` | arm64 rows | `archive-missed-packages` was the one that behaved, because its gate variable is never declared and so matches nothing. That is the property this restores everywhere. ## What this changes Each of the six gets a `none` option on its gate variable and defaults to it, so a manual run has to name its target explicitly. The reason is recorded next to the default, where someone would go to change it. `none` is used rather than dropping the default so the expression always has a defined value to compare, instead of relying on undefined-variable semantics. Cron triggers are untouched — they match on the `cron:` name, not the variable. ## Verification `crow lint .crow/` reports all ten configs valid. Auditing every pipeline that accepts a manual event: ``` archive-missed-packages.yaml: gate=task default=<none> auto-apply-patches.yaml: gate=auto_apply_patches default='false' build-all-versions-install-deps.yaml gate=target_arch default=none build-all-versions.yaml: gate=target_arch default=none process-updates.yaml: gate=process_cran_updates default=none repair-built-stamp.yaml: gate=repair_built_stamp default=none trial-build-registry.yaml: gate=trial_build_registry default='false' weekly-audit-missing.yaml: gate=weekly_audit_missing default=none weekly-patch-proposals.yaml: gate=weekly_patch_proposals default='false' weekly-rebuild-missing.yaml: gate=weekly_rebuild_missing default=none ``` Every gate now defaults to something that matches no matrix row.
A manual pipeline creation instantiates every file in .crow/, and a declared
variable default is applied even when the run never passed that variable. So a
gate like target_arch, defaulting to amd64, matched its own amd64 matrix rows on
any manual run of any pipeline. Triggering a weekly-audit-missing run for one
slot started build-all-versions (including its Upload package indexes step) and
process-updates across every row.

#155 fixed the three pipelines that had no gate at all; these six had a gate
whose default was permissive, which left them just as exposed.

- add a 'none' option to each gate variable and default to it, so a manual run
  must name its target explicitly
- record why the default must match nothing, next to the default itself

Cron triggers are unaffected: they match on the cron name, not the variable.
pat-s merged commit f8e31af75b into main 2026-08-09 15:31:15 +00:00
pat-s deleted branch fix/gate-defaults-match-nothing 2026-08-09 15:31:15 +00:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
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
devxy/build-cran-binaries!158
No description provided.