Skip to content

Run the instruction drift check as a step - #94

Merged
sehkone merged 3 commits into
mainfrom
sehkone/issue-93
Sep 10, 2026
Merged

sehkone merged 3 commits into
mainfrom
sehkone/issue-93

Conversation

@sehkone

@sehkone sehkone commented Sep 10, 2026

Copy link
Copy Markdown
Contributor

Closes #93.

The drift check was a job calling aicers/agent-instructions/.github/workflows/check-drift.yml@main as a reusable workflow. Actions is free on a public repository, so there is no bill to cut here — what the arrangement cost was a job: a scheduling slot and a row in every one of the 56 runs of the last thirty days, for nine seconds of byte comparison. As a step it runs inside a job that already exists. aicers/agent-instructions#60 shipped the check as a composite action, and the other consumers already carry it this way.

What changed

  • ci.yml: the instructions job is gone; markdown gains id: checkout on its checkout and - uses: aicers/agent-instructions/check-drift@main as its last step.
  • update-instructions.yml: the header comment said the apply moves the pin in .agents/instructions.toml. No such file exists in any consumer — the pin is .agent-instructions.toml. The other copy of that wrong path was in the job comment this change deletes.

.agent-instructions.toml and the marked blocks in AGENTS.md are untouched, the check does the same work with the same messages, and markdown keeps both its runner and its lint action — this is not a runner move and not a tool change.

Why markdown

In the consumers that have a change filter this placement is forced: the filter counts *.md as inert, AGENTS.md is a .md file, so a pull request confined to a generated region is docs-only and a step in a gated job would be skipped on exactly the change that causes drift.

This workflow has no change filter and no gated job, so that reason does not apply and the choice rests on other grounds: markdown is already the job for this class of file, it is where every sibling consumer keeps the step, and it is the job that would have to stay ungated if a path filter is ever added here.

Why the step is guarded

      - uses: aicers/agent-instructions/check-drift@main
        if: ${{ !cancelled() && steps.checkout.outcome == 'success' }}

A step's default is success(), so without this the drift check would be skipped whenever the lint ahead of it failed — hiding drift on the pull requests that touch the most Markdown. As two jobs they always reported independently, and they are independent. !cancelled() rather than always() so a cancelled run stops; the checkout clause keeps a failed checkout from being reported as drift, since the action fails outright when it cannot read the pin file and that message names the pin for a problem that is not the pin's.

Branch protection

Nothing to edit, and this is the part CI cannot demonstrate. GET /repos/aicers/deploy-core/branches/main/protection answers 404 "Branch not protected", so no status check is required on main and Instructions / check never was. Organization-level rulesets need admin:org to read and were not inspected — worth a maintainer's glance that no organization rule names the check this removes.

Verification

actionlint is clean on the edited file. A drift run and its revert are posted below.

The check was a job calling `check-drift.yml` as a reusable workflow.
Actions is free on a public repository, so nothing was billed for it;
what it cost was a job -- a scheduling slot and a row in all 56
runs of the last thirty days -- for nine seconds of byte comparison. As
a step it runs inside a job that already exists, and the fleet's other
consumers now carry it the same way.

`markdown` hosts it. In the consumers that have a change filter the
placement is forced: AGENTS.md counts as inert documentation there, so a
pull request confined to a generated region is docs-only and a gated
step would be skipped on exactly the change that causes drift. This
workflow has no filter, so the choice rests on `markdown` already being
the job for this class of file -- and on its being the job that would
have to stay ungated if a filter is ever added.

A step's default `success()` would skip it whenever the lint ahead of it
failed, which the two jobs never did to each other, so the step carries
`!cancelled()` and requires only that the checkout succeeded -- the
action reports a workspace it cannot read as a problem with the pin.

The header of update-instructions.yml named `.agents/instructions.toml`,
which exists in no consumer; the pin is `.agent-instructions.toml`.

Closes #93
Temporary: proves the drift check still fails from its new home.
Reverted in the next commit.
Restores the marked block. The failing run it produced is linked from
the pull request.
@sehkone

sehkone commented Sep 10, 2026

Copy link
Copy Markdown
Contributor Author

Test plan results

A drifted block fails. Run 34420363698 (f7bbdcc, one character inside shared:workflow in AGENTS.md) — Markdown failed while every other job passed.

actions/jobs/<id> reports exactly one failed step in it: Run aicers/agent-instructions/check-drift@main. Everything ahead of it passed, so the failure is the drift check and nothing else.

Also visible in the log: pinned to 0.4.0; the latest release is 0.4.0. The pin-behind warning resolved the latest release rather than reporting that it could not; the two look alike in a log and mean opposite things.

The revert goes green. Run 34421767890 (2e48950) — every job success. No job named Instructions / check appears in either run.

@sehkone
sehkone merged commit 4111110 into main Sep 10, 2026
3 checks passed
@sehkone
sehkone deleted the sehkone/issue-93 branch September 10, 2026 02:58
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Run the instruction drift check as a step, not a job

1 participant