Deviation History
This record preserves the observations behind earlier architecture deviations. Current requirements and coverage are shown by their generated anchor pages; open limitations are attached to the corresponding TODO implementation/test entries.
These entries preserve confirmed contradictions observed before the migration to generated coverage. “Open” and “resolved” below describe the recorded snapshot. Each entry retains its contract, observed behavior, and the evidence then required to close it without weakening the destination design.
New limitations belong in the relevant rule's implementation/test entries, and new plans belong in scoped RFDs. This history is not an active backlog or a second current status registry.
Open deviations
KD-7: Operator typing lacks generic and unknown-Self closure
- Contracts: crates.sage_ir.checking.body.elaboration, crates.sage_ir.checking.body.operator_calls, and crates.sage_ir.inference.numeric_domains, plus crates.sage_ir.types.operators.trait_calls. Together they require every proven overloadable operation, including generic cases, to complete as a resolved trait call, with ambiguity and user type errors represented diagnostically.
- Observed implementation: Ground primitive, comparison, and local
user-defined binary expressions instantiate the well-known trait
method's real signature, use ordinary impl proof and result normalization,
and complete as static trait calls. Invalid
bool + boolproduces one diagnostic and an error node. A generic body such asT: Add<Output = T>is still rejected because Sage does not represent the associated-type equality assumption. WhenSelfis initially unknown, Sage also lacks a general way to import constraints common to the complete viable candidate set; even a valid expression such as1 + 2u32may therefore end with unresolved integer inference rather than selecting the proof-derived type. - Consequence: The covered ground slice rejects same-typed invalid
arithmetic and completes successful overloadable syntax as resolved calls,
but valid generic and unknown-
Selfprograms can still be rejected. The implementation cannot yet satisfy BODY-A5/TIR-A6 uniformly across primitive, generic, and user-defined operands. - Closure evidence: Existing integrations inspect
u32addition, mixed-integer shift, comparison borrows, a localLeft + Right -> Sumimpl, selected-impl narrowing, failed-proof recovery, and lazy boolean preservation; an independent oracle comparison matches those representative successful forms exactly. To close this deviation, represent and consume applicable associated-type equality assumptions, add a general completeness-aware candidate-answer hint mechanism rather than an operator-specific table, cover the remaining token/domain/where-clause matrix, and compare the remaining representative accepted and rejected cases against the independent rustc oracle. Completed IR must contain resolved calls for every successful overloadable case, including generic operands, and explicit lazy boolean nodes for&&and||.
KD-3: Derive helper attributes do not produce the promised warning
- Contract: No derive helper attributes, with the user-visible response governed by crates.sage_ir.crate.explicit_restrictions.
- Observed implementation: Sage does not yet import a proc-macro derive's
registered helper-attribute names. A helper such as
#[serde(...)]is therefore treated like an unknown potentially active attribute: the affected item is omitted from the definite expanded set and completeness becomes conservative, rather than retaining the item and reporting a warning. - Consequence: Code using a recognized derive's helper attributes can lose otherwise usable semantic information and receive no focused explanation.
- Closure evidence: A fixture using a registered external derive helper must retain the attributed item, emit an unknown-helper warning at the helper span, and remain complete for semantic facts which the helper cannot alter. An arbitrary unclassified active attribute must continue to produce conservative incompleteness rather than being assumed inert.
Closed deviations
KD-4: Stash byte storage did not guarantee entry alignment
- Contract: crates.sage_stash.storage.handle_ownership, together with the
StashDatarepresentation contract that every accepted value can be read through its typed handle. - Closed: 2026-09-02. The stash now owns a raw byte allocation whose
Layoutretains the strongest alignment requested by any admitted type. Growth and stronger alignment requests relocate the stored byte prefix into a correctly aligned allocation without changing entry offsets or handles. - Evidence:
over_aligned_scalar_slice_and_zst_have_aligned_addresseschecks scalar, slice, and zero-sized entries with 64- and 128-byte alignment;over_aligned_entries_survive_growth_clone_and_hash_cons_lookupforces relocation and verifies cloning and deduplication; andover_aligned_values_copy_between_stashesverifies structural copying into an independently aligned destination. Thesage-stashtest target passes under Miri.
KD-6: Never-to-any coercion was modeled as subtyping
- Contracts: crates.sage_ir.inference.subtyping_and_coercion, crates.sage_ir.checking.body.elaboration, and Completed bodies are elaborated typed trees.
- Closed: 2026-09-01.
require_subno longer treatsTy::Neveras a subtype of every type, mutable-reference subtyping relates its pointee types by equality, and coercion sites select never-to-any separately. The selected conversion becomes an explicitTyExprData::NeverToAnynode and survives body finalization. - Evidence:
never_to_any_does_not_apply_beneath_mutable_referencerejects&mut !where&mut u32is required.top_level_never_to_any_is_explicit_in_typed_iraccepts a diverging body at au32result coercion site, andcall_argument_never_to_any_is_explicit_in_typed_irdoes the same for a direct-call argument. Both inspect the completed node's!operand andu32result;struct_field_never_to_any_uses_the_value_spancovers a field coercion and its operand span, whileexternal_inherent_call_accepts_a_never_argumentcovers the resolved-method path against rustc-provided metadata. Thenever_result_does_not_create_a_never_to_never_coercionandinferred_never_join_does_not_retain_never_to_never_coercionsexclude redundant conversion for known and join-inferred targets.generic_call_arguments_are_order_independent_and_fall_back_to_neververifies that later non-diverging constraints determine a generic expected type regardless of argument order, while a target constrained only by divergence falls back to!without a conversion;never_fallback_wakes_suspended_method_lookupverifies that this fallback wakes a consumer suspended on the inferred type instead of deadlocking, andquiescent_never_fallback_does_not_settle_unrelated_targetsverifies that intermediate recovery does not settle targets which later body constraints can still determine.external_generic_method_defers_never_until_other_constraints_settleverifies the same deferred choice for a rustc-metadata-backed generic method. The source-drivenbasics/never_to_any.rsoracle case compares Sage's and rustc's independently emitted trees by exact text at the function-result, direct-call, and struct-field conversion sites.
KD-5: The scripted inspector advertised products it could not return
- Contracts: crates.sage_inspector.inspection.source_evidence and crates.sage_inspector.inspection.product_availability.
- Closed: 2026-08-31. The scripted provider and
--fixturecommand path were removed. Catalogs and products now come only from the live provider over Rust source, so precomputed catalog and response models cannot drift apart. - Evidence:
real_command_serves_embedded_assets_and_correlated_request_logslaunches the live sample project, selectsDbfrom the source-built directory, and fetches its advertised identity page through the production actor and Axum server. The same test snapshots the representative visible result and actor-owned demand.
KD-1: Associated-item CST spans used the owner as their base
- Contracts: crates.sage_ir.types.spans.relative_composition and Nested spans are relative to stable item provenance.
- Closed: 2026-08-18. Associated-item placement is stored separately from
the item-local function, type, or const CST; relative diagnostics now resolve
from the associated item's own absolute span. The
cst_basespecial case was removed. - Evidence:
moving_associated_items_preserves_symbol_query_keyscovers all three associated kinds through both the trait and impl parsing paths across sibling insertion, removal, and reordering, andmoving_associated_item_reuses_method_signature_and_bodyproves through the post-edit Salsa traces for both owners that an unchanged moved method retains its semantic queries.
KD-2: Most local-symbol CST fields participated in symbol identity
- Contracts: crates.sage_ir.crate.identity_before_detail, crates.sage_ir.modules.parse.detail_firewall, and crates.sage_ir.symbols.local_identity.
- Closed: 2026-08-18. CST, module source/attributes, variant shape, and local generic-parameter spans are tracked detail rather than definition identity.
- Evidence:
detail_edits_preserve_local_symbol_query_keyscovers every top-level local item shape,enum_detail_edits_preserve_variant_query_keyscovers variants and constructors while consuming the updated self-contained variant CST, andmoving_associated_items_preserves_symbol_query_keyscovers associated functions, types, and constants under both trait and impl owners across sibling insertion, removal, and reordering.local_normalization_reads_one_keyed_value_without_impl_item_enumerationverifies that focused and aggregate impl-item paths share the canonical per-item producer query and that editing a sibling value does not rerun the requested-value query.