Skip to content

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.

sdf:frontend-format-check | [warn] app/generated/types.ts
sdf: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.

Measured on a branch whose only solutions/ontological/desktop/** change is bun.lock:

  • The committed file passes bunx prettier --check cleanly.
  • Running the codegen the way CI does — cargo check --manifest-path src-tauri/Cargo.toml, which is what fires src-tauri/build.rs — reproduces the file byte for byte (sha256 8d42f48d…d5cd before and after, same for transport.ts), and the regenerated file is prettier-clean.
  • git status is 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.

  • sdf:codegen declares src-nuxt/app/generated among its outputs, and its command is cargo check; src-tauri/build.rs runs the pipeline and rewrites those files on every check of the crate.
  • sdf:lint also runs cargo over the same crate, so it triggers the same rewrite.
  • sdf:frontend-format-check is inherited from the tauri aspect as-is, with no deps on codegen and no shared mutex, so moon is free to run it concurrently with sdf: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.0
21:04:55 sdf:frontend-format-check | Checking formatting...
21:05:01 sdf:frontend-format-check | [warn] app/generated/types.ts

The 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.

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.


← Back to Backlog