Agent X is a verifiable decision engine: it reads documents, checks claims against the live web, scores decisions, and refuses to act on anything it cannot prove — leaving a tamper-evident record anyone can recompute without trusting us.

The problem

Every AI product today has the same failure mode. It is not that the AI is wrong. It is that the AI is confidently wrong, and nothing records why anyone believed it.

Inspiration

The expensive failure in AI is not "the model was wrong." It is "the model was confidently wrong, and nothing recorded why anyone believed it."

Three versions of the same disaster:

  1. A document AI reads a vendor invoice and reports a total. Finance approves payment. Nobody can later prove what the document actually said.
  2. An AI advisor tells a founder their idea is strong. It cites sources. The sources do not exist.
  3. A security dashboard shows an exposed industrial device. The device was placeholder demo data. An operator dispatches a team.

In all three the output looked identical to a true output. That is the entire problem.

We did not want another AI that produces answers. We wanted one that produces answers you can check — and that refuses to act when it cannot.

What it does

Agent X is a verifiable decision engine. One invariant governs everything:

$$\textbf{Assertion} \neq \textbf{EffectiveFact}$$

An assertion is "this document, page 3, in these exact words, claims X." An effective fact is "X is a value the system is willing to act on."

Extraction confidence is a statement about the parser, not about the world. A crisp scan of an obsolete runbook has high confidence and low authority — and a system that blends those into one number has destroyed the only signal that mattered.

WHAT EVERY AI TOOL DOES

document ──▶ [ AI ] ──▶ "Total: $4,200" ──▶ human approves (no evidence, no record)

WHAT AGENT X DOES

document ──▶ hash the bytes ──▶ extract ASSERTIONS (value + page + exact quote + confidence) ──▶ detect CONFLICTS between sources ──▶ gate: promote automatically OR route to a human ──▶ EFFECTIVE FACT (versioned, cites its assertions) ──▶ action permitted only if the fact exists ──▶ every step appended to a hash chain

Four capabilities on one spine

Document Trust Gate — reads vendor and compliance packets into typed assertions with page-level citations and exact printed quotes. Detects conflicts between sources, holds anything it would not promote alone, and closes each packet at a named disposition — CLEARED, REVIEW_COMPLETE, HOLD, AWAITING_EVIDENCE, EXCEPTION_APPROVED, REJECTED — never a numeric trust score, because a number implies a calibration nobody has validated.

Idea Investigation — writes its own search plan, retrieves live web evidence, scores five weighted dimensions from what actually came back, computes a verdict it is structurally forbidden from authoring, runs a sensitivity analysis on its own numbers, and names every dimension it could not establish. A cross-examine mode re-runs the whole investigation biased toward disconfirming evidence.

Threat Intelligence — maps incident and advisory text onto MITRE ATT&CK (ICS and Enterprise) with per-mapping evidence, cross-references the live CISA Known Exploited Vulnerabilities catalogue, and fuses physical hazard proximity from USGS, NOAA and GDACS so the operational picture includes the storm as well as the open port.

Payables — turns a read invoice into an approval workflow governed by an explicit finite-state machine, where an invoice whose total could not be established cannot be approved at all.

Vendor Packet Review runs all four over a single upload and seals the result into one recomputable chain.

The mathematics

The hash chain

Every step is appended so that tampering is detectable by recomputation rather than by trusting a log:

$$H_0 = \underbrace{000\ldots0}{64}, \qquad H_n = \text{SHA256}\big(H{n-1} \,|\, \text{canon}(d_n)\big)$$

where \(\text{canon}(d)\) is canonical JSON — sorted keys, no whitespace — so identical content always hashes identically.

A record is intact if and only if:

$$\text{intact} \iff \forall n:\; H_n = \text{SHA256}\big(H_{n-1} \,|\, \text{canon}(d_n)\big)$$

Real output from our test suite:

original chain → intact: True edited step 2 (total → 999999) → intact: False, broken_at: 2

You do not trust our logs. You recompute them.

