Skip to content

chore(plugins): gate the crates the workspace cannot see - #325

Merged
LKSNDRTMLKV merged 2 commits into
mainfrom
chore/gates-that-cannot-pass-vacuously
Sep 21, 2026
Merged

LKSNDRTMLKV merged 2 commits into
mainfrom
chore/gates-that-cannot-pass-vacuously

Conversation

@LKSNDRTMLKV

Copy link
Copy Markdown
Member

Stacked on #322 — both touch plugin sources, so this branches from it rather
than racing it. Retarget to main before #322 merges.

Found auditing what actually runs in just check.

Plugin code had no formatting check and no lint. At all.

exclude = ["plugins/*"] puts the ten plugin crates outside cargo fmt --all
and cargo clippy --workspace. test-plugins covered their behaviour; their
shape was covered by nothing.

Seven of the ten were unformatted when fmt-check-plugins was first run.
Clippy happened to be clean, which is luck rather than a gate.

Adds fmt-check-plugins, lint-plugins and fmt-plugins, wires the first two
into check and into the CI plugins job, and formats the crates so the gate
can pass.

🚨 test-plugins passed vacuously, and that exact bug has bitten before

for plugin in plugins/product-group-*; do ... done
echo "All plugin tests passed."

A loop over a glob that matches nothing succeeds. Demonstrated by simulating the
rename that already happened once:

$ # glob changed to plugins/sector-*
All plugin tests passed.
EXIT=0  <-- green, having tested nothing

These directories were plugins/sector-*. The CI wasm job globbed them, went
silently green at the rename, and gained a [ "$built" -gt 0 ] || exit 1 guard
as a result — its comment says so. That guard was never applied to this recipe,
which is the one just check runs.

Every looping plugin gate now counts what it did and fails on zero.

The guards have their own self-test

A guard nobody has watched fail is itself unverified, so plugin-gates-self-test
runs each loop against a glob that matches nothing and requires a non-zero exit.
It is in check and in CI:

ERROR: no plugins matched
ERROR: no plugins matched
ERROR: no plugins matched
Plugin gate guards fail on an empty match, as they must.

The fmt gate was also mutation-tested — ugly code added to one plugin fails it.

build-plugins no longer carries a hand-written list

It named its ten plugins one per line while test-plugins and the CI wasm job
globbed the same directory. An eleventh plugin would have been tested, linted
and never built. Now globbed, with the same count assertion.

Verification

just check green, 1561/1561, plus:

10 plugin crates formatted correctly.
10 plugin crates linted clean.
All 10 plugin test suites passed.
Plugin gate guards fail on an empty match, as they must.

No CHANGELOG entry: nothing here changes a published crate: the plugin diffs are
cargo fmt output only.

@LKSNDRTMLKV LKSNDRTMLKV added type/defect Something published or encoded here is wrong or unbackable now urgency/next Blocks work already scheduled surface/docs-only Contained to documentation; no code depends on it labels Sep 19, 2026
Base automatically changed from fix/plugins-follow-the-identifier to main September 21, 2026 15:22
@LKSNDRTMLKV
LKSNDRTMLKV force-pushed the chore/gates-that-cannot-pass-vacuously branch from 4bcffd2 to b40a213 Compare September 21, 2026 15:29
@LKSNDRTMLKV

Copy link
Copy Markdown
Member Author

Rebased onto main now that #322 has landed (delta conserved exactly — same file/line stat before and after), plus one change from reviewing it.

plugin-gates-self-test did not test the recipes

It looped for gate in test fmt-check lint and ran the same inline copy of the guard three times — $gate was never referenced inside the body. So it proved a fact about bash (a counted loop with a guard fails on an empty match), not a fact about test-plugins, fmt-check-plugins or lint-plugins. Delete the guard from any one of them and the self-test stays green.

That is the same vacuous pass this PR exists to eliminate, one level up — and by the PR's own standard ("a guard nobody has watched fail is itself unverified"), a self-test nobody has watched catch a real removal is in the same position.

Fix: the four looping recipes take prefix=PLUGIN_PREFIX (one PLUGIN_PREFIX := "product-group" at the top of the justfile, so the prefix also stops being repeated five times), and the self-test drives the real recipes with a prefix that matches nothing. Each guard fires before the loop body, so no cargo invocation happens and it stays fast. build-plugins is now covered too — it has the same guard and was not in the self-test.

Watched to fail, on the case that matters. Deleting the guard from lint-plugins alone:

SELF-TEST FAILED: lint-plugins passed on an empty match
error: Recipe `plugin-gates-self-test` failed with exit code 1

The old self-test passes that mutation; the new one does not.

just check green, 1564/1564, plus 10 plugin crates formatted correctly / 10 plugin crates linted clean / All 10 plugin test suites passed / Plugin gate guards fail on an empty match, as they must.

@LKSNDRTMLKV
LKSNDRTMLKV merged commit 79bcedb into main Sep 21, 2026
20 of 21 checks passed
@LKSNDRTMLKV
LKSNDRTMLKV deleted the chore/gates-that-cannot-pass-vacuously branch September 21, 2026 15:32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

surface/docs-only Contained to documentation; no code depends on it type/defect Something published or encoded here is wrong or unbackable now urgency/next Blocks work already scheduled

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant