B-OMPW-sdf-format-check-races-codegen
sdf:frontend-format-check can fail on a file nobody edited, because another
task in the same job rewrites that file while prettier is reading it.
What fails
Section titled “What fails”sdf:frontend-format-check | [warn] app/generated/types.tssdf:frontend-format-check | [warn] Code style issues found in the above file.solutions/ontological/desktop/src-nuxt/app/generated/types.ts carries
// Auto-generated by ontogen. DO NOT EDIT.
Why it is not the file’s content
Section titled “Why it is not the file’s content”Measured on a branch whose only solutions/ontological/desktop/** change is
bun.lock:
- The committed file passes
bunx prettier --checkcleanly. - Running the codegen the way CI does —
cargo check --manifest-path src-tauri/Cargo.toml, which is what firessrc-tauri/build.rs— reproduces the file byte for byte (sha2568d42f48d…d5cdbefore and after, same fortransport.ts), and the regenerated file is prettier-clean. git statusis empty afterwards: the pipeline reproduces every committed generated file exactly.
So the generator’s complete output is correct and formatted. What prettier read in CI was not that.
The race
Section titled “The race”sdf:codegendeclaressrc-nuxt/app/generatedamong itsoutputs, and its command iscargo check;src-tauri/build.rsruns the pipeline and rewrites those files on every check of the crate.sdf:lintalso runs cargo over the same crate, so it triggers the same rewrite.sdf:frontend-format-checkis inherited from the tauri aspect as-is, with nodepsoncodegenand no shared mutex, so moon is free to run it concurrently withsdf:lint.
In the failing run both tasks started in the same second, and cargo was actively
compiling the sdf crate when prettier read the file:
21:04:51 sdf:frontend-format-check (start)21:04:51 sdf:lint (start)21:04:55 sdf:lint | Compiling sdf v0.1.021:04:55 sdf:frontend-format-check | Checking formatting...21:05:01 sdf:frontend-format-check | [warn] app/generated/types.tsThe project already uses a project-scoped mutex for exactly this class of
problem — the comment at moon.yml:25-31 explains that four tasks
independently invoke Nuxt and must not overlap. The same reasoning was never
extended to the task that WRITES the generated tree and the tasks that READ it.
Why it looks intermittent
Section titled “Why it looks intermittent”It depends on whether cargo actually rebuilds the crate inside the window. A run
with a warm Rust cache does not recompile sdf, nothing rewrites the generated
tree, and the format check passes — which is why other PRs touching
solutions/ontological/desktop/** have seen this job pass. A cold or
invalidated cache widens the write window and the read lands inside it.
The job is path-filtered on solutions/ontological/desktop/**, so it runs
rarely; two different concurrency artifacts showed up in three consecutive runs
of it (this one, and EEXIST: failed to link package: @sksizer/graph-canvas
during install), which is consistent with a task graph whose concurrency has had
little exercise.
Order the readers after the writer: give frontend-format-check (and
frontend-lint, which reads the same tree) deps: ['codegen'], or put the
codegen writer and the generated-file readers in one mutex, the way the four
Nuxt-invoking tasks already are. Either makes the job deterministic instead of
cache-timing dependent.