JevDSL (jev_dsl v0.1.0)

Copy Markdown View Source

Compile-time Elixir macro DSL, two-tier caching layer, and execution runner for TypeSafe Jev (SystemOneSDK) semantic contracts.

JevDSL compiles %SystemOneSDK.Prepared{} contracts at build time (defnoul, defchoice, defscore, defjev, defalias), caches rehydrated Jason.Fragment wire payloads in :persistent_term in O(1), provides deterministic SHA-256 content-addressed L1/L2 caching (JevDSL.Cache), and generates evaluate/3, evaluate!/3, evaluate_many/3, available?/2, cache_key/2, contract/1, prepared/1, and __export_cue__/0 directly on your contract module.

Both atoms and strings are supported interchangeably for contract keys, question keys, stab-clause option keys, and answer lookups (fetch_answer/2, choice?/2, probability/2).

Quick Start

defmodule MyApp.TriageContracts do
  use JevDSL,
    otp_app: :my_app,
    cache: JevDSL.Cache.ETS

  defnoul :is_spam do
    "Does this message contain unsolicited promotional spam?"
  end

  defchoice :sentiment,
    ask: "Classify the overall tone of the message." do
    positive -> "Constructive, appreciative, or favorable tone."
    neutral -> "Factual or informational without strong emotion."
    negative -> "Critical, frustrated, or dissatisfied tone."
  end

  defscore :completeness,
    ask: "Rate how complete the submission is." do
    incomplete -> "Missing required identity or contact fields."
    partial -> "Core fields are present but optional context is missing."
    complete -> "All identity, contact, and biographical fields are populated."
  end

  defjev :ticket_triage do
    noul :requires_escalation do
      "Does this issue require immediate engineering escalation?"
    end

    choice :priority,
      ask: "Select the appropriate response priority." do
      urgent -> "Production outage or security incident."
      normal -> "Standard bug report or feature question."
    end

    score :clarity,
      ask: "Rate the clarity of the reproduction steps." do
      vague -> "No steps or environment details provided."
      clear -> "Includes clear steps and expected vs actual behavior."
    end
  end
end

Evaluating Contracts

# Single evaluation (automatically cached by state + contract fingerprint)
{:ok, response} = MyApp.TriageContracts.evaluate(:sentiment, %{text: "Great work!"})

# Concurrent batch evaluation (resolves L1/L2 cache hits first, batches only misses)
results = MyApp.TriageContracts.evaluate_many(:is_spam, [%{body: "a"}, %{body: "b"}])

# Deterministic unit tests via 1-arity `:eval_fn` (or `:cache_only` / `SystemOneSDK.Test`)
{:ok, mocked} =
  MyApp.TriageContracts.evaluate(:is_spam, %{body: "a"},
    eval_fn: fn _state -> {:ok, %{answers: %{is_spam: %{noul: 0.05}}}} end
  )

Summary

Functions

Returns true if a ChoiceAnswer (or choice value) selected expected_option, comparing atoms and strings equivalently.

Aliases a secondary or legacy contract name (atom or string) to a canonical contract name.

Defines a single-question Choice contract (SystemOneSDK.Question.Choice) using key -> "description" stab clauses. Preserves the exact declaration order of options and compiles option keys as atoms.

Defines a multi-question contract combining choice, noul, and/or score sub-questions.

Defines a single-question Noul (boolean probability) contract (SystemOneSDK.Question.Noul).

Defines a single-question ordered Score contract (SystemOneSDK.Question.Score, 2..10 rubric levels) using label -> "description" stab clauses.

Exports compiled Jev contracts into a CUE schema document.

Fetches an answer from a %SystemOneSDK.SystemOneResponse{} (or map with :answers), matching key whether passed as an atom or a string.

Fetches an answer by atom or string key, raising KeyError if not present.

Rehydrates and caches the Jason.Fragment wire encoder on a compile-time %SystemOneSDK.Prepared{} struct.

Fetches the probability for option_key (atom or string) from a ChoiceAnswer or probability map.

Functions

choice?(choice, expected)

@spec choice?(
  SystemOneSDK.ChoiceAnswer.t() | map() | atom() | String.t(),
  atom() | String.t()
) ::
  boolean()

Returns true if a ChoiceAnswer (or choice value) selected expected_option, comparing atoms and strings equivalently.

Examples

iex> ans = %SystemOneSDK.ChoiceAnswer{choice: "positive", confidence: 0.9, probabilities: %{"positive" => 0.9}}
iex> JevDSL.choice?(ans, :positive)
true
iex> JevDSL.choice?(ans, "positive")
true
iex> JevDSL.choice?(ans, :negative)
false

defalias(alias_name, target_name)

(macro)

Aliases a secondary or legacy contract name (atom or string) to a canonical contract name.

defchoice(name, opts_or_block, maybe_block \\ nil)

(macro)

Defines a single-question Choice contract (SystemOneSDK.Question.Choice) using key -> "description" stab clauses. Preserves the exact declaration order of options and compiles option keys as atoms.

defjev(name, list)

(macro)

Defines a multi-question contract combining choice, noul, and/or score sub-questions.

defnoul(name, opts_or_block \\ [], maybe_block \\ nil)

(macro)

Defines a single-question Noul (boolean probability) contract (SystemOneSDK.Question.Noul).

Supports a string block, ask: "..." option, or true -> "..." / false -> "..." stab clauses.

defscore(name, opts_or_block, maybe_block \\ nil)

(macro)

Defines a single-question ordered Score contract (SystemOneSDK.Question.Score, 2..10 rubric levels) using label -> "description" stab clauses.

export_cue(contracts_map)

@spec export_cue(%{optional(atom() | String.t()) => JevDSL.Contract.t() | map()}) ::
  String.t()

Exports compiled Jev contracts into a CUE schema document.

fetch_answer(arg1, key)

@spec fetch_answer(SystemOneSDK.SystemOneResponse.t() | map(), atom() | String.t()) ::
  {:ok, term()} | :error

Fetches an answer from a %SystemOneSDK.SystemOneResponse{} (or map with :answers), matching key whether passed as an atom or a string.

Examples

iex> resp = %{answers: %{tone: %{choice: "positive"}}}
iex> JevDSL.fetch_answer(resp, :tone)
{:ok, %{choice: "positive"}}
iex> JevDSL.fetch_answer(resp, "tone")
{:ok, %{choice: "positive"}}
iex> JevDSL.fetch_answer(resp, :missing)
:error

fetch_answer!(response, key)

@spec fetch_answer!(SystemOneSDK.SystemOneResponse.t() | map(), atom() | String.t()) ::
  term()

Fetches an answer by atom or string key, raising KeyError if not present.

hydrate_prepared(prep)

@spec hydrate_prepared(SystemOneSDK.Prepared.t()) :: SystemOneSDK.Prepared.t()

Rehydrates and caches the Jason.Fragment wire encoder on a compile-time %SystemOneSDK.Prepared{} struct.

probability(probs, option_key)

@spec probability(SystemOneSDK.ChoiceAnswer.t() | map(), atom() | String.t()) ::
  {:ok, number()} | :error

Fetches the probability for option_key (atom or string) from a ChoiceAnswer or probability map.

Examples

iex> ans = %SystemOneSDK.ChoiceAnswer{choice: "positive", confidence: 0.9, probabilities: %{"positive" => 0.9, "neutral" => 0.1}}
iex> JevDSL.probability(ans, :positive)
{:ok, 0.9}
iex> JevDSL.probability(ans, "neutral")
{:ok, 0.1}