soma.cell

Auditor independence — one firm, one client, ONE role

In 2000, Arthur Andersen billed Enron $25 million for the audit — and $27 million for consulting. The firm certifying the books had a bigger business interest in pleasing management than in challenging it. When Enron collapsed, Andersen's partners were found shredding audit workpapers; the firm itself dissolved, taking 85,000 jobs with it. Sarbanes-Oxley §201 answered by making the dual role itself illegal: a registered public accounting firm may not provide most consulting services to an audit client. Not "disclose it" — may not hold both. Here the prohibition is arithmetic. A firm/client pair can hold at most ONE engagement. Signing the audit writes 1; selling consulting to the same client tries to write 2 — and the engagement ledger refuses. The conflict isn't reviewed by an ethics board after the fact; it is a value the books cannot hold. The audit itself runs a machine where `opinion_issued` is terminal: once signed, an opinion cannot be quietly recalled and re-negotiated.

A Soma program from the governance part of the verified corpus: 117 lines, cells EngagementLedger, IndependenceTests. It passes soma check with soma 3.2.4.

How it is built

The cell EngagementLedger declares 5 signals in its face: sign_audit(firm: String, client: String) -> Map, sell_consulting(firm: String, client: String) -> Map, do_fieldwork(firm: String, client: String) -> Map, issue_opinion(firm: String, client: String) -> Map and engagement_load(firm: String, client: String) -> Int; keeps 1 memory slot: engagements (Map<String, Int>, persistent and consistent) under the invariant engagements >= 0 && engagements <= 1. Its state machine audit starts in proposed and allows 3 transitions: proposed -> engaged, engaged -> fieldwork and fieldwork -> opinion_issued. opinion_issued is terminal. Handlers: sign_audit (line 47), sell_consulting (line 59), do_fieldwork (line 70), issue_opinion (line 76) and engagement_load (line 82).

The file also holds 1 test cell (IndependenceTests) with 14 assertions, run by soma test.

Generated from soma describe on this file.

The source

auditor_independence.cell

// ============================================================================
// AUDITOR INDEPENDENCE — one firm, one client, ONE role
// ============================================================================
//
// In 2000, Arthur Andersen billed Enron $25 million for the audit — and
// $27 million for consulting. The firm certifying the books had a bigger
// business interest in pleasing management than in challenging it. When
// Enron collapsed, Andersen's partners were found shredding audit
// workpapers; the firm itself dissolved, taking 85,000 jobs with it.
// Sarbanes-Oxley §201 answered by making the dual role itself illegal:
// a registered public accounting firm may not provide most consulting
// services to an audit client. Not "disclose it" — may not hold both.
//
// Here the prohibition is arithmetic. A firm/client pair can hold at
// most ONE engagement. Signing the audit writes 1; selling consulting
// to the same client tries to write 2 — and the engagement ledger
// refuses. The conflict isn't reviewed by an ethics board after the
// fact; it is a value the books cannot hold. The audit itself runs a
// machine where `opinion_issued` is terminal: once signed, an opinion
// cannot be quietly recalled and re-negotiated.
// ============================================================================

cell EngagementLedger {
    face {
        signal sign_audit(firm: String, client: String) -> Map
        signal sell_consulting(firm: String, client: String) -> Map
        signal do_fieldwork(firm: String, client: String) -> Map
        signal issue_opinion(firm: String, client: String) -> Map
        signal engagement_load(firm: String, client: String) -> Int
    }

    memory {
        // firm:client -> engagements held. The Andersen position
        // (audit + consulting, same client) is the unrepresentable 2.
        engagements: Map<String, Int> [persistent, consistent]
        invariant engagements >= 0 && engagements <= 1
    }

    // an audit engagement's life; opinion_issued is TERMINAL
    state audit {
        initial: proposed
        proposed -> engaged
        engaged -> fieldwork
        fieldwork -> opinion_issued
    }

    on sign_audit(firm: String, client: String) {
        let k = "{firm}:{client}"
        let w = try { engagements.set(k, (engagements.get(k) ?? 0) + 1) }
        if w.error != () {
            return map("ok", false, "reason",
                "SOX 201: {firm} already holds an engagement at {client}")
        }
        let r = try { transition(k, "engaged") }
        if r.error != () { return map("ok", false, "reason", "{r.error}") }
        return map("ok", true, "audit", k)
    }

    on sell_consulting(firm: String, client: String) {
        // SAME ledger, SAME invariant: the second hat does not fit
        let k = "{firm}:{client}"
        let w = try { engagements.set(k, (engagements.get(k) ?? 0) + 1) }
        if w.error != () {
            return map("ok", false, "reason",
                "SOX 201: {firm} cannot consult for an audit client ({client})")
        }
        return map("ok", true, "consulting", k)
    }

    on do_fieldwork(firm: String, client: String) {
        let r = try { transition("{firm}:{client}", "fieldwork") }
        if r.error != () { return map("ok", false, "reason", "{r.error}") }
        return map("ok", true, "state", "fieldwork")
    }

    on issue_opinion(firm: String, client: String) {
        let r = try { transition("{firm}:{client}", "opinion_issued") }
        if r.error != () { return map("ok", false, "reason", "{r.error}") }
        return map("ok", true, "state", "opinion_issued")
    }

    on engagement_load(firm: String, client: String) {
        return engagements.get("{firm}:{client}") ?? 0
    }
}

