<?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: Anubhav Dash</title>
    <description>The latest articles on DEV Community by Anubhav Dash (@an0n99x).</description>
    <link>https://dev.to/an0n99x</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%2F3572735%2F965a7b68-9338-485f-b89d-03780ef3c6ac.jpeg</url>
      <title>DEV Community: Anubhav Dash</title>
      <link>https://dev.to/an0n99x</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/an0n99x"/>
    <language>en</language>
    <item>
      <title>Deadweight: price your generosity before you ship it</title>
      <dc:creator>Anubhav Dash</dc:creator>
      <pubDate>Mon, 07 Sep 2026 00:55:02 +0000</pubDate>
      <link>https://dev.to/an0n99x/deadweight-price-your-generosity-before-you-ship-it-52op</link>
      <guid>https://dev.to/an0n99x/deadweight-price-your-generosity-before-you-ship-it-52op</guid>
      <description>&lt;p&gt;&lt;em&gt;Built for the &lt;a href="https://dev.to/challenges"&gt;DEV Weekend Challenge: Generosity Edition&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Live:&lt;/strong&gt; &lt;a href="https://deadweight-jet.vercel.app" rel="noopener noreferrer"&gt;https://deadweight-jet.vercel.app&lt;/a&gt; &lt;br&gt;
&lt;strong&gt;Repo:&lt;/strong&gt; &lt;a href="https://github.com/AnubhavDash/DeadWeight" rel="noopener noreferrer"&gt;https://github.com/AnubhavDash/DeadWeight&lt;/a&gt;&lt;/p&gt;


&lt;h2&gt;
  
  
  The coat
&lt;/h2&gt;

&lt;p&gt;Someone in Rasuwa needs a coat. You have a coat. The arithmetic looks finished.&lt;/p&gt;

&lt;p&gt;It isn't. Between your hands and theirs sit an air waybill, a customs broker, a sorting line paid by the hour, a warehouse in a country whose warehouses are already full, and — often enough — an incinerator. Every one of those steps has a published rate. None of them appear on the box.&lt;/p&gt;

&lt;p&gt;This has a name in the humanitarian sector. They call the arrival of unrequested goods &lt;strong&gt;the second disaster&lt;/strong&gt;, and they have been asking people to stop for forty years. The Logistics Cluster writes guidance about it. OCHA writes guidance about it. The IFRC's disaster-law reviews keep finding the same story: after Cyclone Pam, unsolicited donations sat in Vanuatu for twelve months. Airlink has put a number on the share of donated goods that is simply inappropriate for the response receiving it.&lt;/p&gt;

&lt;p&gt;And still the boxes come, because the impulse behind them is &lt;em&gt;correct&lt;/em&gt;. Someone is cold and you have a coat. There is nothing wrong with that instinct. What's wrong is that nobody ever shows you the invoice.&lt;/p&gt;

&lt;p&gt;So I built the invoice.&lt;/p&gt;
&lt;h2&gt;
  
  
  What it is
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://deadweight-jet.vercel.app" rel="noopener noreferrer"&gt;Deadweight&lt;/a&gt; is a ledger for the gap between giving something and it arriving.&lt;/p&gt;

&lt;p&gt;You build a consignment on a manifest — winter jackets out of a wardrobe, bottled water by the litre, used shoes, soft toys, the medicine cabinet. You pick a route: air (days, and the only way into the cut-off districts), road over the Birgunj–Raxaul crossing (weeks), or sea and road (months, because Nepal is landlocked and the ocean stops at Kolkata).&lt;/p&gt;

&lt;p&gt;Then it prices the whole journey in USD, line by line, and every line opens:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;DECLARED VALUE                                        $2,800.00
3 line items

unusable used clothing                              -$1,615.00
  15% of this class arrives usable        SOURCE  [ASSUMPTION]

not needed or not appropriate                         -$540.00
  40% of this class arrives usable        SOURCE  [ASSUMPTION]

air freight DEL→KTM                                    -$84.00
  56.0 kg × $1.50/kg                     SOURCE

sorting labour                                          -$0.31
  0.4 h × $0.70/h local wage             SOURCE  [ASSUMPTION]

disposal                                                -$4.14
  43.1 kg unusable × $0.096/kg           SOURCE  [ASSUMPTION]

NET VALUE DELIVERED                                     $556.55

  BURDENS — 20% of declared value delivered
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Every row shows the rate, the range it came from, the publisher, the date, and the multiplication. The verdict is &lt;code&gt;LANDS&lt;/code&gt;, &lt;code&gt;BURDENS&lt;/code&gt;, or &lt;code&gt;BECOMES ASH&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fwrufbdt7gzlhe79f8ta8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fwrufbdt7gzlhe79f8ta8.png" alt="The real ledger in the browser: declared value $2,800.00 at the top, five expandable subtractions, and a net delivered value of $556.55 under a BURDENS verdict" width="800" height="942"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Two things about that table matter more than the verdict.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;It reads every source at its kindest end by default.&lt;/strong&gt; Costs low, usefulness high, storage at zero. A donor who doesn't like the answer can't accuse the table of stacking the deck, because it already stacked it in their favour. (You can flip it to midpoint, or to harshest, and watch $556.55 delivered become $339.73 &lt;em&gt;lost&lt;/em&gt;.)&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;It says out loud which of its own cells are assumptions.&lt;/strong&gt; Four of the fourteen rate cells are reasoned from guidance rather than quoted from a source, and each one is tagged &lt;code&gt;ASSUMPTION&lt;/code&gt; everywhere it appears, with its range, publisher, date and low confidence. A project that prices other people's generosity does not get to hide its own soft spots.&lt;/p&gt;

&lt;h2&gt;
  
  
  The half that makes it not a lecture
&lt;/h2&gt;

&lt;p&gt;A tool that only tells you your coat was a mistake is a tool nobody uses twice. The question the ledger provokes is &lt;em&gt;then what should I send?&lt;/em&gt; — and if the app can't answer that, the whole thing is a sermon.&lt;/p&gt;

&lt;p&gt;So it answers it by computation. It takes your own declared total, spends it on something the flash appeal actually named, and runs &lt;strong&gt;that&lt;/strong&gt; counterfactual manifest through the same engine, at the same freight mode, at the same reading of the sources:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;1,866 × Water purification tablets (strip of 10)&lt;/strong&gt; — LANDS&lt;br&gt;
$2,799.00 declared · $2,630.87 delivered · 94% of it&lt;br&gt;
&lt;strong&gt;+$2,074.32 more reaches the response&lt;/strong&gt; than the manifest above, for the money&lt;br&gt;
already being spent.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F8249e99760dcdka0j7b9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F8249e99760dcdka0j7b9.png" alt="The same money, sent differently: a card for 1,866 water purification tablets marked LANDS, with its own declared, delivered and percentage figures" width="800" height="593"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;No new conversion table is introduced. Nothing is quoted that wasn't already quoted. The comparison is the engine disagreeing with itself about two ways to spend one sum of money, which is a claim you can check line by line on both sides.&lt;/p&gt;

&lt;p&gt;And when nothing on the appeal's list beats what you've already put on the manifest, the panel says so and offers nothing. It never manufactures an improvement to have something to say.&lt;/p&gt;

&lt;h2&gt;
  
  
  The rule the codebase exists to enforce
&lt;/h2&gt;

&lt;p&gt;Here's the part I actually care about as an engineer.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;One deterministic function owns every number, and no model is ever allowed to produce one.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;price()&lt;/code&gt; is pure. Same manifest, same mode, same reading, same answer, in integer US cents — the money type is branded (&lt;code&gt;type Cents = number &amp;amp; { … }&lt;/code&gt;) so that writing &lt;code&gt;a - b&lt;/code&gt; on two amounts fails to compile and you have to go through &lt;code&gt;addCents(a, negate(b))&lt;/code&gt; on purpose. It is the only thing in the repository that does arithmetic on money. The browser calls it. The route handlers call it. The on-chain program re-derives its verdict from the same rule.&lt;/p&gt;

&lt;p&gt;The language model's job is narration, and the guarantee that it &lt;em&gt;stays&lt;/em&gt; narration is structural rather than hopeful.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The prompt sent to Gemini contains no digits at all.&lt;/strong&gt; Not one. The consignment is described to it in words — the route, the shape of the outcome, whether anything on it was prohibited — and every figure is handed over as a vocabulary of fifteen placeholder tokens instead of a value:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jinja"&gt;&lt;code&gt;&lt;span class="cp"&gt;{{&lt;/span&gt;&lt;span class="nv"&gt;declared&lt;/span&gt;&lt;span class="cp"&gt;}}&lt;/span&gt; &lt;span class="cp"&gt;{{&lt;/span&gt;&lt;span class="nv"&gt;net&lt;/span&gt;&lt;span class="cp"&gt;}}&lt;/span&gt; &lt;span class="cp"&gt;{{&lt;/span&gt;&lt;span class="nv"&gt;owed&lt;/span&gt;&lt;span class="cp"&gt;}}&lt;/span&gt; &lt;span class="cp"&gt;{{&lt;/span&gt;&lt;span class="nv"&gt;efficiency&lt;/span&gt;&lt;span class="cp"&gt;}}&lt;/span&gt; &lt;span class="cp"&gt;{{&lt;/span&gt;&lt;span class="nv"&gt;weight&lt;/span&gt;&lt;span class="cp"&gt;}}&lt;/span&gt; &lt;span class="cp"&gt;{{&lt;/span&gt;&lt;span class="nv"&gt;unusable&lt;/span&gt;&lt;span class="cp"&gt;}}&lt;/span&gt;
&lt;span class="cp"&gt;{{&lt;/span&gt;&lt;span class="nv"&gt;cash&lt;/span&gt;&lt;span class="cp"&gt;}}&lt;/span&gt; &lt;span class="cp"&gt;{{&lt;/span&gt;&lt;span class="nv"&gt;shares&lt;/span&gt;&lt;span class="cp"&gt;}}&lt;/span&gt; &lt;span class="cp"&gt;{{&lt;/span&gt;&lt;span class="nv"&gt;verdict&lt;/span&gt;&lt;span class="cp"&gt;}}&lt;/span&gt; &lt;span class="cp"&gt;{{&lt;/span&gt;&lt;span class="nv"&gt;route&lt;/span&gt;&lt;span class="cp"&gt;}}&lt;/span&gt; &lt;span class="cp"&gt;{{&lt;/span&gt;&lt;span class="nv"&gt;reading&lt;/span&gt;&lt;span class="cp"&gt;}}&lt;/span&gt; &lt;span class="cp"&gt;{{&lt;/span&gt;&lt;span class="nv"&gt;items&lt;/span&gt;&lt;span class="cp"&gt;}}&lt;/span&gt;
&lt;span class="cp"&gt;{{&lt;/span&gt;&lt;span class="nv"&gt;prohibited&lt;/span&gt;&lt;span class="cp"&gt;}}&lt;/span&gt; &lt;span class="cp"&gt;{{&lt;/span&gt;&lt;span class="nv"&gt;appeal&lt;/span&gt;&lt;span class="cp"&gt;}}&lt;/span&gt; &lt;span class="cp"&gt;{{&lt;/span&gt;&lt;span class="nv"&gt;people&lt;/span&gt;&lt;span class="cp"&gt;}}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The model may state a figure only by placing one of those, written exactly as given. It never learns what any of them are worth. Substitution happens afterwards, in one function, from the engine's own output.&lt;/p&gt;

&lt;p&gt;Then &lt;code&gt;normalize()&lt;/code&gt; reads the draft back and &lt;strong&gt;throws the entire thing away&lt;/strong&gt; if:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;a digit appears anywhere outside a placeholder — &lt;code&gt;digits&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;a quantity is stated in words: "twenty per cent", "a third", "half" — &lt;code&gt;words&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;it used a token that doesn't exist, or one that doesn't apply to this particular consignment — &lt;code&gt;token&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;it came back empty, or over length&lt;/li&gt;
&lt;li&gt;the model's own safety filter blocked the brief&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;No repair step, no partial acceptance. A repair step is a negotiation, and the point is that this isn't negotiable.&lt;/p&gt;

&lt;p&gt;And a refused draft isn't a broken feature. The deterministic letter is written in the &lt;em&gt;same fifteen tokens&lt;/em&gt; and finished by the &lt;em&gt;same substitution function&lt;/em&gt;, so when the model is unavailable, or slow, or numeric, what you read is the engine's own prose and the byline changes from a model id to &lt;code&gt;engine&lt;/code&gt;. The feature degrades to the truth instead of to an error toast.&lt;/p&gt;

&lt;h2&gt;
  
  
  Google AI — the letter from the warehouse
&lt;/h2&gt;

&lt;p&gt;The narration isn't a summary bolted on top. It's a letter, written in the voice of the person who unpacked your consignment, writing back to tell you what happened to it. That's a thing a language model is genuinely good at and an engine is not: tone, restraint, the decision not to gloat.&lt;/p&gt;

&lt;p&gt;The route handler walks a chain — &lt;code&gt;gemini-3.8-flash&lt;/code&gt;, then &lt;code&gt;gemini-3.7-flash&lt;/code&gt;, then &lt;code&gt;gemini-3.5-flash&lt;/code&gt;, overridable with &lt;code&gt;GEMINI_MODELS&lt;/code&gt; so a retired model id is a config change rather than a deploy. Sixteen seconds per model, and it moves down the chain on a timeout, an error, a blocked brief, &lt;em&gt;or a draft that failed the clamp&lt;/em&gt;. A model that keeps inventing numbers simply loses its turn.&lt;/p&gt;

&lt;p&gt;That chain isn't defensive theatre — it earned its keep the first time I pointed a real key at it. &lt;code&gt;gemini-2.5-flash&lt;/code&gt; sat at the tail until it started answering &lt;strong&gt;404, "no longer available to new users"&lt;/strong&gt; while still being listed by &lt;code&gt;GET /v1beta/models&lt;/code&gt;: being listed is not being callable. And &lt;code&gt;gemini-3.8-flash&lt;/code&gt;, the newest and the one at the head, answers &lt;strong&gt;503, "experiencing high demand"&lt;/strong&gt; on most attempts right now. So on a live run the letter you read is written by the middle of the chain, the log records both misses by name, and the reader is never shown a spinner that ends in nothing. Every figure in the model's letter came back byte-identical to the engine's — same dollars, same percentage, same kilograms — because the model never had any of them to get wrong.&lt;/p&gt;

&lt;p&gt;The prohibited-items paragraph gets handled separately, because it isn't an arithmetic problem. Donated infant formula and part-used medicine out of a home cabinet can't be accepted at all — not sorted, not stored, not passed to anybody. The letter says so in the words the agencies use, and the ledger doesn't hand them a gentler verdict for being well meant.&lt;/p&gt;

&lt;h2&gt;
  
  
  ElevenLabs — and not becoming somebody's free TTS proxy
&lt;/h2&gt;

&lt;p&gt;The letter is meant to be &lt;em&gt;heard&lt;/em&gt;. Read aloud, "$556.55 of $2,800.00 arrived" lands somewhere a table doesn't.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;eleven_multilingual_v2&lt;/code&gt;, chosen deliberately over the faster models because the docs are clear that the low-latency ones are less reliable at normalising written amounts, and every sentence in this letter has an amount in it. If &lt;code&gt;ELEVENLABS_VOICE_ID&lt;/code&gt; isn't set the handler asks the account for its first voice and uses that, re-checked per request, because a voice can disappear from an account between two calls.&lt;/p&gt;

&lt;p&gt;The voice model is handed &lt;strong&gt;finished prose&lt;/strong&gt;. It is given no figures to reason about and no arithmetic to do. Nothing numeric can reach your ears that &lt;code&gt;price()&lt;/code&gt; didn't compute.&lt;/p&gt;

&lt;p&gt;There's an obvious hole in shipping a public text-to-speech endpoint, so it's closed: &lt;code&gt;/api/letter&lt;/code&gt; returns an HMAC-SHA256 seal alongside the letter, and &lt;code&gt;/api/narrate&lt;/code&gt; will only speak text whose seal verifies (&lt;code&gt;timingSafeEqual&lt;/code&gt;, not &lt;code&gt;===&lt;/code&gt;). Send it your own paragraph and it quietly reads &lt;em&gt;this build's&lt;/em&gt; letter instead — dropped in silence rather than refused, because a seal issued by another process isn't the caller's fault. Set &lt;code&gt;LETTER_SECRET&lt;/code&gt; and the seal survives a redeploy; leave it unset and each process mints a random 32 bytes at boot. &lt;code&gt;src/lib/seal.ts&lt;/code&gt; is honest in its own comments about what that does and doesn't guarantee: it's a brake on casual abuse, not an authentication system.&lt;/p&gt;

&lt;p&gt;No key? The browser's own &lt;code&gt;speechSynthesis&lt;/code&gt; reads it. The button never lies about whether there's a voice behind it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Solana — a notary, and the honest reason for it
&lt;/h2&gt;

&lt;p&gt;I'll say the unfashionable part first: nothing in this app needs a blockchain, and I refuse to pretend otherwise. There's no token, no treasury, no yield, no "transparent donation rails". &lt;strong&gt;The app collects no money at all&lt;/strong&gt; — every giving link leaves the site for a page that can take a donation directly, six of them, starting with GlobalGiving's Nepal fund and Nepal's own disaster relief fund.&lt;/p&gt;

&lt;p&gt;What a public ledger &lt;em&gt;is&lt;/em&gt; honestly good at here is one narrow thing: a decision that can't be quietly revised afterwards. If you price your consignment, read the verdict, and commit it, that record is the thing you can't later claim you never saw. So the program is a notary and nothing else.&lt;/p&gt;

&lt;p&gt;An Anchor program with two instructions and deliberately no third:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="n"&gt;initialize_registry&lt;/span&gt;   &lt;span class="c1"&gt;// one PDA, running totals&lt;/span&gt;
&lt;span class="n"&gt;commit_pledge&lt;/span&gt;         &lt;span class="c1"&gt;// hash, declared, net, verdict — and it checks your work&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;commit_pledge&lt;/code&gt; &lt;strong&gt;re-derives the verdict on-chain from the same rule the engine uses&lt;/strong&gt;, out of the declared and net cents you handed it, and rejects the write if the two disagree. You cannot notarise a flattering verdict against unflattering figures. There is no &lt;code&gt;withdraw&lt;/code&gt;, no treasury account and no lamport path out of the program, because the app takes no donations and the chain should make that structural rather than promised.&lt;/p&gt;

&lt;p&gt;What gets stored is a SHA-256 of a canonical manifest string — version, freight mode, bias, valuation flag, and the lines sorted by item id — so the same consignment always hashes the same way and a different one never collides. Only the top eight lines by declared value go on chain; when a manifest is longer than that, the UI says it was truncated rather than letting you believe the whole thing is up there.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;It's deployed and it holds real entries.&lt;/strong&gt; Devnet, labelled as a demonstration everywhere it appears in the UI, never presented as a live donation channel:&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;Program&lt;/td&gt;
&lt;td&gt;&lt;a href="https://explorer.solana.com/address/DeadwBH8o2uqPTpdA5LDHmz6i7dv8LGtFFtmytKyxZ5F?cluster=devnet" rel="noopener noreferrer"&gt;&lt;code&gt;DeadwBH8o2uqPTpdA5LDHmz6i7dv8LGtFFtmytKyxZ5F&lt;/code&gt;&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Registry PDA&lt;/td&gt;
&lt;td&gt;&lt;a href="https://explorer.solana.com/address/ModqnUh86aLw2rBjuhAvm75RBL1pHEePopQHuWoCr7H?cluster=devnet" rel="noopener noreferrer"&gt;&lt;code&gt;ModqnUh86aLw2rBjuhAvm75RBL1pHEePopQHuWoCr7H&lt;/code&gt;&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Pledge #1&lt;/td&gt;
&lt;td&gt;&lt;a href="https://explorer.solana.com/address/Fs6TUfK6Mbviyo7xrsx7PFximYMdkVxqeUA4P6ZeSem6?cluster=devnet" rel="noopener noreferrer"&gt;&lt;code&gt;Fs6TUfK6Mbviyo7xrsx7PFximYMdkVxqeUA4P6ZeSem6&lt;/code&gt;&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The IDL is uploaded on-chain as well as committed, so an explorer decodes those accounts without being handed a schema. The figures in them came out of &lt;code&gt;price()&lt;/code&gt; and &lt;code&gt;pledgeArgsFor()&lt;/code&gt; directly — I refused to type them by hand even once — and the program accepted them only because its own re-derivation agreed.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fuaklny432g9uoe1o72ta.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fuaklny432g9uoe1o72ta.png" alt="The notary page reading the live devnet registry: 2 entries, $5,600.00 declared, $1,113.10 delivered net, with the program and registry addresses printed above" width="800" height="527"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And I got to test the permanence on myself, which I didn't plan. My first pledge reconstructed the manifest from an earlier draft of this post: 25 jackets, 10 shoes, 60 toys. The app's actual default preset is 15 / 25 / 60 — the &lt;em&gt;other&lt;/em&gt; integer solution to the same two equations, so identical declared total, identical 56.0 kg, identical $556.55, identical verdict, and a &lt;strong&gt;different canonical hash&lt;/strong&gt;. Entry #0 is therefore a perfectly valid record of a consignment that isn't the one the app ships. There is no close instruction. It's still there, and it will be there for as long as devnet is. Entry #1 is the default preset, so that hash is the one you can reproduce by loading the page — but I'm not deleting the first one, because a notary you can tidy up isn't a notary.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;One build note, in case it saves somebody an evening.&lt;/strong&gt; Anchor 1.2.0 defaults to &lt;code&gt;--arch v3&lt;/code&gt;, and the SBPFv3 ELF that platform-tools v1.57 emits is rejected by litesvm 0.10's loader with a flat &lt;code&gt;InvalidAccountData&lt;/code&gt;. Twelve Rust tests that pass under &lt;code&gt;--arch v0&lt;/code&gt; don't run at all without it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;anchor build &lt;span class="nt"&gt;--arch&lt;/span&gt; v0
cargo &lt;span class="nb"&gt;test&lt;/span&gt; &lt;span class="nt"&gt;--manifest-path&lt;/span&gt; programs/deadweight/Cargo.toml   &lt;span class="c"&gt;# 12 tests, LiteSVM&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Second one: this project sets &lt;code&gt;legacy-peer-deps=true&lt;/code&gt; in &lt;code&gt;.npmrc&lt;/code&gt; — because &lt;code&gt;@solana-mobile/wallet-adapter-mobile&lt;/code&gt; declares &lt;code&gt;react-native&lt;/code&gt; as a non-optional peer, npm dutifully installs it, and nothing in a web app ever resolves the &lt;code&gt;index.native.js&lt;/code&gt; that needs it — and that flag applies to &lt;code&gt;npx&lt;/code&gt; runs from the same directory, which is how &lt;code&gt;anchor idl init&lt;/code&gt; came to die on a missing &lt;code&gt;@solana/kit&lt;/code&gt;. &lt;code&gt;npm_config_legacy_peer_deps=false&lt;/code&gt; in front of it, and the IDL uploaded fine.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I refused to build
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;The death toll.&lt;/strong&gt; In the days after the event, published figures ran 160 → 359 → 538 → 579 → over 1,250, with thousands missing, depending on the source and the hour. A number that moves like that gets fetched live with its timestamp and its attribution, or it does not get shown. The live route would have been the ReliefWeb API, which since &lt;strong&gt;1 November 2025&lt;/strong&gt; requires a pre-approved &lt;code&gt;appname&lt;/code&gt; and answers everything else with &lt;code&gt;403 AccessDeniedHttpException&lt;/code&gt; — I verified that during the build. So the fetch isn't in the shipped app and neither is the number. Hardcoding a toll into a project whose entire argument is &lt;em&gt;don't hardcode moving numbers&lt;/em&gt; would have been the exact failure I'm writing about.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Dollars converted into blankets on the ground.&lt;/strong&gt; The tempting version of "send this instead" says "$2,800 buys 400 blankets in Kathmandu". I have no defensible source for that, so it doesn't exist. Both sides of the comparison are priced at the same donor-country retail figures the catalogue already quotes, which means the two ledgers rest on the same &lt;em&gt;kind&lt;/em&gt; of number and the difference between them is the freight and the sorting and the disposal — which is the actual claim.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Any way to give Deadweight money.&lt;/strong&gt; No payment path in the codebase. Not disabled — absent.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Every other disaster.&lt;/strong&gt; Deadweight prices one response, and that's the design rather than a limit I ran out of time to lift. Three of the things that decide a verdict are local. Nepal is landlocked, so the cheap freight mode doesn't exist — a sea leg ends at Kolkata and buys you a road leg and months of transit on top. The sorting wage is Nepal's statutory minimum, dated and converted. And whether an item counts as &lt;em&gt;requested&lt;/em&gt; is scored against &lt;strong&gt;this appeal's own published priority list&lt;/strong&gt;, which is why a blanket passes here and wouldn't in a tropical flood. The engine underneath genuinely doesn't know where it is — &lt;code&gt;logistics.ts&lt;/code&gt; never imports &lt;code&gt;crisis.ts&lt;/code&gt;, it prices a manifest against rate cells and hands back a ledger — but I'm not going to dress that up as portability, because swapping the crisis isn't a config change. It's sourcing a second response's freight, wages and appeal to the same standard, then re-deriving the &lt;em&gt;requested&lt;/em&gt; column against a different priority list. The generic version of this app averages those three away, and the average is precisely what makes a number useless.&lt;/p&gt;

&lt;h2&gt;
  
  
  It works with the GPU switched off, and at 382px
&lt;/h2&gt;

&lt;p&gt;The crate in the header is a particle cloud sampled out of an SVG — canvas-ui's &lt;code&gt;ParticleObject&lt;/code&gt;, driven through its imperative API — and it's the only WebGL in the app. It's gated three ways: three.js is imported inside an effect so it never enters the first load, the context is probed before anything mounts, and &lt;code&gt;prefers-reduced-motion: reduce&lt;/code&gt; skips it outright. All three failure paths paint the same crate as a still image, and the no-WebGL and reduced-motion paths render byte-identical screenshots — I checked that headlessly rather than assuming it.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F82sxo52zv0f6ngscud6k.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F82sxo52zv0f6ngscud6k.png" alt="The same crate twice, side by side: the WebGL particle cloud on the left, the still SVG fallback under prefers-reduced-motion on the right" width="800" height="411"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The crate is &lt;code&gt;aria-hidden&lt;/code&gt; and carries no figure. Every number on the page survives its absence, which is the only accessibility promise worth making about a decorative canvas.&lt;/p&gt;

&lt;p&gt;Checked on Android at 382px wide, where the headline stays above the fold and the full-width canvas doesn't swallow a vertical drag. Crimson appears in exactly two places in the whole design system — negative numbers, and the &lt;code&gt;BECOMES ASH&lt;/code&gt; verdict. Never decorative. When a ledger line goes red it's because money left.&lt;/p&gt;

&lt;h2&gt;
  
  
  Stack
&lt;/h2&gt;

&lt;p&gt;Next.js 16 App Router with Turbopack, React 19, TypeScript in strict mode, Tailwind v4, shadcn, &lt;a href="https://github.com/DavidHDev/canvas-ui" rel="noopener noreferrer"&gt;canvas-ui&lt;/a&gt; and React Bits for the visual layer, Anchor on Solana devnet, Gemini and ElevenLabs behind route handlers, Vercel. Two route handlers in the entire app; every key is read server-side and none is ever shipped to the browser.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;206 tests&lt;/strong&gt; — 194 in TypeScript across 8 files, 12 in Rust against the program under LiteSVM. Most of them exist to hold the engine still: the pricing rule, the branded-cents arithmetic, the prohibited-item paths, the &lt;code&gt;normalize()&lt;/code&gt; refusal, the HMAC seal, and the "send this instead" ranking.&lt;/p&gt;

&lt;h2&gt;
  
  
  Credits
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://github.com/DavidHDev/canvas-ui" rel="noopener noreferrer"&gt;canvas-ui&lt;/a&gt; — © 2026 David Haz, MIT + Commons Clause.&lt;/strong&gt; &lt;code&gt;ParticleObject&lt;/code&gt; is used here under that licence; the copyright notice is retained in the component file and the credit is in the site footer and the README as well as here. The components aren't redistributed as a library from my repo. &lt;a href="https://github.com/DavidHDev" rel="noopener noreferrer"&gt;DavidHDev&lt;/a&gt; builds the nicest visual primitives on the web right now and it isn't close.&lt;/p&gt;

&lt;p&gt;Twenty-seven sources, each cited in the UI with its own date, its publisher, a link that opens off-site, and a grading of how honestly I came by it. Four are &lt;code&gt;primary&lt;/code&gt; — I fetched the document and read it. Two are &lt;code&gt;secondary&lt;/code&gt; — a named third party reports the figure from a study.&lt;/p&gt;

&lt;h2&gt;
  
  
  The coat, again
&lt;/h2&gt;

&lt;p&gt;The response to the 26 August debris flow got a &lt;strong&gt;US$49.6 million flash appeal for 84,000 people&lt;/strong&gt; on 4 September 2026. I didn't decide what that response needs, and neither did my engine. The appeal's own priority list opens with &lt;strong&gt;direct cash assistance&lt;/strong&gt;. That ordering is the whole argument of this project and it isn't mine — it's theirs. All Deadweight does is show you the arithmetic that makes it true, in the one currency where it can't hide, with a source and a date under every row.&lt;/p&gt;

&lt;p&gt;So: keep the instinct. Someone is cold and you have a coat, and that impulse is the only reason any of this machinery exists to be criticised. Just send the thing that arrives.&lt;/p&gt;

