B-WUV6-guard-moon-task-inputs
just ci runs moon run :check :test --affected. Moon selects a task only when a changed file
matches one of that task’s DECLARED inputs. A task whose declared inputs omit its own source is
therefore invisible to the gate: it never runs, and the gate reports “No tasks affected by changed
files” rather than an error. The failure is silent and looks like success.
root:check and root:test had exactly this fault — they declared only the implicit .moon/*.yml
glob, so every change confined to solutions/ontological/ or scripts/ was ungated locally. Fixed
by declaring real inputs on both tasks.
That fix is a point repair. Nothing stops the next task from being added the same way, and nothing catches the adjacent failure modes a sweep of all 103 registered projects turned up:
sdlc(solutions/ontological, layer tool) declares exactly one task,doc-site. Nocheck, notest. It haslayer: tool, so it does not inheritcheckfrom.moon/tasks/ts-lib.yml, which is scoped tolanguage: typescript AND layer: library AND stack: backend.determined-root(solutions/determined, layer tool) likewise has nocheckand notest, while carrying real ungated TypeScript in its ownscripts/andtests/.- Seven registered projects have no
moon.ymlat all, so zero tasks of any kind:agent-call,manifest-graph,shell,test-vue-component,vault-graph-core,vault-path,vault-transform. - Six library projects have one of the pair but not the other:
app-frame(test, no check);context,dashboard-client,graph-canvas,logging(check, no test);obsidian-editorhas a well-scopedtypechecktask thatmoon run :checknever targets because of the name.
Common ancestor: .moon/tasks/rust.yml scopes on language: rust alone and so reaches every rust
project regardless of layer. There is no equivalent inherited task file for layer: tool +
language: typescript. All three TS tool-layer projects (root, sdlc, determined-root) are
hand-rolled as a result, and all three were wrong.
Proposed: a repo-level guard, scripts/guard-moon-task-inputs.ts, wired into just ci-guards and
the ci-guards job. For every registered project with projectLayer != application, assert it has
a reachable check and a reachable test (own or inherited), and that each declares inputs that
would actually match a change to a file inside that project’s own source. Read the task graph with
moon query projects --json, which returns merged tasks with expanded inputs; state.emptyInputs
and an inputs list naming only config files are the two shapes to reject. Carry an explicit
allowlist for the projects that legitimately have neither, with a reason per entry, so the
exceptions are stated rather than assumed.
This belongs in scripts/, not in solutions/ontological. It enforces THIS repo’s moon layout,
which is a consumer-specific convention; per CLAUDE.md that keeps it out of the ontological gate
service and the op registry.
The seven no-moon.yml projects and the two taskless tool projects should be separate follow-ups — the guard would fail on them from day one, so either they get fixed first or they enter the allowlist with a reason.