Diffo.Unknown (Diffo v0.5.1)

Copy Markdown View Source

Sentinel value for "we tried and couldn't determine this in our current view of the graph" — the X state, complementary to Ash's NotLoaded (the U state).

NotLoaded represents the load-lifecycle "uninitialised" — the value wasn't loaded yet; ask again. Unknown represents the post-resolution "tried and couldn't" — the calc ran, the cross-world lookup didn't yield a value. Both are explicit values; consumers pattern-match them as distinct outcomes alongside concrete values and nil.

Shape

%Diffo.Unknown{
  world:   MyApp.SomeResource,   # outermost (Domain, Resource) producer — stored as Resource
  reason:  :role_not_declared,   # world-local atom; vocabulary owned by the producing world
  context: %{role: :uni, }      # world-local diagnostic data
}

:world is the outermost (Domain, Resource) pair the Unknown was produced under, stored as the Resource module since the Domain is derivable via Ash.Resource.Info.domain/1. The Domain alone is insufficient — within a single Domain, multiple concrete resources can extend the same base fragment (e.g. Diffo.Provider.AssignmentRelationship and Diffo.Provider.DefinedSimpleRelationship are distinct worlds in the same Domain). Together Domain + Resource identify the producer uniquely.

:reason is atom() at the structural level only — no enum narrowing. Each calc moduledoc declares its own reason vocabulary; the central type stays open. Reasons are world-local; the producing world owns the vocabulary.

:context is term() — each world decides what to put there. Diagnostic, not load-bearing.

Discipline (per AGENTS.md)

  • Compile-time stamping of :world. Transformers that inject cross-boundary calcs pass the consumer's resource as an opt; the calc stamps it on every Unknown it emits. No runtime resource lookup needed.
  • Calcs are total. A calc that crosses a boundary never raises on missing data — it returns the value, nil, or %Diffo.Unknown{}. The consumer pattern-matches.
  • Projection across worlds, free composition within. An outer-world calc that encounters an inner-world Unknown wraps it (%Diffo.Unknown{world: OuterResource, reason: :inner_unknown, context: %{inner: original}}); calcs within the same world share vocabulary and can read each other's :reason directly without projecting through.
  • No central reason registry. Resist the urge to enumerate reasons anywhere shared. Each world documents its vocabulary in the moduledocs of the calcs that produce it.
  • The metadata describes the producer only. The consumer brings its own world context. AshNeo4j-side: see AshNeo4j.worlds/1 for the symmetric "outer-world metadata on reads" primitive.

Summary

Functions

Returns the Ash Domain of the producing world (the outermost world that emitted this Unknown). Derived from :world via Ash.Resource.Info.domain/1.

Types

t()

@type t() :: %Diffo.Unknown{context: term(), reason: atom(), world: module()}

Functions

domain(unknown)

@spec domain(t()) :: module() | nil

Returns the Ash Domain of the producing world (the outermost world that emitted this Unknown). Derived from :world via Ash.Resource.Info.domain/1.