<?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: Yash Fadadu</title>
    <description>The latest articles on DEV Community by Yash Fadadu (@yashforsure).</description>
    <link>https://dev.to/yashforsure</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%2F1499242%2Fc468b08d-c03f-451e-b6d4-447926e18e1a.png</url>
      <title>DEV Community: Yash Fadadu</title>
      <link>https://dev.to/yashforsure</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/yashforsure"/>
    <language>en</language>
    <item>
      <title>FraudLens: We Built a Fraud Investigator on TigerGraph, Not a Fraud Classifier</title>
      <dc:creator>Yash Fadadu</dc:creator>
      <pubDate>Thu, 24 Sep 2026 03:05:21 +0000</pubDate>
      <link>https://dev.to/yashforsure/fraudlens-we-built-a-fraud-investigator-on-tigergraph-not-a-fraud-classifier-3knc</link>
      <guid>https://dev.to/yashforsure/fraudlens-we-built-a-fraud-investigator-on-tigergraph-not-a-fraud-classifier-3knc</guid>
      <description>&lt;h1&gt;
  
  
  FraudLens: building a fraud investigator on TigerGraph, not a fraud classifier
&lt;/h1&gt;

&lt;p&gt;&lt;em&gt;By Team TrustMeBro (Yash, Manan, Priyank), built at Goa Hackerhouse 2026 with @TigerGraphDB and @247pmstudio&lt;/em&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Why we didn't build a classifier
&lt;/h2&gt;

&lt;p&gt;Before Goa Hackerhouse 2026, none of us had used a graph database seriously. The challenge changed that. We were given a bank's card transactions, a history of closed fraud investigations, and 20 open alerts, and asked to build an agent that &lt;em&gt;investigates&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;That word matters. A classifier looks at one transaction and outputs "fraud: 0.91". But the data warns that most high-scoring alerts are actually legitimate. A real analyst doesn't stop at the score. They ask:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Does this purchase fit how this customer normally spends?&lt;/li&gt;
&lt;li&gt;Has this device been used on other cards?&lt;/li&gt;
&lt;li&gt;Have we seen this pattern before, and how did that case end?&lt;/li&gt;
&lt;li&gt;Is there an innocent explanation?&lt;/li&gt;
&lt;li&gt;Is it worth calling the customer before blocking the card?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Almost all of those questions are about &lt;strong&gt;relationships&lt;/strong&gt;. That's why we built on a graph.&lt;/p&gt;




&lt;h2&gt;
  
  
  What FraudLens does
&lt;/h2&gt;

&lt;p&gt;Give FraudLens an alert (a risk score, a customer complaint, or an analyst note) and it runs a full investigation:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Confirms the alert makes sense.&lt;/strong&gt; Does the transaction exist, belong to that card, and does the card belong to that customer?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Gathers evidence from the graph.&lt;/strong&gt; Transaction history, spending baseline, devices, regions, email domains, connected cards.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tests the known fraud patterns.&lt;/strong&gt; Card testing, account takeover, new-device online fraud, out-of-region use, and recurring charges that were disputed but are really legitimate.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Looks for the innocent explanation.&lt;/strong&gt; This step is required, not optional.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Retrieves similar past cases&lt;/strong&gt; from the bank's closed-case history.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Estimates probability and uncertainty&lt;/strong&gt;, then makes an initial decision.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Asks for more evidence only if the answer could change the decision.&lt;/strong&gt; For example, it can ask the customer to confirm the purchase. If no possible answer would change the recommended action, it skips the request.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Makes a final decision&lt;/strong&gt;, filing a suspicious activity report (SAR) when policy requires one.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Writes the whole case back to TigerGraph&lt;/strong&gt;, then reads it back to confirm the write actually happened.&lt;/li&gt;
&lt;/ol&gt;




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



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;            Alert (risk score / complaint / analyst note)
                                │
                                ▼
                   ┌─────────────────────────┐
                   │ LangGraph investigator  │  plan → evidence → counter-evidence
                   │   (stateful workflow)   │  → memory → assess → need more?
                   └────────────┬────────────┘
           business tools only  │  (no raw database access)
                                ▼
                   ┌─────────────────────────┐
                   │ TigerGraph (Savanna)    │  schema, ~26 installed GSQL queries,
                   │ GSQL + graph algorithms │  ring discovery, case memory
                   └────────────┬────────────┘
                                ▼
    ┌──────────────────┐  ┌───────────────────┐  ┌──────────────────────┐
    │ Policy engine    │  │ Evidence simulator│  │ LLM (Gemini)         │
    │ R1–R10, routes   │  │ seeded responses  │  │ planning + prose only│
    │ auto / L1 / L2   │  └───────────────────┘  │ deterministic backup │
    └──────────────────┘                         └──────────────────────┘
                                │
                                ▼
          FastAPI  →  React analyst workbench  +  20 validated answer files
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each layer has one job, and a clear list of things it is &lt;strong&gt;not&lt;/strong&gt; allowed to do:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Layer&lt;/th&gt;
&lt;th&gt;Owns&lt;/th&gt;
&lt;th&gt;Never owns&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;TigerGraph + GSQL&lt;/td&gt;
&lt;td&gt;Relationships, traversal, pattern evidence, case memory&lt;/td&gt;
&lt;td&gt;Fraud verdicts&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Policy engine&lt;/td&gt;
&lt;td&gt;Rules R1–R10, approval routes, when a report is required&lt;/td&gt;
&lt;td&gt;Reasoning or graph access&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;LangGraph agent&lt;/td&gt;
&lt;td&gt;State, which evidence to gather, when to stop&lt;/td&gt;
&lt;td&gt;Approving any action&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;LLM&lt;/td&gt;
&lt;td&gt;Planning, summarising, explaining&lt;/td&gt;
&lt;td&gt;Facts, policy, IDs, probability&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The split we care about most: &lt;strong&gt;the LLM cannot approve anything.&lt;/strong&gt; It can recommend blocking a card. A deterministic policy engine decides whether that action is allowed and who has to approve it: &lt;code&gt;auto&lt;/code&gt;, a level-1 analyst (&lt;code&gt;L1&lt;/code&gt;), or a level-2 analyst (&lt;code&gt;L2&lt;/code&gt;). The API checks this a second time, so a client calling the API directly can't execute an action that needs approval either.&lt;/p&gt;




&lt;h2&gt;
  
  
  How we used TigerGraph
&lt;/h2&gt;

&lt;h3&gt;
  
  
  The graph model
&lt;/h3&gt;

&lt;p&gt;We didn't turn all 400+ columns in the dataset into vertices. Only the things investigations actually walk through became vertices. The rest stayed as transaction attributes.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Core entities:&lt;/strong&gt; &lt;code&gt;Customer&lt;/code&gt;, &lt;code&gt;Card&lt;/code&gt;, &lt;code&gt;Transaction&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Shared origins:&lt;/strong&gt; &lt;code&gt;DeviceProfile&lt;/code&gt;, &lt;code&gt;EmailDomain&lt;/code&gt;, &lt;code&gt;BillingRegion&lt;/code&gt; (how separate cards turn out to be linked)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Case memory:&lt;/strong&gt; &lt;code&gt;FraudCase&lt;/code&gt;, &lt;code&gt;Evidence&lt;/code&gt;, &lt;code&gt;EvidenceRequest&lt;/code&gt;, &lt;code&gt;ActionDecision&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Key edges:&lt;/strong&gt; &lt;code&gt;OWNS&lt;/code&gt;, &lt;code&gt;MADE&lt;/code&gt;, &lt;code&gt;FROM_DEVICE&lt;/code&gt;, &lt;code&gt;BILLED_IN&lt;/code&gt;, &lt;code&gt;INVOLVES&lt;/code&gt;, &lt;code&gt;SIMILAR_TO&lt;/code&gt;, &lt;code&gt;HAS_EVIDENCE&lt;/code&gt;, &lt;code&gt;RECOMMENDS&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;One detail we liked: a &lt;code&gt;NEXT&lt;/code&gt; edge links each card's transactions in time order. Looking at "what happened around this transaction" then becomes a short walk along those edges, not a scan of the whole table.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Data loaded:&lt;/strong&gt; 590,742 transactions, 13,553 customers, 14,317 cards, 9,702 device profiles, 576,425 &lt;code&gt;NEXT&lt;/code&gt; edges, and 5,565 closed historical cases.&lt;/p&gt;

&lt;h3&gt;
  
  
  GSQL does the graph work
&lt;/h3&gt;

&lt;p&gt;We had one rule: &lt;strong&gt;if a question is about relationships, TigerGraph answers it.&lt;/strong&gt; No Pandas joins, and no asking the LLM to guess whether two accounts are connected. We wrote about 26 installed queries, grouped like this:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Anchor and context:&lt;/strong&gt; &lt;code&gt;get_case_anchor&lt;/code&gt;, &lt;code&gt;get_card_window&lt;/code&gt;, &lt;code&gt;get_customer_baseline&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Pattern detection:&lt;/strong&gt; &lt;code&gt;detect_card_testing&lt;/code&gt;, &lt;code&gt;detect_account_takeover&lt;/code&gt;, &lt;code&gt;detect_region_anomaly&lt;/code&gt;, &lt;code&gt;detect_cnp_burst&lt;/code&gt;, &lt;code&gt;detect_recurring_charge&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Relationships:&lt;/strong&gt; &lt;code&gt;find_device_connections&lt;/code&gt;, &lt;code&gt;get_shared_origin_ring&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Graph algorithms:&lt;/strong&gt; &lt;code&gt;connected_cards_component&lt;/code&gt;, &lt;code&gt;find_high_fanout_origins&lt;/code&gt;, &lt;code&gt;refresh_device_fanout&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Case memory:&lt;/strong&gt; &lt;code&gt;find_similar_cases&lt;/code&gt;, &lt;code&gt;get_case_history&lt;/code&gt;, &lt;code&gt;get_case_graph&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Write-back:&lt;/strong&gt; &lt;code&gt;upsert_case&lt;/code&gt;, &lt;code&gt;add_case_evidence&lt;/code&gt;, &lt;code&gt;add_action_decision&lt;/code&gt;, &lt;code&gt;verify_case_bundle&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Every read query takes a &lt;code&gt;cutoff&lt;/code&gt; time.&lt;/strong&gt; A case opened on 5 December must not see anything from 6 December. We made the cutoff a required parameter rather than a convention, so it can't be forgotten, and it can be tested.&lt;/p&gt;

&lt;p&gt;Here is part of &lt;code&gt;get_shared_origin_ring&lt;/code&gt;, which finds other cards that used the same device, region, or email domain inside the time window:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="n"&gt;RingTxnsByDevice&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;OriginMatch&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;o&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;DEVICE_USED_BY&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;Transaction&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;
                   &lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;datetime_diff&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cutoff&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ts&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
                     &lt;span class="k"&gt;AND&lt;/span&gt; &lt;span class="n"&gt;datetime_diff&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ts&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;window_start&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;RingTxnsByRegion&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;OriginMatch&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;o&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;BILLING_REGION_OF&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;Transaction&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;
                   &lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;datetime_diff&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cutoff&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ts&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
                     &lt;span class="k"&gt;AND&lt;/span&gt; &lt;span class="n"&gt;datetime_diff&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ts&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;window_start&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;RingTxnsAll&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;RingTxnsByDevice&lt;/span&gt; &lt;span class="k"&gt;UNION&lt;/span&gt; &lt;span class="n"&gt;RingTxnsByRegion&lt;/span&gt; &lt;span class="k"&gt;UNION&lt;/span&gt; &lt;span class="n"&gt;RingTxnsByEmail&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="n"&gt;RingCards&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="k"&gt;c&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;RingTxns&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;MADE_BY&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;Card&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="k"&gt;c&lt;/span&gt;
            &lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="k"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;card_id&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;exclude_card_id&lt;/span&gt;
            &lt;span class="n"&gt;ACCUM&lt;/span&gt; &lt;span class="o"&gt;@@&lt;/span&gt;&lt;span class="n"&gt;connected_cards&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="k"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;card_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                  &lt;span class="o"&gt;@@&lt;/span&gt;&lt;span class="n"&gt;connected_customers&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="k"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;customer_id&lt;/span&gt;
            &lt;span class="k"&gt;LIMIT&lt;/span&gt; &lt;span class="n"&gt;max_cards&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  MCP: small tools, not a database connection
&lt;/h3&gt;

&lt;p&gt;The agent reaches TigerGraph through tools named after what an investigator does: &lt;code&gt;find_connected_accounts&lt;/code&gt;, &lt;code&gt;trace_money_flow&lt;/code&gt;, &lt;code&gt;find_device_connections&lt;/code&gt;, &lt;code&gt;find_similar_cases&lt;/code&gt;, and so on. Our own MCP server exposes 12 of these tools, all read-only and all enforcing the cutoff. The official &lt;code&gt;tigergraph-mcp&lt;/code&gt; server is also registered, restricted to read-only tools.&lt;/p&gt;

&lt;p&gt;Writing is deliberately &lt;strong&gt;not&lt;/strong&gt; a tool the model can call. A model that can write arbitrary graph data could create its own evidence. Case write-back goes through one checked persistence step instead.&lt;/p&gt;

&lt;h3&gt;
  
  
  Evidence that can be checked
&lt;/h3&gt;

&lt;p&gt;Every piece of evidence records its source and the exact query that produced it, for example &lt;code&gt;query:get_case_anchor(card_id=C12382-K1, customer_id=C12382, txn_id=3514030)&lt;/code&gt;. An analyst can re-run the query and check the claim. Conclusions the agent draws are stored separately and never presented as facts.&lt;/p&gt;

&lt;h3&gt;
  
  
  Case memory that has to be earned
&lt;/h3&gt;

&lt;p&gt;When a case closes, FraudLens writes the case, its evidence, evidence requests, actions and links to similar past cases into the graph. Each case gets a fixed ID, so re-running a case overwrites it instead of creating a duplicate. Then &lt;code&gt;verify_case_bundle&lt;/code&gt; reads it back and compares counts and a hash. The answer file only says &lt;code&gt;written_to_graph: true&lt;/code&gt; if the two match.&lt;/p&gt;

&lt;p&gt;Past bank cases and our agent's own cases are stored the same way, but each is tagged with a trust tier. That way, the agent's own conclusions are never cited as if they were the bank's confirmed outcomes.&lt;/p&gt;




&lt;h2&gt;
  
  
  Results
&lt;/h2&gt;

&lt;p&gt;We ran all 20 benchmark cases in time order against the live TigerGraph graph, so earlier cases became memory for later ones.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Cases investigated&lt;/td&gt;
&lt;td&gt;20 of 20, all passing the answer validator&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Written to graph and verified by read-back&lt;/td&gt;
&lt;td&gt;20 of 20&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Verdicts&lt;/td&gt;
&lt;td&gt;7 fraud, 12 legitimate, 1 uncertain&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Suspicious activity reports&lt;/td&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Graph queries per case&lt;/td&gt;
&lt;td&gt;21–34&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The mostly-legitimate split is intended. The challenge warns that about half these alerts turn out to be legitimate, and an agent that blocks everything scores badly.&lt;/p&gt;

&lt;p&gt;The evidence request made a visible difference. In one case the initial recommendation was to &lt;em&gt;monitor&lt;/em&gt; the card, and after new evidence it changed to &lt;em&gt;block&lt;/em&gt; (L1 approval). In another, an initial &lt;em&gt;block&lt;/em&gt; became &lt;em&gt;close, no fraud&lt;/em&gt; once the customer confirmed the purchase.&lt;/p&gt;

&lt;p&gt;The system also keeps working if the LLM is down. When our free-tier model quota ran out, the explanations fell back to evidence-based template text, and every verdict, action and report stayed the same.&lt;/p&gt;




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

&lt;p&gt;&lt;strong&gt;Test data only finds the bugs you expect.&lt;/strong&gt; Our small test data passed everything. Real data and a live database found new problems:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Fake links.&lt;/strong&gt; The most "shared" device profiles were &lt;code&gt;unknown | unknown | unknown&lt;/code&gt; (1,011 customers) and one very common Windows + Chrome setup (842 customers). Those are common settings, not real devices, but they linked unrelated people. That pushed our report rate to 70%. Requiring a profile to be specific before it can link anyone brought it down to 6 of 20.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;GSQL surprises on a live instance.&lt;/strong&gt; &lt;code&gt;Case&lt;/code&gt; and &lt;code&gt;count&lt;/code&gt; are reserved words, so we renamed our vertex type to &lt;code&gt;FraudCase&lt;/code&gt;. Boolean defaults didn't parse the way we expected. Loading files by column name failed on Savanna because the server can't see our local files, so we switched to column positions. In some query outputs, field names came back prefixed (&lt;code&gt;TheCase.bundle_hash&lt;/code&gt; instead of &lt;code&gt;bundle_hash&lt;/code&gt;). That silently broke our write-back check until we renamed every field explicitly.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Check the graph directly, not the logs.&lt;/strong&gt; Our first bulk load reported success but was missing about 14,000 transactions. Only comparing vertex counts against the source file caught it.&lt;/li&gt;
&lt;/ul&gt;

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

