<?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: SrijanCodes</title>
    <description>The latest articles on DEV Community by SrijanCodes (@ionfwsrijan).</description>
    <link>https://dev.to/ionfwsrijan</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%2F3886452%2Fa09dfcdf-e15b-427c-b39d-1f8cd35824e1.png</url>
      <title>DEV Community: SrijanCodes</title>
      <link>https://dev.to/ionfwsrijan</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/ionfwsrijan"/>
    <language>en</language>
    <item>
      <title>When 11/11 Cases Isn't Enough: Building an Outbreak Investigator with FalkorDB</title>
      <dc:creator>SrijanCodes</dc:creator>
      <pubDate>Sun, 18 Oct 2026 22:59:57 +0000</pubDate>
      <link>https://dev.to/ionfwsrijan/when-1111-cases-isnt-enough-building-an-outbreak-investigator-with-falkordb-1lkc</link>
      <guid>https://dev.to/ionfwsrijan/when-1111-cases-isnt-enough-building-an-outbreak-investigator-with-falkordb-1lkc</guid>
      <description>&lt;p&gt;Eleven people got sick. Two ingredients appeared in all eleven cases. Two suppliers tied.&lt;/p&gt;

&lt;p&gt;The case counts narrowed the search, but they couldn’t tell us which lot was responsible. To break the tie, we needed evidence that was independent of exposure counts—and a way to show exactly how the investigation reached its conclusion.&lt;/p&gt;

&lt;p&gt;That was the challenge behind &lt;strong&gt;BatchZero&lt;/strong&gt;, our Graph Hacks 2026 project for the FalkorDB track.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;The outbreak and Port Meridian are fictional.&lt;/strong&gt; BatchZero uses synthetic data to demonstrate an investigation workflow; it is not a real public-health system.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Why represent an outbreak as a graph?
&lt;/h2&gt;

&lt;p&gt;An investigation follows relationships:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Person → Case → Exposure → Menu item → Ingredient → Lot → Supplier → Shipment&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;The question isn’t only “What did these cases have in common?” It’s also “Which facilities served that ingredient? Which lots did they receive? Where did those lots travel? What evidence supports the source we eventually identify?”&lt;/p&gt;

&lt;p&gt;A graph lets us follow those connected paths directly. In BatchZero, the case and supply-chain data live alongside hypotheses, evidence, agent sessions, and tool-call records in FalkorDB.&lt;/p&gt;

&lt;p&gt;For example, the shared-ingredient query traverses from cases through people and exposure events to menu items and ingredients:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cypher"&gt;&lt;code&gt;&lt;span class="k"&gt;MATCH&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="py"&gt;c:&lt;/span&gt;&lt;span class="k"&gt;Case&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;-&lt;/span&gt;&lt;span class="ss"&gt;[&lt;/span&gt;&lt;span class="nc"&gt;:HAS_CASE&lt;/span&gt;&lt;span class="ss"&gt;]&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="py"&gt;p:&lt;/span&gt;&lt;span class="n"&gt;Person&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="ss"&gt;[&lt;/span&gt;&lt;span class="nc"&gt;:PARTICIPATED&lt;/span&gt;&lt;span class="ss"&gt;]&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="py"&gt;e:&lt;/span&gt;&lt;span class="n"&gt;ExposureEvent&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;
      &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="ss"&gt;[&lt;/span&gt;&lt;span class="nc"&gt;:INVOLVES&lt;/span&gt;&lt;span class="ss"&gt;]&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="py"&gt;m:&lt;/span&gt;&lt;span class="n"&gt;MenuItem&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="ss"&gt;[&lt;/span&gt;&lt;span class="nc"&gt;:CONTAINS&lt;/span&gt;&lt;span class="ss"&gt;]&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="py"&gt;i:&lt;/span&gt;&lt;span class="n"&gt;Ingredient&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;c.case_id&lt;/span&gt; &lt;span class="ow"&gt;IN&lt;/span&gt; &lt;span class="n"&gt;$case_ids&lt;/span&gt;
&lt;span class="k"&gt;RETURN&lt;/span&gt; &lt;span class="n"&gt;i.name&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="n"&gt;ingredient&lt;/span&gt;&lt;span class="ss"&gt;,&lt;/span&gt;
       &lt;span class="nf"&gt;count&lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="k"&gt;DISTINCT&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="n"&gt;cases&lt;/span&gt;
&lt;span class="k"&gt;ORDER&lt;/span&gt; &lt;span class="k"&gt;BY&lt;/span&gt; &lt;span class="n"&gt;cases&lt;/span&gt; &lt;span class="k"&gt;DESC&lt;/span&gt;&lt;span class="ss"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ingredient&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That traversal gives us a shared-exposure picture. It does &lt;strong&gt;not&lt;/strong&gt; prove which ingredient caused the outbreak.&lt;/p&gt;

&lt;h2&gt;
  
  
  The tie that counts couldn’t break
&lt;/h2&gt;

&lt;p&gt;In the synthetic case, two ingredients appeared across all eleven cases, and two suppliers tied. A ranking based only on exposure frequency could not choose between them.&lt;/p&gt;

&lt;p&gt;The next step was to look for independent evidence. BatchZero models isolates and genomic matches as graph nodes and relationships. Patient isolates matched the environmental isolate associated with lot &lt;code&gt;MG-4417&lt;/code&gt; at no more than two SNPs. The competing lettuce lot, &lt;code&gt;LET-2210&lt;/code&gt;, had no matching isolate in the scenario.&lt;/p&gt;

&lt;p&gt;That evidence changed the investigation: &lt;code&gt;MG-4417&lt;/code&gt; became the leading source hypothesis, while the competing hypothesis was refuted. The important part of the demo is not just the answer—it’s the path from the evidence to the answer.&lt;/p&gt;

&lt;h2&gt;
  
  
  A plausible record can still be wrong
&lt;/h2&gt;

&lt;p&gt;We also included a temporal trap. One exposure record was dated after a patient’s symptom onset. If an agent treats every retrieved record as valid, that meal can become a misleading lead.&lt;/p&gt;

&lt;p&gt;BatchZero checks the exposure date against the case onset and the pathogen’s incubation window. The out-of-window record is excluded from the valid exposure set instead of being used as evidence for the source.&lt;/p&gt;

&lt;p&gt;This is the distinction we wanted to explore: retrieval can find a record, but an investigation has to decide whether that record makes sense.&lt;/p&gt;

&lt;h2&gt;
  
  
  Four agents, with different responsibilities
&lt;/h2&gt;

&lt;p&gt;BatchZero models the workflow as four roles:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Intake Officer&lt;/strong&gt; builds the initial case file.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cluster Analyst&lt;/strong&gt; compares cases and develops candidate hypotheses.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Supply Chain Tracer&lt;/strong&gt; follows ingredients, lots, suppliers, and shipments.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Briefing Officer&lt;/strong&gt; prepares the findings and response actions.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Each role uses a separate MCP server subprocess with its own set of tools. The capabilities help enforce the sequence: for example, the Cluster Analyst cannot draft a recall if that action is not exposed to its tool surface.&lt;/p&gt;

&lt;p&gt;We used MCP so the available actions are part of the runtime setup, rather than relying only on instructions in a prompt.&lt;/p&gt;

&lt;h2&gt;
  
  
  Keep the reasoning, not just the answer
&lt;/h2&gt;

&lt;p&gt;A conclusion is much easier to review when it can be traced back to its evidence. BatchZero records tool calls and sessions in the graph, and evidence links back to the tool call that produced it.&lt;/p&gt;

&lt;p&gt;That creates a path like:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Hypothesis → Evidence → ToolCall → Session&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;The graph also stores agent memory, including investigation hypotheses and distilled facts. That means the system can represent both the outbreak and the reasoning built while investigating it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Make the demo reproducible
&lt;/h2&gt;

&lt;p&gt;Live demos can fail for ordinary reasons: a missing API key, a network hiccup, or a model rate limit. BatchZero keeps the agent interface swappable. With a Groq API key, Groq can drive the tool loop; without one, the deterministic replay follows the same workflow against FalkorDB.&lt;/p&gt;

&lt;p&gt;The repository documents a benchmark command that runs the replay three times:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python &lt;span class="nt"&gt;-m&lt;/span&gt; batchzero.demo.replay &lt;span class="nt"&gt;--benchmark&lt;/span&gt; 3
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The project reports the correct source identification across all three benchmark runs. The demo and implementation are available in the &lt;a href="https://github.com/ionfwsrijan/BatchZero" rel="noopener noreferrer"&gt;BatchZero repository&lt;/a&gt;, and the &lt;a href="https://github.com/ionfwsrijan/BatchZero/blob/main/docs/demo.mp4" rel="noopener noreferrer"&gt;walkthrough video&lt;/a&gt; shows the investigation running in the UI.&lt;/p&gt;

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

&lt;p&gt;A few lessons stood out:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Model the relationships that drive the decision.&lt;/strong&gt; The useful part of the graph was not its shape on a diagram; it was the ability to traverse exposure, supply, and genomic relationships as part of the investigation.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Treat counts as a starting point.&lt;/strong&gt; Shared exposure narrowed the candidates, but independent evidence was needed to break the tie.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Validate records before reasoning from them.&lt;/strong&gt; A record can exist and still fall outside the relevant time window.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Keep provenance close to the conclusion.&lt;/strong&gt; Linking evidence to the tool call that produced it makes the result easier to reconstruct.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Use capabilities to reinforce process.&lt;/strong&gt; Role-scoped tools make some invalid actions unavailable to an agent at that stage.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The source in this synthetic scenario was lot &lt;code&gt;MG-4417&lt;/code&gt;. The graph helped us explain not only which hypothesis won, but what evidence supported it and how the investigation got there.&lt;/p&gt;

&lt;p&gt;If you build systems where decisions depend on following evidence across many connected entities, we’d love to hear what representations and audit trails have worked for you.&lt;/p&gt;

</description>
      <category>python</category>
      <category>database</category>
      <category>ai</category>
      <category>hackathon</category>
    </item>
    <item>
      <title>Catching config drift before it breaks prod</title>
      <dc:creator>SrijanCodes</dc:creator>
      <pubDate>Sun, 11 Oct 2026 14:49:49 +0000</pubDate>
      <link>https://dev.to/ionfwsrijan/catching-config-drift-before-it-breaks-prod-47po</link>
      <guid>https://dev.to/ionfwsrijan/catching-config-drift-before-it-breaks-prod-47po</guid>
      <description>&lt;p&gt;It's 5pm on a Friday. CI is green, tests pass, the image is built. You deploy — and the app&lt;br&gt;
crashes on boot because &lt;code&gt;DATABASE_URL&lt;/code&gt; isn't set in the environment. It &lt;em&gt;was&lt;/em&gt; in the &lt;code&gt;.env&lt;/code&gt; on&lt;br&gt;
your machine. It just never made it into the Kubernetes deployment. Nobody notices, because&lt;br&gt;
nothing checks that the three places agree.&lt;/p&gt;

&lt;p&gt;This is config drift, and it's one of the most common causes of "it worked on my machine."&lt;/p&gt;
&lt;h2&gt;
  
  
  Why &lt;code&gt;.env&lt;/code&gt; linters don't catch this
&lt;/h2&gt;

&lt;p&gt;Most env-var tooling validates a &lt;code&gt;.env&lt;/code&gt; file against a &lt;strong&gt;schema you write by hand&lt;/strong&gt;. That&lt;br&gt;
schema drifts too, and — crucially — it doesn't know what your code actually reads.&lt;br&gt;
If someone deletes a key your app requires, or mistypes &lt;code&gt;DB_HOST&lt;/code&gt; as &lt;code&gt;DBHOST&lt;/code&gt;, the linter is&lt;br&gt;
happy because the file matches the schema.&lt;/p&gt;

&lt;p&gt;The source of truth is your &lt;strong&gt;code&lt;/strong&gt;. So I built a linter that reads it.&lt;/p&gt;
&lt;h2&gt;
  
  
  What conflint does
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/conflint/conflint" rel="noopener noreferrer"&gt;conflint&lt;/a&gt; parses your source to find every env var /&lt;br&gt;
config key your app actually reads, then reconciles that set against every place the value&lt;br&gt;
should exist — &lt;code&gt;.env&lt;/code&gt;, &lt;code&gt;docker-compose&lt;/code&gt;, GitHub Actions, Kubernetes and Terraform.&lt;/p&gt;

&lt;p&gt;It knows:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Rule&lt;/th&gt;
&lt;th&gt;Meaning&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;CL001&lt;/td&gt;
&lt;td&gt;read in code, defined &lt;strong&gt;nowhere&lt;/strong&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;CL002&lt;/td&gt;
&lt;td&gt;defined for real, &lt;strong&gt;never read&lt;/strong&gt; by code&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;CL003&lt;/td&gt;
&lt;td&gt;undefined name is &lt;strong&gt;one edit away&lt;/strong&gt; from a known one (typo)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;CL004&lt;/td&gt;
&lt;td&gt;high-entropy &lt;strong&gt;secret committed&lt;/strong&gt; in a config source&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;CL005&lt;/td&gt;
&lt;td&gt;documented in &lt;code&gt;.env.example&lt;/code&gt; but no real source provides it (&lt;strong&gt;drift&lt;/strong&gt;)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;CL006&lt;/td&gt;
&lt;td&gt;required value defined but &lt;strong&gt;empty&lt;/strong&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;CL007&lt;/td&gt;
&lt;td&gt;defined twice / &lt;strong&gt;conflicting&lt;/strong&gt; across sources&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;CL008&lt;/td&gt;
&lt;td&gt;secret equals a &lt;strong&gt;weak/default&lt;/strong&gt; placeholder&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;CL009&lt;/td&gt;
&lt;td&gt;used or provided, but &lt;strong&gt;undocumented&lt;/strong&gt; in the example file&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Scanners today: &lt;strong&gt;Python&lt;/strong&gt; (AST), &lt;strong&gt;JavaScript/TypeScript&lt;/strong&gt;, &lt;strong&gt;Go&lt;/strong&gt;, &lt;strong&gt;Ruby&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fy2w9kerm41zk3yb6jq78.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fy2w9kerm41zk3yb6jq78.gif" alt="confl check finding a committed secret, a missing variable and a typo" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  A concrete example
&lt;/h2&gt;

&lt;p&gt;Say your app looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# app.py
&lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;

&lt;span class="n"&gt;DATABASE_URL&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;environ&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;DATABASE_URL&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="n"&gt;API_KEY&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getenv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;API_KEY&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;REDIS_URL&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;environ&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;REDIS_URL&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;redis://localhost:6379&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and your &lt;code&gt;.env&lt;/code&gt; 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;API_KEY=sk-live-4f9a2b7c8d1e6f3a5b0c9d8e7f6a5b4c
DATABSE_URL=postgres://localhost:5432/app
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Running &lt;code&gt;confl check&lt;/code&gt; gives you:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;conflint checked 2 files (3 config reads, 2 definitions) in 7ms

.env:1:1
  CL004 error: 'API_KEY' looks like a committed secret in dotenv:1
    hint: Move real secrets to a secrets manager; keep placeholders in .env.example

app.py:3:16
  CL001 error: 'DATABASE_URL' is read in code but not defined in any configuration source:3
    hint: Add it to your .env (then run `confl sync` to refresh .env.example)

app.py:5:13
  CL001 warning: 'REDIS_URL' is read in code but not defined in any configuration source:5
    hint: Add it to your .env (then run `confl sync` to refresh .env.example)

2 files checked - 2 errors, 3 warnings, 0 infos
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Three real problems caught in 7 milliseconds: a committed secret, a missing required variable,&lt;br&gt;
and (implicitly) a typo — note &lt;code&gt;DATABSE_URL&lt;/code&gt; is defined but never read, which is why&lt;br&gt;
&lt;code&gt;DATABASE_URL&lt;/code&gt; is "missing."&lt;/p&gt;
&lt;h2&gt;
  
  
  Quickstart
&lt;/h2&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pip &lt;span class="nb"&gt;install &lt;/span&gt;conflint
confl check            &lt;span class="c"&gt;# lint the whole project&lt;/span&gt;
confl &lt;span class="nb"&gt;sync&lt;/span&gt;             &lt;span class="c"&gt;# regenerate an accurate .env.example&lt;/span&gt;
confl explain DATABASE_URL   &lt;span class="c"&gt;# who reads it? where is it defined?&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h2&gt;
  
  
  Wire it into CI and pre-commit
&lt;/h2&gt;

&lt;p&gt;GitHub Action (inline PR annotations):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Lint configuration&lt;/span&gt;
  &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;conflint/conflint@v0.1.2&lt;/span&gt;
  &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;reporter&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;github&lt;/span&gt;
    &lt;span class="na"&gt;fail-level&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;error&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or a pre-commit hook:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;repo&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;https://github.com/conflint/conflint&lt;/span&gt;
  &lt;span class="na"&gt;rev&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;v0.1.2&lt;/span&gt;
  &lt;span class="na"&gt;hooks&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;conflint&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Output formats: &lt;code&gt;text&lt;/code&gt;, &lt;code&gt;--json&lt;/code&gt; (stable schema), &lt;code&gt;--sarif&lt;/code&gt; (GitHub/GitLab/Azure code scanning),&lt;br&gt;
&lt;code&gt;--github&lt;/code&gt; (workflow annotations), and JUnit XML for Jenkins.&lt;/p&gt;

&lt;h2&gt;
  
  
  Honest limitations
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;It's &lt;strong&gt;early&lt;/strong&gt; (v0.1.2, MIT). The rule set and source coverage are opinionated and evolving.&lt;/li&gt;
&lt;li&gt;Static analysis means it infers &lt;em&gt;reads&lt;/em&gt;; dynamically constructed keys (e.g. &lt;code&gt;os.environ[prefix + x]&lt;/code&gt;)
can't be resolved and may need &lt;code&gt;ignore-names&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;It's not a secret &lt;strong&gt;scanner&lt;/strong&gt; replacement — it catches secrets specifically in config sources,
not across full git history (use gitleaks/trufflehog for that).&lt;/li&gt;
&lt;/ul&gt;

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

&lt;ul&gt;
&lt;li&gt;Repo: &lt;a href="https://github.com/conflint/conflint" rel="noopener noreferrer"&gt;https://github.com/conflint/conflint&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Docs: &lt;a href="https://conflint.readthedocs.io" rel="noopener noreferrer"&gt;https://conflint.readthedocs.io&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;PyPI: &lt;a href="https://pypi.org/project/conflint" rel="noopener noreferrer"&gt;https://pypi.org/project/conflint&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I'd love feedback on the rule set and which scanners/sources to add next. If it's useful,&lt;br&gt;
a ⭐ helps others find it.&lt;/p&gt;

</description>
      <category>devops</category>
      <category>python</category>
      <category>kubernetes</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Afterlight Atlas: Designing Planetary Futures</title>
      <dc:creator>SrijanCodes</dc:creator>
      <pubDate>Sat, 18 Apr 2026 21:57:53 +0000</pubDate>
      <link>https://dev.to/ionfwsrijan/afterlight-atlas-designing-planetary-futures-44o0</link>
      <guid>https://dev.to/ionfwsrijan/afterlight-atlas-designing-planetary-futures-44o0</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for &lt;a href="https://dev.to/challenges/weekend-2026-04-16"&gt;Weekend Challenge: Earth Day Edition&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

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

&lt;p&gt;I built &lt;strong&gt;Afterlight Atlas&lt;/strong&gt;, a cinematic Earth Day web experience for imagining, comparing, and presenting better planetary futures.&lt;/p&gt;

&lt;p&gt;A lot of climate tools are useful, but they often focus on damage, guilt, or optimization. I wanted to build something that answered a different question:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What does a repaired future actually feel like?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;So instead of making another carbon calculator or eco dashboard, I made an interactive world-building instrument where people can:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;choose a future seed such as &lt;code&gt;Mycelial City&lt;/code&gt;, &lt;code&gt;Tidal Commons&lt;/code&gt;, &lt;code&gt;Canopy Republic&lt;/code&gt;, or &lt;code&gt;Solar Bazaar&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;tune seven planetary levers across energy, mobility, food, water, materials, biodiversity, and civic care&lt;/li&gt;
&lt;li&gt;watch a live world respond through narrative, metrics, atmosphere, and visual tone&lt;/li&gt;
&lt;li&gt;compare that future against a baseline and immediately see whether it is actually stronger&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The part I think makes this project stand out is that &lt;strong&gt;Afterlight Atlas is not just a pretty sustainability interface&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;It does four things at once:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;It makes climate action feel emotionally tangible.&lt;br&gt;
The app turns policy and infrastructure choices into a world you can feel through tone, language, atmosphere, and future storytelling.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;It frames sustainability as composition, not punishment.&lt;br&gt;
You are not being told how bad things are. You are composing a better civilization and seeing how different systems reinforce each other.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;It gives judges a fast evaluation layer.&lt;br&gt;
The app includes &lt;strong&gt;Judge Mode&lt;/strong&gt;, which compares the active future against either the seed baseline or a saved alternate scenario and explains the delta clearly.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;It works as both a product and a presentation.&lt;br&gt;
It includes &lt;strong&gt;Present Mode&lt;/strong&gt;, saved snapshots, comparison export, and a one-click &lt;strong&gt;Best Future&lt;/strong&gt; preset so it can be explored, pitched, and judged quickly.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Core features:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;four original future seeds with distinct climate philosophies&lt;/li&gt;
&lt;li&gt;seven adjustable planetary levers&lt;/li&gt;
&lt;li&gt;live planet score and world-state generation&lt;/li&gt;
&lt;li&gt;six speculative systems signals: atmosphere, biodiversity, community, ocean, circularity, and heat&lt;/li&gt;
&lt;li&gt;story-rich future dispatches instead of dry dashboard copy&lt;/li&gt;
&lt;li&gt;three-horizon future timelines for 2035, 2060, and 2085&lt;/li&gt;
&lt;li&gt;repair rituals that turn the scenario into grounded action prompts&lt;/li&gt;
&lt;li&gt;save/load alternate futures&lt;/li&gt;
&lt;li&gt;Judge Mode for baseline comparison&lt;/li&gt;
&lt;li&gt;Present Mode for cleaner walkthroughs&lt;/li&gt;
&lt;li&gt;exportable comparison card image&lt;/li&gt;
&lt;li&gt;one-click Best Future preset&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;Live app:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://afterlight-atlas.vercel.app/" rel="noopener noreferrer"&gt;https://afterlight-atlas.vercel.app/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The app is fully deployed and ready to explore in the browser.&lt;/p&gt;

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

&lt;p&gt;GitHub repository:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/ionfwsrijan/Afterlight-Atlas" rel="noopener noreferrer"&gt;https://github.com/ionfwsrijan/Afterlight-Atlas&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Key files:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;src/main.ts&lt;/code&gt; for rendering, interactions, Judge Mode, Present Mode, sharing actions, and export flows&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;src/engine.ts&lt;/code&gt; for world derivation, scoring, baseline comparison, and share-state helpers&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;src/data.ts&lt;/code&gt; for world seeds, lever metadata, and theme definitions&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;src/style.css&lt;/code&gt; for the editorial UI system and presentation layer&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;I started with one strong constraint:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;If judges only spend a short time on each project, the experience needs to explain itself almost immediately.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;That shaped the build in a few important ways.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. I avoided the default Earth Day pattern
&lt;/h3&gt;

&lt;p&gt;The obvious path would have been a calculator, green tips app, or climate dashboard.&lt;/p&gt;

&lt;p&gt;Instead, I designed Afterlight Atlas as a &lt;strong&gt;speculative climate composition instrument&lt;/strong&gt;. That let me build something more memorable, more visual, and more emotionally resonant while still staying grounded in meaningful systems like energy, mobility, water, biodiversity, and care.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. I made Judge Mode a first-class feature
&lt;/h3&gt;

&lt;p&gt;One of the hardest parts of any challenge entry is not just making something good, but making it easy to judge.&lt;/p&gt;

&lt;p&gt;So I built &lt;strong&gt;Judge Mode&lt;/strong&gt;, which compares the current world against either:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the original seed baseline&lt;/li&gt;
&lt;li&gt;a saved alternate snapshot&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It then surfaces:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;score delta&lt;/li&gt;
&lt;li&gt;strongest gain&lt;/li&gt;
&lt;li&gt;main watchout&lt;/li&gt;
&lt;li&gt;metric swings&lt;/li&gt;
&lt;li&gt;lever shifts&lt;/li&gt;
&lt;li&gt;a verdict&lt;/li&gt;
&lt;li&gt;a recommendation&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That means a judge does not have to guess why one version is better. The app tells them.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. I optimized for fast evaluation
&lt;/h3&gt;

&lt;p&gt;Challenge judges usually review a lot of projects quickly, so I added presentation-oriented features that reduce friction:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Present Mode&lt;/strong&gt; for a cleaner walkthrough&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Export Comparison Card&lt;/strong&gt; for a pitch-friendly PNG&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Best Future&lt;/strong&gt; for a one-click strong scenario&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Together, those features make the project faster to understand and easier to remember.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. I treated Earth Day as both emotional and technical
&lt;/h3&gt;

&lt;p&gt;I wanted the project to fit the Earth Day theme more deeply than just using green colors and eco language.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Emotionally&lt;/strong&gt;, it fits because it is about hope, repair, stewardship, and imagination. It asks users to picture what a healthier relationship with the planet could feel like in everyday life.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Technically&lt;/strong&gt;, it fits because the underlying levers and comparisons are built around real systems-level concerns:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;distributed clean energy&lt;/li&gt;
&lt;li&gt;lower-emission mobility&lt;/li&gt;
&lt;li&gt;watershed resilience&lt;/li&gt;
&lt;li&gt;circular material flows&lt;/li&gt;
&lt;li&gt;biodiversity recovery&lt;/li&gt;
&lt;li&gt;civic resilience and care&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So the project is not just atmospheric. It is structured around meaningful planetary systems.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. I kept the simulation honest
&lt;/h3&gt;

&lt;p&gt;Afterlight Atlas is a &lt;strong&gt;speculative decision-and-storytelling interface&lt;/strong&gt;, not a climate science model.&lt;/p&gt;

&lt;p&gt;The goal is not to predict the future precisely. The goal is to make tradeoffs, futures, and systemic thinking vivid enough that people can compare them, discuss them, and care about them.&lt;/p&gt;

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