Decision Primitives

v1.0.0

In-depth reference for SystemOne decision primitives: Noul (binary likelihoods), Choice (categorical criteria), and Score (bounded ranges and rubrics).

Decision Primitives

Decision Primitives are the fundamental building blocks of Obelaw SystemOne. Instead of unstructured prompting, primitives represent formal mathematical and probabilistic questions.

SystemOne ships with three core primitives:

  1. Noul: Binary and Bernoulli likelihood estimation [0.0, 1.0].
  2. Choice: Categorical classification across defined options with probability distributions.
  3. Score: Bounded numerical ratings or ordered rubric scales.

All primitives implement Obelaw\SystemOne\Contracts\PrimitiveInterface and Illuminate\Contracts\Support\Arrayable.

flowchart TD
    Root["SystemOne Decision Primitives<br/><code>PrimitiveInterface</code>"]

    NoulNode["<b>Noul</b><br/>Binary &amp; Bernoulli Likelihood<br/>Output: <code>float [0.0, 1.0]</code>"]
    ChoiceNode["<b>Choice</b><br/>Categorical Classification<br/>Output: <code>string</code> (Key) + Softmax Dist"]
    ScoreNode["<b>Score</b><br/>Bounded Ranges &amp; Rubrics<br/>Output: <code>float</code> / <code>int</code>"]

    Root --> NoulNode
    Root --> ChoiceNode
    Root --> ScoreNode

    subgraph NoulUseCases["Use Cases"]
        N1["Fraud detection<br/>Policy compliance<br/>Spam filtering"]
    end

    subgraph ChoiceUseCases["Use Cases"]
        C1["Department routing<br/>Sentiment labeling<br/>Incident triage"]
    end

    subgraph ScoreUseCases["Use Cases"]
        S1["Credit scoring<br/>ICP lead fit (1-10)<br/>Priority rubrics"]
    end

    NoulNode --> NoulUseCases
    ChoiceNode --> ChoiceUseCases
    ScoreNode --> ScoreUseCases

1. Noul (Binary Likelihood)

Noul answers binary yes/no questions by returning a calibrated Bernoulli probability between 0.0 (0% likelihood) and 1.0 (100% likelihood).

Syntax & Construction

use Obelaw\SystemOne\Primitives\Noul;

// Fluent factory
$primitive = Noul::make('Is this customer inquiry urgent?');

// Or fluently update instructions
$primitive->instructions('Does this transaction indicate fraud?');

Response Evaluation

When evaluated by a driver, Noul produces a float value representing confidence in the affirmative statement:

$response = SystemOne::state($orderData)
    ->ask('is_fraud', Noul::make('Is this payment transaction fraudulent?'))
    ->run();

// Raw probability value (float)
$probability = $response->value('is_fraud'); // e.g. 0.94

// Convenience threshold checks
if ($response->isPositive('is_fraud', threshold: 0.75)) {
    // Triggers if probability > 0.75
    $order->markAsSuspicious();
}

if ($response->isNegative('is_fraud', threshold: 0.20)) {
    // Triggers if probability <= 0.20
    $order->approveInstantly();
}
flowchart LR
    State["Application State<br/>(Order Data)"] --> NoulEval["Noul Evaluation<br/><i>'Is payment fraudulent?'</i>"]
    NoulEval --> Prob["Calibrated Likelihood<br/><code>value('is_fraud') = 0.94</code>"]
    Prob --> T1{"isPositive(&gt; 0.75)?"}
    Prob --> T2{"isNegative(&le; 0.20)?"}
    T1 -- "Yes (0.94 &gt; 0.75)" --> Mark["markAsSuspicious()"]
    T2 -- "No (0.94 &gt; 0.20)" --> Skip["Continue Pipeline"]

Serialized Schema

Noul::toArray() serializes into:

{
  "type": "noul",
  "instructions": "Is this payment transaction fraudulent?"
}

Common Use Cases

  • Fraud & Anomaly Detection: Is this login anomalous? Does this claim exhibit fraudulent indicators?
  • Content Moderation: Does this user post violate safety policies?
  • Customer Churn Risk: Is this customer expressing high intent to cancel?
  • Spam Filtering: Is this form submission automated bot spam?

2. Choice (Categorical Classification)

Choice resolves decisions where the output must match one option from a defined set of criteria. It computes a softmax probability distribution across all choices.

Syntax & Construction

Choice supports both flat lists and associative key-value criteria:

Providing descriptions alongside keys gives the model explicit semantic boundaries for each category:

use Obelaw\SystemOne\Primitives\Choice;

$choice = Choice::make('Which department should handle this ticket?', [
    'billing' => 'Invoices, refunds, chargebacks, and payment methods',
    'support' => 'Technical bugs, platform outages, and troubleshooting',
    'sales' => 'Plan upgrades, enterprise custom quotes, and demo requests',
    'legal' => 'Terms of service, GDPR data requests, and compliance',
]);

List Criteria

If options are self-evident:

$choice = Choice::make('Select customer sentiment', [
    'positive',
    'neutral',
    'negative',
]);

Fluent Criteria Builder

Add criteria dynamically at runtime:

$choice = Choice::make('Assign bug severity')
    ->criterion('sev1', 'Critical production outage affecting all users')
    ->criterion('sev2', 'Major feature broken with no workaround')
    ->criterion('sev3', 'Minor cosmetic issue or localized glitch');

Response Evaluation

The response provides the winning category, the model’s confidence, and the full probability breakdown:

$response = SystemOne::state($ticketText)
    ->ask('department', $choice)
    ->run();

// The winning category key
$selected = $response->value('department'); // "billing"

// Confidence of the selected pick (0.0 to 1.0)
$confidence = $response->confidence('department'); // 0.892

// Full probability distribution across all criteria
$probabilities = $response->probabilities('department');
/*
[
    'billing' => 0.892,
    'support' => 0.075,
    'sales'   => 0.023,
    'legal'   => 0.010,
]
*/
flowchart LR
    State["Ticket Text State"] --> ChoiceEval["Choice Evaluation<br/><i>'Which department should handle this ticket?'</i>"]
    ChoiceEval --> Dist["Softmax Distribution Across Criteria<br/>billing: 89.2%<br/>support: 7.5%<br/>sales: 2.3%<br/>legal: 1.0%"]
    Dist --> Winner["Resolved Selection<br/><code>value(): 'billing'</code><br/><code>confidence(): 0.892</code>"]

Serialized Schema

Choice::toArray() serializes into:

{
  "type": "choice",
  "instructions": "Which department should handle this ticket?",
  "criteria": {
    "billing": "Invoices, refunds, chargebacks, and payment methods",
    "support": "Technical bugs, platform outages, and troubleshooting",
    "sales": "Plan upgrades, enterprise custom quotes, and demo requests"
  }
}

3. Score (Bounded Ranges & Rubrics)

Score evaluates continuous numerical ratings or maps state against an ordered rubric scale.

Mode A: Bounded Numerical Range

Used when you need a rating within a specific numerical boundary (e.g., 1 to 10, or 0 to 100):

use Obelaw\SystemOne\Primitives\Score;

// Factory helper for range
$score = Score::range('Rate lead purchase intent from 1 to 10', 1, 10);

// Or via fluent setters
$score = Score::make('Calculate credit risk score')
    ->min(300)
    ->max(850);

Mode B: Ordered Rubric Scale

Used when evaluating qualitative quality levels that have an inherent order:

$rubric = Score::rubric('Rate ticket urgency', [
    'Low',
    'Medium',
    'High',
    'Critical',
]);

When evaluated as a rubric, the driver returns the continuous rating mapped against the rubric indices (e.g. 3.8 indicates very close to “Critical”).

Response Evaluation

$response = SystemOne::state($leadProfile)
    ->ask('fit_score', Score::range('ICP fit score 1-10', 1, 10))
    ->ask('urgency', Score::rubric('Buyer timeline', ['Browsing', 'Evaluating', 'Ready to Buy']))
    ->run();

$fit = $response->value('fit_score'); // 8.7 (float)
$urgency = $response->value('urgency'); // 2.9 (float)
$confidence = $response->confidence('fit_score'); // 0.91
flowchart TD
    subgraph RangeMode["Mode A: Bounded Numerical Range"]
        R1["Score::range('ICP fit score 1-10', 1, 10)"] --> R2["Continuous Numerical Output: 8.7 / 10<br/><code>confidence(): 0.91</code>"]
    end

    subgraph RubricMode["Mode B: Ordered Rubric Scale"]
        B1["Score::rubric('Buyer timeline', ['Browsing', 'Evaluating', 'Ready to Buy'])"] --> B2["Interpolated Scale Position: 2.9 / 3.0<br/>(Tightly maps toward 'Ready to Buy')"]
    end

Serialized Schema

Range Schema:

{
  "type": "score",
  "instructions": "ICP fit score 1-10",
  "min": 1,
  "max": 10
}

Rubric Schema:

{
  "type": "score",
  "instructions": "Buyer timeline",
  "criteria": [
    "Browsing",
    "Evaluating",
    "Ready to Buy"
  ]
}

Primitive Comparison Cheat Sheet

PrimitiveReturn TypePrimary MethodsBest For
Noulfloat [0.0, 1.0]make(), isPositive(), isNegative()Binary classification, anomaly detection, policy compliance.
Choicestring (Key)make(), criterion(), probabilities()Categorization, routing, intent dispatch, multi-class labels.
Scorefloat / intrange(), rubric(), min(), max()Quality ratings, credit scoring, lead qualification, urgency.

Next Steps

Our Premium Sponsors

Obelaw is proudly open-source. Continued development, bug fixes, and community support are made possible by the generosity of our sponsors.

Sponsor Obelaw