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
Decided (2026-06-05):nexits canonical everywhere (exit CLI alias 1 cycle, JSON key unchanged); remove the 3 unreachable MetricsError variants; FunctionSpan.name→Option<String> (drop error); add additive input() accessors to the parse errors. See the resolved-decisions comment.
Summary
A cluster of small public shape / error-type ergonomics fixes that are each a
SemVer break and so must batch into 2.0.
Findings
ParseMetricError / ParseLangError expose no accessor. ParseMetricError(String) (src/metric_set.rs) and ParseLangError
(src/macros/mod.rs) wrap a private String; callers can only Display
the rejected input, not recover it programmatically. Contrast MetricsError::LanguageDisabled(LANG), which exposes its payload. Add fn input(&self) -> &str (additive — could ship pre-2.0) and finalize the
representation at 2.0.
MetricsError reserved variants.EmptyRoot, NonUtf8Path, ParseHasErrors (src/error.rs) are documented as never-produced today.
Since the enum is #[non_exhaustive], the reserved variants buy nothing that #[non_exhaustive] doesn't, while forcing every exhaustive matcher to handle
dead cases. At 2.0 either wire them up behind the strict-mode toggles they
document, or remove them.
Exit-metric has three spellings.Metric::Exit (Display = "exit"), Metric::NAMES/JSON key = "nexits", CodeMetrics::nexits field
(src/metric_set.rs, src/spaces.rs). Metric::Display not round-tripping
to the canonical NAMES spelling is a footgun for anyone using Display
output as a config key. Pick one canonical string end-to-end at 2.0.
(Distinct from fix(cli): reconcile metric-name spelling between diff --metric and check --threshold #514, which reconciled diff --metric vs check --threshold.)
FunctionSpan sentinel.FunctionSpan uses name: String + error: bool (src/function.rs), setting name = String::new() + error = true on parse failure — the exact anti-pattern FuncSpace/Ops
avoid with name: Option<String>. Change to name: Option<String> and drop error at 2.0.
Why 2.0-worthy
Items 2–4 are shape breaks; item 1's representation change is too (the accessor
itself is additive). Batching them keeps the 2.0 break surface coherent.
Acceptance
Parse errors expose their rejected input.
No documented-unreachable MetricsError variants remain (or they are wired
up).
One canonical exit-metric spelling across Metric, the field, and Display.
FunctionSpan::name is Option<String>; error removed.
Implemented on fix/issue-536 (commit fe588965), batched into the 2.0 integration branch. See the resolution comment for full per-item detail.
Item 1 (breaking):Metric::Exit -> Metric::Nexits, Display -> "nexits"; exit is a hidden FromStr alias for one cycle (not in NAMES). Field/JSON key already nexits, so serialized output is unchanged.
Item 2 (breaking, partial): Removed NonUtf8Path + ParseHasErrors (never constructed). EmptyRoot kept -- it is still constructed at two defensive .ok_or(MetricsError::EmptyRoot)? guards (src/ops.rs, src/spaces.rs); per the STOP rule, a live error path is not deleted silently. Enum stays #[non_exhaustive].
Item 3 (breaking):FunctionSpan.name -> Option<String>, error dropped; wire::FunctionSpan DTO + From synced; web /function shape and tests updated.
Item 4 (additive):input(&self) -> &str on ParseMetricError and ParseLangError.
Full workspace tests + fmt/clippy/doc/xtask/self-scan gates pass; no snapshot drift. Issue left open for the integration branch / acceptance review.
Summary
A cluster of small public shape / error-type ergonomics fixes that are each a
SemVer break and so must batch into 2.0.
Findings
ParseMetricError/ParseLangErrorexpose no accessor.ParseMetricError(String)(src/metric_set.rs) andParseLangError(
src/macros/mod.rs) wrap a privateString; callers can onlyDisplaythe rejected input, not recover it programmatically. Contrast
MetricsError::LanguageDisabled(LANG), which exposes its payload. Addfn input(&self) -> &str(additive — could ship pre-2.0) and finalize therepresentation at 2.0.
MetricsErrorreserved variants.EmptyRoot,NonUtf8Path,ParseHasErrors(src/error.rs) are documented as never-produced today.Since the enum is
#[non_exhaustive], the reserved variants buy nothing that#[non_exhaustive]doesn't, while forcing every exhaustive matcher to handledead cases. At 2.0 either wire them up behind the strict-mode toggles they
document, or remove them.
Exit-metric has three spellings.
Metric::Exit(Display="exit"),Metric::NAMES/JSON key ="nexits",CodeMetrics::nexitsfield(
src/metric_set.rs,src/spaces.rs).Metric::Displaynot round-trippingto the canonical
NAMESspelling is a footgun for anyone usingDisplayoutput as a config key. Pick one canonical string end-to-end at 2.0.
(Distinct from fix(cli): reconcile metric-name spelling between diff --metric and check --threshold #514, which reconciled
diff --metricvscheck --threshold.)FunctionSpansentinel.FunctionSpanusesname: String+error: bool(src/function.rs), settingname = String::new()+error = trueon parse failure — the exact anti-patternFuncSpace/Opsavoid with
name: Option<String>. Change toname: Option<String>and droperrorat 2.0.Why 2.0-worthy
Items 2–4 are shape breaks; item 1's representation change is too (the accessor
itself is additive). Batching them keeps the 2.0 break surface coherent.
Acceptance
MetricsErrorvariants remain (or they are wiredup).
Metric, the field, andDisplay.FunctionSpan::nameisOption<String>;errorremoved.Part of the pre-2.0 review (#505).
Resolution
Implemented on
fix/issue-536(commitfe588965), batched into the 2.0 integration branch. See the resolution comment for full per-item detail.Metric::Exit->Metric::Nexits,Display->"nexits";exitis a hiddenFromStralias for one cycle (not inNAMES). Field/JSON key alreadynexits, so serialized output is unchanged.NonUtf8Path+ParseHasErrors(never constructed).EmptyRootkept -- it is still constructed at two defensive.ok_or(MetricsError::EmptyRoot)?guards (src/ops.rs,src/spaces.rs); per the STOP rule, a live error path is not deleted silently. Enum stays#[non_exhaustive].FunctionSpan.name->Option<String>,errordropped;wire::FunctionSpanDTO +Fromsynced; web/functionshape and tests updated.input(&self) -> &stronParseMetricErrorandParseLangError.Full workspace tests + fmt/clippy/doc/xtask/self-scan gates pass; no snapshot drift. Issue left open for the integration branch / acceptance review.