&lt;p&gt;Nothing in this app takes your money. When you're ready, give to the same four places it points at. Every one of them is a page I opened and confirmed can take a donation, and they're in the order the site argues for: the further up, the more of the dollar is spent inside Nepal by someone who was already there.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;a href="https://www.globalgiving.org/projects/nepal-flood-relief-fund/" rel="noopener noreferrer"&gt;GlobalGiving Nepal Flood Relief Fund&lt;/a&gt; — flexible grants to Nepali organisations already working in the districts, which is in-region procurement under another name.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://pmdrf.nchl.com.np/" rel="noopener noreferrer"&gt;Nepal's Prime Minister's Disaster Relief Fund&lt;/a&gt; — the country's own fund, taking cards from anywhere in the world. Spendable by law on rescue, treatment, relief, rehabilitation and infrastructure, not on administration, and audited annually. It's what the GIVE button in the header points at.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://donate.redcrossredcrescent.org/ifrc/nepal-flash-floods/~my-donation?_cv=1" rel="noopener noreferrer"&gt;IFRC Nepal flash floods appeal&lt;/a&gt; — funds the Nepal Red Cross Society, which was in the districts before there was an appeal to write.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.directrelief.org/emergency/nepal-floods-2026/" rel="noopener noreferrer"&gt;Direct Relief&lt;/a&gt; — medical supply, procured against a request from the field.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Live:&lt;/strong&gt; &lt;a href="https://deadweight-jet.vercel.app" rel="noopener noreferrer"&gt;https://deadweight-jet.vercel.app&lt;/a&gt; &lt;strong&gt;Repo:&lt;/strong&gt; &lt;a href="https://github.com/AnubhavDash/DeadWeight" rel="noopener noreferrer"&gt;https://github.com/AnubhavDash/DeadWeight&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Built for the DEV Weekend Challenge: Generosity Edition. Categories: Solana, Google AI, ElevenLabs. Price your generosity before you ship it.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>devchallenge</category>
      <category>weekendchallenge</category>
    </item>
    <item>
      <title>CanineIQ - Are You Actually Ready for the Dog You Want?</title>
      <dc:creator>Anubhav Dash</dc:creator>
      <pubDate>Sun, 16 Aug 2026 17:04:59 +0000</pubDate>
      <link>https://dev.to/an0n99x/canineiq-are-you-actually-ready-for-the-dog-you-want-c88</link>
      <guid>https://dev.to/an0n99x/canineiq-are-you-actually-ready-for-the-dog-you-want-c88</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for &lt;a href="https://dev.to/challenges/weekend-2026-08-13"&gt;Weekend Challenge: Dog Days Edition&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

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

&lt;p&gt;I watched the &lt;a href="https://www.indiatoday.in/india/story/pitbull-mauls-patiala-couple-both-hospitalised-woman-undergoes-plastic-surgery-2969903-2026-08-13" rel="noopener noreferrer"&gt;CCTV footage&lt;/a&gt; in this India Today report of a couple being mauled by a pitbull while they viewed a rental home. The moment they opened the gate, the dog was on them - and it kept attacking even after its owner ordered it to stop, because it had been left to roam free. The dog wasn't evil. The ownership was irresponsible.&lt;/p&gt;

&lt;p&gt;That video is why CanineIQ exists. It's a dog welfare intervention disguised as an assessment - 8 blunt questions about living situation, experience, time, training plan, budget, household safety, motivation, and how stable your life is. Then it scores how well your answers match the &lt;em&gt;documented&lt;/em&gt; needs of the breed you want. Not stereotypes. Not marketing. The actual work the dog will need from you.&lt;/p&gt;

&lt;p&gt;You walk away with three things most "which dog should I get?" quizzes refuse to give you:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;A deterministic 0–100 readiness score&lt;/strong&gt; with a plain verdict: &lt;code&gt;READY&lt;/code&gt;, &lt;code&gt;CAUTION&lt;/code&gt;, or &lt;code&gt;NOT_READY&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A letter written from the dog's perspective&lt;/strong&gt;, read aloud in a soft, sympathetic voice - it calls you out if you chose the breed for status, and tells you what it actually needs if you're not ready.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A breed health transparency page&lt;/strong&gt; documenting the genetic damage we've bred into popular dogs - French Bulldogs needing palate surgery by age 3, Pugs that can't breathe during exercise - with sources.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The name says it: &lt;em&gt;CanineIQ - Are You Ready?&lt;/em&gt; It's built for International Dog Day because every year thousands of powerful "status breeds" get surrendered, neglected, or end up in bite incidents because the humans who chose them weren't ready for the responsibility.&lt;/p&gt;

&lt;p&gt;The other half of the same problem: French Bulldogs are the world's most popular breed, and a huge share of them will need palate surgery by age three because we bred them to have faces that can't function. The dogs deserve honesty even when the humans buying them don't want to hear it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Demo
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Live:&lt;/strong&gt; &lt;a href="https://canineiq.vercel.app/" rel="noopener noreferrer"&gt;https://canineiq.vercel.app/&lt;/a&gt;&lt;br&gt;
&lt;strong&gt;Video:&lt;/strong&gt; &lt;a href="https://youtu.be/C8REqujvyx4" rel="noopener noreferrer"&gt;https://youtu.be/C8REqujvyx4&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It works out of the box - no API keys to set up, no desktop required. The whole flow (assessment, verdict, the dog's letter, read-aloud voice) is tested and usable on a real Android phone as well as desktop.&lt;/p&gt;

