<?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: Alfino Hatta</title>
    <description>The latest articles on DEV Community by Alfino Hatta (@alfinohatta).</description>
    <link>https://dev.to/alfinohatta</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%2F4015611%2F06c0614c-40f0-491a-b71d-d9a3d81cb788.jpg</url>
      <title>DEV Community: Alfino Hatta</title>
      <link>https://dev.to/alfinohatta</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/alfinohatta"/>
    <language>en</language>
    <item>
      <title>Building Recourse.ai: A Parametric Insurance Prototype for the Age of Agentic AI</title>
      <dc:creator>Alfino Hatta</dc:creator>
      <pubDate>Sat, 18 Jul 2026 09:49:19 +0000</pubDate>
      <link>https://dev.to/alfinohatta/building-recourseai-a-parametric-insurance-prototype-for-the-age-of-agentic-ai-1mdc</link>
      <guid>https://dev.to/alfinohatta/building-recourseai-a-parametric-insurance-prototype-for-the-age-of-agentic-ai-1mdc</guid>
      <description>&lt;p&gt;Every enterprise I've talked to in the last year has the same story: AI agents are being deployed faster than risk and compliance teams can review them. Procurement moves in weeks, legal review moves in quarters, and the gap in between is where the real exposure lives.&lt;/p&gt;

&lt;p&gt;Traditional Errors &amp;amp; Omissions (E&amp;amp;O) insurance was never designed for this pace. It assumes a world where risk changes slowly enough that an annual form and a broker phone call are sufficient to underwrite it. That assumption breaks down completely with autonomous systems. An agent can make thousands of decisions an hour, and a subtle failure mode (what people in this space call "silent AI" risk) can run for weeks before a human notices anything is wrong. By the time a claim gets filed under the old model, the damage has already compounded, and the insurer is reconstructing what happened from logs and depositions instead of live data.&lt;/p&gt;

&lt;p&gt;I wanted to sit with a narrower, more concrete question: what would insurance look like if it were driven by live operational signals instead of static paperwork? Not as a thought experiment, but as something I could actually build and click through. That question turned into &lt;strong&gt;Recourse.ai&lt;/strong&gt;, an Android prototype built with the Lloyd's Lab ecosystem in mind. It bridges AI operational telemetry with parametric insurance workflows, converting real-time agent behavior into instant, verifiable payouts whenever a pre-agreed safety threshold gets crossed.&lt;/p&gt;

&lt;p&gt;This post walks through what the app does, why I made the architectural choices I made, where I deliberately cut corners as a prototype, and what I'd change before anyone put real money behind it.&lt;/p&gt;

&lt;h2&gt;
  
  
  What "parametric" actually means here
&lt;/h2&gt;

&lt;p&gt;Parametric insurance isn't a new idea. It's used heavily in areas like crop insurance and catastrophe bonds, where a payout is triggered automatically once a measurable condition is met (rainfall below X millimeters, wind speed above Y knots), rather than requiring a lengthy claims investigation to establish fault and damages.&lt;/p&gt;

&lt;p&gt;Recourse applies that same logic to AI operations. Instead of rainfall or wind speed, the triggering condition is something like "agent error rate exceeds a defined threshold for a defined window" or "an agent takes an action outside its approved guardrails." Once that condition is met and verified against the policy's rules, the payout process starts automatically. No adjuster has to reconstruct what happened weeks later. The telemetry data that triggered the payout &lt;em&gt;is&lt;/em&gt; the evidence.&lt;/p&gt;

&lt;p&gt;This matters because it changes the incentive structure on both sides. Insurers can price risk based on live signals rather than guesswork, and the organizations being insured have a direct incentive to invest in better guardrails, because better guardrails literally lower their premiums and reduce their exposure to slow claims.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Recourse actually does
&lt;/h2&gt;

