MGS1037: a tool's observation is keyed as its version
A spell declares the same command as a tool's probe and its observe, and declares no
key to narrow the version half:
[fail] observation keyed as version: 1 tool(s) declare one command as both version and
observation probe without narrowing the version half, so a value moving on the feed's
clock invalidates targets that never run the tool
spell "go" tool "govulncheck" declares `govulncheck -version` as both probe and
observe with no key, so everything that command prints keys every target in every
project binding the spell, not just the targets driving the tool
The two probes differ in reach, not in what they run
That is the whole of it, and it is easy to miss because the command can be identical.
An observation is scoped. It reaches the targets whose ops drive the binary, worked
out from the same static op list magus describe target prints. A target that never
composes the op carries no obs: line.
A version probe is not scoped. It runs for every project that binds the spell and lands in the key of every target in that project, because a toolchain upgrade changes what every target produces. That is correct for a version and wrong for anything else.
Declare one command as both and narrow neither, and the output's observation-class half travels down the unscoped channel. Whatever moves on the feed's clock then invalidates targets that never run the tool.
What it cost when it happened
The go spell declared govulncheck -version as both. That command prints four lines, and
the last is the vulnerability database's publication date:
Go: go1.26.6
Scanner: govulncheck@v1.3.0
DB: https://vuln.go.dev
DB updated: 2026-09-16 18:00:43 +0000 UTC
With no key, the whole output keyed the cache, so build in a project that never
scanned anything carried the database's publication date. Every release of that database
invalidated every build, test and lint entry in every Go project. The scoped observe
probe was already declared and already correct; the version probe was a second path
around it.
Resolve it
Which of the two applies depends on whether the command can report the tool's own version separately from the feed's.
Drop the version probe, keep the observation. Right when it cannot.
govulncheck -version prints the Go version first, so extracting a semver takes the
wrong tool's version and throws the database date away. The observation still carries all
four lines to the targets that drive the op, so nothing that should invalidate stops
invalidating. Check first whether the tool declares supported bounds: dropping the
probe drops the version window with it, and a tool with no bounds was feeding no gate.
Declare a VersionKey that extracts the version alone. Right when it can. A genuine
tool upgrade then keys every target, as it should, while the feed keys only its drivers.
Keying on a command's whole output stays legal. The zero VersionKey is deliberately
conservative, because it is the only setting that cannot silently discard something the
tool considers part of its identity. This check does not forbid that; it requires that
you meant it, in the one case where conservative is the wrong default.
Why it is declared, not measured
The hazard is visible in the spell's tool table, so nothing has to run to find it. That also means the check cannot tell you whether a probe's output actually contains something that moves. It reports the shape that makes the leak possible, and the two fixes above are how an author says which they intended.