&lt;p&gt;Try the worst-case: pick a Great Dane, answer every question with the least responsible option (no budget, no experience, small apartment, young kids, "I want it for protection"), and listen to the letter the dog writes you. Then try the French Bulldog on the health page and read what its breathing is really like.&lt;/p&gt;

&lt;h2&gt;
  
  
  Code
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Repository:&lt;/strong&gt; &lt;a href="https://github.com/AnubhavDash/CanineIQ" rel="noopener noreferrer"&gt;https://github.com/AnubhavDash/CanineIQ&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The repo contains the full React SPA, the Vercel serverless functions (&lt;code&gt;api/&lt;/code&gt;), the deterministic scoring engine, the 40-breed trait table, and the fact-checked health content with sources.&lt;/p&gt;

&lt;h2&gt;
  
  
  How I Built It
&lt;/h2&gt;

&lt;h3&gt;
  
  
  The scoring is the hard part, and it's not an LLM
&lt;/h3&gt;

&lt;p&gt;The core design decision: &lt;strong&gt;Gemini never decides the score.&lt;/strong&gt; A deterministic engine (&lt;code&gt;api/score.js&lt;/code&gt;) weighs each of the 8 answers against the chosen breed's documented needs - energy, space, fragility, grooming, health cost, household safety, trainability, difficulty. That produces a 0–100 score and the verdict (&lt;code&gt;READY&lt;/code&gt; ≥ 70, &lt;code&gt;CAUTION&lt;/code&gt; ≥ 40, &lt;code&gt;NOT_READY&lt;/code&gt; below).&lt;/p&gt;

&lt;p&gt;Gemini's job is &lt;em&gt;writing&lt;/em&gt;: a personalised narrative built around that fixed score, with top warnings, genuine strengths, per-answer findings, and the dog's letter. The API validates and normalizes every response server-side, so a hallucinated score or an off-script alternate-breed suggestion gets overridden deterministically before the user ever sees it. The LLM can't lie to you; that's the whole point of a welfare tool.&lt;/p&gt;

&lt;h3&gt;
  
  
  Rate-limit resilience
&lt;/h3&gt;

&lt;p&gt;Both the assessment and photo-identification functions run a &lt;strong&gt;model fallback chain&lt;/strong&gt; (&lt;code&gt;gemini-3.5-flash-lite&lt;/code&gt; → &lt;code&gt;gemini-3.1-flash-lite&lt;/code&gt; → &lt;code&gt;gemini-3.6-flash&lt;/code&gt;), so a popular demo can't kill the app. Same for the speech endpoint (&lt;code&gt;eleven_v3&lt;/code&gt; → &lt;code&gt;eleven_multilingual_v2&lt;/code&gt; → &lt;code&gt;eleven_flash_v2_5&lt;/code&gt;), and the browser falls back to native &lt;code&gt;SpeechSynthesis&lt;/code&gt; if the API is unavailable.&lt;/p&gt;

&lt;h3&gt;
  
  
  40 breeds, 10 photographed locally, 30 lazily loaded
&lt;/h3&gt;

&lt;p&gt;Ten core breeds ship as local assets; the other 30 load images from the &lt;a href="https://dog.ceo/" rel="noopener noreferrer"&gt;Dog CEO API&lt;/a&gt; via a searchable dropdown. You can also &lt;strong&gt;snap a photo&lt;/strong&gt; of a dog and Gemini's multimodal model identifies the breed, auto-selecting it for the assessment.&lt;/p&gt;

&lt;h3&gt;
  
  
  The dog speaks
&lt;/h3&gt;

&lt;p&gt;The signature feature is a letter written from the dog's point of view, generated alongside the verdict and read aloud with &lt;strong&gt;ElevenLabs&lt;/strong&gt; emotional text-to-speech - a soft, sympathetic voice with &lt;code&gt;[sighs]&lt;/code&gt; delivery. If you chose the breed for status, it calls that out. The verdict strip is unmissable: breed, score, verdict, right above the letter.&lt;/p&gt;

&lt;h3&gt;
  
  
  Honest health content
&lt;/h3&gt;

&lt;p&gt;The &lt;a href="https://canineiq.vercel.app/#/health" rel="noopener noreferrer"&gt;Breed Health&lt;/a&gt; page documents what was done to these breeds genetically, what the dog experiences day-to-day, surgery rates, what breeders won't tell buyers, and whether it's ethical to buy one at all - citing OFA, AKC Canine Health Foundation, The Kennel Club (UK), RSPCA, and Cambridge/Cornell veterinary research. Figures are framed as qualitative ranges because inherited-disease risk is line-specific, not a single statistic.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prize Categories
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Best Use of Google AI&lt;/strong&gt; - the assessment narrative engine, breed health analysis, and photo-based breed identification all run on the Gemini API, with strict server-side validation so the model never controls the score.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Best Use of ElevenLabs&lt;/strong&gt; - the dog's letter is spoken in an emotional voice profile, with a graceful fallback to browser speech synthesis.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>devchallenge</category>
      <category>weekendchallenge</category>
    </item>
  </channel>
</rss>