&lt;p&gt;At its core, the app turns AI operational risk into something measurable and insurable. It does this through three connected capabilities:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Quantifying risk.&lt;/strong&gt; Every monitored AI agent gets a "Guardrail Maturity Score," calculated from its live behavior rather than a self-reported checklist filled out once and forgotten. The score reflects things like how often an agent operates within its defined boundaries, how it responds to anomalous inputs, and how frequently human intervention is required.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Automating payouts.&lt;/strong&gt; When a defined threshold is breached (say, an agent's error rate crosses a contractually agreed limit, or a kill-switch is triggered), the parametric rules engine verifies the condition against the policy and initiates a payout. In the prototype, this is modeled to clear in under 48 hours, a dramatic contrast to the 90-plus days typical of traditional E&amp;amp;O claims.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Benchmarking performance.&lt;/strong&gt; For finance leaders, the app surfaces real-time ROI and efficiency metrics, showing how the cost of automation compares against traditional benchmarks and how much has been recovered through the insurance layer itself.&lt;/p&gt;

&lt;h2&gt;
  
  
  Designing around real personas
&lt;/h2&gt;

&lt;p&gt;Rather than build a generic dashboard and hope it was useful to everyone, I anchored the whole app around four personas who would actually interact with a product like this:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Persona&lt;/th&gt;
&lt;th&gt;Primary objective&lt;/th&gt;
&lt;th&gt;Key feature used&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;CFO / COO&lt;/td&gt;
&lt;td&gt;ROI and financial stability&lt;/td&gt;
&lt;td&gt;Executive metric grid (recovered funds, efficiency gains)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Head of AI&lt;/td&gt;
&lt;td&gt;Operational reliability&lt;/td&gt;
&lt;td&gt;Agent telemetry and automatic safety kill switches&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;General Counsel&lt;/td&gt;
&lt;td&gt;Governance and audit&lt;/td&gt;
&lt;td&gt;Region-specific compliance audits (EU AI Act, DIFC)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Broker&lt;/td&gt;
&lt;td&gt;Capacity distribution&lt;/td&gt;
&lt;td&gt;Capacity monitoring and parametric policy management&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Every screen in the app maps back to one of these people's actual job. The login flow is persona-driven, so a CFO signing in sees financial recovery numbers front and center, while a Head of AI signing in lands on agent-level telemetry. The incident deep-dive view is written for General Counsel, with estimated financial exposure and jurisdictional legal context laid out clearly enough to drop into a board memo. And the policy triggers screen exists mainly for brokers, showing the rules engine logic in a way that's transparent rather than a black box.&lt;/p&gt;

&lt;p&gt;This persona-first approach shaped a lot of small decisions that might otherwise seem arbitrary, like why the executive entry screen is built for instant boardroom demonstrations rather than a typical consumer onboarding flow. The app isn't trying to be sticky or habit-forming. It's trying to be legible to a specific decision maker in under thirty seconds.&lt;/p&gt;

&lt;h2&gt;
  
  
  Architecture decisions
&lt;/h2&gt;

&lt;p&gt;I went with a decoupled &lt;strong&gt;MVVM (Model-View-ViewModel) architecture&lt;/strong&gt; on Android. The main reason was separation of concerns: I wanted the UI layer to stay dumb and testable, while all the payout logic and business rules lived somewhere I could reason about independently of any particular screen.&lt;/p&gt;

&lt;p&gt;In practice, that means Activities and their Adapters handle rendering and user input, ViewModels hold UI state as &lt;code&gt;StateFlow&lt;/code&gt;, and Repositories own the job of fetching and shaping data, whether that data comes from a live database or a fallback source. Business logic, including the payout engine itself, sits behind the Repository layer so it isn't entangled with any specific view.&lt;/p&gt;

&lt;h3&gt;
  
  
  The resilient data layer
&lt;/h3&gt;

&lt;p&gt;The more interesting design problem was the data layer. Live demos are unforgiving. A dropped database connection mid-pitch, in front of a room full of underwriters or CFOs, kills credibility instantly, regardless of how good the actual product is. So instead of assuming a database connection would always be available, I built the repository layer to support two paths:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;A live &lt;strong&gt;JDBC connection to MySQL 8.0&lt;/strong&gt;, giving realistic query behavior across a nine-table insurance schema covering agents, policies, incidents, and thresholds.&lt;/li&gt;
&lt;li&gt;A &lt;strong&gt;"Local Mode" fallback&lt;/strong&gt; that transparently swaps in high-fidelity mock data if the database isn't reachable, so the app never shows a blank screen or a crash dialog in front of an audience.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;That fallback logic lives in a custom &lt;code&gt;DatabaseHelper&lt;/code&gt; class. Critically, the ViewModels above it don't need to know or care which path actually served the data. They just receive a domain object and update state accordingly. This kept the resiliency logic contained in one place instead of scattered as defensive &lt;code&gt;try/catch&lt;/code&gt; blocks across every screen.&lt;/p&gt;

&lt;p&gt;Here's the request lifecycle when a user opens an incident, which illustrates how the fallback fits into the normal flow rather than being a special case bolted on afterward:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;User selects an incident
  -&amp;gt; View requests detail(incidentId) from ViewModel
    -&amp;gt; ViewModel asks Repository for telemetry and thresholds
      -&amp;gt; Repository queries MySQL (JOIN across agents/policies tables)
        -&amp;gt; if connected: return the ResultSet
        -&amp;gt; if not connected: fall back to mock strategic data
    -&amp;gt; Repository returns a single domain object either way
  -&amp;gt; ViewModel updates UI state
-&amp;gt; View renders the risk report and claim status
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Kotlin Coroutines and &lt;code&gt;StateFlow&lt;/code&gt; handle the asynchronous plumbing end to end. That combination kept the UI layer free of nested callbacks and made loading, success, and error states straightforward to represent and test, since each state is just a value the ViewModel emits rather than a chain of listener callbacks.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why "Local Mode" isn't just a demo hack
&lt;/h3&gt;

&lt;p&gt;It would be easy to dismiss the mock data fallback as a shortcut for pitching investors, and honestly, part of its purpose is exactly that. But it also reflects something real about how these systems need to behave in production. An insurance workflow tool that goes dark the moment a database connection blips is not a tool anyone will trust with time-sensitive payout logic. Building the resiliency pattern in from day one, even in a prototype, forced me to think about failure modes early rather than treating them as an afterthought once something breaks in front of a real user.&lt;/p&gt;

&lt;h2&gt;
  
  
  The technology stack, and why each piece was chosen
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Kotlin&lt;/strong&gt; as the primary language, leaning on Jetpack KTX extensions (things like &lt;code&gt;isVisible&lt;/code&gt;) to keep the codebase concise and idiomatic rather than fighting Java-style verbosity.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Material 3&lt;/strong&gt; for the UI layer, styled with a navy and teal palette. The goal was to make the app read as serious enterprise fintech rather than a generic consumer mobile app, since the audience is CFOs and General Counsel, not retail users.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Coroutines and StateFlow&lt;/strong&gt; for asynchronous data handling throughout, which kept state management consistent across every screen instead of mixing patterns.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;MySQL 8.0 with JDBC&lt;/strong&gt; on the backend. I chose direct JDBC over building a full REST API layer because speed of prototyping mattered more than production correctness at this stage, with the explicit understanding that a real deployment would need an authenticated API in between.&lt;/li&gt;
&lt;li&gt;Hardcoded &lt;strong&gt;compliance engines&lt;/strong&gt; covering EU AI Act Article 14, DIFC Regulation 10, and the MAS Sandbox Plus. These aren't placeholder text. The audit trail in the incident detail view reflects the actual regulatory language for each jurisdiction, so the compliance story holds up under scrutiny from someone who actually knows these frameworks.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Data flow and the sequence behind a claim
&lt;/h2&gt;

&lt;p&gt;To make the parametric trigger verification concrete, it helps to walk through the full sequence rather than just describing it in prose. When a user selects an incident from the dashboard, the View asks the ViewModel for detail on that specific incident ID. The ViewModel, in turn, asks the Repository to fetch both the telemetry data and the relevant policy thresholds. The Repository issues a SQL query that joins across the agents and policies tables in MySQL.&lt;/p&gt;

&lt;p&gt;If the database connection is healthy, the query returns a ResultSet that gets mapped into a domain object. If the connection isn't available, the Repository silently falls back to loading the equivalent mock data, constructed to be realistic enough that a viewer can't tell the difference during a demo. Either way, the ViewModel receives a single, consistent domain object, updates the UI state, and the View renders the risk report along with the current claim status.&lt;/p&gt;

&lt;p&gt;The point of walking through this in detail is that the fallback isn't a separate code path that diverges from the "real" one. It's integrated at the point where data enters the system, which means every downstream consumer of that data behaves identically regardless of where the data actually came from.&lt;/p&gt;

&lt;h2&gt;
  
  
  Security and compliance considerations
&lt;/h2&gt;

&lt;p&gt;A few principles guided the security and compliance design, even at prototype stage:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Data minimization.&lt;/strong&gt; The telemetry layer only captures agent metadata and financial amounts, deliberately avoiding personally identifiable information wherever possible. This wasn't an afterthought bolted on before a compliance review. It was a constraint from the first schema design, because the whole pitch of the product depends on being trustworthy with sensitive operational data.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Deterministic, inspectable rules.&lt;/strong&gt; The parametric verification logic is intentionally deterministic. Given the same telemetry and the same policy thresholds, it produces the same payout decision every time. This matters because the entire value proposition of parametric insurance collapses if the trigger logic feels like a black box. If a General Counsel can't explain to a board why a payout did or didn't happen, the product hasn't actually solved the trust problem it set out to solve.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Local resiliency, with an asterisk.&lt;/strong&gt; In a production environment, direct JDBC access from the client app would be replaced with an authenticated REST API. Using JDBC directly in the prototype was a deliberate trade-off for demo performance and development speed, not a decision I'd defend for a real deployment handling real policyholder data.&lt;/p&gt;

&lt;h2&gt;
  
  
  Licensing choice: why AGPL-3.0
&lt;/h2&gt;

&lt;p&gt;I licensed the project under the GNU Affero General Public License v3.0 rather than a more permissive option like MIT or Apache 2.0, and this wasn't a default choice made without thinking about it.&lt;/p&gt;

&lt;p&gt;The core argument for parametric insurance in this space is that claims shouldn't be a black box. If that's the actual thesis of the product, then the rules engine deciding who gets paid and when should be inspectable by the people affected by it, not locked away inside a proprietary hosted service that nobody outside the company can audit. AGPL specifically closes the loophole that plain GPL leaves open: if someone takes this code, modifies it, and runs it as a hosted service without redistributing the source, standard GPL wouldn't require them to share those changes. AGPL does. That felt directly aligned with what the project is trying to prove, rather than an incidental legal detail.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I'd change before this went anywhere near production
&lt;/h2&gt;

&lt;p&gt;I want to be upfront about the parts of this that are deliberately prototype-grade, because a technical write-up that only talks about what worked isn't very useful to anyone else building something similar.&lt;/p&gt;

&lt;p&gt;The direct JDBC connection from the client is the biggest one. It's fine for a controlled demo running against a database I control, but it would be a serious liability in production. Any real version of this needs an authenticated REST or GraphQL API sitting between the client and the database, with proper access control and rate limiting.&lt;/p&gt;

&lt;p&gt;The compliance engine is currently rules-based and hardcoded per jurisdiction. That works for three regions in a demo, but it doesn't scale. A production version would need to externalize that logic into a proper policy engine, something more like a rules-as-configuration system, so that adding a new jurisdiction doesn't mean shipping a new app build.&lt;/p&gt;

&lt;p&gt;The mock data, while high fidelity, is still fabricated. Before any real underwriting decisions get made on top of this, the telemetry ingestion pipeline needs to be validated against actual agent logging formats from real deployments, which vary a lot more than a clean mock dataset suggests.&lt;/p&gt;

&lt;p&gt;And finally, the "Guardrail Maturity Score" as implemented is a reasonable first pass at quantifying agent behavior, but it hasn't been validated against actual loss data. Turning it into something an actuary would sign off on requires a much longer feedback loop between the score and real claims history, which by definition doesn't exist yet for a category this new.&lt;/p&gt;

&lt;h2&gt;
  
  
  Lessons from building it
&lt;/h2&gt;

&lt;p&gt;A few things stood out to me while working on this that I think generalize beyond this specific project.&lt;/p&gt;

&lt;p&gt;Building resiliency in early, even for a prototype, pays off. The Local Mode fallback started as a way to survive flaky demo wifi, but it ended up shaping how I thought about the whole data layer, and it's a pattern I'd default to again for anything that needs to be presented live.&lt;/p&gt;

&lt;p&gt;Designing around named personas rather than generic user stories made a surprising number of small UI decisions obvious that would otherwise have required guesswork. Once I knew a CFO was the one looking at a given screen, questions like "what number goes at the top" answered themselves.&lt;/p&gt;

&lt;p&gt;And choosing a license is a design decision, not an administrative one. AGPL wasn't the "safe" default choice for a project hoping to attract commercial interest, but it was the choice that actually matched what the product claims to stand for.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where it's headed
&lt;/h2&gt;

&lt;p&gt;Recourse is explicitly positioned as a first-mover bet in the agentic AI insurance space, and the roadmap reflects that ambition in stages. The near-term plan is a beachhead in D2C retail, operating inside regulatory sandboxes like MAS and ADGM where the compliance burden of a full launch is lower. From there, the path runs toward securing A-rated capacity and formalizing a broker channel, since parametric insurance at scale needs real underwriting capacity behind it, not just clever software. The longer-term pivot is toward white-labeled, embedded platform distribution, so the parametric rules engine could eventually sit inside other companies' products rather than only existing as a standalone app.&lt;/p&gt;

&lt;p&gt;None of that is guaranteed, and a lot of it depends on things outside the codebase, like regulatory appetite and actual underwriting partnerships. But having a working prototype that a CFO, a Head of AI, and a General Counsel can each click through and immediately understand is a meaningfully different starting point than a slide deck.&lt;/p&gt;




&lt;p&gt;If you want to look at the actual implementation, including the mock data layer, the compliance engine logic, and the full MVVM structure, the source is on GitHub: &lt;a href="https://github.com/alfinohatta/recourse" rel="noopener noreferrer"&gt;github.com/alfinohatta/recourse&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>android</category>
      <category>mobile</category>
      <category>agents</category>
    </item>
    <item>
      <title>Building Northbridge Analytics: Turning Gut Feelings Into Governed Data</title>
      <dc:creator>Alfino Hatta</dc:creator>
      <pubDate>Wed, 08 Jul 2026 07:24:38 +0000</pubDate>
      <link>https://dev.to/alfinohatta/building-northbridge-analytics-turning-gut-feelings-into-governed-data-1g2o</link>
      <guid>https://dev.to/alfinohatta/building-northbridge-analytics-turning-gut-feelings-into-governed-data-1g2o</guid>
      <description>&lt;p&gt;Every large organization has the same quiet problem: the best information about risk doesn't live in a database. It lives in Slack threads, hallway conversations, and the "gut feeling" of a regional expert who's watched a particular market or regulatory environment for years. That judgment is valuable, but it's almost never quantified, almost never checked against reality, and almost never connected to an auditable trail of action.&lt;/p&gt;

&lt;p&gt;I've watched this play out from the outside, too. A risk committee gets a slide that says "our regional lead is concerned about currency exposure in this market," and that's it. No number, no history of whether that lead has been right before, no comparison to what the actual market is pricing in. The concern might be completely justified. It might also be recency bias from one bad quarter. Nobody in the room has a good way to tell the difference, so the decision either gets made on vibes or gets deferred until it's too late to act cheaply.&lt;/p&gt;

&lt;p&gt;I wanted to build something that closes that gap: a tool that forces expert intuition into a number, benchmarks that number against real market data, and keeps a governed record of what happened next. That's how &lt;strong&gt;Northbridge Analytics&lt;/strong&gt; was born, a decision-support platform aimed at CFOs and Chief Risk Officers who need more than anecdotes when they're deciding whether to hedge exposure.&lt;/p&gt;

&lt;h2&gt;
  
  
  The core idea
&lt;/h2&gt;

&lt;p&gt;Northbridge is built around one simple tension: &lt;strong&gt;internal belief vs. external reality.&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;ICP (Internal Consensus Probability)&lt;/strong&gt;, a weighted probability derived from what your own regional experts believe will happen.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;EMP (External Market Probability)&lt;/strong&gt;, the real-time signal coming from prediction markets and financial data.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When those two numbers drift apart, that's a blind spot. Someone inside the organization either knows something the market doesn't, or the organization is dangerously out of touch. Either way, it's worth surfacing, and Northbridge's Divergence Engine does exactly that, flagging significant gaps so they can be reviewed before they become expensive.&lt;/p&gt;

&lt;p&gt;I spent a lot of time thinking about what "significant" should mean here. A naive version of this feature would just subtract ICP from EMP and flag anything over some fixed threshold, like ten percentage points. But a ten-point gap on a coin-flip event isn't the same as a ten-point gap on something the market already prices as a near-certainty. So the divergence calculation has to account for where the two numbers sit on the probability curve, not just the raw distance between them. Getting that math right, so that the flags actually correspond to decisions worth making instead of noise, took several iterations.&lt;/p&gt;

&lt;p&gt;To make the internal side trustworthy over time, I added reputation weighting based on &lt;strong&gt;Brier Skill Scores&lt;/strong&gt;, so experts who are consistently accurate carry more influence in the consensus than those who are just loud or senior. Calibration, not politics, should decide whose forecast matters most. This part mattered a lot to me personally. Anyone who has sat in a room where the most confident person automatically wins the argument knows how badly that can go. A system that quietly tracks who has actually been right, and lets that history shape influence over time, is a small structural nudge toward better decisions. It doesn't eliminate politics, but it makes the politics have to argue with a track record.&lt;/p&gt;

&lt;h2&gt;
  
  
  Architecture decisions
&lt;/h2&gt;

&lt;p&gt;I built the client as a native &lt;strong&gt;Kotlin&lt;/strong&gt; Android app, following an MVVM pattern with StateFlow for reactive, lifecycle-aware state management. A few decisions I made early on, and why:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Offline-first with Room.&lt;/strong&gt; Regional experts don't always have reliable connectivity, whether that's someone traveling, working from a site with poor infrastructure, or just being on a flight when a market moves. Local persistence via Room, which sits on top of SQLite, had to be the source of truth on-device, syncing to the backend when possible. This meant designing the local schema first and treating the network as an enhancement rather than a dependency, which is the opposite of how a lot of apps are built by default.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Retrofit and MySQL as the "Global Ledger."&lt;/strong&gt; The backend needed to act as a single, centralized record. Every forecast, review, and hedge approval writes to an audit log that can't quietly disappear. I used Retrofit to handle the HTTP layer cleanly and kept the API contracts strict, since a governance tool is only as trustworthy as its ability to prove that nothing has been altered after the fact.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Repository pattern.&lt;/strong&gt; A &lt;code&gt;RiskRepository&lt;/code&gt; sits between the UI and both the local Room database and the remote API, handling sync logic and running the divergence calculations before pushing results back into state. Keeping this logic out of the ViewModels made the sync behavior much easier to reason about and test in isolation, and it meant the UI layer never had to know or care whether a given probability came from the cache or from a fresh network call.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Governed workflows over free-for-all inputs.&lt;/strong&gt; Once a probability estimate is submitted, it's immutable. If a hedge gets approved, that's logged too. The whole point is an audit trail a risk committee can actually trust. This constraint shaped the database design from day one. Instead of allowing updates to existing rows, corrections and revisions are stored as new entries that reference the original, so the full history of how a belief evolved is always visible rather than overwritten.&lt;/p&gt;

&lt;p&gt;Putting it together, the pipeline looks roughly like this: an expert submits a quantified estimate, the app recalculates the weighted internal consensus, the Divergence Engine compares it to the external market signal, and if the gap crosses a threshold, it flags the CFO or CRO for review. An approved hedge gets committed to the ledger, and the whole thing can be exported as a PDF for the board. Every step in that chain is designed to leave a trace, so that six months later someone can reconstruct exactly what was known, by whom, and when.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I learned
&lt;/h2&gt;

&lt;p&gt;The hardest part wasn't the Kotlin or the sync logic. It was designing for governance rather than just functionality. It's easy to build a form that captures a probability. It's harder to build a system where that probability can never be quietly edited after the fact, where every state transition is logged, and where the audit trail is actually useful to a risk committee months later. That constraint shaped almost every technical decision, from making estimates immutable at the database layer to structuring the role-based access control around who's even allowed to resolve an event.&lt;/p&gt;

&lt;p&gt;I also learned how much thought has to go into role design before a single screen gets built. Deciding who can submit a forecast, who can review a divergence flag, and who has the authority to approve a hedge is not a UI problem, it's an organizational modeling problem. I ended up sketching out the actual approval chain of a hypothetical CFO's office on paper before writing any permission logic, because getting that model wrong would mean rebuilding a lot of the backend later.&lt;/p&gt;

&lt;p&gt;Another lesson was around how to present uncertainty without letting the interface lie by omission. It would have been easy to just show a single blended probability number on the main screen and call it a day. But a single number hides disagreement. If three experts are clustered tightly around 30% and two are convinced it's 70%, that's a very different situation from five experts who all independently landed on 45%, even though the weighted average might look similar. So the UI needed to expose the spread of opinion, not just the summary statistic, which pushed me to think more carefully about how to visualize distributions on a small mobile screen without overwhelming the user.&lt;/p&gt;

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

&lt;p&gt;There's plenty on the roadmap. I want to build deeper reporting around "value protected" metrics, so a CFO can see not just that a hedge was approved but what it likely saved the organization in expected terms. I'm also interested in more sophisticated calibration across multiple event cycles, since Brier scores get more meaningful the more forecasting history an expert accumulates, and right now the reputation system is still working with a fairly thin data set. Beyond that, I'd like to extend the client past Android, since a lot of the value of Northbridge only compounds if more of an organization's experts can easily contribute a forecast from whatever device they happen to be using.&lt;/p&gt;

&lt;p&gt;But even in its current state, Northbridge does the one thing I set out to do. It turns scattered judgment into a number, and it turns that number into something governed.&lt;/p&gt;

&lt;p&gt;If you're curious about the code, architecture diagrams, or want to run it locally, the full project is open source here:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;GitHub:&lt;/strong&gt; &lt;a href="https://github.com/alfinohatta/northbridge" rel="noopener noreferrer"&gt;github.com/alfinohatta/northbridge&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>programming</category>
      <category>opensource</category>
      <category>apigateway</category>
    </item>
    <item>
      <title>Building Quorra: An Android Decision-Intelligence Platform That Actually Explains Itself</title>
      <dc:creator>Alfino Hatta</dc:creator>
      <pubDate>Mon, 06 Jul 2026 16:51:07 +0000</pubDate>
      <link>https://dev.to/alfinohatta/building-quorra-an-android-decision-intelligence-platform-that-actually-explains-itself-1m12</link>
      <guid>https://dev.to/alfinohatta/building-quorra-an-android-decision-intelligence-platform-that-actually-explains-itself-1m12</guid>
      <description>&lt;h2&gt;
  
  
  Why I built a "reasoning layer" instead of another dashboard
&lt;/h2&gt;

&lt;p&gt;If you've spent any time in operations, retail, or supply chain, you've seen this pattern before: a company invests heavily in dashboards, everyone's staring at the same charts, and yet decisions still get made on gut feel, or worse, they don't get made at all until it's too late. That gap between &lt;em&gt;having data&lt;/em&gt; and &lt;em&gt;acting on it&lt;/em&gt; is what pushed me to build &lt;strong&gt;Quorra&lt;/strong&gt;, a Decision-Intelligence (DI) platform for Android.&lt;/p&gt;

&lt;p&gt;Quorra isn't trying to be a prettier BI tool. It's trying to solve a much harder problem: turning fragmented operational data from systems like ERP, CRM, and WMS into recommendations that people can actually trust and act on, with a human still firmly in control.&lt;/p&gt;

&lt;p&gt;The more I dug into this space, the more I realized that "more data" was never the actual bottleneck for most operations teams. Most facilities I looked at were already drowning in dashboards, KPI widgets, and nightly reports. What they lacked was a layer that could take all of that raw signal and turn it into something closer to a recommendation: not just "here's what happened," but "here's what you should probably do next, and here's why."&lt;/p&gt;

&lt;p&gt;That distinction, between reporting and reasoning, became the entire premise of the project.&lt;/p&gt;

&lt;h2&gt;
  
  
  The problem I kept running into
&lt;/h2&gt;

&lt;p&gt;Every enterprise I looked at had some version of the same three issues:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Decision paralysis.&lt;/strong&gt; Managers simply can't process data fast enough to act on it in time. By the time a stock-out or a margin problem shows up clearly on a dashboard, the window to act cheaply has usually already closed.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A trust deficit.&lt;/strong&gt; Black-box AI recommendations get ignored because nobody can see the reasoning behind them. If a system tells an operator to reroute inventory but can't explain why, the natural response is to ignore it, especially when the stakes are financial.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Expensive reversals.&lt;/strong&gt; Misallocated inventory or a mispriced contract is painful and costly to undo once it's already happened. Once a decision is executed, walking it back is rarely as simple as clicking undo.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Dashboards show you the "what." They almost never show you the "so what do I do about it," and they definitely don't tell you &lt;em&gt;why&lt;/em&gt; a recommendation makes sense. I kept coming back to the idea that the real product wasn't a dashboard at all. It was a decision, packaged with enough context that a human could sign off on it confidently and quickly.&lt;/p&gt;

&lt;p&gt;That reframing changed almost everything about how I approached the build, from the data model up to the UI.&lt;/p&gt;

&lt;h2&gt;
  
  
  The approach: Human-on-the-Loop, not full automation
&lt;/h2&gt;

&lt;p&gt;Instead of building something that auto-approves decisions, I designed Quorra around &lt;strong&gt;Human-on-the-Loop (HOTL)&lt;/strong&gt;, a design philosophy that sits deliberately between full automation and manual analysis. The system proposes, ranks, and explains, but a person always makes the final call on anything high-stakes. I wanted the app to behave less like an autopilot and more like a very well-prepared analyst standing behind the decision-maker's shoulder.&lt;/p&gt;

&lt;p&gt;Every recommendation ships with three things baked in:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A plain-language justification for &lt;em&gt;why&lt;/em&gt; it's being suggested, written so a non-technical facility lead can understand it without needing a data science background.&lt;/li&gt;
&lt;li&gt;A dual-confidence score, one for data quality and one for model confidence, so the source of uncertainty is never hidden behind a single vague percentage.&lt;/li&gt;
&lt;li&gt;A sandbox "what-if" environment to simulate the outcome before committing to it, so the cost of testing an idea is close to zero.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That last piece became one of my favorite parts of the build: a simulation laboratory where a manager can test a scenario, such as "what if this shipment is two days late," before touching anything real. Instead of asking people to trust a black box, the app lets them poke at it, run a few scenarios, and build their own intuition for when the system's recommendations are solid and when they should be second-guessed.&lt;/p&gt;

&lt;p&gt;I think this is the part of the project I'd defend most strongly if someone pushed back on it. Full automation is tempting because it looks more impressive in a demo, but in high-stakes operational environments, an unexplainable automated decision is a liability, not a feature. HOTL is slower to demo but far more likely to actually get adopted and trusted by real teams.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's under the hood
&lt;/h2&gt;

&lt;p&gt;Quorra is a native Android app, and I made a conscious decision early on to keep the stack fully native rather than reaching for a cross-platform framework. Given how much of the UI depends on custom visualizations and role-based rendering, native Kotlin gave me more control over performance and layout precision than I would have had otherwise.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Frontend and UI&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Kotlin 2.1.0 as the core language for the entire app.&lt;/li&gt;
&lt;li&gt;Jetpack Compose for a declarative, "command center" style interface that could adapt fluidly based on user role and context.&lt;/li&gt;
&lt;li&gt;Material 3 for the enterprise-grade visual system, giving the app a consistent, professional feel without having to design a component library from scratch.&lt;/li&gt;
&lt;li&gt;Custom Canvas API charts for trendlines and gauges. Off-the-shelf chart libraries weren't going to give me the visual density and customization the recommendation views needed, so I built these by hand.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Backend and data&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Room for offline-first local persistence, since facility environments don't always have reliable connectivity and the app needs to keep functioning when the network drops.&lt;/li&gt;
&lt;li&gt;Retrofit 2.11 for type-safe API sync with enterprise backends, handling the messier job of reconciling remote system data with what's stored locally.&lt;/li&gt;
&lt;li&gt;Coroutines and StateFlow for reactive state management throughout the app, which turned out to be essential once the UI needed to update in near real time as new recommendations came in.&lt;/li&gt;
&lt;li&gt;Gson for serializing the more complex data models, particularly the nested reasoning objects attached to each recommendation.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Tooling&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;KSP for annotation processing with Room, which cut build times noticeably compared to the older KAPT approach.&lt;/li&gt;
&lt;li&gt;Gradle Kotlin DSL for the build configuration, mostly for the stronger typing and better IDE support.&lt;/li&gt;
&lt;li&gt;MockK and JUnit for testing, especially around the reconciliation logic between local and remote data.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The architecture follows a fairly classic MVVM-plus-repository pattern, but the repository layer does more work than usual. It functions as the single source of truth reconciling local Room data with remote sync, which matters a lot when the app needs to keep functioning in low-connectivity facilities. In practice, this meant spending a disproportionate amount of time on conflict resolution logic: what happens when a recommendation gets updated on the server while a facility lead is mid-review on a phone with no signal. Getting that right was far less glamorous than building the simulation lab, but it mattered just as much for the app to be trustworthy in the field.&lt;/p&gt;

&lt;h2&gt;
  
  
  Designing for four very different users
&lt;/h2&gt;

&lt;p&gt;One thing that shaped a lot of early decisions was realizing Quorra needed to serve genuinely different personas, not just "the user" as a single abstract concept. Early prototypes tried to build one interface that served everyone, and it was a mess: too cluttered for an operator who just needed to glance and act, too shallow for an approver who needed full context before signing off on a six-figure decision.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Persona&lt;/th&gt;
&lt;th&gt;Role&lt;/th&gt;
&lt;th&gt;What they need&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Operator&lt;/td&gt;
&lt;td&gt;Facility lead&lt;/td&gt;
&lt;td&gt;Monitor the feed, catch stock-outs or risk, simulate recovery paths&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Approver&lt;/td&gt;
&lt;td&gt;Audit or finance lead&lt;/td&gt;
&lt;td&gt;Review high-stakes escalations, sign off on capital commitments&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Configurer&lt;/td&gt;
&lt;td&gt;Data or IT manager&lt;/td&gt;
&lt;td&gt;Manage the underlying "playbook" logic, watch data source health&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Admin&lt;/td&gt;
&lt;td&gt;System administrator&lt;/td&gt;
&lt;td&gt;Set governance rules, manage cross-facility permissions&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Splitting the app by persona meant building UI that reactively adapts based on role. An Approver sees sign-off controls that an Operator never even renders, and vice versa, rather than the same screen with certain buttons simply hidden or disabled. It also meant baking governance into the architecture from day one: automated escalation rules trigger based on financial thresholds or confidence deficits, rather than being bolted on later as an afterthought.&lt;/p&gt;

&lt;p&gt;This ended up paying off in a way I didn't fully anticipate. Because each persona's needs were modeled explicitly, adding new governance rules later (for example, a new escalation threshold for a specific facility type) was a matter of adjusting configuration rather than rewriting UI logic. Treating personas as first-class citizens in the data model, not just in the design mockups, turned out to be one of the better architectural decisions I made.&lt;/p&gt;

&lt;h2&gt;
  
  
  The audit ledger: making trust auditable, not just claimed
&lt;/h2&gt;

&lt;p&gt;A recommendation engine is only as trustworthy as its paper trail. Quorra keeps an immutable audit ledger that records every decision, which persona made it, and the reasoning behind it at the time it was made. This wasn't a compliance checkbox I added late in the process. It was part of the initial data model, because I wanted trust in the system to be something that could be independently verified rather than something the app simply asserted about itself.&lt;/p&gt;

&lt;p&gt;Combined with an "Operational Best Practices" rule I baked directly into the logic, never auto-approve anything flagged as high risk, always require a written reasoning note for overrides, the goal was to make the system's trustworthiness something you can verify, not something you have to take on faith. If an approver overrides a recommendation, that override and its justification live permanently in the ledger, visible to anyone reviewing that decision later.&lt;/p&gt;

&lt;p&gt;In hindsight, this is probably the single feature that would matter most in a real enterprise deployment. Dashboards and recommendation engines are common. A genuinely auditable decision trail, one that survives scrutiny from finance or compliance teams months after the fact, is much rarer, and it's the kind of thing that only works if it's designed in from the start rather than added after the fact.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I'd tell someone starting a similar project
&lt;/h2&gt;

&lt;p&gt;If you're building something in this decision-support space, a few things I learned along the way:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Explainability isn't a UI feature, it's an architecture decision.&lt;/strong&gt; You can't bolt "why" onto a recommendation after the fact. The reasoning needs to be a first-class object in your data model from the start, stored, versioned, and retrievable, not just rendered as a tooltip in the interface.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Offline-first is not optional for operational tools.&lt;/strong&gt; Facilities and warehouses don't always have great connectivity, and a DI tool that stops working when the network drops isn't a DI tool, it's a liability that people will stop trusting the first time it fails them at a critical moment.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Simulation is more valuable than prediction.&lt;/strong&gt; People trust "let me test this" far more than they trust "trust me, this will work." Giving users a low-stakes way to explore a recommendation before committing to it does more for adoption than any amount of model accuracy tuning.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Design for the least technical persona first.&lt;/strong&gt; If the interface makes sense to the facility operator glancing at it between tasks, it will almost certainly still make sense to the more technical personas. The reverse is rarely true.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Governance is cheaper to build early than to retrofit.&lt;/strong&gt; Escalation thresholds, audit trails, and override rules are much easier to weave into the core data model at the start than to graft onto a system that was never designed to be scrutinized.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Try it out
&lt;/h2&gt;

&lt;p&gt;Quorra is open source and built entirely in Kotlin. If you want to dig into the architecture, the persona-based UI logic, or the simulation lab implementation, the full code is on GitHub:&lt;/p&gt;

&lt;p&gt;👉 &lt;strong&gt;&lt;a href="https://github.com/alfinohatta/Quorra" rel="noopener noreferrer"&gt;github.com/alfinohatta/Quorra&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Feedback, issues, and pull requests are all welcome, especially if you've tackled similar explainability or offline-sync challenges in your own projects. If you end up poking around the repo, I'd genuinely love to hear what you'd have built differently.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>openai</category>
      <category>mobile</category>
      <category>analytics</category>
    </item>
    <item>
      <title>Building Corroborate.ai: An Auditable Way to Decide What an AI Actually "Knows"</title>
      <dc:creator>Alfino Hatta</dc:creator>
      <pubDate>Sat, 04 Jul 2026 23:32:16 +0000</pubDate>
      <link>https://dev.to/alfinohatta/building-corroborateai-an-auditable-way-to-decide-what-an-ai-actually-knows-1n9m</link>
      <guid>https://dev.to/alfinohatta/building-corroborateai-an-auditable-way-to-decide-what-an-ai-actually-knows-1n9m</guid>
      <description>&lt;h2&gt;
  
  
  Why I built a knowledge arbitration engine instead of just another memory layer
&lt;/h2&gt;

&lt;p&gt;If you've spent any real time building with LLMs, you've probably run into the same wall I did. Memory systems today are very good at storing things and surprisingly bad at explaining why they believe what they believe. Most of the popular options, things like Mem0, Zep, and similar tools, tend to boil the whole problem down to a single model call. The model looks at a handful of facts, picks a winner, and the system moves on with its life. There's no audit trail, no way to reason about why one claim beat another, and honestly, no real concept that a fact could be true in one place and false in another.&lt;/p&gt;

&lt;p&gt;That last part is what actually bothered me enough to start building something new.&lt;/p&gt;

&lt;p&gt;Think about it for a second. A pricing rule can be perfectly legal in Germany and illegal in the United States. A regulation can be accurate today and obsolete in six months. Two sources can both look credible on paper and still flatly contradict each other. Collapsing all of that nuance into a single black box LLM judgment felt like exactly the wrong foundation for anything used in insurance, legal, or banking contexts, domains where you eventually have to explain your reasoning to a regulator, not just satisfy a user with a plausible sounding answer.&lt;/p&gt;

&lt;p&gt;So I built &lt;strong&gt;Corroborate.ai&lt;/strong&gt;, an Android reference client for a knowledge arbitration engine that treats truth not as a single yes or no output, but as a function of context. The mechanism at the center of it all is something I call a &lt;strong&gt;Confidence Auction&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  The problem with letting one model call decide what's true
&lt;/h2&gt;

&lt;p&gt;Before I get into how Corroborate.ai works, I want to spend a little more time on why I think the "single model call" approach is such a fragile pattern, because it's genuinely everywhere right now.&lt;/p&gt;

&lt;p&gt;When you ask an LLM something like "is this claim true," you're really asking it to do three jobs at once. First, it has to retrieve or recall relevant information. Second, it has to weigh the credibility of that information against competing information. Third, it has to make a final judgment call and phrase that judgment confidently, because that's how these models are trained to communicate. The problem is that all three of those jobs happen inside a single opaque forward pass. You get an answer, but you don't get the reasoning that produced it, and you definitely don't get anything you could hand to a compliance officer or an auditor and say "here's why the system believed this."&lt;/p&gt;

&lt;p&gt;For a lot of consumer use cases, that's a perfectly acceptable trade off. Nobody needs an audit trail for a chatbot recommending a recipe. But the moment you're dealing with regulated industries, that opacity turns into liability. If your system tells an insurance agent that a policy exclusion applies, and it turns out to be wrong, "the LLM said so" is not an answer anyone wants to give a regulator, a client, or a court.&lt;/p&gt;

&lt;p&gt;I wanted a system where the reasoning was visible by construction, not bolted on after the fact as an explanation generated by yet another LLM call trying to rationalize a decision it already made.&lt;/p&gt;

&lt;h2&gt;
  
  
  The core idea: deterministic scoring instead of a single vibe check
&lt;/h2&gt;

&lt;p&gt;Instead of asking an LLM to render a verdict, Corroborate.ai runs every candidate claim through a &lt;strong&gt;deterministic scorer ensemble&lt;/strong&gt;. Each claim is evaluated along several independent dimensions, and each of those dimensions is computed by its own dedicated scorer rather than a single model guessing at all of them simultaneously.&lt;/p&gt;

&lt;p&gt;The dimensions are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Source Reliability (Sr).&lt;/strong&gt; How trustworthy is the origin of this claim? A claim from a verified regulatory filing should not carry the same weight as one scraped from an anonymous forum post.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Recency Decay (St).&lt;/strong&gt; How stale is this information? Facts age, and some age faster than others. A claim about a tax rate from three years ago should decay differently than a claim about a scientific constant.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Corroboration (Sc).&lt;/strong&gt; How many independent sources back this claim up? A single unverified assertion should never be treated the same as a claim that multiple unrelated sources agree on.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Regional Authority (Sa).&lt;/strong&gt; Does this claim actually hold in the jurisdiction relevant to the user? This is the dimension that captures the Germany versus United States pricing example I mentioned earlier.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Once each of these scores is computed, they get combined using a &lt;strong&gt;geometric mean&lt;/strong&gt; rather than a simple arithmetic average. This was a deliberate and, honestly, a somewhat contentious design decision when I was sketching it out on paper.&lt;/p&gt;

&lt;p&gt;Here's why it matters. With an arithmetic mean, a claim can compensate for a terrible score on one dimension by having a great score on another. A claim that's wildly out of date but happens to come from a hundred corroborating sources could still average out to looking trustworthy. A geometric mean does not let you get away with that. If any single dimension collapses toward zero, the entire combined score collapses with it. In practice, that means a claim that's extremely recent and well corroborated but legally invalid in the user's region gets correctly punished instead of sneaking through because its other scores were strong. One bad dimension cannot be quietly averaged away.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Contradiction Guard: knowing when to say "I'm not sure"
&lt;/h2&gt;

&lt;p&gt;Here's the part of the system I'm probably proudest of. When two competing claims land within a 0.10 confidence delta of each other after scoring, the system does not just pick whichever one is marginally higher and move on. Instead, it triggers something called the &lt;strong&gt;Contradiction Guard&lt;/strong&gt;, which returns both candidates to the caller as genuinely ambiguous, along with their individual scores and provenance.&lt;/p&gt;

&lt;p&gt;This might sound like a small implementation detail, but I think it's actually the philosophical center of the entire project. Most AI systems are optimized to always produce a confident sounding answer, because that's what feels useful in a demo. But a confident wrong answer is worse than an honest "these two things are in tension and here's why." In regulated domains especially, an honest admission of ambiguity, backed by transparent scoring, is a feature, not a failure. It gives a human reviewer exactly what they need to make the final call themselves, instead of quietly inheriting a hidden coin flip from the model.&lt;/p&gt;

&lt;h2&gt;
  
  
  How a claim actually gets resolved, end to end
&lt;/h2&gt;

&lt;p&gt;It's worth walking through the full request lifecycle, because the architecture reflects the same philosophy as the scoring logic. Nothing gets to happen silently.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The Android client sends a query to an API Gateway, along with metadata about the requesting tenant and the relevant region.&lt;/li&gt;
&lt;li&gt;The gateway routes the request to the correct regional partition. Data residency is not an afterthought bolted onto the routing layer later. It's baked into the design from the very first hop, since a claim resolved under the wrong jurisdiction's data isn't just inconvenient, it can be actively wrong.&lt;/li&gt;
&lt;li&gt;A Resolution Engine retrieves the most relevant semantic candidates for the query and hands them off to the Scorer Ensemble.&lt;/li&gt;
&lt;li&gt;Each scorer computes its dimension independently, and the results are fused together using the geometric mean described above.&lt;/li&gt;
&lt;li&gt;If the confidence delta between the top two candidates is too small, the Contradiction Guard kicks in and the client receives an ambiguous response with both candidates and their full scoring breakdown attached. Otherwise, the client receives a single resolved claim, complete with provenance information and a reference into a signed, append only audit log.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;That audit log deserves its own mention. It's a &lt;strong&gt;Merkle anchored, append only log&lt;/strong&gt;, meaning every resolution event produces a signed record that cannot be quietly edited or deleted after the fact. If you ever need to demonstrate provenance to satisfy something like the EU AI Act, or simply to answer an internal question about why the system behaved a certain way six months ago, that log is designed to give you a real, tamper evident answer instead of a best guess reconstructed from memory.&lt;/p&gt;

&lt;h2&gt;
  
  
  The stack behind the client
&lt;/h2&gt;

&lt;p&gt;On the Android side, the client itself is built with a fairly modern and, I think, pretty clean set of tools:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Kotlin&lt;/strong&gt; as the primary language throughout the app.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Jetpack Compose&lt;/strong&gt; paired with &lt;strong&gt;Material 3&lt;/strong&gt; for the entire UI layer, which made it much easier to represent the scoring breakdowns and ambiguous claim states visually instead of burying them in plain text.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Retrofit&lt;/strong&gt;, &lt;strong&gt;OkHttp&lt;/strong&gt;, and &lt;strong&gt;Kotlinx Serialization&lt;/strong&gt; handling networking and data mapping between the client and the backend services.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;On the backend integration side, the architecture assumes a &lt;strong&gt;Neo4j&lt;/strong&gt; graph database for modeling relationships between claims, since so much of what makes a claim credible or not depends on its relationships to other claims and sources. Semantic search over candidate claims is handled through &lt;strong&gt;Qdrant&lt;/strong&gt; as a vector store, and raw encrypted episodes, meaning the underlying source material a claim was derived from, live in S3 style object storage. All of it ultimately gets anchored by the Merkle audit log so that nothing in the pipeline is invisible after the fact.&lt;/p&gt;

&lt;h2&gt;
  
  
  Compliance was not an afterthought
&lt;/h2&gt;

&lt;p&gt;Given that the intended use cases sit in insurance, legal, and banking, I made the decision early on to build regulatory behavior directly into the system rather than treating it as something to bolt on right before a launch. Two pieces of that I'm especially glad I got right from the start.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;GDPR Article 17 erasure cascades.&lt;/strong&gt; When a user requests deletion, the system does not simply delete a row in a database and call it done. Linked episodes tied to that user are hard deleted. Claims that still have independent corroboration from other, unrelated sources get PII stripped rather than destroyed outright, since the underlying fact might still be legitimately known and referenced from elsewhere even after this particular user's data is gone. Claims that have no independent corroboration left after the user's data is removed get hard deleted entirely, since keeping them around would mean keeping information that only existed because of the deleted user in the first place.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Role based access control.&lt;/strong&gt; The system defines three roles. AGENT covers basic resolve and ingest actions, the kind of everyday operations most users of the system will perform. VERIFIER is meant for human in the loop review, letting a qualified person step in and confirm or override an ambiguous resolution. ADMIN is reserved for configuration changes and erasure operations, keeping the most sensitive capabilities gated behind the appropriate permission level rather than leaving them open to anyone with basic access.&lt;/p&gt;

&lt;h2&gt;
  
  
  Some of the harder design decisions along the way
&lt;/h2&gt;

&lt;p&gt;Building this wasn't a straight line, and a few decisions took longer to settle on than I expected going in.&lt;/p&gt;

&lt;p&gt;Choosing the geometric mean over a simpler weighted average was one of them. It's mathematically stricter, and stricter math means more claims end up flagged as ambiguous rather than confidently resolved. Early on, that felt like it might make the system less useful, since users generally want answers, not more questions. But the more I thought about the target use cases, the clearer it became that a system used in insurance or legal contexts should be biased toward honest uncertainty rather than false confidence. A slightly less "decisive" system that's honest about its limits is more trustworthy, and ultimately more useful, than one that always has an answer ready.&lt;/p&gt;

&lt;p&gt;Deciding how aggressive to make the erasure cascade was another one. It would have been simpler to just hard delete everything tied to a user on request and call it compliant. But that approach ignores the reality that facts can be independently corroborated by other sources that have nothing to do with the user requesting deletion. Building the PII stripping path instead of a blanket deletion took more engineering effort, but it respects both the user's right to be forgotten and the integrity of facts that other, unrelated sources still legitimately support.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I'd tell someone building something similar
&lt;/h2&gt;

&lt;p&gt;If you're building any kind of AI memory or retrieval system that has to survive real contact with a compliance team, or honestly even one that just needs to earn genuine user trust, my biggest takeaway is this. Resist the temptation to let a single LLM call be your source of truth. It's fast, it's easy to prototype, and it demos beautifully. But it gives you nothing to audit and nothing to explain when someone eventually asks why the system believed something. Building a deterministic, inspectable scoring layer took a lot more upfront design work than just wiring up a prompt, but it's the difference between a system you can defend with evidence and one you can only apologize for after the fact.&lt;/p&gt;

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

&lt;p&gt;The project is still evolving, and there's plenty left on the roadmap. I want to expand the Neo4j and Qdrant integration further, refine the heuristics behind the Contradiction Guard so its ambiguity threshold can adapt a bit more intelligently to context, and generally keep hardening the compliance tooling as I learn more about what regulated industries actually need in practice. If any of this resonates with a problem you're facing, or you just want to dig into the internals, the full source and architecture details are on GitHub.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Check out the repo here: &lt;a href="https://github.com/alfinohatta/Corroborate.ai" rel="noopener noreferrer"&gt;github.com/alfinohatta/Corroborate.ai&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Corroborate.ai is licensed under AGPL-3.0. Contributions and feedback are welcome, especially on the Confidence Auction mechanics.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>kotlin</category>
      <category>nlp</category>
      <category>rag</category>
    </item>
  </channel>
</rss>