The promotion gate

A claim is promoted automatically only if:

$$\text{promote}(a) \iff \text{conf}(a) \geq \theta_c \;\wedge\; \text{auth}(a) \geq \theta_a \;\wedge\; a \notin \text{Conflicted}$$

with \(\theta_c = 0.98\) and \(\theta_a = 90\). These are deliberately high, because the failure is asymmetric: wrongly promoting puts a bad number into a real action, while wrongly queueing costs a reviewer five seconds. So it queues.

Conflict detection with per-predicate tolerance

$$\text{conflict} \iff \frac{|x - y|}{\max(|x|, |y|, 1)} > \tau(p)$$

where the tolerance depends on what kind of thing is being compared:

$$\tau(\text{money}) = 0, \qquad \tau(\text{delay}) = 0.05, \qquad \tau(\text{default}) = 0.01$$

Money has zero tolerance, because "close enough" on an amount is exactly how a fee stops being visible. And a rule pure arithmetic misses:

$$\text{unit}(x) \neq \text{unit}(y) \;\Longrightarrow\; \text{conflict}$$

100 USD vs 100 EUR is a conflict even though \(100 = 100\).

Comparison Result
100.00 vs 100.0 agree — same money, different text
100 USD vs 100 EUR CONFLICT — incomparable
100.00 vs 100.01 CONFLICT — money is exact
180 days vs 90 days CONFLICT — real disagreement

Severity depends on who disagrees:

$$\text{severity} = \begin{cases} \text{blocking} & |{a : \text{auth}(a) \geq 80}| \geq 2 \;\vee\; p \in \text{Critical}\ \text{material} & |{a : \text{auth}(a) \geq 80}| = 1\ \text{minor} & \text{otherwise} \end{cases}$$

Two authoritative documents contradicting each other is a different event from a phone photo contradicting a signed contract.

Evidence combination

Independent facts supporting the same claim are combined by noisy-OR, never averaged:

$$c = 1 - \prod_{i}(1 - c_i)$$

Three weak independent sources make a claim stronger. Averaging would destroy that.

The decision score the model may not compute

$$S = \sum_i w_i s_i, \qquad s_i \in [0, 100], \qquad \sum_i w_i = 1$$

$$w_{\text{demand}} = 0.30,\; w_{\text{competition}} = 0.20,\; w_{\text{differentiation}} = 0.20,\; w_{\text{monetization}} = 0.15,\; w_{\text{execution}} = 0.15$$

$$V(S) = \begin{cases} \text{BUILD} & S \geq 70\ \text{REFINE} & 45 \leq S < 70\ \text{SHELVE} & S < 45 \end{cases}$$

The model supplies only the five sub-scores. \(S\) and \(V\) are computed in code. This makes it structurally impossible for the headline to contradict the reasoning beneath it — the classic failure where a paragraph explains that competition is brutal and an 82 sits on top of it. Sub-scores are clamped, \(s_i \leftarrow \max(0, \min(100, s_i))\), because a model returning 140 for demand is out of contract, not enthusiastic.

Sensitivity — what would change the verdict

A score alone is a dead end, so we derive what to actually do:

$$\text{gap} = T_{\text{next}} - S, \qquad \text{headroom}_i = (100 - s_i)\cdot w_i$$

$$\text{fragility} = \min_i {\delta : V(S \mid s_i - \delta) < V(S)}$$

Real output:

sub-scores: demand 62, competition 38, differentiation 55, monetization 58, execution 52

S = 0.30(62) + 0.20(38) + 0.20(55) + 0.15(58) + 0.15(52) = 53.7 → 54 V(54) = REFINE gap to BUILD = 16 any single dimension able to close it alone? NO fragility: verdict holds unless demand falls 31 points

That stops being a score and starts being a brief.

Geographic hazard proximity

$$a = \sin^2!\left(\tfrac{\Delta\varphi}{2}\right) + \cos\varphi_1\cos\varphi_2\sin^2!\left(\tfrac{\Delta\lambda}{2}\right), \qquad d = 2R\arcsin\sqrt{a}$$

with \(R = 6371\) km, plus initial bearing:

$$\theta = \operatorname{atan2}\big(\sin\Delta\lambda\cos\varphi_2,\; \cos\varphi_1\sin\varphi_2 - \sin\varphi_1\cos\varphi_2\cos\Delta\lambda\big)$$

No country filter, deliberately. A wildfire in Ontario is a genuine threat to a Michigan grid asset, and a state-scoped query misses it entirely. Validated against known truth: Detroit → Toronto computes to 333 km bearing 63° (ENE).

The citation guard

Exhibits \(E\) are retrieved before the model is called. Afterwards, every citation is checked server-side:

$$\forall k \in \text{citations}: \quad k \notin E \;\Longrightarrow\; \text{strip } [k], \text{ keep the sentence}$$

The claim survives, demoted to unsourced — deleting the sentence would hide that the model asserted something unsupported. Then sourcing is measured, not claimed:

$$\text{sourcing_rate} = \frac{|{\text{sentences with a valid citation}}|}{|{\text{sentences}}|}, \qquad \text{exhibits_unused} = |E| - |E \cap \text{cited}|$$

That last metric is the one a product is least inclined to volunteer about itself: retrieving 21 documents and using 6 is a weaker result than retrieving 6 and using 6.

input : "SpaceX runs a rideshare programme [1]. SEOPS resells it [2,9]. The market is growing fast [47]." removed (invented): [9, 47] sourcing_rate: 0.5 exhibits_used: 2 exhibits_unused: 1

The payables state machine

$$\delta: \mathcal{S} \to 2^{\mathcal{S}}, \qquad \text{transition}(i, s') \text{ succeeds} \iff s' \in \delta(s(i))$$

HELD ──▶ PENDING ──▶ APPROVED ──▶ PAID │ │ │ └──▶ REJECTED ◀────────┘

PAID, REJECTED → terminal

$$\text{approve}(i) \text{ permitted} \iff \text{total}(i) \neq \emptyset \;\wedge\; \text{vendor}(i) \neq \emptyset$$

An illegal transition raises — and the refusal is itself written to the audit log, because a refusal is the record of a control working.

How we built it

Python 3.12, FastAPI, Pydantic v2, CockroachDB/PostgreSQL, Jinja2 server-rendered UI. SHA-256 hash chaining, ECDSA over P-256 for signed attestations, AES-256-GCM envelope encryption for crypto-shredded erasure.

The architecture is deliberately layered so that every capability inherits the same guarantees rather than reimplementing them:

┌─────────────────────────────────────────────────────────────┐ │ SURFACE Intelligence screen · Capabilities · Verify │ ├─────────────────────────────────────────────────────────────┤ │ TRACKS Document Idea Threat Payables │ │ Trust Gate Investigation Intel │ │ + Vendor Packet Review (all four) │ ├─────────────────────────────────────────────────────────────┤ │ KERNELS Corroboration │ Trust Gate │ Extraction │ ├─────────────────────────────────────────────────────────────┤ │ FOUNDATION Hash chain · Governor · ECDSA signing │ └─────────────────────────────────────────────────────────────┘

One corroboration gateway serves every capability that needs the current state of the world — checking a claim printed in a vendor document, asking whether an idea already has competitors, sweeping for incidents near a physical asset. All three inherit the same provider fallback chain and the same citation guard. One hash rule covers every record, so a verifier that can check an erasure certificate can check a resolution receipt.

Capabilities are declared in a single registry that resolves availability at call time by probing the backing module — nothing is hardcoded as available, because a hardcoded status is a claim that survives the code it describes being deleted.

The Vendor Packet Review flow

READ hash bytes → extract with page citations → detect conflicts unread fields stay ABSENT and are named ▼ CORROBORATE only claims the document PRINTED are searched no result → "unverified", never "false" ▼ RAISE PAYABLE built ONLY from promoted facts no total established → HELD → approval returns 409 ▼ ASSESS only infrastructure the document DISCLOSED nothing disclosed → stage reports SKIPPED and why ▼ SEAL all steps hash-chained; a button recomputes it live

Stage 3 cannot invent a total, because stage 1 refused to establish one. That dependency is the product — the result is better than any stage alone, which is the only honest justification for composing them.

Challenges we ran into

Determinism versus live evidence. Our internal corpus retrieval is deterministic and offline, and that property is load-bearing — a record's chain is only meaningful if it can be reconstructed. Live web search cannot offer that; a search API returns different rows on different days. Folding live results into the deterministic path was the obvious first design and it was wrong: it would have silently turned a reproducible record irreproducible while leaving every reproducibility claim standing. They are now separate subsystems with separate guarantees. Live evidence is auditable — pinned to provider, query, timestamp and upstream search ID — but explicitly not reproducible, and the API reports reproducible: false rather than letting a caller assume otherwise.

A scalar-only fact model. Our first gate treated an invoice's eight line items as an eight-way conflict, freezing the packet and sending a reviewer to adjudicate a disagreement that does not exist. Conflict detection rests on an assumption true of most predicates and false of a few — that one subject has one value. Repeating predicates now collect into a single list-valued fact instead of contesting each other.

Retrieval volume read as market signal. An early version of the scorer counted whatever a search returned as competitor evidence — and concluded a satellite-rideshare marketplace was in a crowded field on the strength of a tax-ID validator and a thread about breweries. We added a relevance gate requiring an exhibit to actually mention a distinctive term from the idea, and we report how many were excluded rather than quietly dropping them.

Keyword-index semantics. A Google-shaped natural-language query returns zero hits on a strict AND-index, which the system then reported as "the web is silent" — a false negative dressed as a finding. Queries are now narrowed at the provider that needs narrowing, rather than degrading the query every other provider handles correctly.

Salience is not word order. Our first keyword extractor took the leading terms of a sentence, so "a booking platform for small satellite operators to compare and reserve rideshare slots" searched for booking small and dropped satellite and rideshare — the only two words identifying the idea at all.

Accomplishments that we're proud of

We refused four shortcuts that would have made the demo better. Each is a pattern that is extremely tempting in a hackathon, and each is absent by deliberate decision:

Shortcut refused Why it is dangerous
A sample asset feed when discovery is unconfigured A fabricated exposed water-treatment plant in a threat matrix is something an operator acts on
Defaulting domain availability to "available" A founder reading "available" about a name nobody checked will go and build a brand on it
Deriving invoice line items and tax from the total An approval carrying a tax figure nobody computed is one somebody signs
Synthesising a vendor contact address A plausible address that reaches nobody — or worse, reaches someone else

Instead:

POST /api/agentx/threatintel/discover (no Censys key) → 503 "Asset discovery needs CENSYS_API_KEY. No assets are returned and none are invented."

It is genuinely live with zero API keys. Hacker News/Algolia, CISA KEV (1,694 live entries), USGS, NOAA and GDACS need no credential — so anyone cloning the repo gets real URLs that were really fetched, not a fixture wearing a live label. Every configured key improves that answer; none is required for it to be true.

Honest degradation everywhere. Every capability distinguishes cannot from found nothing. An absent search result returns "unverified, not false." A failed geo feed warns that fewer events are shown than are actually occurring. The local extraction tier is labelled as such rather than presented as schema-aware extraction. The in-memory ledger reports durable: false, because "approved" means something different when the approval does not survive a restart.

Verified, not asserted: 650 tests passing with 0 errors. 79 routes swept with 0 faults. 0 dead controls across 73 buttons and links in 9 templates. 0 dependencies added.

What we learned

Trust is an engineering problem, not a copywriting one. Every guarantee here is a mechanism, not a promise: the model is structurally prevented from writing its own headline score; fabricated citations are removed, not warned about; an unreadable invoice is unapprovable, not merely flagged.

The honest answer is usually the more useful one. Reporting exhibits_unused, naming the dimensions we could not establish, admitting the ledger is not durable — every one of those made the output more actionable, not less impressive.

"Cannot" and "found nothing" are different findings. Collapsing them is the single most common way an automated system starts manufacturing conclusions — and it is the one mistake that is invisible in a demo and expensive in production.

Availability belongs per capability, not per product. A missing credential should disable the one thing that needs it, not the whole surface that contains it.

What's next for Agent X

  • Anchoring chain heads to an external timestamping authority for non-repudiation
  • Organisation-specific policy packs with versioned approval thresholds
  • STIX/TAXII bidirectional ingestion so external threat feeds enrich asset dossiers automatically
  • Shared review queues with team annotations, so reviewers collaborate instead of working in silos

Three concrete versions of this:

A document AI reads a vendor invoice and reports a total. A finance person approves payment. Nobody can later prove what the document actually said. An AI startup advisor tells a founder their idea is great. It cites sources. The sources do not exist. A security tool shows an exposed industrial device. The device was a placeholder in the demo data. An operator dispatches a team. In all three, the output looked identical to a true output. That is the whole problem.

Agent X's thesis: every consequential claim must be (a) bound to evidence, (b) gated by a human where risk warrants, and (c) recorded in a way a stranger can verify without trusting the operator.

The core idea, in one diagram

    WHAT EVERY AI TOOL DOES
    ───────────────────────

document ──▶ [ AI ] ──▶ "Total: $4,200" ──▶ human approves (no evidence, no record)

    WHAT AGENT X DOES
    ─────────────────

document ──▶ hash the bytes ──▶ extract ASSERTIONS (value + page + exact quote + confidence) ──▶ detect CONFLICTS between sources ──▶ gate: promote automatically OR send to human ──▶ EFFECTIVE FACT (versioned, cites its assertions) ──▶ action allowed only if fact exists ──▶ every step appended to a hash chain The single invariant that makes this work:

                Assertion  ≠  EffectiveFact

An assertion is "this document, on page 3, in these words, claims X." An effective fact is "X is a value the system will act on."

Extraction confidence is a statement about the parser, not about the world. A crisp scan of an obsolete runbook has high confidence and low authority. Blending those into one number destroys the only signal that mattered.

What we actually built Six separate hackathon projects were merged into one product — not bolted together side by side. Four capability tracks over three shared kernels, all on one audit spine.

┌─────────────────────────────────────────────────────────────┐ │ SURFACE Intelligence screen · Capabilities · Verify │ ├─────────────────────────────────────────────────────────────┤ │ TRACKS Document Idea Threat Payables│ │ Trust Gate Investigation Intel │ │ + Vendor Packet Review (all four) │ ├─────────────────────────────────────────────────────────────┤ │ KERNELS Corroboration │ Trust Gate │ Extraction │ ├─────────────────────────────────────────────────────────────┤ │ FOUNDATION Hash chain · Governor · ECDSA signing │ └─────────────────────────────────────────────────────────────┘

THE MATH

  1. The hash chain (tamper evidence) Every step of every decision is appended to a chain:

    H₀ = 0000...0 (64 zeros, the genesis hash)

    Hₙ = SHA256( Hₙ₋₁ ‖ canon(dₙ) ) where canon(d) is canonical JSON — sorted keys, no whitespace — so the same content always hashes the same, and ‖ is concatenation.

Plain English: each step's fingerprint is computed from the previous step's fingerprint plus this step's content. Change any step, and every fingerprint after it stops matching.

Verification — anyone holding the record recomputes:

intact  ⟺  ∀n :  Hₙ == SHA256( Hₙ₋₁ ‖ canon(dₙ) )

Proof it works (real output from our test):

original chain              → intact: True
edited step 2 (total→999999) → intact: False, broken_at: 2

You do not have to trust our logs. You recompute them.

  1. The promotion gate (assertion → fact) A claim is promoted automatically only if:

    promote(a) ⟺ conf(a) ≥ θc ∧ auth(a) ≥ θa ∧ a ∉ Conflicted

    where θc = 0.98 (confidence threshold) θa = 90 (source authority threshold) Otherwise it goes to a human. Thresholds are deliberately high because the failure is asymmetric:

    wrongly promoting → a bad number enters a real action wrongly queueing → a reviewer loses 5 seconds So it queues.

  2. Conflict detection (per-predicate tolerance) Two sources disagree on the same fact key. Do they actually conflict?

                | x − y |
    

    conflict ⟺ ───────────────── > τ(p) max(|x|,|y|,1) where τ(p) is the tolerance for that predicate:

    τ(money) = 0.0 ← exact. "close enough" is how a fee disappears τ(delay_mins) = 0.05 τ(default) = 0.01 Plus a rule pure arithmetic misses:

    unit(x) ≠ unit(y) ⟹ conflict, regardless of numeric equality 100 USD vs 100 EUR is a conflict even though 100 = 100.

Results this produces:

100.00  vs  100.0   → agree      (same money, different text)
100 USD vs 100 EUR  → CONFLICT   (incomparable)
100.00  vs  100.01  → CONFLICT   (money has zero tolerance)
180 days vs 90 days → CONFLICT   (real disagreement)
  1. Conflict severity (who is disagreeing matters)

    severity = blocking if |{a : auth(a) ≥ 80}| ≥ 2 ∨ p ∈ Critical material if |{a : auth(a) ≥ 80}| = 1 minor otherwise Two authoritative documents contradicting each other is a different event from a phone photo contradicting a signed contract.

  2. Evidence confidence (noisy-OR) Multiple independent facts supporting the same claim are combined by noisy-OR, not averaged:

    c = 1 − ∏ (1 − cᵢ) i Plain English: three weak independent pieces of evidence make a claim stronger, not average-weak. Averaging would destroy that.

  3. The decision score (the model is not allowed to do this arithmetic) For idea/venture evaluation, five sub-scores are weighted:

    S = Σ wᵢ · sᵢ where s ∈ [0,100] i

    w_demand = 0.30 w_competition = 0.20 w_differentiation = 0.20 w_monetization = 0.15 w_execution = 0.15 ───── 1.00 Verdict is a step function:

    V(S) = BUILD if S ≥ 70 REFINE if 45 ≤ S < 70 SHELVE if S < 45 Critical design rule: the model supplies only the five sub-scores. S and V are computed here. This makes it structurally impossible for the headline number to contradict the reasoning underneath it — the classic failure where a paragraph explains that competition is brutal and an 82 sits above it.

Sub-scores are clamped before weighting:

sᵢ ← max(0, min(100, sᵢ))

A model returning 140 for demand is not expressing enthusiasm worth preserving. It is out of contract.

  1. Sensitivity analysis (what would change the verdict) A score alone is a dead end. We compute:

Gap to next verdict:

gap = T_next − S        where T_next ∈ {45, 70}

Headroom per dimension (where effort actually pays):

headroomᵢ = (100 − sᵢ) · wᵢ

Can any single dimension close the gap alone?

∃i : V( S with sᵢ → 100 ) = V_next  ?

Fragility — the smallest single drop that demotes the verdict:

fragility = min { δ : V( S with sᵢ − δ ) < V(S) }
             i

Real output from our engine, reproducing a documented run exactly:

sub-scores: demand 62, competition 38, differentiation 55,
            monetization 58, execution 52

S = 0.30(62) + 0.20(38) + 0.20(55) + 0.15(58) + 0.15(52)
  = 18.6 + 7.6 + 11.0 + 8.7 + 7.8
  = 53.7  →  54

V(54) = REFINE
gap to BUILD = 16
any single lever closes it? NO
fragility: holds unless demand falls 31 points

That last line stops being a score and starts being a brief.

  1. Geographic proximity (haversine + bearing) Physical hazards near an industrial asset:

    a = sin²(Δφ/2) + cos φ₁ · cos φ₂ · sin²(Δλ/2)

    d = 2R · arcsin( √a ) R = 6371 km Bearing from asset to hazard:

    θ = atan2( sin Δλ · cos φ₂ , cos φ₁ · sin φ₂ − sin φ₁ · cos φ₂ · cos Δλ ) No country filter, deliberately. A wildfire in Ontario is a real threat to a Michigan grid asset. A state-scoped query misses it entirely. That is why this is geometry and not a region lookup.

Validated against known truth:

Detroit → Toronto:  333 km, bearing 63° (ENE)     [actual: ~333 km, ENE]
  1. Citation guard (hallucinated sources stripped server-side) Given exhibits E = {1..n} retrieved before the model was called:

    for each citation [k] in model output: if k ∉ E → strip [k], keep the sentence The claim survives, demoted to unsourced. Deleting the sentence would hide that the model asserted something unsupported.

Sourcing rate is then measured, not claimed:

                |sentences carrying a valid citation|
sourcing_rate = ──────────────────────────────────────
                      |sentences|

And the metric a product is least inclined to volunteer about itself:

exhibits_unused = |E| − |E ∩ cited|

Retrieving 21 documents and using 6 is a weaker result than retrieving 6 and using 6. We report the difference.

Real output:

input : "SpaceX runs a rideshare programme [1]. SEOPS resells it [2,9].
         The market is growing fast [47]."
removed (invented): [9, 47]
sourcing_rate: 0.5   exhibits_used: 2   exhibits_unused: 1
  1. Invoice state machine (money cannot move backwards)

    HELD ──▶ PENDING ──▶ APPROVED ──▶ PAID │ │ │ └──▶ REJECTED ◀────────┘

    PAID → {} (terminal) REJECTED → {} (terminal) Transition is allowed iff s' ∈ δ(s). Illegal transitions raise, and the refusal is itself written to the audit log — a refusal is the record of a control working.

Plus a guard:

approve(i) allowed  ⟺  total(i) ≠ ∅  ∧  vendor(i) ≠ ∅

An invoice whose total could not be read cannot be approved at all.

The hero flow — vendor packet review One upload runs every capability, each stage consuming the last:

┌────────────────────────────────────────────────────────────────┐ │ 1. READ │ │ hash bytes → extract with page citations → detect conflicts │ │ unread fields stay ABSENT and are named │ └───────────────────────────┬────────────────────────────────────┘ ▼ ┌────────────────────────────────────────────────────────────────┐ │ 2. CORROBORATE │ │ only claims the document PRINTED are searched │ │ no result → "unverified", never "false" │ └───────────────────────────┬────────────────────────────────────┘ ▼ ┌────────────────────────────────────────────────────────────────┐ │ 3. RAISE PAYABLE │ │ built ONLY from promoted facts │ │ no total established → invoice HELD → approval returns 409 │ └───────────────────────────┬────────────────────────────────────┘ ▼ ┌────────────────────────────────────────────────────────────────┐ │ 4. ASSESS EXPOSURE │ │ only infrastructure the document DISCLOSED │ │ nothing disclosed → stage reports SKIPPED + why │ └───────────────────────────┬────────────────────────────────────┘ ▼ ┌────────────────────────────────────────────────────────────────┐ │ 5. SEAL │ │ all steps hash-chained; "Recompute" button proves it live │ └────────────────────────────────────────────────────────────────┘

Why this is more than five tools in a row: stage 3 cannot invent a total, because stage 1 refused to establish one. The dependency is the product.

Built With

  • aes-256-gcm
  • censys
  • cisa-kev
  • cockroachdb
  • ecdsa
  • fastapi
  • gdacs
  • hacker-news-api
  • httpx
  • javascript
  • jinja
  • litellm
  • mitre-att&ck
  • noaa
  • nutrient-dws
  • postgresql
  • pydantic
  • pytest
  • python
  • serpapi
  • sha-256
  • tailwindcss
  • usgs
  • xano
Share this project:

Updates

Submission history