Skip to content

Spec audit: §0.2 / §0.3 design-principle violations elsewhere in the spec #653

@aallan

Description

@aallan

Summary

Audit during PR #650 surfaced ~10 spec sites where the documented language behaviour is in tension with the stated design principles in §0.2 ("Explicitness") and §0.2.3 / §0.3.2 ("One canonical form / no shorthand / no implicit conversions / no default arguments").

Each item is individually defensible as a deliberate ergonomic tradeoff, but the principles as currently written claim absoluteness ("There is no implicit behaviour for the model to infer or hallucinate") that the spec then partly contradicts in later chapters. The result is a spec that's internally inconsistent on its own foundational rules.

Drift inventory

# Site Tension Severity
A spec/09-standard-library.md §9.1.2 "Every Vera program implicitly has access to a standard prelude" — Option<T>, Result<T, E>, Ordering, UrlParts, combinators, array operations available without declaration. High — most foundational implicit surface in the language.
B spec/01 §1.7 + spec/04 §interpolation Non-String types in \(...) "automatically converted to String". Defended in §4 as "InterpolatedString is the canonical form — the interpolation syntax IS the explicit marker"; arguably defensible. Medium
C spec/02-types.md §2.5 "A function type with no effects annotation defaults to effects(pure)." §0.3.2 explicitly bans "default arguments". Medium
D spec/05-functions.md §5.4 "Multiple requires clauses are equivalent to a single requires with &&." Two textual forms for the same constraint — direct violation of §0.2.3 "no equivalent alternatives". Medium
E spec/03-slot-references.md §3.7 @Fn<A,B>.0 documented as "shorthand for the function argument". §0.3.2 explicitly bans "shorthand syntax". Needs investigation of whether this is shorthand or actually the only form. Medium
F spec/09 ability auto-derivation "If all fields of an ADT support Eq, the ADT supports Eq automatically." Auto-derivation across Eq / Ord / Hash / Show. Medium
G spec/09 State.get() "State<T>.get() — the Unit parameter is implicit." Low (single built-in)
H spec/07-effects.md §7.5 IO IO operations "available automatically when effects(<IO>) is specified" — programs don't declare effect IO { ... }. The IO effect is hard-wired; all other effects are user-declared. Medium
I spec/07-effects.md §7.5 resume "Operations implicitly have access to the resume continuation" in handler arms. Implicit name binding. Low (handler-local)
J spec/08-modules.md §8.2 "Every module may optionally declare its identity with a module statement". §0.2.3 bans optional syntax. Low (parser flexibility)
K spec/02-types.md §2.2.1 (new) Int <: Nat flows without explicit cast (verifier-mediated). Partly mitigated by reframing wording in PR #650 from "implicit" → "syntactically silent but semantically verified", anchored to "verification is a first-class citizen" exception. Low (verifier-checked)

Proposed resolution shape

Two options, not mutually exclusive:

Option 1 — Strengthen §0.3 to enumerate the deliberate implicit surfaces

Add a §0.3.6 or similar:

Implicit surfaces excluded from §0.2.2 — the following are deliberate exceptions where the cost of explicitness outweighs the principle benefit:

  1. The standard prelude (§9.1.2) — Option, Result, Ordering, UrlParts, and their associated combinator and accessor functions are available without declaration.
  2. The IO effect (§7.5) — operations are available when effects(<IO>) is declared, without a user-side effect IO { ... } declaration.
  3. The resume continuation (§7.5) — implicitly bound inside handler arms.
  4. Ability auto-derivation (§9.X) — built-in abilities (Eq, Ord, Hash, Show) are derived automatically for ADTs whose fields support them.
  5. Primitive-to-String coercion inside InterpolatedString (§1.7) — primitive types (Int, Nat, Bool, Byte, Float64) are wrapped via *_to_string automatically; the interpolation syntax \(...) is the explicit marker.
  6. effects(pure) default on function-type annotations (§2.5) — type-level annotation only; function declarations still require an explicit effects(...) clause.
  7. Verifier-mediated subtyping (§2.2.1) — Int <: Nat is accepted at type-check time but the verifier discharges an obligation; the conversion is syntactically silent but semantically verified.
  8. State<T>.get() Unit-arg elision (§9.X) — single built-in exception.

This makes the principle honest. The cost is acknowledging the design has 8 narrowly-scoped exceptions; the benefit is that the spec no longer contradicts itself.

Option 2 — Triage each item separately

Some of the "exceptions" above may not be defensible on inspection:

  • D (multiple requires equivalence) — the "one canonical form" violation here is real. The justification ("more precise error reporting") could instead be solved by a different mechanism (e.g., named requires clauses) without two textual forms.
  • E (@Fn<A,B>.0 shorthand) — needs investigation. If @Fn<A,B>.0 is the only way to refer to the function argument (and the word "shorthand" is misleading), §3.7 should be reworded. If there's an alternative long form, one of the two should be deprecated.
  • J (optional module statement) — §10 grammar already marks visibility as parser-flexible-but-checker-mandatory. The module statement could do the same: parser accepts both forms, but a future linter/vera fmt could enforce one canonical shape.

Items where the implicit-ness is genuinely load-bearing (A, B, F, H, I, K) get enumerated in §0.3 via Option 1. Items where the implicit-ness is just unfixed legacy (D, E, J) get individual close-out PRs.

Recommendation

Both. Start with Option 1 (§0.3 enumeration) as one PR — honest framing, no behaviour change. Then file 3 follow-up issues for D, E, J as separate triage candidates.

Why this matters

LLMs reading the spec take §0.2.2 literally ("there is no implicit behaviour"). When the same model then writes a Vera program that depends on prelude Option or auto-derived Eq, it experiences a contradiction with the principle as it understood it. The honest framing reduces this confusion — "the language has X implicit surfaces, here they are, expect them" is better than an absolute claim that the rest of the spec quietly walks back.

Source

Audit performed 2026-05-11 during PR #650 review pass.

Related

  • PR Small docs sweep: #557 + #561 + #560 + #607 + #608 + #512 #650 — addressed item K (the §2.2.1 Int↔Nat wording) by reframing "implicitly" → "syntactically silent but semantically verified". This is the model fix for how to discuss verifier-mediated subtyping; could be extended to other items.
  • §0.2.2 — the principle being audited.
  • §0.3.2 — the non-goal being audited.

Metadata

Metadata

Assignees

No one assigned

    Labels

    documentationImprovements or additions to documentation

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions