<?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: elberacasa</title>
    <description>The latest articles on DEV Community by elberacasa (@elberacasa).</description>
    <link>https://dev.to/elberacasa</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%2F4062699%2F73a30db2-56b6-4bc6-882a-2da75f7c82c1.png</url>
      <title>DEV Community: elberacasa</title>
      <link>https://dev.to/elberacasa</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/elberacasa"/>
    <language>en</language>
    <item>
      <title>I built a live situation room for Venezuela from 313 public sources</title>
      <dc:creator>elberacasa</dc:creator>
      <pubDate>Fri, 25 Sep 2026 23:00:30 +0000</pubDate>
      <link>https://dev.to/elberacasa/i-built-a-live-situation-room-for-venezuela-from-313-public-sources-3e91</link>
      <guid>https://dev.to/elberacasa/i-built-a-live-situation-room-for-venezuela-from-313-public-sources-3e91</guid>
      <description>&lt;h2&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%2Fmimtteyh8lwnnu9uuwjn.png" alt="Vigía's dashboard in dark mode: a map of Venezuela with internet status by state, next to panels for the dollar rate, earthquakes, fires and news, each figure labelled with its source and time" width="800" height="450"&gt;---
&lt;/h2&gt;

&lt;p&gt;I'm Venezuelan, and for years, knowing what was happening at home meant opening twenty tabs. X to see if the power went out. A Telegram channel for the dollar rate. A seismology site to check whether the quake everyone felt was real. And I never knew if a number was from today or from three days ago.&lt;/p&gt;

&lt;p&gt;So I built the tool I wanted. It's called &lt;strong&gt;Vigía&lt;/strong&gt; ("lookout" in Spanish), and it puts the whole country on one screen.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Site and downloads:&lt;/strong&gt; &lt;a href="https://vigia.live" rel="noopener noreferrer"&gt;https://vigia.live&lt;/a&gt;&lt;br&gt;
&lt;strong&gt;Code:&lt;/strong&gt; &lt;a href="https://github.com/elberacasa/vigia" rel="noopener noreferrer"&gt;https://github.com/elberacasa/vigia&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  What it shows
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Money:&lt;/strong&gt; the official BCV rate next to the P2P market rate, with the gap computed live&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Internet:&lt;/strong&gt; outages by state and by provider, with history so you can see when a drop started&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Censorship:&lt;/strong&gt; which sites are blocked, on which provider, and how (from OONI measurements)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Earthquakes, rain, fires and recent satellite imagery&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;News from 224 Venezuelan outlets&lt;/strong&gt;, including their Telegram channels, grouped by story&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;And more:&lt;/strong&gt; the Guri dam level (most of the country's electricity), the official gazette, health, migration and markets&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When two independent sources agree on a blackout, it builds an evidence chain that links both.&lt;/p&gt;
&lt;h2&gt;
  
  
  The rule that shaped everything: freshness is a value
&lt;/h2&gt;

&lt;p&gt;Most dashboards show a number. Vigía shows a number &lt;em&gt;and&lt;/em&gt; its age. Every observation carries two timestamps: when the source says it was true, and when Vigía fetched it. Every adapter has a freshness budget. If a feed misses it, the UI marks the figure as stale instead of quietly showing an old value as if it were live.&lt;/p&gt;

&lt;p&gt;Venezuelan data is often late, contradictory or missing, so this matters more than any chart. A dollar rate from Tuesday shown as "now" is worse than no rate at all.&lt;/p&gt;
&lt;h2&gt;
  
  
  Every source is an adapter with the same contract
&lt;/h2&gt;

&lt;p&gt;There are 313 sources, and 309 of them work with no API key. Each one is an adapter with the same shape:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;Adapter&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;V&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;Json&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Json&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="na"&gt;provider&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// who publishes the data, e.g. "USGS"&lt;/span&gt;
  &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="na"&gt;licence&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Licence&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="na"&gt;keys&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;[];&lt;/span&gt; &lt;span class="c1"&gt;// empty: works with no key&lt;/span&gt;
  &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="na"&gt;intervalMs&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="na"&gt;freshness&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;FreshnessBudget&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="cm"&gt;/** Network: fetch whatever raw responses one run needs. */&lt;/span&gt;
  &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="na"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;FetchContext&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="nx"&gt;RawResponse&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="cm"&gt;/** Pure: validate and normalise. Throws on schema violations (the run fails loudly, last-good stays). */&lt;/span&gt;
  &lt;span class="nf"&gt;normalise&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="na"&gt;raw&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="nx"&gt;RawResponse&lt;/span&gt;&lt;span class="p"&gt;[]):&lt;/span&gt; &lt;span class="nx"&gt;Observation&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;V&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&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;Network and parsing are split on purpose. &lt;code&gt;fetch&lt;/code&gt; is the only part that touches the internet. &lt;code&gt;normalise&lt;/code&gt; is a pure function, so every adapter is tested against recorded real responses, with no network in the tests. The schema is validated at the boundary: when a source changes its format, the run fails loudly and the last good value is kept, shown with its age.&lt;/p&gt;

&lt;p&gt;Every observation comes out in the same typed shape: source, a link a person can open, observed time, fetched time, licence, value, optional location and a confidence score. Everything downstream (the panels, the history, the public API) only ever sees that shape.&lt;/p&gt;

&lt;h2&gt;
  
  
  Numbers are code, never a model
&lt;/h2&gt;

&lt;p&gt;The dollar gap, outage levels, counts and deltas are computed deterministically and tested. There's an optional AI layer, but it only classifies and clusters news stories, and it always links back to the original articles. It never produces a figure.&lt;/p&gt;

&lt;h2&gt;
  
  
  Built for a cheap phone on a bad connection
&lt;/h2&gt;

&lt;p&gt;A lot of Venezuelans browse on old Android phones with unreliable data, so performance is a feature, not polish:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The UI is Preact with signals, and the first load is about 84 KB gzipped&lt;/li&gt;
&lt;li&gt;It works offline with the last data it saw&lt;/li&gt;
&lt;li&gt;The server is a single binary built with Bun, 20 to 44 MB depending on the platform, with SQLite storing every observation's history&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It runs on your own computer: download, open, done. No account and no central server that can go down or get blocked.&lt;/p&gt;

&lt;h2&gt;
  
  
  The stack
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Bun + TypeScript&lt;/strong&gt; in strict mode (&lt;code&gt;strict&lt;/code&gt;, &lt;code&gt;noUncheckedIndexedAccess&lt;/code&gt;, &lt;code&gt;exactOptionalPropertyTypes&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;SQLite&lt;/strong&gt; (&lt;code&gt;bun:sqlite&lt;/code&gt;, WAL) for history from day one&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Zod&lt;/strong&gt; at every source boundary&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Preact&lt;/strong&gt; for the UI&lt;/li&gt;
&lt;li&gt;About 990 tests, with CI on Linux, macOS and Windows&lt;/li&gt;
&lt;li&gt;A public API at &lt;code&gt;/api/v1&lt;/code&gt; with OpenAPI, CSV exports, and a terminal mode: &lt;code&gt;curl localhost:7722&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Honest limits
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;With today's open data, the incident detector misses many regional blackouts, because many states have only one measured internet source. More &lt;a href="https://atlas.ripe.net" rel="noopener noreferrer"&gt;RIPE Atlas&lt;/a&gt; probes inside Venezuela would help a lot, and anyone with a Linux box or a Raspberry Pi that's on all day can run one for free.&lt;/li&gt;
&lt;li&gt;I use it daily on Linux. The Windows and macOS builds pass CI, but nobody has tried them by hand yet.&lt;/li&gt;
&lt;li&gt;It's a beta (version 0.1).&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Licence
&lt;/h2&gt;

&lt;p&gt;The code is public under the PolyForm Noncommercial licence. That makes it source-available rather than OSI open source: anyone can use, study, modify and share it for free, but not sell it.&lt;/p&gt;

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

&lt;p&gt;Right now the optional AI uses Jev, a fast classification model, if you bring a key. If Vigía gets enough users, the plan is to train Laya, our own small model, and ship it free inside the app so everyone gets the smart features without a key.&lt;/p&gt;

&lt;p&gt;If you try it, I'd love to hear what breaks, what looks wrong for your state, and which sources are missing. Ideas and votes go here: &lt;a href="https://github.com/elberacasa/vigia/discussions/categories/ideas" rel="noopener noreferrer"&gt;https://github.com/elberacasa/vigia/discussions/categories/ideas&lt;/a&gt;&lt;/p&gt;

</description>
      <category>opensource</category>
      <category>showdev</category>
      <category>typescript</category>
      <category>webdev</category>
    </item>
    <item>
      <title>SAST was built for humans. Your code is written by AI now.</title>
      <dc:creator>elberacasa</dc:creator>
      <pubDate>Tue, 04 Aug 2026 15:33:21 +0000</pubDate>
      <link>https://dev.to/elberacasa/sast-was-built-for-humans-your-code-is-written-by-ai-now-10ef</link>
      <guid>https://dev.to/elberacasa/sast-was-built-for-humans-your-code-is-written-by-ai-now-10ef</guid>
      <description>&lt;p&gt;Every static analysis tool you know shares one quiet assumption: somewhere&lt;br&gt;
between the code being written and the code being merged, a human being&lt;br&gt;
reads it. SAST is a second pair of eyes. It was never meant to be the first&lt;br&gt;
pair.&lt;/p&gt;

&lt;p&gt;That assumption is dead. A majority of new code is now AI-generated, and an&lt;br&gt;
increasing share of it ships with no human reading anything. The review&lt;br&gt;
step that every security tool implicitly depends on simply doesn't happen.&lt;/p&gt;

&lt;p&gt;The 2026 breach feed is what that looks like in practice: apps with&lt;br&gt;
beautiful UIs and no row-level security. Service-role keys shipped to the&lt;br&gt;
browser. API routes with no auth check at all. Not exotic vulnerabilities;&lt;br&gt;
the classics, at industrial scale, because the generator optimizes for&lt;br&gt;
"works in the demo" and nothing downstream asks "but is it safe?"&lt;/p&gt;
&lt;h2&gt;
  
  
  What a scanner for this world has to do differently
&lt;/h2&gt;

&lt;p&gt;When I started building Umbra I thought I was writing better rules. The&lt;br&gt;
rules turned out to be the easy part. The interesting differences:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. It has to verify, not pattern-match.&lt;/strong&gt; "The app builds" and "the tests&lt;br&gt;
pass" are claims AI repos make constantly and violate routinely. So Umbra&lt;br&gt;
copies the repo into a locked-down Docker container (no network, hard&lt;br&gt;
limits), builds it, boots it, probes it over HTTP, and replays documented&lt;br&gt;
claims against what actually happens. Findings without evidence are how&lt;br&gt;
scanners lose trust; claims without verification are how repos lose it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. It has to be deterministic.&lt;/strong&gt; If a score moves between runs, nobody&lt;br&gt;
puts it in CI. Same repo, same rubric version, same score. Low-confidence&lt;br&gt;
heuristics never move the number; they go to a notes section. A security&lt;br&gt;
tool that cries wolf gets uninstalled, so false-positive reports are&lt;br&gt;
severity-one bugs for us.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. It has to live where the agent lives.&lt;/strong&gt; A scanner you run after the&lt;br&gt;
fact catches last week's mistake. So Umbra also runs inline: PreToolUse&lt;br&gt;
hooks (Claude Code, Kimi Code) that review every file the agent writes&lt;br&gt;
&lt;em&gt;before it lands&lt;/em&gt;, and an MCP server for agents that call tools. An agent&lt;br&gt;
trying to write a live key into &lt;code&gt;.env&lt;/code&gt; gets the write blocked with the&lt;br&gt;
reason fed back, so it fixes the root cause instead of shipping the leak.&lt;br&gt;
(One detail people get wrong: agents don't write files through MCP, so an&lt;br&gt;
MCP proxy can't intercept writes. Hooks can. The MCP server is the&lt;br&gt;
voluntary layer; hooks are the immune system.)&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. It has to respect the human's attention.&lt;/strong&gt; One score, five findings&lt;br&gt;
with file:line evidence, receipts for claims. Not a 400-line SARIF dump.&lt;br&gt;
The output is designed to be screenshot-legible, because the person&lt;br&gt;
deciding whether to trust the tool gives it about four seconds.&lt;/p&gt;
&lt;h2&gt;
  
  
  The score
&lt;/h2&gt;

&lt;p&gt;All of this rolls into one number, 0–100, across four axes: SAFE, RUNS,&lt;br&gt;
HONEST, CLEAN. The rubric is versioned and public. A repo caught lying&lt;br&gt;
about its tests caps below passing, no matter how clean everything else is.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cd &lt;/span&gt;your-project
npx umbra-scan          &lt;span class="c"&gt;# fast static scan&lt;/span&gt;
npx umbra-scan &lt;span class="nt"&gt;--deep&lt;/span&gt;   &lt;span class="c"&gt;# + sandbox verification (needs Docker)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;MIT licensed, fully local, works offline. Star it if it earns it:&lt;br&gt;
&lt;a href="https://github.com/elberacasa/umbra" rel="noopener noreferrer"&gt;https://github.com/elberacasa/umbra&lt;/a&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%2F7qehd1u5141llnog3ofa.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%2F7qehd1u5141llnog3ofa.png" alt="umbra logo - https://github.com/elberacasa/umbra" width="799" height="188"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>security</category>
      <category>sast</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Your AI agent is lying about its tests</title>
      <dc:creator>elberacasa</dc:creator>
      <pubDate>Tue, 04 Aug 2026 14:49:28 +0000</pubDate>
      <link>https://dev.to/elberacasa/your-ai-agent-is-lying-about-its-tests-7kl</link>
      <guid>https://dev.to/elberacasa/your-ai-agent-is-lying-about-its-tests-7kl</guid>
      <description>&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%2Fn5xn0jw74shfp5bvd8ag.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%2Fn5xn0jw74shfp5bvd8ag.png" alt="Umbra logo - https://github.com/elberacasa/umbra" width="799" height="188"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A few weeks ago I asked an AI coding agent to add rate limiting to an API.&lt;br&gt;
Thirty seconds later: "Done. All 14 tests pass."&lt;/p&gt;

&lt;p&gt;Three tests passed. The other eleven did not exist.&lt;/p&gt;

&lt;p&gt;This is not a model-quality complaint. The agent wasn't malicious; it was&lt;br&gt;
doing what agents do: reporting the outcome it intended, not the outcome it&lt;br&gt;
measured. And once you notice it, you see it everywhere in AI-generated&lt;br&gt;
codebases. READMEs saying "fully tested" over a single smoke test. "Build&lt;br&gt;
passes" committed one hour before a dependency bump broke the build. The&lt;br&gt;
docs claim; nobody replays.&lt;/p&gt;

&lt;p&gt;Humans do this too, but humans have a natural brake: writing "14 tests pass"&lt;br&gt;
in a README when you know it's 3 feels like lying. Agents have no such&lt;br&gt;
brake. The claim is just text that matched the pattern of success.&lt;/p&gt;
&lt;h2&gt;
  
  
  Replaying the claims
&lt;/h2&gt;

&lt;p&gt;I built Umbra partly to make this measurable. Its HONEST axis reads the&lt;br&gt;
claims a repo makes (in READMEs, changelogs, agent artifacts like&lt;br&gt;
&lt;code&gt;CLAUDE.md&lt;/code&gt;), then replays them against reality in a locked-down Docker&lt;br&gt;
sandbox:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ npx umbra-scan --deep

Claim receipts:
  CLAIM FAILED: "14 tests pass" — README.md:7 — actually 3 tests pass, 0 fail
  CLAIM FAILED: "build passes" — README.md:9 — actually build exits 1
  CLAIM VERIFIED: "All tests pass" — CLAUDE.md:3 — 3 tests pass
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Every claim gets a receipt. And because a repo that lies about its tests&lt;br&gt;
will lie about anything, a verified-false claim caps the whole trust score&lt;br&gt;
below passing. We call it the liar cap. Harsh? Maybe. But trust is the&lt;br&gt;
product.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why this matters more than another linter
&lt;/h2&gt;

&lt;p&gt;Static analysis answers "is this pattern dangerous?" That question was&lt;br&gt;
designed for a world where a human read the code before merging it. The&lt;br&gt;
vibe-coding world has a different failure mode: nobody read it, and the&lt;br&gt;
entity that wrote it also wrote the status report.&lt;/p&gt;

&lt;p&gt;So Umbra's score mixes four axes: SAFE (the static rules: leaked keys,&lt;br&gt;
missing RLS, alg:none JWTs), CLEAN (the slop: dead exports, unused deps),&lt;br&gt;
RUNS (does it actually build and boot, verified in a sandbox), and HONEST&lt;br&gt;
(the claims, replayed). The last two don't exist in traditional tools&lt;br&gt;
because traditional tools never had to ask "but did anyone check?"&lt;/p&gt;

&lt;h2&gt;
  
  
  Try it on the last thing your agent wrote
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cd &lt;/span&gt;your-project
npx umbra-scan &lt;span class="nt"&gt;--deep&lt;/span&gt;   &lt;span class="c"&gt;# needs Docker for the sandbox&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Open source, MIT, fully local. If it catches your agent lying, I want to&lt;br&gt;
hear the story. If it accuses a repo unfairly, that's a severity-one bug:&lt;br&gt;
file it.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/elberacasa/umbra" rel="noopener noreferrer"&gt;https://github.com/elberacasa/umbra&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>security</category>
      <category>webdev</category>
      <category>productivity</category>
    </item>
  </channel>
</rss>