&lt;ul&gt;
&lt;li&gt;Calibrate the fraud probability against the bank's closed-case history, measured over time.&lt;/li&gt;
&lt;li&gt;Load the policy and regulatory documents into the graph as searchable chunks. The schema for this (&lt;code&gt;Document&lt;/code&gt;, &lt;code&gt;DocumentChunk&lt;/code&gt;, &lt;code&gt;CITES&lt;/code&gt;) is already in place.&lt;/li&gt;
&lt;li&gt;Route the investigator's own tool calls over MCP. Today it calls the same tool functions directly.&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;Thanks to &lt;strong&gt;@TigerGraphDB&lt;/strong&gt; and &lt;strong&gt;@247pmstudio&lt;/strong&gt; for Goa Hackerhouse 2026. We came in knowing tables and left thinking in graphs. 🙌&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Team TrustMeBro: Yash, Manan, Priyank&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>database</category>
      <category>fintech</category>
      <category>security</category>
    </item>
    <item>
      <title>🚀 What Really Happens When You Call .add() Twice? Classic BLoC vs BlocSignal</title>
      <dc:creator>Yash Fadadu</dc:creator>
      <pubDate>Thu, 06 Aug 2026 17:57:52 +0000</pubDate>
      <link>https://dev.to/yashforsure/what-really-happens-when-you-call-add-twice-classic-bloc-vs-blocsignal-5969</link>
      <guid>https://dev.to/yashforsure/what-really-happens-when-you-call-add-twice-classic-bloc-vs-blocsignal-5969</guid>
      <description>&lt;p&gt;We've all been there.&lt;/p&gt;

&lt;p&gt;You're building a Flutter app with BLoC, and somewhere in your business logic you write:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="n"&gt;myBloc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;LoadUserData&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;span class="n"&gt;myBloc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;FetchUserPreferences&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Immediately, a thought pops into your head...&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;🤔 &lt;strong&gt;"Wait... did I just overwrite the first event before the UI even had a chance to rebuild?"&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Or maybe:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Will &lt;code&gt;EventB&lt;/code&gt; execute before &lt;code&gt;EventA&lt;/code&gt; finishes?&lt;/li&gt;
&lt;li&gt;Will the UI skip &lt;code&gt;StateA&lt;/code&gt;?&lt;/li&gt;
&lt;li&gt;If I read &lt;code&gt;bloc.state&lt;/code&gt; immediately after &lt;code&gt;.add()&lt;/code&gt;, what state do I get?&lt;/li&gt;
&lt;li&gt;What happens if I call &lt;code&gt;.add()&lt;/code&gt; &lt;strong&gt;10,000 times&lt;/strong&gt;?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let's lift the hood and compare &lt;strong&gt;Classic BLoC&lt;/strong&gt; and &lt;strong&gt;BlocSignal&lt;/strong&gt;.&lt;/p&gt;




&lt;h1&gt;
  
  
  🤯 The Common Misconception
&lt;/h1&gt;

&lt;p&gt;Many developers imagine something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;EventA
   ↓
StateA

EventB
   ↓
StateB

↓

UI only sees StateB 😱
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The fear is that rapid-fire &lt;code&gt;.add()&lt;/code&gt; calls somehow overwrite each other before Flutter can render.&lt;/p&gt;

&lt;p&gt;Fortunately...&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;That's not how either implementation works.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The difference lies in &lt;strong&gt;how state propagates&lt;/strong&gt;, not whether events get lost.&lt;/p&gt;




&lt;h1&gt;
  
  
  🐢 Classic BLoC (Streams)
&lt;/h1&gt;

&lt;p&gt;Traditional &lt;code&gt;flutter_bloc&lt;/code&gt; is built on top of &lt;strong&gt;Dart Streams&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;A simplified flow looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.add(Event)

        ↓

 StreamController

        ↓

 Event Handler

        ↓

 emit(State)

        ↓

 State Stream

        ↓

 BlocBuilder Listener

        ↓

 markNeedsBuild()

        ↓

 Flutter Frame
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Notice something important:&lt;/p&gt;

&lt;p&gt;Flutter &lt;strong&gt;does not rebuild immediately&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;It simply marks the widget as &lt;strong&gt;dirty&lt;/strong&gt; and rebuilds during the next rendering frame.&lt;/p&gt;




&lt;h2&gt;
  
  
  So what happens?
&lt;/h2&gt;

&lt;p&gt;Imagine:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="n"&gt;bloc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;EventA&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;span class="n"&gt;bloc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;EventB&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Internally it behaves more like:&lt;br&gt;
&lt;/p&gt;

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

↓

Handler runs

↓

emit(StateA)

↓

Widget marked dirty

↓

EventB

↓

Handler runs

↓

emit(StateB)

↓

Widget marked dirty again

↓

Flutter renders

↓

Latest state displayed
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No event is lost.&lt;/p&gt;

&lt;p&gt;Both handlers execute.&lt;/p&gt;

&lt;p&gt;The UI simply paints the &lt;strong&gt;latest settled state&lt;/strong&gt; when Flutter decides to render the next frame.&lt;/p&gt;




&lt;h1&gt;
  
  
  ⚡ BlocSignal (Signals)
&lt;/h1&gt;

&lt;p&gt;BlocSignal keeps the familiar BLoC programming model...&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="n"&gt;bloc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(...)&lt;/span&gt;
&lt;span class="n"&gt;emit&lt;/span&gt;&lt;span class="p"&gt;(...)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;...but replaces &lt;strong&gt;Streams&lt;/strong&gt; with &lt;strong&gt;Signals&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Its propagation path is much shorter.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.add(Event)

      ↓

Handler

      ↓

emit(State)

      ↓

Signal

      ↓

BlocSignalBuilder

      ↓

markNeedsBuild()

      ↓

Flutter Frame
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The biggest difference is:&lt;/p&gt;

&lt;p&gt;The handler executes &lt;strong&gt;synchronously&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Meaning this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="n"&gt;bloc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;EventA&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;

&lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bloc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;state&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;already prints&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;StateA
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;because the state has already been updated before &lt;code&gt;.add()&lt;/code&gt; returns.&lt;/p&gt;

&lt;p&gt;Then...&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="n"&gt;bloc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;EventB&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;starts.&lt;/p&gt;

&lt;p&gt;So EventB always sees the latest state.&lt;/p&gt;




&lt;h1&gt;
  
  
  🤔 Doesn't that rebuild the UI every time?
&lt;/h1&gt;

&lt;p&gt;This is probably the most interesting question.&lt;/p&gt;

&lt;p&gt;Suppose you do something completely unreasonable 😂&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;10000&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;bloc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;IncrementEvent&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Many people imagine:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;markNeedsBuild()

↓

Build

↓

markNeedsBuild()

↓

Build

↓

markNeedsBuild()

↓

Build
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;10,000 times.&lt;/p&gt;

&lt;p&gt;Fortunately...&lt;/p&gt;

&lt;p&gt;Flutter is much smarter than that.&lt;/p&gt;




&lt;h1&gt;
  
  
  🎨 What &lt;code&gt;markNeedsBuild()&lt;/code&gt; Actually Does
&lt;/h1&gt;

&lt;p&gt;Calling&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="n"&gt;markNeedsBuild&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;does &lt;strong&gt;not&lt;/strong&gt; immediately rebuild the widget.&lt;/p&gt;

&lt;p&gt;It simply tells Flutter:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"This widget is dirty."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Internally it's roughly equivalent to:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;_dirty = true;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If it's already dirty...&lt;/p&gt;

&lt;p&gt;Setting&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;_dirty = true;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;again changes nothing.&lt;/p&gt;

&lt;p&gt;So&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;markNeedsBuild()

markNeedsBuild()

markNeedsBuild()

markNeedsBuild()
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;still results in&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;_dirty == true
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once Flutter reaches the next frame...&lt;/p&gt;

&lt;p&gt;it performs &lt;strong&gt;one build&lt;/strong&gt; using the latest state.&lt;/p&gt;




&lt;h1&gt;
  
  
  📊 Classic BLoC vs BlocSignal
&lt;/h1&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Feature&lt;/th&gt;
&lt;th&gt;Classic BLoC 🐢&lt;/th&gt;
&lt;th&gt;BlocSignal ⚡&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;State Propagation&lt;/td&gt;
&lt;td&gt;Stream-based&lt;/td&gt;
&lt;td&gt;Signal-based&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Handler Execution&lt;/td&gt;
&lt;td&gt;Stream/event pipeline&lt;/td&gt;
&lt;td&gt;Direct synchronous execution&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;bloc.state&lt;/code&gt; immediately after &lt;code&gt;.add()&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Depends on propagation timing&lt;/td&gt;
&lt;td&gt;Updated immediately&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Internal Dispatch&lt;/td&gt;
&lt;td&gt;Stream subscriptions&lt;/td&gt;
&lt;td&gt;Signal dependency graph&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;UI Rendering&lt;/td&gt;
&lt;td&gt;Flutter frame pipeline&lt;/td&gt;
&lt;td&gt;Flutter frame pipeline&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Widget Rebuild&lt;/td&gt;
&lt;td&gt;Deferred to Flutter&lt;/td&gt;
&lt;td&gt;Deferred to Flutter&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Developer Experience&lt;/td&gt;
&lt;td&gt;Mature &amp;amp; battle-tested&lt;/td&gt;
&lt;td&gt;Familiar API with Signals underneath&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h1&gt;
  
  
  🎯 So... what does BlocSignal actually optimize?
&lt;/h1&gt;

&lt;p&gt;The optimization isn't that Flutter suddenly rebuilds faster.&lt;/p&gt;

&lt;p&gt;Flutter's rendering pipeline is exactly the same.&lt;/p&gt;

&lt;p&gt;Instead, BlocSignal removes much of the reactive plumbing:&lt;/p&gt;

&lt;p&gt;❌ StreamController&lt;/p&gt;

&lt;p&gt;❌ Stream subscriptions&lt;/p&gt;

&lt;p&gt;❌ Stream dispatch&lt;/p&gt;

&lt;p&gt;❌ Async propagation through streams&lt;/p&gt;

&lt;p&gt;Replacing it with:&lt;/p&gt;

&lt;p&gt;✅ Direct synchronous state updates&lt;/p&gt;

&lt;p&gt;✅ Signal dependency propagation&lt;/p&gt;

&lt;p&gt;✅ Immediate state availability&lt;/p&gt;

&lt;p&gt;This makes the execution path shorter and more predictable.&lt;/p&gt;




&lt;h1&gt;
  
  
  💙 Final Thoughts
&lt;/h1&gt;

&lt;p&gt;Calling:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="n"&gt;bloc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;EventA&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;span class="n"&gt;bloc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;EventB&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;is perfectly safe.&lt;/p&gt;

&lt;p&gt;Neither Classic BLoC nor BlocSignal loses events.&lt;/p&gt;

&lt;p&gt;The key difference is &lt;strong&gt;how the new state travels from your business logic to the UI&lt;/strong&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;🐢 &lt;strong&gt;Classic BLoC&lt;/strong&gt; uses a Stream-based propagation pipeline.&lt;/li&gt;
&lt;li&gt;⚡ &lt;strong&gt;BlocSignal&lt;/strong&gt; replaces that pipeline with synchronous Signal propagation.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Both still rely on Flutter's rendering engine, which intelligently batches widget rebuilds into the next frame.&lt;/p&gt;

&lt;p&gt;So no matter how many times you call &lt;code&gt;.add()&lt;/code&gt;, Flutter only paints what actually matters—the latest settled state.&lt;/p&gt;

</description>
      <category>flutter</category>
      <category>dart</category>
      <category>blocsignal</category>
    </item>
    <item>
      <title>🔥 Solved 1000 LeetCode Questions — Here's What I Learned (and Didn't)</title>
      <dc:creator>Yash Fadadu</dc:creator>
      <pubDate>Fri, 30 May 2025 06:25:58 +0000</pubDate>
      <link>https://dev.to/yashforsure/solved-1000-leetcode-questions-heres-what-i-learned-and-didnt-1ab1</link>
      <guid>https://dev.to/yashforsure/solved-1000-leetcode-questions-heres-what-i-learned-and-didnt-1ab1</guid>
      <description>&lt;h2&gt;
  
  
  ✅ 1000 LeetCode Questions — Done!
&lt;/h2&gt;

&lt;p&gt;Just hit a &lt;strong&gt;huge milestone&lt;/strong&gt;:&lt;br&gt;&lt;br&gt;
Hello I'm &lt;strong&gt;Yash Fadadu&lt;/strong&gt;, I’ve completed &lt;strong&gt;1000 questions&lt;/strong&gt; on &lt;a href="https://leetcode.com/" rel="noopener noreferrer"&gt;LeetCode&lt;/a&gt; ✌️&lt;br&gt;&lt;br&gt;
And no — I’m not at Google. Not yet at Microsoft either.&lt;/p&gt;

&lt;p&gt;But that’s not what this post is about.&lt;/p&gt;




&lt;h2&gt;
  
  
  ✨ Was it worth it?
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Short answer:&lt;/strong&gt; Yes. But &lt;em&gt;not for the reasons you might think.&lt;/em&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;❓ &lt;em&gt;Did I become a DSA expert?&lt;/em&gt; – Not yet&lt;br&gt;&lt;br&gt;
💼 &lt;em&gt;Got an offer from FAANG?&lt;/em&gt; – No&lt;br&gt;&lt;br&gt;
🧠 &lt;em&gt;Learned something deeper?&lt;/em&gt; – 100%&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  💡 What I Actually Learned
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;Solving LeetCode isn’t about flexing IQ.&lt;br&gt;&lt;br&gt;
It’s about &lt;strong&gt;consistency&lt;/strong&gt;, &lt;strong&gt;discipline&lt;/strong&gt;, and learning to &lt;strong&gt;think like a developer&lt;/strong&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ul&gt;
&lt;li&gt;You can study all the patterns and still get stuck. That’s &lt;em&gt;normal.&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;You won’t love every part of it — but that’s the point.&lt;/li&gt;
&lt;li&gt;It teaches you to show up even when it’s tough.&lt;/li&gt;
&lt;li&gt;It’s about building &lt;strong&gt;mental endurance&lt;/strong&gt; as much as technical skill.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I often felt like ditching LeetCode to focus on building real-world things — AI tools, beautiful UIs, full-stack apps.&lt;br&gt;&lt;br&gt;
But this journey reminded me:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;🔁 &lt;em&gt;“You grow most when you don’t feel like it.”&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  📝 Tips If You're Just Starting
&lt;/h2&gt;

&lt;p&gt;Here’s what helped me — and might help you:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;📚 &lt;strong&gt;Master the basics&lt;/strong&gt;: Arrays, Strings, Linked Lists, Trees
&lt;/li&gt;
&lt;li&gt;🎯 Learn core patterns: Two Pointers, Sliding Window, Binary Search, Recursion&lt;/li&gt;
&lt;li&gt;🤏 Start with &lt;strong&gt;easy problems&lt;/strong&gt; — they build confidence&lt;/li&gt;
&lt;li&gt;⏱️ Stuck for more than an hour? &lt;strong&gt;Read the solution&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;🧠 Study a topic &lt;strong&gt;before&lt;/strong&gt; attempting questions on it&lt;/li&gt;
&lt;li&gt;🔁 Make it a &lt;strong&gt;daily habit&lt;/strong&gt;, not a sprint&lt;/li&gt;
&lt;li&gt;🔍 Get good at &lt;strong&gt;time &amp;amp; space complexity&lt;/strong&gt; — it’ll make your intuition stronger&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  ✅ Real Benefits I’ve Seen
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;🧩 Understanding DSA helped me in &lt;strong&gt;blockchain&lt;/strong&gt;, &lt;strong&gt;AI/ML&lt;/strong&gt;, &lt;strong&gt;game dev&lt;/strong&gt;, and &lt;strong&gt;full-stack&lt;/strong&gt; work.&lt;/li&gt;
&lt;li&gt;💡 I write cleaner, more optimized code.&lt;/li&gt;
&lt;li&gt;🔐 Most of all, it &lt;strong&gt;changed my mindset&lt;/strong&gt;: I now look at problems with more clarity and confidence.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  🛠️ Let's Connect
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://leetcode.com/u/_mYash1994/" rel="noopener noreferrer"&gt;My LeetCode&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/yashh1994" rel="noopener noreferrer"&gt;My GitHub&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  🚀 What’s Next?
&lt;/h2&gt;

&lt;p&gt;1000 done.&lt;br&gt;&lt;br&gt;
Now chasing &lt;strong&gt;2000&lt;/strong&gt; 🧠⚡&lt;br&gt;&lt;br&gt;
Because the goal is never just a number — it’s to become better than yesterday.&lt;/p&gt;

&lt;p&gt;If you're on the same journey, let’s connect.&lt;br&gt;&lt;br&gt;
Drop your milestones, tips, or struggles in the comments! 🙌&lt;/p&gt;




</description>
      <category>leetcode</category>
      <category>1000questions</category>
      <category>dsa</category>
      <category>algorithms</category>
    </item>
    <item>
      <title>🧠 The S-400 and Smart Defense: How AI Algorithms Could Revolutionize Automated Air Defense</title>
      <dc:creator>Yash Fadadu</dc:creator>
      <pubDate>Fri, 23 May 2025 10:06:25 +0000</pubDate>
      <link>https://dev.to/yashforsure/the-s-400-and-smart-defense-how-ai-algorithms-could-revolutionize-automated-air-defense-1d0a</link>
      <guid>https://dev.to/yashforsure/the-s-400-and-smart-defense-how-ai-algorithms-could-revolutionize-automated-air-defense-1d0a</guid>
      <description>&lt;p&gt;The S-400 Triumf air defense system is a marvel of military engineering. With the ability to track and destroy aircraft, drones, and missiles over 400 km away, it’s one of the most feared SAM systems in the world.&lt;/p&gt;

&lt;p&gt;But here’s the reality: while the S-400 uses advanced automation, it doesn't yet use true AI—as in learning algorithms that improve over time.&lt;/p&gt;

&lt;p&gt;So, what if we applied real machine learning? Let’s explore the algorithms that could bring the next level of intelligence to air defense systems like the S-400.&lt;/p&gt;

&lt;p&gt;**🔄 Current Automation in the S-400&lt;br&gt;
The S-400 currently uses:&lt;/p&gt;

&lt;p&gt;Rule-based threat prioritization: if X is moving fast at Y altitude, treat it as a missile.&lt;/p&gt;

&lt;p&gt;Predefined radar tracking filters: such as Kalman filters to estimate object trajectories.&lt;/p&gt;

&lt;p&gt;Hard-coded decision trees for assigning missiles to targets.&lt;/p&gt;

&lt;p&gt;These systems are fast and reliable, but they’re not adaptive. They can’t learn from new types of threats or behavior.&lt;/p&gt;

&lt;p&gt;🤖 What AI Can Add: The Algorithms That Matter&lt;br&gt;
Let’s go over specific AI/ML algorithms that could supercharge an air defense system:&lt;/p&gt;

&lt;h2&gt;
  
  
  1. 🧮 Convolutional Neural Networks (CNNs) for Visual Target Identification
&lt;/h2&gt;

&lt;p&gt;If integrated with optical or infrared sensors:&lt;/p&gt;

&lt;p&gt;Purpose: Classify aircraft, drones, or decoys visually.&lt;/p&gt;

&lt;p&gt;How it works: CNNs learn patterns in images (like turbine shapes, wing profiles) and can outperform traditional object detection in noisy environments.&lt;/p&gt;

&lt;p&gt;Example use: Detect if a low-flying object is a real UAV or a decoy balloon.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. 📈 Reinforcement Learning (RL) for Engagement Decision-Making
&lt;/h2&gt;

&lt;p&gt;Purpose: Learn optimal defense strategies through simulation and feedback.&lt;/p&gt;

&lt;p&gt;How it works: RL agents (like Deep Q-Networks or PPO) try different missile-target strategies in a simulated battlefield. Over time, they learn what decisions lead to success.&lt;/p&gt;

&lt;p&gt;Example use: Learn the best firing sequence when faced with a saturation drone swarm attack.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. 🧠 LSTM (Long Short-Term Memory) Networks for Trajectory Prediction
&lt;/h2&gt;

&lt;p&gt;Purpose: Predict where a target will go based on past movement.&lt;/p&gt;

&lt;p&gt;How it works: LSTMs are a type of Recurrent Neural Network (RNN) that can learn temporal patterns—perfect for motion prediction in noisy environments.&lt;/p&gt;

&lt;p&gt;Example use: Predict where a hypersonic missile will be 3 seconds from now, even if it suddenly changes direction.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. 🔍 Anomaly Detection with Autoencoders
&lt;/h2&gt;

&lt;p&gt;Purpose: Spot spoofed or jammed radar signals.&lt;/p&gt;

&lt;p&gt;How it works: An autoencoder learns the "normal" signal patterns. When it sees a signal that doesn’t fit, it flags it as a potential threat or decoy.&lt;/p&gt;

&lt;p&gt;Example use: Detect radar jamming or stealth aircraft signature anomalies.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. 🧾 Decision Trees + XGBoost for Threat Classification
&lt;/h2&gt;

&lt;p&gt;Purpose: Classify threats based on structured data (speed, altitude, radar cross-section).&lt;/p&gt;

&lt;p&gt;How it works: These models excel at classifying tabular input—like sensor values—into risk levels.&lt;/p&gt;

&lt;p&gt;Example use: Score each target in real-time with a “threat score” from 0 to 100.&lt;/p&gt;

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

&lt;p&gt;The future battlefield will be filled with:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Swarm drones&lt;/li&gt;
&lt;li&gt;Hypersonic missiles&lt;/li&gt;
&lt;li&gt;AI-driven stealth aircraft&lt;/li&gt;
&lt;li&gt;ECM (Electronic Counter Measures)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;To survive, air defense systems need to be just as smart as they are fast.&lt;/p&gt;

&lt;h2&gt;
  
  
  🧑‍💻 Developers: Your Skills Matter
&lt;/h2&gt;

&lt;p&gt;If you're a developer working in:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;AI/ML&lt;/li&gt;
&lt;li&gt;Embedded systems&lt;/li&gt;
&lt;li&gt;Edge computing&lt;/li&gt;
&lt;li&gt;Signal processing&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;...you can help build the brains behind these next-gen defense systems. It's not just about writing software—it's about writing code that makes life-and-death decisions smarter, safer, and more accountable.&lt;/p&gt;

&lt;h2&gt;
  
  
  🧠 Final Thoughts
&lt;/h2&gt;

&lt;p&gt;The S-400’s automation is solid—but static. By integrating real AI algorithms, we could enable defense systems to learn from experience, adapt to new threats, and respond faster than any human could.&lt;/p&gt;

&lt;p&gt;💬 What’s your take on using machine learning in defense systems? Exciting? Risky? Both? Drop your thoughts below.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Ghibli Art Generation AI — The Fusion of Machine Learning and Animated Aesthetics</title>
      <dc:creator>Yash Fadadu</dc:creator>
      <pubDate>Wed, 14 May 2025 14:10:08 +0000</pubDate>
      <link>https://dev.to/yashforsure/ghibli-art-generation-ai-the-fusion-of-machine-learning-and-animated-aesthetics-ico</link>
      <guid>https://dev.to/yashforsure/ghibli-art-generation-ai-the-fusion-of-machine-learning-and-animated-aesthetics-ico</guid>
      <description>&lt;h2&gt;
  
  
  🧠 Overview
&lt;/h2&gt;

&lt;p&gt;Ghibli-style art generation through AI represents a fascinating application of generative deep learning models, particularly those based on diffusion architectures. These systems are capable of producing high-quality, stylized illustrations that resemble the iconic aesthetics of Studio Ghibli’s animation—characterized by soft color palettes, emotional atmospheres, and richly detailed environments.&lt;/p&gt;

&lt;h2&gt;
  
  
  🔍 How It Works
&lt;/h2&gt;

&lt;p&gt;Ghibli art generation is typically powered by text-to-image and image-to-image models, such as Stable Diffusion, DreamBooth, or LoRA-tuned variants. These models are trained or fine-tuned on large datasets of artwork that resemble or replicate the Ghibli aesthetic.&lt;/p&gt;

&lt;p&gt;Key components include:&lt;/p&gt;

&lt;p&gt;Diffusion Models: Probabilistic generative models that iteratively denoise random noise into meaningful images. When trained on Ghibli-style datasets, these models learn to reproduce similar artistic features.&lt;/p&gt;

&lt;p&gt;DreamBooth / LoRA Fine-Tuning: Techniques used to customize a base model to learn specific art styles. DreamBooth helps the model internalize unique visual characteristics by overfitting on a small curated dataset (e.g., 100–500 images of Ghibli-style frames or fan art).&lt;/p&gt;

&lt;p&gt;Text Prompt Engineering: Users describe scenes in natural language (e.g., “a magical forest with floating lanterns”), and the model interprets this to generate corresponding imagery, integrating the learned Ghibli-like features.&lt;/p&gt;

&lt;p&gt;Image-to-Image Translation: Users can input photos or sketches, and the model reinterprets them in Ghibli style, preserving structure while applying the aesthetic transformation.&lt;/p&gt;

&lt;h2&gt;
  
  
  📊 Dataset Considerations
&lt;/h2&gt;

&lt;p&gt;Due to copyright constraints, training typically avoids using original Studio Ghibli frames directly. Instead, fine-tuning datasets often consist of:&lt;/p&gt;

&lt;p&gt;High-quality fan art&lt;/p&gt;

&lt;p&gt;Open-source anime-style illustrations&lt;/p&gt;

&lt;p&gt;Stylized concept art that reflects similar themes and color schemes&lt;/p&gt;

&lt;p&gt;Data augmentation (color jittering, cropping, flipping) is used to improve generalization while preserving artistic coherence.&lt;/p&gt;

&lt;h2&gt;
  
  
  🧠 Technical Stack
&lt;/h2&gt;

&lt;p&gt;While implementations vary, a standard Ghibli-style art generation stack might include:&lt;/p&gt;

&lt;p&gt;Model Backbone: Stable Diffusion 1.5 or SDXL&lt;/p&gt;

&lt;p&gt;Fine-Tuning Framework: DreamBooth, LoRA, or Textual Inversion&lt;/p&gt;

&lt;p&gt;Inference Backend: Python + PyTorch with Hugging Face Transformers &amp;amp; diffusers&lt;/p&gt;

&lt;p&gt;Frontend Interface: Web apps built with React or Gradio for demo interactions&lt;/p&gt;

&lt;p&gt;Deployment: GPU-accelerated platforms like Hugging Face Spaces, Replicate, or custom servers using NVIDIA GPUs&lt;/p&gt;

&lt;h2&gt;
  
  
  ✨ Applications
&lt;/h2&gt;

&lt;p&gt;Creative Art Generation: Allowing users to visualize fantasy scenes or original characters in a beloved animated style.&lt;/p&gt;

&lt;p&gt;Concept Design: Useful for illustrators and indie animators needing quick prototyping in an established aesthetic.&lt;/p&gt;

&lt;p&gt;Education: Demonstrating how AI can learn and replicate complex visual styles from limited data.&lt;/p&gt;

</description>
    </item>
  </channel>
</rss>
