Context
Two small refinements to Aether's error/failure model, prompted by reading the el language (/home/paul/scm/el), which has a clean portable-first I/O error contract (opaque error + closed ErrorKind union + optional raw OS i64 code — el docs/DESIGN.md:1099-1126) and a two-tier failure model whose unrecoverable failures print a stable, greppable category name (index_out_of_bounds, bitstring_size_mismatch, …) + location, then exit — no stack unwinding (el EXAMPLES.md:1143-1159).
Checked both against Aether first so this only asks for what's actually missing. Notably, EINTR retry is already handled across std.os (aether_os.c — ~10 sites loop on EINTR), so that part of el's model is a no-op for us; not asking for it.
Part A — attach the raw OS code to std.fs's portable error kinds
Aether's std.fs has portable structured error kinds (KIND_OK, KIND_NOT_FOUND, KIND_PERMISSION_DENIED, …, std/fs/module.ae:60-63) returned via the (value, kind, message) convention. std.io also exposes the global errno as a message string (io.errno_message() / perror, std/io/module.ae:57,195). What's missing is the raw numeric OS code carried alongside the portable kind on a structured fs error.
el's contract is the useful shape: a portable ErrorKind for cross-platform switching plus an optional target-specific i64 code for the cases where the caller genuinely needs the exact errno (e.g. distinguishing EAGAIN vs EWOULDBLOCK, or logging the precise OS error). The portable kind stays the primary surface; the raw code is an escape hatch, not the default.
Ask: add a raw-OS-code accessor to the fs split-error surface — e.g. a fs_get_error_code() companion to the existing kind/message getters (thread-local, same pattern as fs_get_stat_*), populated from errno at the point of failure. Portable KIND_* unchanged; this is purely additive. Windows fills it from GetLastError() (or leaves 0 where not meaningful).
Part B — a stable, greppable panic-category vocabulary
Aether's unrecoverable failures already go through aether_panic(...) (no unwinding beyond the deferred-free journal — good, matches el's no-landing-pads approach). But the category strings are ad-hoc free-form:
"precondition violation: <expr> in <fn>" (codegen_func.c:1232, codegen_stmt.c:3457)
"forced unwrap of none" (codegen_expr.c:2345)
- the
expr! unwrap-or-trap forwards the error slot's own string (codegen_expr.c:2415)
- runtime bounds/overflow traps elsewhere
There's no stable vocabulary — each site invents its wording, so a caller/CI can't reliably grep or match on "was this an out-of-bounds vs a forced-none vs a precondition." el pins a fixed set of category names (index_out_of_bounds, division_by_zero, overflow, invalid_shift, bitstring_size_mismatch, …) emitted verbatim + source location.
Ask: standardize the panic categories — a documented, stable set of leading tokens (precondition_violation:, forced_unwrap_none:, index_out_of_bounds:, integer_overflow:, division_by_zero:, …) that every aether_panic site uses as a prefix, with the human detail after. Benefits: CI can assert on a category, downstreams can triage by grepping a stable token, and the docs get a canonical failure-category list. Purely a message-format + docs contract — no unwinding/semantic change.
Why filed together
Both are the same theme (make failure legible and portable) and both are low-risk, additive contracts rather than semantic changes. Split into two PRs if preferred — Part A is stdlib/C, Part B is codegen message-format + a docs table. Aligns with the existing docs/error-unification.md direction.
Not urgent — filed for consideration.
Context
Two small refinements to Aether's error/failure model, prompted by reading the
ellanguage (/home/paul/scm/el), which has a clean portable-first I/O error contract (opaque error + closedErrorKindunion + optional raw OSi64code —eldocs/DESIGN.md:1099-1126) and a two-tier failure model whose unrecoverable failures print a stable, greppable category name (index_out_of_bounds,bitstring_size_mismatch, …) + location, then exit — no stack unwinding (elEXAMPLES.md:1143-1159).Checked both against Aether first so this only asks for what's actually missing. Notably, EINTR retry is already handled across
std.os(aether_os.c— ~10 sites loop onEINTR), so that part ofel's model is a no-op for us; not asking for it.Part A — attach the raw OS code to
std.fs's portable error kindsAether's
std.fshas portable structured error kinds (KIND_OK,KIND_NOT_FOUND,KIND_PERMISSION_DENIED, …,std/fs/module.ae:60-63) returned via the(value, kind, message)convention.std.ioalso exposes the global errno as a message string (io.errno_message()/perror,std/io/module.ae:57,195). What's missing is the raw numeric OS code carried alongside the portable kind on a structured fs error.el's contract is the useful shape: a portableErrorKindfor cross-platform switching plus an optional target-specifici64code for the cases where the caller genuinely needs the exact errno (e.g. distinguishingEAGAINvsEWOULDBLOCK, or logging the precise OS error). The portable kind stays the primary surface; the raw code is an escape hatch, not the default.Ask: add a raw-OS-code accessor to the fs split-error surface — e.g. a
fs_get_error_code()companion to the existing kind/message getters (thread-local, same pattern asfs_get_stat_*), populated fromerrnoat the point of failure. PortableKIND_*unchanged; this is purely additive. Windows fills it fromGetLastError()(or leaves 0 where not meaningful).Part B — a stable, greppable panic-category vocabulary
Aether's unrecoverable failures already go through
aether_panic(...)(no unwinding beyond the deferred-free journal — good, matchesel's no-landing-pads approach). But the category strings are ad-hoc free-form:"precondition violation: <expr> in <fn>"(codegen_func.c:1232,codegen_stmt.c:3457)"forced unwrap ofnone"(codegen_expr.c:2345)expr!unwrap-or-trap forwards the error slot's own string (codegen_expr.c:2415)There's no stable vocabulary — each site invents its wording, so a caller/CI can't reliably grep or match on "was this an out-of-bounds vs a forced-none vs a precondition."
elpins a fixed set of category names (index_out_of_bounds,division_by_zero,overflow,invalid_shift,bitstring_size_mismatch, …) emitted verbatim + source location.Ask: standardize the panic categories — a documented, stable set of leading tokens (
precondition_violation:,forced_unwrap_none:,index_out_of_bounds:,integer_overflow:,division_by_zero:, …) that everyaether_panicsite uses as a prefix, with the human detail after. Benefits: CI can assert on a category, downstreams can triage by grepping a stable token, and the docs get a canonical failure-category list. Purely a message-format + docs contract — no unwinding/semantic change.Why filed together
Both are the same theme (make failure legible and portable) and both are low-risk, additive contracts rather than semantic changes. Split into two PRs if preferred — Part A is stdlib/C, Part B is codegen message-format + a docs table. Aligns with the existing
docs/error-unification.mddirection.Not urgent — filed for consideration.