cell test IndependenceTests {
    rules {
        // Andersen signs the Enron audit — one engagement, lawful
        assert sign_audit("andersen", "enron").ok == true
        assert engagement_load("andersen", "enron") == 1

        // THE $27M TEMPTATION: consulting for the same client. The
        // ledger cannot hold the 2 — refused at the write.
        assert sell_consulting("andersen", "enron").ok == false
        assert_fails engagements.set("andersen:enron", 2)
        assert engagement_load("andersen", "enron") == 1

        // and symmetrically: a consulting-first firm cannot take the audit
        assert sell_consulting("mckinsey", "enron").ok == true
        assert sign_audit("mckinsey", "enron").ok == false

        // different client, no conflict — independence is per-pair
        assert sell_consulting("andersen", "dynegy").ok == true

        // the audit machine: no opinion without fieldwork
        assert issue_opinion("andersen", "enron").ok == false
        assert_fails transition("andersen:enron", "opinion_issued")
        assert do_fieldwork("andersen", "enron").ok == true
        assert issue_opinion("andersen", "enron").ok == true

        // a signed opinion is history — no recall, no re-negotiation
        assert_fails transition("andersen:enron", "fieldwork")
        assert_fails transition("andersen:enron", "proposed")
    }
}

What the toolchain says

Run on a fresh copy of the program at build time; the outputs are pasted unedited.

$ soma check auditor_independence.cell
✓ All checks passed.
$ soma test auditor_independence.cell
test IndependenceTests ...
  ✓ assert sign_audit("andersen", "enron").ok == true
  ✓ assert engagement_load("andersen", "enron") == 1
  ✓ assert sell_consulting("andersen", "enron").ok == false
  ✓ assert_fails engagements.set("andersen:enron", 2) — raised memory invariant violated on 'engagements': engagements >= 0 && engagements <= 1 — rejected write of 2 (key "andersen:enron"); the slot is unchanged
  ✓ assert engagement_load("andersen", "enron") == 1
  ✓ assert sell_consulting("mckinsey", "enron").ok == true
  ✓ assert sign_audit("mckinsey", "enron").ok == false
  ✓ assert sell_consulting("andersen", "dynegy").ok == true
  ✓ assert issue_opinion("andersen", "enron").ok == false
  ✓ assert_fails transition("andersen:enron", "opinion_issued") — raised invalid transition: engaged → opinion_issued. Current state: 'engaged'. Valid targets: [fieldwork]
  ✓ assert do_fieldwork("andersen", "enron").ok == true
  ✓ assert issue_opinion("andersen", "enron").ok == true
  ✓ assert_fails transition("andersen:enron", "fieldwork") — raised invalid transition: opinion_issued → fieldwork. Current state: 'opinion_issued'. Valid targets: []
  ✓ assert_fails transition("andersen:enron", "proposed") — raised invalid transition: opinion_issued → proposed. Current state: 'opinion_issued'. Valid targets: []

14 tests: 14 passed, 0 failed
$ soma verify auditor_independence.cell
Verifying auditor_independence.cell...

State machine 'audit': 4 states, initial 'proposed'
  States: [engaged, fieldwork, opinion_issued, proposed]

  ✓ 4 states, 3 transitions
  ✓ all states reachable from 'proposed'
  ✓ terminal states: [opinion_issued]
  ✓ no deadlocks
  ✓ liveness: every state can eventually reach a terminal state
  ✓ think-isolated: CTL safety properties hold regardless of LLM output (3 handlers, 5 literal transitions, 0 dynamic)
  ✓ termination: all 5 handlers structurally terminate
  ✓ refinement: handler `sign_audit` ⟶ {engaged}
  ✓ refinement: handler `do_fieldwork` ⟶ {fieldwork [if true], fieldwork [if not (true)]}
  ✓ refinement: handler `issue_opinion` ⟶ {opinion_issued [if true], opinion_issued [if not (true)]}
  · transition sources: `sign_audit`, `do_fieldwork`, `issue_opinion` call transition(id, target) without declaring the source — the runtime refuses a move the graph forbids, but the proof does not see where the handler starts; `transition(id, from, to)` names the edge (checked by `soma check`, refused at run time from any other state)

EngagementLedger/invariants:

  ✓ invariant engagements >= 0 — writer 'sell_consulting' proven by induction (writes (engagements.get(k) ?? 0) + 1)
  ✓ invariant engagements >= 0 — writer 'sign_audit' proven by induction (writes (engagements.get(k) ?? 0) + 1)
  ⚠ invariant engagements >= 0 && engagements <= 1 — runtime-checked (computed values): sell_consulting → engagements [engagements <= 1] because `engagements` has no known range; `k` = "{firm}:{client}" — not bounded, sign_audit → engagements [engagements <= 1] because `engagements` has no known range; `k` = "{firm}:{client}" — not bounded

12 passed, 1 warnings, 0 failures

  Temporal properties for 'audit':
  ✓ deadlock_free — no deadlocks in any reachable state
Temporal: 1 passed, 0 failed
VERIFY OK

Builtins used

map, transition

Source file: /corpus/governance/auditor_independence.cell · examples/corpus/governance/auditor_independence.cell