Summary
docs/conventions/ecosystem-commands/ecosystem.schema.json defines a structured gates array (name/cmd/trigger-globs/remediation) that any ecosystem config — bundled or consumer-tracked — can declare. Demonstrated in docs/conventions/ecosystem-commands/examples/dotnet.yaml's nuget-lockfile-drift entry (pre-existing) and, as of PR #910, plugins/toolchain/reference/ecosystems/go.yaml's go-mod-tidy-drift entry.
Neither plugins/toolchain/skills/check/SKILL.md nor skills/lint/SKILL.md actually execute this resolved array. The only gate-execution mechanism either skill documents is "Project-declared CI-parity gates" (check/SKILL.md line ~121), which is explicitly prose-based and consumer-CLAUDE.md-only — "These live in the consumer's own conventions (its CLAUDE.md / rules / commands reference) — this plugin ships none of its own." That sentence is itself now stale once a bundled ecosystem YAML does ship a gates entry.
Net effect: a gates entry in any ecosystem config (bundled default or a consumer's own tracked .claude/ecosystems/<eco>.yaml) is currently inert — resolved as part of the four-rung ladder's command surface, never invoked by any documented workflow step.
Where this was caught
Surfaced by an automated Codex review pass on PR #910 (plugins/toolchain/reference/ecosystems/go.yaml line 42 / plugins/toolchain/skills/check/SKILL.md line 121) while adding the Go ecosystem's go-mod-tidy-drift gate. Confirmed by re-reading check/SKILL.md in full — no loop/step consumes the resolved gates field anywhere.
Scope
Cross-cutting toolchain plugin change (affects every ecosystem that declares or could declare gates, not Go-specific) — deliberately not folded into #832's PR, which is scoped to adding the Go ecosystem itself. The go-mod-tidy-drift entry in go.yaml is left in place (schema-correct, matches the existing example-fixture precedent, documents intent) — it will start actually running once this is wired up, with no further Go-specific change needed.
Suggested fix shape
Add a step to check/SKILL.md (and lint/SKILL.md if applicable) that, after resolving each affected ecosystem's command surface, iterates its resolved gates array and runs each gate.cmd when the changed-files set matches gate.trigger-globs, reporting pass/fail + gate.remediation on failure — same reporting shape already described for "project-declared" gates, just sourced from the structured array instead of requiring consumer CLAUDE.md prose. Update the stale "this plugin ships none of its own" sentence once real bundled gates exist.
Work-class: C3 (bug-fix-shaped) — attended triage 2026-07-23, operator-ratified. 🤖
Summary
docs/conventions/ecosystem-commands/ecosystem.schema.jsondefines a structuredgatesarray (name/cmd/trigger-globs/remediation) that any ecosystem config — bundled or consumer-tracked — can declare. Demonstrated indocs/conventions/ecosystem-commands/examples/dotnet.yaml'snuget-lockfile-driftentry (pre-existing) and, as of PR #910,plugins/toolchain/reference/ecosystems/go.yaml'sgo-mod-tidy-driftentry.Neither
plugins/toolchain/skills/check/SKILL.mdnorskills/lint/SKILL.mdactually execute this resolved array. The only gate-execution mechanism either skill documents is "Project-declared CI-parity gates" (check/SKILL.mdline ~121), which is explicitly prose-based and consumer-CLAUDE.md-only — "These live in the consumer's own conventions (itsCLAUDE.md/ rules / commands reference) — this plugin ships none of its own." That sentence is itself now stale once a bundled ecosystem YAML does ship agatesentry.Net effect: a
gatesentry in any ecosystem config (bundled default or a consumer's own tracked.claude/ecosystems/<eco>.yaml) is currently inert — resolved as part of the four-rung ladder's command surface, never invoked by any documented workflow step.Where this was caught
Surfaced by an automated Codex review pass on PR #910 (
plugins/toolchain/reference/ecosystems/go.yamlline 42 /plugins/toolchain/skills/check/SKILL.mdline 121) while adding the Go ecosystem'sgo-mod-tidy-driftgate. Confirmed by re-readingcheck/SKILL.mdin full — no loop/step consumes the resolvedgatesfield anywhere.Scope
Cross-cutting
toolchainplugin change (affects every ecosystem that declares or could declaregates, not Go-specific) — deliberately not folded into #832's PR, which is scoped to adding the Go ecosystem itself. Thego-mod-tidy-driftentry ingo.yamlis left in place (schema-correct, matches the existing example-fixture precedent, documents intent) — it will start actually running once this is wired up, with no further Go-specific change needed.Suggested fix shape
Add a step to
check/SKILL.md(andlint/SKILL.mdif applicable) that, after resolving each affected ecosystem's command surface, iterates its resolvedgatesarray and runs eachgate.cmdwhen the changed-files set matchesgate.trigger-globs, reporting pass/fail +gate.remediationon failure — same reporting shape already described for "project-declared" gates, just sourced from the structured array instead of requiring consumer CLAUDE.md prose. Update the stale "this plugin ships none of its own" sentence once real bundled gates exist.Work-class: C3 (bug-fix-shaped) — attended triage 2026-07-23, operator-ratified. 🤖