Skip to content
Beskid Platform specification

Beskid

Jump to a Beskid service

Beskid

Jump to a Beskid service

Contracts and edge cases

Platform spec article

Contracts and edge cases

Spec standingStandard

Owner
Piotr Mikstacki
Submitter
Piotr Mikstacki
IDRuleLevel
API-SHAPE-001Every public corelib item SHALL receive a resolved tier through the cascade or stay as tier: None (which consumers MUST treat as supported).MUST
API-SHAPE-002@tier(...) directives SHALL only carry the values standard, supported, unstable, or their Tier1 / Tier2 / Tier3 aliases (case-insensitive). Unknown values are a hard parse-time diagnostic.MUST
API-SHAPE-003The resolver SHALL stop at the closest directive in the cascade (item → parent module → package default → workspace default). Conflicting directives are not merged.MUST
API-SHAPE-004The beskid_corelib prelude SHALL only re-export modules whose effective tier is standard.MUST
API-SHAPE-005api.json SHALL emit tier as a lowercase string at the schema’s documented camelCase position, and SHALL omit the field when the resolver leaves it as None.MUST
API-SHAPE-006api.json schema version SHALL be at least 4 whenever any item carries a tier field.MUST
API-SHAPE-007Tier 1 (Standard) signatures SHALL stay stable for the full v0.x line; breaking changes require a major version bump and a normative ADR.MUST
API-SHAPE-008Tier 2 (Supported) signatures SHALL stay stable within a v0.x minor; behavior MAY evolve when preceded by a deprecation cycle.MUST
API-SHAPE-009Tier 3 (Unstable) items SHALL NOT be re-exported from any prelude or surfaced as default IDE completions; signatures MAY change without notice.MUST
API-SHAPE-010Consumers (IDE / registry / lints) SHOULD render a tier badge next to each documented item so authors see the stability promise without leaving the docs surface.SHOULD

A function with @tier(standard) declared on a parameter of a Tier 3 type is still classified Tier 1 by the resolver — the cascade only looks at the item and its module, not the types it references. Authors SHOULD avoid this pattern; the verification suite calls it out as a warning so reviewers can either drop the function to Tier 3 or escalate the type to Tier 2.

If both an item and its parent module carry @tier(...), the item directive wins. The resolver never merges conflicting values and never emits a diagnostic for the override; this is intentional so authors can demote a single function (for example Collections.Map.ContainsKey is unstable inside a supported module).

The prelude validator inspects beskid_corelib/src/Prelude.bd (and the per-package preludes) for pub mod ...; re-exports. Every re-exported module’s effective tier MUST be standard; otherwise the publish job fails with a deterministic diagnostic citing the offending module and its resolved tier.

@tier(stable) (no such tier), @tier() (empty), or @tier(standard, supported) (multi-value) are rejected at analysis time. The resolver does not silently default; the item stays tier: None and a diagnostic surfaces the offending span so the author can fix it.

compiler/corelib/packages/compiler-sdk/ mirrors the compiler’s internal syntax tree and is regenerated by tooling. Its modules carry @tier(unstable) at the module level so the cascade hands every generated row to consumers as Tier 3 without per-item annotation.

When a tier diagnostic fires, the message SHALL include:

  • The fully qualified item name (Sample::Module::Item).
  • The source span of the offending directive.
  • The current effective tier (or None when no cascade level matched).
  • A pointer to this article so newcomers can read the cascade rules.