Skip to content

release: a workflow-only fix reaches no consumer until an unrelated dep-check release moves v1 (measured: 2-3 days) #52

Description

@usetheodev

Severity: HIGH — every reusable workflow in this repository is delivered by the moving v1
ref, and v1 only advances as a side effect of publishing the @theokit/dep-check npm package.
A change that touches only .github/workflows/** therefore sits on main, correct and merged,
reaching zero of the ten consumers until somebody happens to release the package.

Evidence

release.yml triggers on push: tags: ['dep-check-v*'], and advance-v1 is gated further:

if: needs.publish.result == 'success' && startsWith(github.ref, 'refs/tags/dep-check-v')

Both conditions are right for what they guard. Neither has anything to do with a workflow change.

Measured on this repository's own history:

commit landed on main v1 next moved stale for
863a274 feat(checks-pass) 2026-09-01 13:41 2026-09-04 20:42 (dep-check-v0.10.0) 3d 7h
e1c663a fix(preview) 2026-09-02 16:08 same ~2d 4h
a4c8128 fix(preview) 2026-09-02 18:40 same ~2d 2h
8137d9b fix(preview) 2026-09-02 18:47 same ~2d 2h
2b90a81 fix(preview) 2026-09-02 21:09 same ~2d

Four of those five are fixes to preview.yml, one of them specifically so that a preview which
falls back to publishing everything announces that it is not installable. For two days every
consumer kept producing the silent version, and nothing said so.

Why this is not the same as the pin discipline

dep-check.yml deliberately splits the two: the workflow moves by ref so a policy change
reaches every caller, while the tool is a semver artifact that moves by a bump somebody
reviewed. That reasoning is written at the top of the file and it is correct.

The defect is that the mechanism does not implement it. Today the policy cannot move at all
without the tool moving, which is the exact coupling the split exists to avoid.

Repro

  1. Merge any change that touches only .github/workflows/** into main.
  2. git fetch --tags --force && git rev-parse v1 — still the previous commit.
  3. Any consumer resolving @v1 runs the old workflow, indefinitely.

Suggested fix

Advance v1 on a push to main that changed workflows or composite actions, with the guard that
already exists for the release path: v1 must never point at a commit whose declared
@theokit/dep-check version is not the published one
, or consumers get
npx @theokit/dep-check@<missing> failing at the point of use. That invariant is the real reason
advance-v1 is gated on a successful publish; a workflow-only path needs the same invariant
checked directly rather than inherited from the publish.

Doing it by hand instead is the option this repository already rejected in advance-v1's own
docblock: "Moving it by hand was the last manual step in a release, and it has been missed on two
of six."

Related


How this was found: standardising the promotion gate across the ten consumers, the follow-up
step "convert the consumers to thin callers" required knowing when @v1 would serve the new
workflow. The answer was "at the next unrelated package release".

No secrets, tokens or credentials appear in this report.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions