You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
morphic compile <spec> -o /dev/null does not work, and its failure is indistinguishable
from a different failure a caller cares about.
replaceFile publishes by rename: it writes <dir>/.<base>.tmpXXXXXXXX beside the
destination and renames it over. /dev refuses the creation, so the run dies at create output and returns 2 — overwriting the exit 1 the diagnostics had already earned.
Reproduced on main @ dbf0054 with a spec carrying an unresolvable $ref:
$ morphic compile bad.yaml -o /dev/null; echo "EXIT=$?"
error openapi/unresolved-ref bad.yaml#: not found -- struct is nil at /components/schemas
error openapi/unresolved-ref bad.yaml#/paths/~1x/get/.../schema: unresolved $ref "#/components/schemas/Missing"
morphic: create output "/dev/null": open /dev/.null.tmpc8d319552ad96472: operation not permitted
EXIT=2
$ morphic compile bad.yaml -o out.json >/dev/null; echo "EXIT=$?"
error openapi/unresolved-ref ...
EXIT=1
Same spec, same diagnostics, different exit code — decided by whether the destination's
directory tolerates a temp file. A caller reading the exit code cannot tell "the spec has
errors" (1) from "the output could not be written" (2).
Scope
This is not specific to /dev/null. Any destination whose directory will not take a new
entry has the same shape: a character device, a read-only directory holding a writable
file, a FIFO. TestWriteParsed_ReadOnlyDirFails already pins the read-only-directory case
as a deliberate consequence of publishing by rename, and replaceFile's doc comment
records the trade honestly. What is not recorded is that the resulting exit code
overwrites a meaningful one.
Notes
morphic validate (added in #81) removes the need for -o /dev/null as a lint gate, which
was its main use. It does not address the exit-code masking, which applies to any
unwritable destination — so this is filed separately rather than folded in.
Two directions worth weighing:
Keep the write failure at 2 but make it not overwrite a diagnostics failure — the exit
code would report the more serious of the two.
Problem
morphic compile <spec> -o /dev/nulldoes not work, and its failure is indistinguishablefrom a different failure a caller cares about.
replaceFilepublishes by rename: it writes<dir>/.<base>.tmpXXXXXXXXbeside thedestination and renames it over.
/devrefuses the creation, so the run dies atcreate outputand returns 2 — overwriting the exit 1 the diagnostics had already earned.Reproduced on
main@dbf0054with a spec carrying an unresolvable$ref:Same spec, same diagnostics, different exit code — decided by whether the destination's
directory tolerates a temp file. A caller reading the exit code cannot tell "the spec has
errors" (1) from "the output could not be written" (2).
Scope
This is not specific to
/dev/null. Any destination whose directory will not take a newentry has the same shape: a character device, a read-only directory holding a writable
file, a FIFO.
TestWriteParsed_ReadOnlyDirFailsalready pins the read-only-directory caseas a deliberate consequence of publishing by rename, and
replaceFile's doc commentrecords the trade honestly. What is not recorded is that the resulting exit code
overwrites a meaningful one.
Notes
morphic validate(added in #81) removes the need for-o /dev/nullas a lint gate, whichwas its main use. It does not address the exit-code masking, which applies to any
unwritable destination — so this is filed separately rather than folded in.
Two directions worth weighing:
code would report the more serious of the two.
accepting that a non-regular destination gets no atomicity because it has no bytes to
protect. This one interacts with engine: spec problems surface as Go errors and usage exit codes instead of diagnostics #58's exit-code taxonomy.