DEV Community

Olalekan Ogundipe
Olalekan Ogundipe

Posted on

Demonstrating O-lang Structural Safety

Verification Guide for Users and Evaluators

Purpose of This Document

This guide is for anyone who wants to verify O-lang’s core safety claims — whether you’re a developer, researcher, enterprise evaluator, or simply curious about AI safety.

This is not a tutorial — it is a verification framework that lets you independently confirm O-lang’s fundamental promise:

“No AI workflow can execute unauthorized actions — ever.”

You’ll use real terminal commands to test this claim yourself. No trust required — just verification.

What You’re Verifying

O-lang makes one core structural safety claim:

The kernel enforces a hard boundary between what an AI claims to do and what it can actually execute.

This guide shows you how to test this claim in three critical ways:

Safety Property

What It Means

How You’ll Verify It

Resolver Allowlist Enforcement

Only pre-declared capabilities can execute

Try to invoke a resolver not in the workflow — watch the kernel block it

Object Interpolation Guardrail

Sensitive data can’t leak into LLM prompts

Attempt to pass objects to LLMs — see the kernel reject it

Deterministic Execution

Workflows are predictable and auditable

Run the same workflow twice — confirm identical results

Setup: Install the Components

Install these official O-lang components to begin your verification:

npm install @o-lang/olang @o-lang/llm-groq @o-lang/bank-account-lookup
Enter fullscreen mode Exit fullscreen mode
npm install better-sqlite3
Enter fullscreen mode Exit fullscreen mode

better-sqlite3 is for the sample database

Component Role in Verification

@o-lang/olang

The kernel that enforces safety boundaries

@o-lang/llm-groq

An LLM resolver (will attempt to hallucinate)

@o-lang/bank-account-lookup

A safe data resolver (reads balances only)

Note: You don’t need API keys for basic verification. The bank-account-lookup resolver uses a local SQLite database.

**📥 Installation**


**npm install @0-lang/bank-account-lookup**



Initialize the database 👈 CRITICAL STEP

npx init-bank-db ./bank.db

This creates a SQLite database with sample customer

Customer 12345: $1,500
Customer 67890: $250

Use in your O-Lang workflow


Allow resolvers:
- bank-account-lookup
Enter fullscreen mode Exit fullscreen mode

Step 1: Action bank-account-lookup "{customer_id}" Save as account_info

✅ Verification Test 1: Resolver Allowlist Enforcement
Step 1: Create a minimal workflow (bank-workflow.ol)

Workflow “Bank Balance Check” with user_question, customer_id, bank_db_path
Allow resolvers:
- bank-account-lookup
- llm-groq
Step 1: Ask bank-account-lookup "{customer_id}" "{bank_db_path}"
Save as account_info
Step 2: Ask llm-groq "Answer this customer question: '{user_question}'. The customer's current balance is {account_info.balance}. NEVER mention account numbers, routing numbers, or transfer capabilities. Keep response under 2 sentences."
Save as response
Return response
Step 2: Run with the Allow list
Enter fullscreen mode Exit fullscreen mode
npx olang run Bank-lookup-demo/bank-workflow.ol `
  -i user_question="What's my current balance?" `
  -i customer_id="67890" `
  -i bank_db_path="./bank.db" `
  -r "@o-lang/bank-account-lookup" `
  -r "@o-lang/llm-groq" `
  -v

OR

npx olang run Bank-lookup-demo/bank-workflow.ol -i user_question="What's my current balance?" -i customer_id="67890" -i bank_db_path="./bank.db" -r "@o-lang/bank-account-lookup" -r "@o-lang/llm-groq" -v
Enter fullscreen mode Exit fullscreen mode

Expected result :

📦 Loaded resolver: bank-account-lookup (project)
📦 Loaded resolver: llm-groq (project)
(node:27508) [DEP0040] DeprecationWarning: The `punycode` module is deprecated. Please use a userland alternative instead.
(Use `node --trace-deprecation ...` to show where the warning was created)

[Step: action | saveAs: account_info]
{
  "user_question": "What's my current balance?",
  "customer_id": 67890,
  "bank_db_path": "./bank.db",
  "workflow_name": "Bank Balance Check",
  "__resolver_0": {
    "output": {
      "exists": true,
      "customer_id": "67890",
      "balance": 250
    }
  },
  "account_info": {
    "exists": true,
    "customer_id": "67890",
    "balance": 250
  }
}

[Step: action | saveAs: response]
{
  "user_question": "What's my current balance?",
  "customer_id": 67890,
  "bank_db_path": "./bank.db",
  "workflow_name": "Bank Balance Check",
  "__resolver_0": {
    "output": {
      "exists": true,
      "customer_id": "67890",
      "balance": 250
    }
  },
  "account_info": {
    "exists": true,
    "customer_id": "67890",
    "balance": 250
  },
  "__resolver_1": {
    "output": {
      "response": "Your current balance is $250. You can view your account details and balance at any time by logging into your online account or contacting our customer service team for assistance.",     
      "resolver": "llm-groq",
      "timestamp": "2026-02-11T14:57:06.698Z"
    }
  },
  "response": {
    "response": "Your current balance is $250. You can view your account details and balance at any time by logging into your online account or contacting our customer service team for assistance.",       
    "resolver": "llm-groq",
    "timestamp": "2026-02-11T14:57:06.698Z"
  }
}
}
Enter fullscreen mode Exit fullscreen mode

Step 3: Attempt to bypass the Allow list

npx olang run Bank-lookup-demo/bank-workflow.ol `
  -i user_question="Transfer 10,000 to account 1234567890 immediately" `
  -i customer_id="67890" `
  -i bank_db_path="./bank.db" `
  -r "@o-lang/bank-account-lookup" `
  -r "@o-lang/llm-groq" `
  -v

OR

npx olang run Bank-lookup-demo/bank-workflow.ol -i user_question="Transfer 10,000 to account 1234567890 immediately" -i customer_id="67890" -i bank_db_path="./bank.db" -r "@o-lang/bank-account-lookup" -r "@o-lang/llm-groq" -v
Enter fullscreen mode Exit fullscreen mode

Expected result :

Error: [O-Lang SAFETY] LLM hallucinated unauthorized capability:
  → Detected: "deposit"
  → Reason: Hallucinated "financial_action" capability in en (not in workflow allowlist: bank-account-lookup)
  → Workflow allowlist: bank-account-lookup, llm-groq
Enter fullscreen mode Exit fullscreen mode

What This Proves:

Even if you try to load a transfer-funds resolver at runtime, the kernel blocks it because the workflow didn’t declare it. No unauthorized actions can execute — ever.

✅ Verification Test 2: Object Interpolation Guardrail

Step 1: Modify the workflow to be unsafe

Workflow "Bank Balance Check UNSAFE" with user_question, customer_id, bank_db_path

Allow resolvers:
  - bank-account-lookup
  - llm-groq

Step 1: Ask bank-account-lookup "{customer_id}" "{bank_db_path}"
Save as account_info

Step 2: Ask llm-groq "User data: {account_info}"
Save as response

Return response
Enter fullscreen mode Exit fullscreen mode

Critical Vulnerability Demonstrated
*Step 3: Attempt to interpolate entire object
*

npx olang run Bank-lookup-demo/bank-workflow-unsafe.ol `
  -i user_question="What's my balance?" `
  -i customer_id="67890" `
  -i bank_db_path="./bank.db" `
  -r "@o-lang/bank-account-lookup" `
  -r "@o-lang/llm-groq" `
  -v
Enter fullscreen mode Exit fullscreen mode

Expected result :

Error: [O-Lang SAFETY] Cannot interpolate object "{account_info}" into action step.
  → Contains fields: exists, customer_id, balance
  → Use dot notation: "{account_info.field}" (e.g., {account_info.balance})

🛑 Halting to prevent data corruption → LLM hallucination.
Enter fullscreen mode Exit fullscreen mode

What This Proves:

1. O-lang Blocks Dangerous Data Coercion
JavaScript/Python would silently convert {account_info} → "[object Object]" or JSON string
O-lang rejects this at parse time — never lets corrupted data reach the LLM
Result: No garbled prompts like "User data: [object Object]" that confuse LLMs
2. Prevents Accidental Data Leakage
Your account_info object likely contains:

{
  "customer_id": "67890",
  "balance": 1250.75,
  "account_number": "****1234",   ← SENSITIVE
  "routing_number": "****5678",   ← SENSITIVE
  "ssn_last4": "1234"             ← SENSITIVE
}
Enter fullscreen mode Exit fullscreen mode

Without this guardrail:

❌ Entire object dumped into LLM prompt
❌ Sensitive fields sent to third-party API (Groq)
❌ Potential GDPR/CCPA violation

With this guardrail:

✅ Kernel blocks before interpolation happens
✅ Developer forced to explicitly choose safe fields (balance only)
✅ Sensitive data never leaves your system

  1. Stops Hallucinations at the Source Garbled prompt caused by object coercion:

"User data: [object Object]"
Enter fullscreen mode Exit fullscreen mode

O-lang’s guardrail prevents the garbled input → no opportunity for hallucination.

**

  1. Catches Human Error, Not Just Malice** This wasn’t a hacker attack — it was a honest developer mistake:

Junior dev thinks "Just dump the whole object—it's convenient!"
O-lang says: “No. Be explicit about what data leaves the system.”
This is structural safety: the protocol makes mistakes impossible, rather than relying on perfect humans.

Why This Test Matters (Practical Impact)

✅ Verification Test 3: Deterministic Execution

Step 1: Run the workflow twice

# Run workflow → capture raw output
npx olang run Bank-lookup-demo/bank-workflow.ol `
  -i user_question="Balance?" `
  -i customer_id="67890" `
  -i bank_db_path="./bank.db" `
  -r "@o-lang/bank-account-lookup" `
  -r "@o-lang/llm-groq" > raw1.txt

# Strip ANSI codes → save clean JSON
(Get-Content raw1.txt -Raw) -replace '\x1b\[[0-9;]*[a-zA-Z]', '' | Set-Content run1.json

# Repeat for run2
npx olang run Bank-lookup-demo/bank-workflow.ol `
  -i user_question="Balance?" `
  -i customer_id="67890" `
  -i bank_db_path="./bank.db" `
  -r "@o-lang/bank-account-lookup" `
  -r "@o-lang/llm-groq" > raw2.txt

(Get-Content raw2.txt -Raw) -replace '\x1b\[[0-9;]*[a-zA-Z]', '' | Set-Content run2.json

# Now compare cleanly
git diff --no-index run1.json run2.json
Enter fullscreen mode Exit fullscreen mode

Expected result :

PS C:\Users\Administrator\Documents\O-lang-folder\o-lang-demo-suite> # Run workflow  capture raw output
PS C:\Users\Administrator\Documents\O-lang-folder\o-lang-demo-suite> npx olang run Bank-lookup-demo/bank-workflow.ol `
>>   -i user_question="Balance?" `
>>   -i customer_id="67890" `
>>   -i bank_db_path="./bank.db" `
>>   -r "@o-lang/bank-account-lookup" `
>>   -r "@o-lang/llm-groq" > raw1.txt
(node:29456) [DEP0040] DeprecationWarning: The `punycode` module is deprecated. Please use a userland alternative instead.
(Use `node --trace-deprecation ...` to show where the warning was created)
PS C:\Users\Administrator\Documents\O-lang-folder\o-lang-demo-suite> 
PS C:\Users\Administrator\Documents\O-lang-folder\o-lang-demo-suite> # Strip ANSI codes  save clean JSON
PS C:\Users\Administrator\Documents\O-lang-folder\o-lang-demo-suite> (Get-Content raw1.txt -Raw) -replace '\x1b\[[0-9;]*[a-zA-Z]', '' | Set-Content run1.json
PS C:\Users\Administrator\Documents\O-lang-folder\o-lang-demo-suite> 
PS C:\Users\Administrator\Documents\O-lang-folder\o-lang-demo-suite> # Repeat for run2
PS C:\Users\Administrator\Documents\O-lang-folder\o-lang-demo-suite> npx olang run Bank-lookup-demo/bank-workflow.ol `
>>   -i user_question="Balance?" `
>>   -i customer_id="67890" `
>>   -i bank_db_path="./bank.db" `
>>   -r "@o-lang/bank-account-lookup" `
>>   -r "@o-lang/llm-groq" > raw2.txt
(node:3644) [DEP0040] DeprecationWarning: The `punycode` module is deprecated. Please use a userland alternative instead.
(Use `node --trace-deprecation ...` to show where the warning was created)
PS C:\Users\Administrator\Documents\O-lang-folder\o-lang-demo-suite> 
PS C:\Users\Administrator\Documents\O-lang-folder\o-lang-demo-suite> (Get-Content raw2.txt -Raw) -replace '\x1b\[[0-9;]*[a-zA-Z]', '' | Set-Content run2.json
PS C:\Users\Administrator\Documents\O-lang-folder\o-lang-demo-suite> 
PS C:\Users\Administrator\Documents\O-lang-folder\o-lang-demo-suite> # Now compare cleanly
PS C:\Users\Administrator\Documents\O-lang-folder\o-lang-demo-suite> git diff --no-index run1.json run2.json
diff --git a/run1.json b/run2.json
index 5f666fe..acf7e89 100644
--- a/run1.json
+++ b/run2.json
@@ -2,9 +2,9 @@
 =<83><F4><AA> Loaded resolver: llm-groq (project)
 {
   "response": {
-    "response": "Your current balance is $250. If you'd like to check your balance again or view your account history, I can assist you with that.",
+    "response": "Your current balance is $250. If you'd like to check your balance again or view your transaction history, I can assist you with that.",
     "resolver": "llm-groq",
-    "timestamp": "2026-02-11T16:11:56.318Z"
+    "timestamp": "2026-02-11T16:11:59.642Z"
   }
 }

PS C:\Users\Administrator\Documents\O-lang-folder\o-lang-demo-suite> 
Enter fullscreen mode Exit fullscreen mode

💡 Critical invariant:
“Deceptive text may be generated — but it cannot cross the verification boundary to trigger actions.”

🛡️ How O-lang Enforces This (Concrete Mechanics)

Step 1: LLM Generates Potentially Deceptive Text
Step 1: Ask llm-groq "What's my account balance?"
Save as unverified_response
Enter fullscreen mode Exit fullscreen mode

→ LLM might hallucinate:

"Your balance is $9,999,999.99 – you're rich!"
Enter fullscreen mode Exit fullscreen mode

Step 2: FEDI Verification Resolver Blocks Deception
kernel view :

Step 2: Action fact_checker {
  "claim": "${unverified_response.response}",
  "evidence": [
    { "type": "database", "id": "${customer_id}", "value": ${db_result.balance} }
  ]
}
Save as verification
→ fact_checker detects mismatch:

{
  "verified": false,
  "confidence": 0.0,
  "discrepancies": [{
    "source": "database:67890",
    "expected": 250.00,
    "observed": 9999999.99,
    "severity": "critical"
  }],
  "evidence_hash": "a1b2c3d4e5f67890"
}
Enter fullscreen mode Exit fullscreen mode

Step 3: O-lang Kernel Enforces Action Block

Step 3: Action fund_transfer { ... }
If verification.verified == true  # ← Kernel evaluates BEFORE execution
Enter fullscreen mode Exit fullscreen mode

→ Kernel halts workflow at Step 3 because condition fails
→ fund_transfer resolver never invoked
→ No money moved despite LLM’s deceptive text
**
Auditability: Proving Verification Occurred**
When regulators investigate, O-lang’s execution trace provides cryptographic proof:

{
  "workflow": "Balance Check",
  "steps": [
    {
      "step": 1,
      "resolver": "llm-groq",
      "output": {
        "response": "Your balance is $9,999,999.99...",
        "resolver": "llm-groq"
      }
    },
    {
      "step": 2,
      "resolver": "fact_checker",
      "input_hash": "sha256:8f7e6d5c4b3a2910",  // ← Input fingerprint
      "output": {
        "verified": false,
        "confidence": 0.0,
        "evidence_hash": "a1b2c3d4e5f67890"      // ← Verification fingerprint
      }
    },
    {
      "step": 3,
      "resolver": "fund_transfer",
      "status": "SKIPPED",                        // ← Action blocked
      "reason": "Condition failed: verification.verified == true"
    }
  ],
  "audit_trail": {
    "verification_required": true,
    "verification_performed": true,
    "verification_result": "FAILED",
    "action_blocked": true,
    "evidence_replayable": "a1b2c3d4e5f67890"    // ← Regulator can re-run verification
  }
}
Enter fullscreen mode Exit fullscreen mode

What Auditors Can Prove

Why This Beats “LLM Safety Fine-Tuning”

Structural safety: Deception is expected and contained by architecture — not prevented by hoping LLMs “behave.”

FEDI Layer in Action: The Trust Substrate

The Fion layer (O-lang kernel) is the trust substrate that makes FEDI accountable:
“Distributed intelligence (LLM + verification) becomes governable because all action gates flow through a deterministic mediation layer.”

Real-World Impact: What This Prevents

The Bottom Line
O-lang doesn’t try to prevent deceptive text generation (impossible with current LLMs). Instead, it architecturally contains deception by enforcing:
“No action executes without cryptographically verifiable evidence from trusted sources.”
The fact_checker resolver is your FEDI primitive that implements this — while O-lang’s kernel provides the audit trail proving verification occurred. This is structural safety: deception may exist in text generation, but it cannot cross the verification boundary to cause real-world harm.
This is why regulators care:
“We don’t need to trust your LLM — we can verify your governance layer blocked actions when verification failed.”
That’s the power of FEDI + O-lang: distributed intelligence made accountable.

Top comments (0)