The immediate breakage is already fixed upstream (zig-utils/zig-js#625, merged). This is so it cannot happen again from a repository nobody here pushed to.
What went wrong
build.zig.zon reaches zig-js and its zig-regex / zig-gc by relative path, so Zig's package manager has no .url + hash to verify and nothing recorded which revision a build used. This action cloned each default branch — which hands the question of whether craft's CI is green to whoever last pushed to another repo.
That is not hypothetical. zig-js sized a SIMD loop by @sizeOf(@Vector(8, u8)), which is 8 on aarch64 and 16 on x86_64. Every Linux job here failed to compile for three days over a change nobody made in this repo — and because macOS stayed green, it read as a platform problem rather than a dependency one.
The action's own comment already conceded the point ("an unrelated push to zig-js can turn a craft build red") and deferred it to a future .url + hash dependency. That still needs zig-js to publish its own dependencies the same way, and this is cheap in the meantime.
What this does
Revisions live in pins.env next to the action:
# fix(lexer): size the SIMD identifier scan by lane count, not byte size (#625)
zig_js=eba3f7cfb8b32d6d84099b10f0e063fa0e0c53c7Bumping one becomes a commit that says which revision changed and why, with CI proving it before it lands. "Whatever main happened to be at 13:32" said neither.
Two details that matter:
- The fetch takes the pinned commit, not the branch tip. A pin may point at something that is no longer the tip, and
--depth 1on a branch would not reach it. - A checkout already at the pin is left alone; one at any other revision is replaced. Several jobs call this action and some run it more than once, so a stale tree must not quietly win.
Local development is untouched: developers still build against their own sibling checkouts, and pins.env is read only by this CI action.
Verification
I ran the action's script directly against a simulated workspace rather than only reading it:
| case | result |
|---|---|
| fresh workspace | all three fetched by SHA in ~8s; the checked-out lexer.zig has const lanes = @typeInfo(Block).vector.len |
| run again unchanged | zig-js already at eba3f7c… — no refetch |
checkout moved to HEAD~1 | zig-js pinned at eba3f7c…, and rev-parse HEAD confirms it moved back |
This PR's own Linux jobs are the real test: they exercise the new action on every leg.