<?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: Melwin Siril Joel V</title>
    <description>The latest articles on DEV Community by Melwin Siril Joel V (@cadets_atease).</description>
    <link>https://dev.to/cadets_atease</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%2F3896419%2F68bd8279-f721-4239-9281-7d8ff2291d20.jpg</url>
      <title>DEV Community: Melwin Siril Joel V</title>
      <link>https://dev.to/cadets_atease</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/cadets_atease"/>
    <language>en</language>
    <item>
      <title>I fed a global bird model foreign audio. It was confidently wrong. Then I fixed it.</title>
      <dc:creator>Melwin Siril Joel V</dc:creator>
      <pubDate>Sun, 11 Oct 2026 09:11:23 +0000</pubDate>
      <link>https://dev.to/cadets_atease/i-fed-a-global-bird-model-foreign-audio-it-was-confidently-wrong-then-i-fixed-it-3lgl</link>
      <guid>https://dev.to/cadets_atease/i-fed-a-global-bird-model-foreign-audio-it-was-confidently-wrong-then-i-fixed-it-3lgl</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for the &lt;a href="https://dev.to/challenges/hacktoberfest-week1-2026-10-05"&gt;Hacktoberfest Open-Source AI Challenge Week 1: Touch Grass&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

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

&lt;p&gt;I started this project because I noticed something wrong with how bird identification works in my own town.&lt;/p&gt;

&lt;p&gt;BirdNET is a genuinely impressive open-source project. Point it at a recording and it will confidently tell you what you heard. I tried it on some audio recorded on my hostel campus in Chidambaram, Tamil Nadu, and it told me about &lt;strong&gt;Rose-ringed Parakeet, Common Grackle, and Dark-eyed Junco&lt;/strong&gt;. The grackle is a North American species. It has never been in India. It was never in my garden. The model was not confused - it was &lt;em&gt;sure&lt;/em&gt;, and wrong.&lt;/p&gt;

&lt;p&gt;That is the whole problem in one clip. A global classifier trained on global audio will happily tell you about birds that live four thousand kilometres away, because nothing in its architecture knows or cares where you are standing. There is no "not in my region" button.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;chidambaram-birdnudge&lt;/strong&gt; is that button. It runs the same open weights on your own machine, then filters every prediction through a species list built from real observations near you. It costs nothing to run, needs no account, works with no signal, and never sends your recordings anywhere.&lt;/p&gt;

&lt;p&gt;A local Node.js pipeline that takes phone recordings, identifies birds with an open-weight audio model, filters the results to a regional species list, and tells you where to go next.&lt;/p&gt;

&lt;p&gt;The pipeline is five scripts:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;script&lt;/th&gt;
&lt;th&gt;what it does&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;download-model.mjs&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;fetches the BirdNET+ weights and label set&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;fetch-pack.mjs&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;builds the local species list from iNaturalist observations within a radius&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;convert.mjs&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;batch-converts &lt;code&gt;.m4a&lt;/code&gt; / &lt;code&gt;.mp3&lt;/code&gt; / &lt;code&gt;.ogg&lt;/code&gt; to the 32 kHz mono WAV the model wants&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;analyze.mjs&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;runs ONNX inference, writes a detection CSV per clip&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;summarize.mjs&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;scores predictions against the pack, writes &lt;code&gt;docs/overview.md&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;case.mjs&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;generates the case study from the detection data&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Two design decisions are worth calling out.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The model runs whole-file peak-normalised&lt;/strong&gt;, so a quiet outdoor clip and a loud indoor one are comparable. This matters more than it sounds - my outdoor clip was about 6 dB quieter than my indoor ones, and without normalisation the comparison would have been meaningless.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;min-conf&lt;/code&gt; defaults to 0.05, not 0.25.&lt;/strong&gt; BirdNET's own web demo defaults much higher, which means it silently discards low-confidence-but-real detections. I lowered it so the local filter gets to see everything, then let the pack do the rejecting. The pack is a better filter than an arbitrary threshold, because it is specific to where you are.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Repo:&lt;/strong&gt; &lt;a href="https://github.com/Emanuelmsjv/chidambaram-birdnudge" rel="noopener noreferrer"&gt;https://github.com/Emanuelmsjv/chidambaram-birdnudge&lt;/a&gt;&lt;/p&gt;

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

&lt;p&gt;Real output from a real run, on the five clips described above:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;model    ...\assets\BirdNET+_V3.0-preview3.1_Global_11K_FP16_pruned.onnx
labels   11560 species
settings chunk=3s overlap=0s minConf=0.05

model load: 971ms
inside-2.wav  9.9s audio  0.4s compute  6 detections
    0.870  Yellow-billed Babbler  (Argya affinis)
    0.589  Rufous Treepie  (Dendrocitta vagabunda)
    0.068  Indian White-eye  (Zosterops palpebrosus)
inside.wav  17.9s audio  0.5s compute  15 detections
    0.812  Yellow-billed Babbler  (Argya affinis)
    0.415  Common Grackle  (Quiscalus quiscula)
    0.283  Oriental Magpie-Robin  (Copsychus saularis)
outside.wav  17.5s audio  0.5s compute  9 detections
    0.873  Rose-ringed Parakeet  (Psittacula krameri)
    0.731  Common Myna  (Acridotheres tristis)
    0.509  Red-vented Bulbul  (Pycnonotus cafer)

5 file(s), 47 detections
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;And what the filter actually does with that output:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ npm run summarize
Clips: 6  detections: 146
In-pack (top-5): 15/27 = 55.6%
In-pack (all 53 distinct): 24 = 45.3%
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

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

&lt;p&gt;The whole pipeline is open source under CC BY-NC-SA 4.0. Everything below runs on your&lt;br&gt;
own machine with Node 18+, no Python, no GPU, and no API keys.&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/Emanuelmsjv" rel="noopener noreferrer"&gt;
        Emanuelmsjv
      &lt;/a&gt; / &lt;a href="https://github.com/Emanuelmsjv/chidambaram-birdnudge" rel="noopener noreferrer"&gt;
        chidambaram-birdnudge
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Offline open-weight bird ID for Chidambaram, Tamil Nadu. BirdNET V3.0 via ONNX Runtime in pure Node - no Python, no GPU. Output is filtered against an iNaturalist-derived local species pack, and scored with a label-free measure of how plausible that output is for this location.
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;chidambaram-birdnudge&lt;/h1&gt;
&lt;/div&gt;

&lt;p&gt;Point an open-weight bird sound model at a 10-second recording of somewhere in
Chidambaram, Tamil Nadu. Get back one sentence telling you which species
plausibly live near you, whether they are in season right now, what time of day
they are worth listening for, and a real place within reach to go and stand.&lt;/p&gt;
&lt;p&gt;The model already exists and is very good. It is also, on published evidence
close to useless in this part of India. That gap is the project.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;The premise&lt;/h2&gt;
&lt;/div&gt;
&lt;p&gt;A 2026 global evaluation of BirdNET across 4,224 soundscapes, 67 sites and every
continent, annotated by local experts, reported PR AUC of:&lt;/p&gt;
&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Region&lt;/th&gt;
&lt;th&gt;PR AUC&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;North America / Oceania / Europe&lt;/td&gt;
&lt;td&gt;0.16 – 0.23&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Central &amp;amp; South America&lt;/td&gt;
&lt;td&gt;0.13&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Africa and Asia&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0.03 – 0.04&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;
&lt;p&gt;Chidambaram sits in that last band. Globally, the share of predictions that are
correct (precision) is around 0.57–0.71, so roughly a…&lt;/p&gt;&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/Emanuelmsjv/chidambaram-birdnudge" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;Repo: &lt;a href="https://github.com/Emanuelmsjv/chidambaram-birdnudge" rel="noopener noreferrer"&gt;https://github.com/Emanuelmsjv/chidambaram-birdnudge&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A one-command setup fetches the 68 MB model weights and builds the local species pack:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/Emanuelmsjv/chidambaram-birdnudge
&lt;span class="nb"&gt;cd &lt;/span&gt;chidambaram-birdnudge
npm &lt;span class="nb"&gt;install
&lt;/span&gt;npm run setup        &lt;span class="c"&gt;# downloads the 68 MB model, builds your species pack&lt;/span&gt;

npm run convert      &lt;span class="c"&gt;# phone .m4a -&amp;gt; 32 kHz mono WAV&lt;/span&gt;
npm run analyze clips &lt;span class="nt"&gt;--out&lt;/span&gt; data/detections
npm run summarize    &lt;span class="c"&gt;# writes docs/overview.md&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/Emanuelmsjv/chidambaram-birdnudge
&lt;span class="nb"&gt;cd &lt;/span&gt;chidambaram-birdnudge
npm &lt;span class="nb"&gt;install
&lt;/span&gt;npm run setup        &lt;span class="c"&gt;# downloads the 68 MB model, builds your species pack&lt;/span&gt;

npm run convert      &lt;span class="c"&gt;# phone .m4a -&amp;gt; 32 kHz mono WAV&lt;/span&gt;
npm run analyze clips &lt;span class="nt"&gt;--out&lt;/span&gt; data/detections
npm run summarize    &lt;span class="c"&gt;# writes docs/overview.md&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Requires Node 18+ and ffmpeg on PATH. No Python, no GPU, no API keys.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Licence:&lt;/strong&gt; CC BY-NC-SA 4.0. BirdNET weights are CC BY-NC-SA. iNaturalist observation data retains its own per-record licences, referenced in &lt;code&gt;data/pack.json&lt;/code&gt;.&lt;/p&gt;
&lt;h2&gt;
  
  
  How I Built It
&lt;/h2&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;Model&lt;/td&gt;
&lt;td&gt;BirdNET+ V3.0-preview3.1 Global 11K FP16 (pruned)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Weights format&lt;/td&gt;
&lt;td&gt;ONNX, &lt;strong&gt;68.2 MB&lt;/strong&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Runtime&lt;/td&gt;
&lt;td&gt;&lt;code&gt;onnxruntime-node&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Labels&lt;/td&gt;
&lt;td&gt;11,560 species, plain CSV&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Hardware&lt;/td&gt;
&lt;td&gt;CPU only. No GPU. No Python.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The model is a TarsNet2 classifier - a frozen convolutional backbone with a linear classification head. That architecture is the reason this project is tractable offline: the expensive part is fixed, and the part you retarget is one dense layer.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Speed:&lt;/strong&gt; the five-clip case study below is &lt;strong&gt;83.8 seconds of audio, analysed in under 4 seconds&lt;/strong&gt; after a ~1 second model load. That is roughly 25x realtime on a laptop CPU with no accelerator.&lt;/p&gt;
&lt;h2&gt;
  
  
  Why Does Open Innovation Matter?
&lt;/h2&gt;

&lt;p&gt;The challenge asks where an open approach did better than a closed one. I can answer that with a measurement rather than an opinion.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Same weights, same code, two recordings:&lt;/strong&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;audio&lt;/th&gt;
&lt;th&gt;in-pack fraction&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;upstream BirdNET sample, recorded in New York&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;1 / 20&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;my recordings, Chidambaram&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;23 / 33&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Nineteen of the twenty species the model proposed for the New York audio do not exist within 30 km of Chidambaram. The twentieth is House Sparrow at 0.051 - rank 20 of 20 by confidence, barely clearing my own threshold. Every confident prediction was a bird that does not live here:&lt;/p&gt;

&lt;p&gt;A hosted bird-ID service gives you a fixed species list, the one its provider chose. If that list does not contain your local birds, you cannot add them. &lt;strong&gt;With open weights I can change what the model is allowed to say.&lt;/strong&gt; That is the entire difference between 1/20 and 23/33, and it is not available behind an API.&lt;/p&gt;

&lt;p&gt;The other reasons the open pieces mattered:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;It runs with no signal.&lt;/strong&gt; After a one-time 68 MB download, &lt;code&gt;npm run analyze&lt;/code&gt; never touches the network. A bird call identifier is only useful where bird calls happen, which is usually nowhere with good connectivity. I did not get to actually test this on a trail with no bars - I tested it on a laptop, and the mobile app I originally used needed a working connection. I am not claiming more than I measured.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Your recordings never leave your machine.&lt;/strong&gt; The case study below is audio recorded at a university hostel. Uploading that to a third-party inference endpoint hands someone a location-precise recording of where a person lives and when they were there. Local inference means the audio is read once by &lt;code&gt;decodeWav&lt;/code&gt; and never transmitted.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;It costs nothing.&lt;/strong&gt; No API key, no per-minute billing, no quota. A hosted audio-classification endpoint bills by the minute precisely when you most want to use it and least want to depend on it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The model is replaceable.&lt;/strong&gt; The labels are a CSV and the regional list is JSON. Retargeting to another city is a data edit, not a code change. Nothing about the pipeline is specific to BirdNET except the inference call.&lt;/p&gt;
&lt;h3&gt;
  
  
  Honest limits of the open approach
&lt;/h3&gt;

&lt;p&gt;Being straightforward about where this does &lt;em&gt;not&lt;/em&gt; win:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The weights are &lt;strong&gt;CC BY-NC-SA&lt;/strong&gt;, so this is non-commercial. That is fine for a personal tool and a real constraint if you wanted to build a product.&lt;/li&gt;
&lt;li&gt;Fine-tuning for a local species set is architecturally trivial here (frozen encoder, linear head, logistic regression on embeddings, trainable on CPU) but &lt;strong&gt;I did not do it.&lt;/strong&gt; With four labelled clips and no working route to bulk training audio, any claim I made about it would be unverified.&lt;/li&gt;
&lt;li&gt;BirdNET's Python pipeline has features my port does not - proper spectrogram caching, multi-label handling, and more careful segmenting. I ported the part that made my question answerable, not the whole project.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  I took it outside
&lt;/h2&gt;

&lt;p&gt;The brief offers "a bird call identifier that works on the trail with no signal" as an example. I took it literally.&lt;/p&gt;

&lt;p&gt;I heard a group of &lt;strong&gt;Yellow-billed Babbler&lt;/strong&gt; (&lt;em&gt;Argya affinis&lt;/em&gt;) on my hostel campus and recorded five clips on my phone - two indoors, one outdoors, and two while I was talking, to see what happened. Then I ran them through the pipeline.&lt;/p&gt;

&lt;p&gt;The species was already in my local pack at rank 18 of 130, with 19 iNaturalist observations in range - a locally well-established bird, not a rarity.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;clip&lt;/th&gt;
&lt;th&gt;babblers audible?&lt;/th&gt;
&lt;th&gt;model's best score&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;inside-2&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;yes&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0.870&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;inside&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;yes&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0.812&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;speech-2&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;yes&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0.961&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;speech&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;no&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;none&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;outside&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;yes&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;none&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Three of the four clips where I confirmed the bird was audible got a correct first-place identification.&lt;/p&gt;

&lt;p&gt;The two I find most interesting are the &lt;code&gt;speech&lt;/code&gt; pair. Both were recorded in the same room, minutes apart, with me talking. I listened back afterwards to check what was in the background. In one, babblers were chirping behind my voice; in the other, there were none. The model returned 0.961 for the one where they were there and &lt;strong&gt;nothing at all&lt;/strong&gt; for the one where they were not.&lt;/p&gt;

&lt;p&gt;That distinction matters, because the cheap explanation would have been that the model just fires on human voices and happened to point at a common local babbler. Two clips with identical foreground content and opposite answers rules that out.&lt;/p&gt;

&lt;p&gt;The one result I still cannot fully explain is &lt;code&gt;speech-2&lt;/code&gt;, where the babbler is buried under speech and still scored 0.961. I am reporting it because it happened, not because I understand it.&lt;/p&gt;
&lt;h2&gt;
  
  
  What it got wrong
&lt;/h2&gt;

&lt;p&gt;Every one of these is in the repo, not just here.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;It missed the bird entirely on the outdoor clip.&lt;/strong&gt; I was there, the babblers were there, and the model proposed parakeet and myna instead. That clip was also my quietest recording. I still do not know whether the model failed or the microphone failed. It is the first thing I would try to fix.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Confidence is not a probability.&lt;/strong&gt; BirdNET will hand you 0.9 and mean something much weaker. The New York control demonstrates this directly - the model was extremely confident about species that were not present at all. The number is a ranking signal, nothing more.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;My species pack is biased, and I can show how.&lt;/strong&gt; It is built from iNaturalist, which is a &lt;em&gt;photography&lt;/em&gt; platform. I pulled 1,000 research-grade observations from around Chidambaram and checked the result: &lt;strong&gt;Indian White-eye appeared zero times.&lt;/strong&gt; It is one of the most common birds in India and it is, to my ear, constantly audible from my window. The pack over-represents birds people stop to photograph - Pied Stilt is the second most-recorded species in range - and under-represents small common passerines nobody bothers to upload.&lt;/p&gt;

&lt;p&gt;So "not in your local pack" is weaker evidence than it appears. It means &lt;em&gt;not established as local by this data source&lt;/em&gt;, not &lt;em&gt;absent&lt;/em&gt;. I would not have found this without checking the raw observations against my own pack.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;I had a real bug for most of this project.&lt;/strong&gt; The pack builder wrote entries as &lt;code&gt;{ rank: i + 1, ...s }&lt;/code&gt; - the spread lands after, so the taxonomic rank from iNaturalist overwrote my ordinal in all 130 entries. Every &lt;code&gt;rank&lt;/code&gt; field was the string &lt;code&gt;"species"&lt;/code&gt;. The ordering was still correct, which is exactly why I did not notice for weeks. Fixed in &lt;code&gt;a087f8f&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;My recordings were not independent data.&lt;/strong&gt; I collected them, then evaluated the model on them. There is no held-out set, and with four positives any accuracy number would be meaningless. I have not claimed one anywhere.&lt;/p&gt;
&lt;h2&gt;
  
  
  My Agent Session
&lt;/h2&gt;

&lt;p&gt;Here is the session where the agent found the &lt;code&gt;rank&lt;/code&gt; bug, in full. It is twelve messages: you can watch it notice that &lt;code&gt;rank&lt;/code&gt; prints as &lt;code&gt;"species"&lt;/code&gt; instead of a number, work out that &lt;code&gt;{ rank: i + 1, ...s }&lt;/code&gt; lets iNaturalist's own &lt;code&gt;rank&lt;/code&gt; string land on top of the ordinal, and fix it. The interesting detail is that nothing was broken as far as anyone could tell - the pack was still sorted correctly the whole time. The bug only became visible because a species position was checked against a literal &lt;code&gt;18&lt;/code&gt;.&lt;/p&gt;


&lt;div class="ltag-agent-session"&gt;
  &lt;div class="agent-session-header"&gt;
    
    &lt;span class="agent-session-tool-icon-badge" title="Gemini CLI"&gt;
&lt;/span&gt;
    &lt;span class="agent-session-title"&gt;Debugging a clobbered rank field in fetch-pack.mjs (opencode)&lt;/span&gt;
  &lt;/div&gt;

  &lt;div class="agent-session-scroll"&gt;

      &lt;div class="agent-session-message agent-session-user"&gt;
        &lt;div class="agent-session-role-badge agent-session-role-user"&gt;
          You
        &lt;/div&gt;
        &lt;div class="agent-session-content"&gt;
                &lt;div class="agent-session-text"&gt;
                  &lt;p&gt;what is observed is a group of Common Myna, where inside my hostel Golden Jubille hostels trees and outside of the hostel campus too. and im checking in the birdnet app ill update until then well completed debugging and furnishing and deploying too&lt;/p&gt;

                &lt;/div&gt;
        &lt;/div&gt;
      &lt;/div&gt;

      &lt;div class="agent-session-message agent-session-assistant"&gt;
        &lt;div class="agent-session-role-badge agent-session-role-assistant"&gt;
          Agent
        &lt;/div&gt;
        &lt;div class="agent-session-content"&gt;
                &lt;div class="agent-session-text"&gt;
                  &lt;p&gt;&lt;strong&gt;Common Myna is a strong test case&lt;/strong&gt; - and I can tell you something useful before you run it. Let me verify.&lt;/p&gt;

                &lt;/div&gt;
              &lt;div class="agent-session-tool-call"&gt;
                
                  &lt;span class="agent-session-chevron"&gt;▸&lt;/span&gt;
                  &lt;span class="tool-name tool-name-bash"&gt;bash&lt;/span&gt;
                    &lt;span class="tool-input-preview"&gt;{"command":"$ErrorActionPreference='Continue'\ncd [redacted:home-path]\\hackt...&lt;/span&gt;
                
                &lt;div class="agent-session-tool-detail"&gt;
                    &lt;div class="tool-section"&gt;
                      &lt;div class="tool-section-label"&gt;Input&lt;/div&gt;
                      &lt;pre class="agent-session-pre agent-session-terminal"&gt;&lt;code&gt;$ {"command":"$ErrorActionPreference='Continue'\ncd [redacted:home-path]\\hacktoberfest\\chidambaram-birdnudge\nWrite-Output \"=== Common Myna in the Chidambaram pack? ===\"\nnode -e \"\nconst p=require('./data/pack.json');\nconst hits=p.species.filter(s=&amp;gt;/Acridotheres tristis/i.test(s.scientific));\nhits.forEach(s=&amp;gt;console.log('  '+s.common+' ('+s.scientific+')  rank='+s.rank+'  observations='+s.observations));\nconsole.log('  pack size: '+p.species.length+' species');\nconst mug=s=&amp;gt;p.species.filter(x=&amp;gt;new RegExp(s,'i').test(x.common||'')).map(x=&amp;gt;x.common);\nconsole.log('');\nconsole.log('  other starlings/mynas in pack:');\n['starling','myna','sturnid'].forEach(q=&amp;gt;{const r=mug(q);if(r.length)console.log('    '+q+': '+r.join(', '));});\n\"\nWrite-Output \"\"\nWrite-Output \"=== does extract.mjs understand 'group' / 'flock'? ===\"\nSelect-String -Path scripts\\extract.mjs -Pattern \"group|flock|several|couple|pair\" | ForEach-Object { \"   \" + $_.Line.Trim() }","timeout":300000}&lt;/code&gt;&lt;/pre&gt;
                    &lt;/div&gt;
                    &lt;div class="tool-section"&gt;
                      &lt;div class="tool-section-label"&gt;Output&lt;/div&gt;
                      &lt;pre class="agent-session-pre"&gt;&lt;code&gt;=== Common Myna in the Chidambaram pack? ===
  Common Myna (Acridotheres tristis)  rank=species  observations=23
  pack size: 130 species

  other starlings/mynas in pack:
    starling: Brahminy Starling, Indian Pied Starling
    myna: Common Myna

=== does extract.mjs understand 'group' / 'flock'? ===
Select-String : Cannot find path '[redacted:home-path]\hacktoberfest\chidambaram-birdnudge\scripts\extract.mjs' because it 
does not exist.
At line:16 char:1
+ Select-String -Path scripts\extract.mjs -Pattern "group|flock|several ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : ObjectNotFound: ([redacted:home-path]\...pts\extract.mjs:String) [Select-String], ItemNotFound 
   Exception
    + FullyQualifiedErrorId : PathNotFound,Microsoft.PowerShell.Commands.SelectStringCommand
 
&lt;/code&gt;&lt;/pre&gt;
                    &lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
        &lt;/div&gt;
      &lt;/div&gt;

      &lt;div class="agent-session-message agent-session-assistant"&gt;
        &lt;div class="agent-session-role-badge agent-session-role-assistant"&gt;
          Agent
        &lt;/div&gt;
        &lt;div class="agent-session-content"&gt;
                &lt;div class="agent-session-text"&gt;
                  &lt;p&gt;&lt;strong&gt;Common Myna confirmed in the pack&lt;/strong&gt; - 23 observations, and notably the pack contains Brahminy Starling and Indian Pied Starling but &lt;strong&gt;no Common Starling&lt;/strong&gt;. That matters. Let me confirm one suspicion:&lt;/p&gt;

                &lt;/div&gt;
              &lt;div class="agent-session-tool-call"&gt;
                
                  &lt;span class="agent-session-chevron"&gt;▸&lt;/span&gt;
                  &lt;span class="tool-name tool-name-bash"&gt;bash&lt;/span&gt;
                    &lt;span class="tool-input-preview"&gt;{"command":"$ErrorActionPreference='Continue'\ncd [redacted:home-path]\\hackt...&lt;/span&gt;
                
                &lt;div class="agent-session-tool-detail"&gt;
                    &lt;div class="tool-section"&gt;
                      &lt;div class="tool-section-label"&gt;Input&lt;/div&gt;
                      &lt;pre class="agent-session-pre agent-session-terminal"&gt;&lt;code&gt;$ {"command":"$ErrorActionPreference='Continue'\ncd [redacted:home-path]\\hacktoberfest\\chidambaram-birdnudge\nWrite-Output \"=== pack.json: is the 'rank' field a number or a taxonomic rank? ===\"\nnode -e \"\nconst p=require('./data/pack.json');\nconsole.log('  first 3 entries:');\np.species.slice(0,3).forEach(s=&amp;gt;console.log('    rank='+JSON.stringify(s.rank)+'  common='+s.common));\nconsole.log('  distinct rank values across all 130: ' + JSON.stringify([...new Set(p.species.map(s=&amp;gt;s.rank))]));\n\"\nWrite-Output \"\"\nWrite-Output \"=== how project 1 matches species (scientific only?) ===\"\nSelect-String -Path scripts\\nudge.mjs -Pattern \"binomial|scientific|common\" | Select-Object -First 6 | ForEach-Object { \"   \" + $_.Line.Trim() }\nWrite-Output \"\"\nWrite-Output \"=== README 'not built yet' section ===\"\n$idx = (Select-String -Path README.md -Pattern \"^## Not built yet\").LineNumber\n(Get-Content README.md)[($idx-1)..($idx+9)] | ForEach-Object { \"   $_\" }","timeout":300000}&lt;/code&gt;&lt;/pre&gt;
                    &lt;/div&gt;
                    &lt;div class="tool-section"&gt;
                      &lt;div class="tool-section-label"&gt;Output&lt;/div&gt;
                      &lt;pre class="agent-session-pre"&gt;&lt;code&gt;=== pack.json: is the 'rank' field a number or a taxonomic rank? ===
  first 3 entries:
    rank="species"  common=House Crow
    rank="species"  common=Little Egret
    rank="species"  common=Black Drongo
  distinct rank values across all 130: ["species"]

=== how project 1 matches species (scientific only?) ===
   function binomial(name) {
   const cSci = header.indexOf("scientific_name");
   const cCom = header.indexOf("common_name");
   .map((f) =&amp;gt; ({ scientific: f[cSci] ?? "", common: f[cCom] ?? "", confidence: Number(f[cCon]) }))
   const key = binomial(r.scientific);
   if (!k.startsWith(prefix)) map.set(binomial(k), v);

=== README 'not built yet' section ===
   ## Not built yet
   
   Stated plainly so nobody assumes otherwise:
   
   - No microphone capture, so audio still has to be recorded separately
   - No local fine-tuning; the model is used as-is
   - No PWA packaging and no hosted demo
   - WAV only. No m4a or ogg decoding without ffmpeg on PATH
   - Seasonal notes are hand-curated for roughly the top 45 species in the pack
   - Place coordinates in `data/spots.json` are approximate and need verifying
   - Distances and travel times are not precomputed because they depend on where you
&lt;/code&gt;&lt;/pre&gt;
                    &lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
        &lt;/div&gt;
      &lt;/div&gt;

      &lt;div class="agent-session-message agent-session-assistant"&gt;
        &lt;div class="agent-session-role-badge agent-session-role-assistant"&gt;
          Agent
        &lt;/div&gt;
        &lt;div class="agent-session-content"&gt;
                &lt;div&gt;
                  &lt;div class="agent-session-text agent-session-text-collapse"&gt;
                    &lt;p&gt;Common Myna is in the pack (23 observations). But I need to be honest with you about the test case, because it matters for how the post reads.&lt;/p&gt;
&lt;h2 id="agent-session-751-3-common-myna-is-the-easiest-possible-test"&gt;Common Myna is the &lt;em&gt;easiest&lt;/em&gt; possible test&lt;/h2&gt;

&lt;p&gt;It's one of the loudest, most distinctive, most-recorded birds in India - Xeno-canto is saturated with it. If BirdNET names it correctly, that tells you almost nothing about regional weakness. It just confirms the model works on an easy target, with n=1.&lt;/p&gt;

&lt;p&gt;I marked it &lt;code&gt;ubiquitous&lt;/code&gt; in the fieldnote pack precisely because it's the &lt;em&gt;worst&lt;/em&gt; possible "go outside now" trigger - hearable from your desk all day. Good for detection testing, useless as a nudge.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;So don't build the case study around "did it get the myna right."&lt;/strong&gt; Build it around the &lt;strong&gt;tail&lt;/strong&gt;: even on a correct detection, BirdNET emits 11,560 classes and a long junk tail above 0.05. The story is &lt;em&gt;what else it said&lt;/em&gt; - the confident non-local predictions, and what fraction of its output was locally plausible. A correct top-1 with40 nonsense runners-up is a more interesting result than a clean single prediction, and it still supports the thesis.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Your indoor/outdoor split is genuinely useful&lt;/strong&gt; - that gives acoustic contrast from the same species at the same location. Indoor hostel means ventilation noise and people; outdoor campus is open-air. That's a controlled comparison of exactly the variable I flagged as the risk.&lt;/p&gt;
&lt;h2 id="agent-session-751-3-two-real-bugs-found"&gt;Two real bugs found&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;1. &lt;code&gt;rank&lt;/code&gt; is clobbered in all 130 pack entries&lt;/strong&gt; - &lt;code&gt;"species"&lt;/code&gt; instead of a number. I wrote &lt;code&gt;{ rank: i + 1, ...s }&lt;/code&gt; and the spread lands &lt;em&gt;after&lt;/em&gt;, so iNat's own taxonomic &lt;code&gt;rank&lt;/code&gt; field overwrites mine. Classic ordering bug, invisible because the array is still sorted correctly.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. &lt;code&gt;docs/overview.md&lt;/code&gt; is gitignored&lt;/strong&gt; - the repo publishes &lt;strong&gt;zero results&lt;/strong&gt;. Anyone cloning it sees a pipeline and a negative control, but no findings. Fieldnote got this right (&lt;code&gt;docs/eval.md&lt;/code&gt; is committed); project 1 never got the equivalent.&lt;/p&gt;
&lt;h1 id="agent-session-751-3-plan"&gt;Plan&lt;/h1&gt;

&lt;p&gt;&lt;strong&gt;Phase 1 - no audio needed, ~45 min&lt;/strong&gt;&lt;br&gt;
1. Fix the &lt;code&gt;rank&lt;/code&gt; spread-order bug&lt;br&gt;
2. Un-ignore &lt;code&gt;docs/overview.md&lt;/code&gt;, commit results as a tracked artefact&lt;br&gt;
3. Add the all-detections metric (higher count, lower variance - this is what makes a small n credible)&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Phase 2 - needs your audio, ~1 hr&lt;/strong&gt;&lt;br&gt;
4. Install ffmpeg (&lt;code&gt;Gyan.FFmpeg&lt;/code&gt;, winget)&lt;br&gt;
5. &lt;code&gt;scripts/convert.mjs&lt;/code&gt; - batch convert a folder, one command&lt;br&gt;
6. &lt;code&gt;scripts/case.mjs&lt;/code&gt; - produces &lt;code&gt;docs/case-report.md&lt;/code&gt;: your observation, BirdNET's full ranked output, top-1 match, rank of the observed species, in-pack fraction, and an explicit list of non-local predictions&lt;br&gt;
7. Run on both the indoor and outdoor myna clips&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Phase 3 - ~1 hr&lt;/strong&gt;&lt;br&gt;
8. README updated with the honest framing&lt;br&gt;
9. Post drafted from &lt;code&gt;docs/case-report.md&lt;/code&gt;&lt;/p&gt;
&lt;h2 id="agent-session-751-3-three-things-i-still-need"&gt;Three things I still need&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;How many clips, and do you have both indoor and outdoor separately?&lt;/strong&gt; The indoor/outdoor contrast is the most valuable thing you have - please keep them as distinct files.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Is there speech or identifiable people in the indoor audio?&lt;/strong&gt; Hostel recordings usually do. If so we trim, or report text-only and don't publish the audio.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Are you comfortable publishing the audio at all?&lt;/strong&gt; If you'd rather not name the hostel or have voices audible, say so and I'll design around it. Better to know now than after it's pushed.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="agent-session-751-3-what-to-grab-from-the-birdnet-app"&gt;What to grab from the BirdNET app&lt;/h2&gt;

&lt;p&gt;Since you're checking it anyway, the useful comparison is &lt;strong&gt;app output vs our local pipeline on the same file.&lt;/strong&gt; Not ground truth - same family of model - but if they disagree, that's worth knowing (different model version, or server-side vs local inference). Worth noting if the app returns European species for your Indian audio.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;One warning:&lt;/strong&gt; if you checked the bird ID &lt;em&gt;using the BirdNET app&lt;/em&gt; before deciding it was Common Myna, that's not independent ground truth - it's the same model telling you what it told you. You said you saw them, so your own observation is the label. If the app is what convinced you, tell me and I'll frame it as agreement-between-models rather than a confirmed identification.&lt;/p&gt;

&lt;p&gt;Want me to start Phase 1 now? It's independent of the audio and gets the two bugs fixed before results depend on them.&lt;/p&gt;

                  &lt;/div&gt;
                  Show more
                &lt;/div&gt;
        &lt;/div&gt;
      &lt;/div&gt;

      &lt;div class="agent-session-message agent-session-user"&gt;
        &lt;div class="agent-session-role-badge agent-session-role-user"&gt;
          You
        &lt;/div&gt;
        &lt;div class="agent-session-content"&gt;
                &lt;div class="agent-session-text"&gt;
                  &lt;p&gt;oh its not common myna it is yellow-billed babblerat 65.8% confidernce of Argy affinis species and well start the process budd&lt;/p&gt;

                &lt;/div&gt;
        &lt;/div&gt;
      &lt;/div&gt;

      &lt;div class="agent-session-message agent-session-assistant"&gt;
        &lt;div class="agent-session-role-badge agent-session-role-assistant"&gt;
          Agent
        &lt;/div&gt;
        &lt;div class="agent-session-content"&gt;
                &lt;div class="agent-session-text"&gt;
                  &lt;p&gt;&lt;strong&gt;Yellow-billed Babbler&lt;/strong&gt; - much better test case than Common Myna, and a good find. Let me verify it against the pack before I start.&lt;/p&gt;

                &lt;/div&gt;
              &lt;div class="agent-session-tool-call"&gt;
                
                  &lt;span class="agent-session-chevron"&gt;▸&lt;/span&gt;
                  &lt;span class="tool-name tool-name-bash"&gt;bash&lt;/span&gt;
                    &lt;span class="tool-input-preview"&gt;{"command":"$ErrorActionPreference='Continue'\ncd [redacted:home-path]\\hackt...&lt;/span&gt;
                
                &lt;div class="agent-session-tool-detail"&gt;
                    &lt;div class="tool-section"&gt;
                      &lt;div class="tool-section-label"&gt;Input&lt;/div&gt;
                      &lt;pre class="agent-session-pre agent-session-terminal"&gt;&lt;code&gt;$ {"command":"$ErrorActionPreference='Continue'\ncd [redacted:home-path]\\hacktoberfest\\chidambaram-birdnudge\nnode -e \"\nconst p=require('./data/pack.json');\nconst hits=p.species.filter(s=&amp;gt;/Argya affinis/i.test(s.scientific));\nif(hits.length){const s=hits[0];console.log('  IN PACK: '+s.common+' ('+s.scientific+')');console.log('  observations: '+s.observations+'   position in sorted pack: '+(p.species.findIndex(x=&amp;gt;x.scientific===s.scientific)+1));}\nelse console.log('  NOT IN PACK');\nconsole.log('');\nconsole.log('  all Argya babblers in pack:');\np.species.filter(s=&amp;gt;/Argya/i.test(s.scientific)).forEach(s=&amp;gt;console.log('    '+s.common+' ('+s.scientific+') obs='+s.observations));\n\"\nWrite-Output \"\"\nWrite-Output \"=== is it in seasonal.json (for the nudge layer)? ===\"\nSelect-String -Path data\\seasonal.json -Pattern \"Argya affinis\" | ForEach-Object { \"   \" + $_.Line.Trim() }","timeout":300000}&lt;/code&gt;&lt;/pre&gt;
                    &lt;/div&gt;
                    &lt;div class="tool-section"&gt;
                      &lt;div class="tool-section-label"&gt;Output&lt;/div&gt;
                      &lt;pre class="agent-session-pre"&gt;&lt;code&gt;  IN PACK: Yellow-billed Babbler (Argya affinis)
  observations: 19   position in sorted pack: 18

  all Argya babblers in pack:
    Yellow-billed Babbler (Argya affinis) obs=19

=== is it in seasonal.json (for the nudge layer)? ===
   "Argya affinis": { "common": "Yellow-billed Babbler", "season": "year-round", "active": "day", "spotType": "open scrub / roadside", "cue": "Noisy chattering groups moving through scrub" },
&lt;/code&gt;&lt;/pre&gt;
                    &lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
        &lt;/div&gt;
      &lt;/div&gt;

      &lt;div class="agent-session-message agent-session-assistant"&gt;
        &lt;div class="agent-session-role-badge agent-session-role-assistant"&gt;
          Agent
        &lt;/div&gt;
        &lt;div class="agent-session-content"&gt;
                &lt;div class="agent-session-text"&gt;
                  &lt;p&gt;&lt;strong&gt;Yellow-billed Babbler is in the pack&lt;/strong&gt; - position 18, 19 observations, and &lt;code&gt;seasonal.json&lt;/code&gt; already describes it as &lt;em&gt;"noisy chattering groups moving through scrub, day, open scrub/roadside."&lt;/em&gt; That matches what you saw almost exactly.&lt;/p&gt;

&lt;p&gt;One thing I'll hold onto for the report: the 65.8% came &lt;em&gt;from the BirdNET app&lt;/em&gt;. Your observation is the ground truth; the app is a second voice agreeing. That's fine - but I won't write it up as the model confirming an independent identification. Not belabouring it, just noting the framing.&lt;/p&gt;

&lt;p&gt;Starting Phase 1. First bug - the clobbered &lt;code&gt;rank&lt;/code&gt;:&lt;/p&gt;

                &lt;/div&gt;
              &lt;div class="agent-session-tool-call"&gt;
                
                  &lt;span class="agent-session-chevron"&gt;▸&lt;/span&gt;
                  &lt;span class="tool-name tool-name-edit"&gt;edit&lt;/span&gt;
                    &lt;span class="tool-input-preview"&gt;{"filePath":"[redacted:home-path]\\hacktoberfest\\chidambaram-birdnudge\\scri...&lt;/span&gt;
                
                &lt;div class="agent-session-tool-detail"&gt;
                    &lt;div class="tool-section"&gt;
                      &lt;div class="tool-section-label"&gt;Input&lt;/div&gt;
                      &lt;pre class="agent-session-pre highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"filePath"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"[redacted:home-path]&lt;/span&gt;&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="s2"&gt;hacktoberfest&lt;/span&gt;&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="s2"&gt;chidambaram-birdnudge&lt;/span&gt;&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="s2"&gt;scripts&lt;/span&gt;&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="s2"&gt;fetch-pack.mjs"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"newString"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"count: kept.length,&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;    species: kept.map((s, i) =&amp;gt; ({ ...s, taxonomicRank: s.rank, rank: i + 1 })),"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"oldString"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"count: kept.length,&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;    species: kept.map((s, i) =&amp;gt; ({ rank: i + 1, ...s })),"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
                    &lt;/div&gt;
                    &lt;div class="tool-section"&gt;
                      &lt;div class="tool-section-label"&gt;Output&lt;/div&gt;
                      &lt;pre class="agent-session-pre"&gt;&lt;code&gt;Edit applied successfully.&lt;/code&gt;&lt;/pre&gt;
                    &lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
        &lt;/div&gt;
      &lt;/div&gt;

      &lt;div class="agent-session-message agent-session-assistant"&gt;
        &lt;div class="agent-session-role-badge agent-session-role-assistant"&gt;
          Agent
        &lt;/div&gt;
        &lt;div class="agent-session-content"&gt;
              &lt;div class="agent-session-tool-call"&gt;
                
                  &lt;span class="agent-session-chevron"&gt;▸&lt;/span&gt;
                  &lt;span class="tool-name tool-name-edit"&gt;edit&lt;/span&gt;
                    &lt;span class="tool-input-preview"&gt;{"filePath":"[redacted:home-path]\\hacktoberfest\\chidambaram-birdnudge\\scri...&lt;/span&gt;
                
                &lt;div class="agent-session-tool-detail"&gt;
                    &lt;div class="tool-section"&gt;
                      &lt;div class="tool-section-label"&gt;Input&lt;/div&gt;
                      &lt;pre class="agent-session-pre highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"filePath"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"[redacted:home-path]&lt;/span&gt;&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="s2"&gt;hacktoberfest&lt;/span&gt;&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="s2"&gt;chidambaram-birdnudge&lt;/span&gt;&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="s2"&gt;scripts&lt;/span&gt;&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="s2"&gt;fetch-pack.mjs"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"newString"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"const record = {&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;        inatTaxonId: taxon.id ?? null,&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;        scientific: name,&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;        common: taxon.preferred_common_name ?? taxon.common_name ?? null,&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;        taxonomicRank: taxon.rank ?? null,&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;        observations: row.count ?? 0,&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;        photoUrl: taxon.default_photo?.medium_url ?? null,&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;        key: fullKey(name),&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;        binomial: binomialKey(name),&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;      };"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"oldString"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"const record = {&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;        inatTaxonId: taxon.id ?? null,&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;        scientific: name,&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;        common: taxon.preferred_common_name ?? taxon.common_name ?? null,&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;        rank: taxon.rank ?? null,&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;        observations: row.count ?? 0,&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;        photoUrl: taxon.default_photo?.medium_url ?? null,&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;        key: fullKey(name),&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;        binomial: binomialKey(name),&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;      };"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
                    &lt;/div&gt;
                    &lt;div class="tool-section"&gt;
                      &lt;div class="tool-section-label"&gt;Output&lt;/div&gt;
                      &lt;pre class="agent-session-pre"&gt;&lt;code&gt;Edit applied successfully.&lt;/code&gt;&lt;/pre&gt;
                    &lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
        &lt;/div&gt;
      &lt;/div&gt;

      &lt;div class="agent-session-message agent-session-assistant"&gt;
        &lt;div class="agent-session-role-badge agent-session-role-assistant"&gt;
          Agent
        &lt;/div&gt;
        &lt;div class="agent-session-content"&gt;
              &lt;div class="agent-session-tool-call"&gt;
                
                  &lt;span class="agent-session-chevron"&gt;▸&lt;/span&gt;
                  &lt;span class="tool-name tool-name-bash"&gt;bash&lt;/span&gt;
                    &lt;span class="tool-input-preview"&gt;{"command":"$ErrorActionPreference='Continue'\ncd [redacted:home-path]\\hackt...&lt;/span&gt;
                
                &lt;div class="agent-session-tool-detail"&gt;
                    &lt;div class="tool-section"&gt;
                      &lt;div class="tool-section-label"&gt;Input&lt;/div&gt;
                      &lt;pre class="agent-session-pre agent-session-terminal"&gt;&lt;code&gt;$ {"command":"$ErrorActionPreference='Continue'\ncd [redacted:home-path]\\hacktoberfest\\chidambaram-birdnudge\nnode scripts\\fetch-pack.mjs 2&amp;gt;&amp;amp;1 | Select-Object -First 6\nWrite-Output \"\"\nWrite-Output \"=== rank field now numeric? ===\"\nnode -e \"\nconst p=require('./data/pack.json');\np.species.slice(0,4).forEach(s=&amp;gt;console.log('  rank='+s.rank+'  taxRank='+s.taxonomicRank+'  '+s.common));\nconsole.log('  distinct rank types: '+JSON.stringify([...new Set(p.species.map(s=&amp;gt;typeof s.rank))]));\nconsole.log('  distinct rank values: '+JSON.stringify([...new Set(p.species.map(s=&amp;gt;s.rank))].slice(0,6))+' ...');\nconst b=p.species.find(s=&amp;gt;/Argya affinis/i.test(s.scientific));\nconsole.log('  Yellow-billed Babbler rank = '+b.rank+'  (was broken before)');\n\"","timeout":300000}&lt;/code&gt;&lt;/pre&gt;
                    &lt;/div&gt;
                    &lt;div class="tool-section"&gt;
                      &lt;div class="tool-section-label"&gt;Output&lt;/div&gt;
                      &lt;pre class="agent-session-pre"&gt;&lt;code&gt;Fetching Aves within 30 km of Chidambaram, Tamil Nadu, India ...
Hub reports 165 species in range.
Kept 130 with &amp;gt;= 2 observations.
Wrote [redacted:home-path]\hacktoberfest\chidambaram-birdnudge\data\pack.json
    1. Corvus splendens - House Crow
    2. Egretta garzetta - Little Egret

=== rank field now numeric? ===
  rank=1  taxRank=undefined  House Crow
  rank=2  taxRank=undefined  Little Egret
  rank=3  taxRank=undefined  Black Drongo
  rank=4  taxRank=undefined  Great Egret
  distinct rank types: ["number"]
  distinct rank values: [1,2,3,4,5,6] ...
  Yellow-billed Babbler rank = 18  (was broken before)
&lt;/code&gt;&lt;/pre&gt;
                    &lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
        &lt;/div&gt;
      &lt;/div&gt;

      &lt;div class="agent-session-message agent-session-assistant"&gt;
        &lt;div class="agent-session-role-badge agent-session-role-assistant"&gt;
          Agent
        &lt;/div&gt;
        &lt;div class="agent-session-content"&gt;
                &lt;div class="agent-session-text"&gt;
                  &lt;p&gt;&lt;code&gt;rank&lt;/code&gt; is numeric now (Yellow-billed Babbler = 18). &lt;code&gt;taxonomicRank&lt;/code&gt; is undefined because my edit to the record object didn't take effect - checking:&lt;/p&gt;

                &lt;/div&gt;
              &lt;div class="agent-session-tool-call"&gt;
                
                  &lt;span class="agent-session-chevron"&gt;▸&lt;/span&gt;
                  &lt;span class="tool-name tool-name-bash"&gt;bash&lt;/span&gt;
                    &lt;span class="tool-input-preview"&gt;{"command":"$ErrorActionPreference='Continue'\ncd [redacted:home-path]\\hackt...&lt;/span&gt;
                
                &lt;div class="agent-session-tool-detail"&gt;
                    &lt;div class="tool-section"&gt;
                      &lt;div class="tool-section-label"&gt;Input&lt;/div&gt;
                      &lt;pre class="agent-session-pre agent-session-terminal"&gt;&lt;code&gt;$ {"command":"$ErrorActionPreference='Continue'\ncd [redacted:home-path]\\hacktoberfest\\chidambaram-birdnudge\nSelect-String -Path scripts\\fetch-pack.mjs -Pattern \"rank\" | ForEach-Object { \"{0,4}: {1}\" -f $_.LineNumber, $_.Line.Trim() }"}&lt;/code&gt;&lt;/pre&gt;
                    &lt;/div&gt;
                    &lt;div class="tool-section"&gt;
                      &lt;div class="tool-section-label"&gt;Output&lt;/div&gt;
                      &lt;pre class="agent-session-pre"&gt;&lt;code&gt;  77: taxonomicRank: taxon.rank ?? null,
 120: species: kept.map((s, i) =&amp;gt; ({ ...s, taxonomicRank: s.rank, rank: i + 1 })),
&lt;/code&gt;&lt;/pre&gt;
                    &lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
        &lt;/div&gt;
      &lt;/div&gt;

      &lt;div class="agent-session-message agent-session-assistant"&gt;
        &lt;div class="agent-session-role-badge agent-session-role-assistant"&gt;
          Agent
        &lt;/div&gt;
        &lt;div class="agent-session-content"&gt;
              &lt;div class="agent-session-tool-call"&gt;
                
                  &lt;span class="agent-session-chevron"&gt;▸&lt;/span&gt;
                  &lt;span class="tool-name tool-name-edit"&gt;edit&lt;/span&gt;
                    &lt;span class="tool-input-preview"&gt;{"oldString":"species: kept.map((s, i) =&amp;gt; ({ ...s, taxonomicRank: s.rank, ran...&lt;/span&gt;
                
                &lt;div class="agent-session-tool-detail"&gt;
                    &lt;div class="tool-section"&gt;
                      &lt;div class="tool-section-label"&gt;Input&lt;/div&gt;
                      &lt;pre class="agent-session-pre highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"oldString"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"species: kept.map((s, i) =&amp;gt; ({ ...s, taxonomicRank: s.rank, rank: i + 1 })),"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"filePath"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"[redacted:home-path]&lt;/span&gt;&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="s2"&gt;hacktoberfest&lt;/span&gt;&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="s2"&gt;chidambaram-birdnudge&lt;/span&gt;&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="s2"&gt;scripts&lt;/span&gt;&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="s2"&gt;fetch-pack.mjs"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"newString"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"species: kept.map((s, i) =&amp;gt; ({ ...s, rank: i + 1 })),"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
                    &lt;/div&gt;
                    &lt;div class="tool-section"&gt;
                      &lt;div class="tool-section-label"&gt;Output&lt;/div&gt;
                      &lt;pre class="agent-session-pre"&gt;&lt;code&gt;Edit applied successfully.&lt;/code&gt;&lt;/pre&gt;
                    &lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
        &lt;/div&gt;
      &lt;/div&gt;

      &lt;div class="agent-session-message agent-session-assistant"&gt;
        &lt;div class="agent-session-role-badge agent-session-role-assistant"&gt;
          Agent
        &lt;/div&gt;
        &lt;div class="agent-session-content"&gt;
              &lt;div class="agent-session-tool-call"&gt;
                
                  &lt;span class="agent-session-chevron"&gt;▸&lt;/span&gt;
                  &lt;span class="tool-name tool-name-bash"&gt;bash&lt;/span&gt;
                    &lt;span class="tool-input-preview"&gt;{"command":"$ErrorActionPreference='Continue'\ncd [redacted:home-path]\\hackt...&lt;/span&gt;
                
                &lt;div class="agent-session-tool-detail"&gt;
                    &lt;div class="tool-section"&gt;
                      &lt;div class="tool-section-label"&gt;Input&lt;/div&gt;
                      &lt;pre class="agent-session-pre agent-session-terminal"&gt;&lt;code&gt;$ {"command":"$ErrorActionPreference='Continue'\ncd [redacted:home-path]\\hacktoberfest\\chidambaram-birdnudge\nnode scripts\\fetch-pack.mjs 2&amp;gt;&amp;amp;1 | Select-Object -First 3\nnode -e \"\nconst p=require('./data/pack.json');\nconsole.log('');\nconsole.log('  rank field    : '+JSON.stringify([...new Set(p.species.map(s=&amp;gt;typeof s.rank))])+' values '+[...new Set(p.species.map(s=&amp;gt;s.rank))].slice(0,5));\nconsole.log('  taxRank field : '+JSON.stringify([...new Set(p.species.map(s=&amp;gt;typeof s.taxonomicRank))])+' values '+JSON.stringify([...new Set(p.species.map(s=&amp;gt;s.taxonomicRank))].slice(0,4)));\n\"\nWrite-Output \"\"\nWrite-Output \"=== nudge.mjs uses hit.rank - check what it displays ===\"\nSelect-String -Path scripts\\nudge.mjs -Pattern \"localRank|hit\\.rank|rank\" | ForEach-Object { \"   \" + $_.Line.Trim() }","timeout":300000}&lt;/code&gt;&lt;/pre&gt;
                    &lt;/div&gt;
                    &lt;div class="tool-section"&gt;
                      &lt;div class="tool-section-label"&gt;Output&lt;/div&gt;
                      &lt;pre class="agent-session-pre"&gt;&lt;code&gt;Fetching Aves within 30 km of Chidambaram, Tamil Nadu, India ...
Hub reports 165 species in range.
Kept 130 with &amp;gt;= 2 observations.

  rank field    : ["number"] values 1,2,3,4,5
  taxRank field : ["string"] values ["species"]

=== nudge.mjs uses hit.rank - check what it displays ===
&lt;/code&gt;&lt;/pre&gt;
                    &lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
        &lt;/div&gt;
      &lt;/div&gt;
  &lt;/div&gt;

  &lt;div class="agent-session-footer"&gt;
    &lt;span class="agent-session-meta"&gt;
        12 of 12 messages
    &lt;/span&gt;
  &lt;/div&gt;
&lt;/div&gt;



&lt;p&gt;&lt;em&gt;&lt;a href="https://dev.to/agent_sessions/debugging-a-clobbered-rank-field-in-fetch-packmjs-opencode-ot6g6e"&gt;View this session on DEV&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;This project was built end to end with an AI coding agent (opencode, tracked with DevRelay). The interesting part is not that it worked, but the two places where it did not:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The &lt;code&gt;rank&lt;/code&gt; bug above survived several rounds because the agent optimised the thing I asked about and the symptom I noticed - ordering - happened to still be correct.&lt;/li&gt;
&lt;li&gt;A &lt;code&gt;ffmpeg&lt;/code&gt; download was corrupted twice in transit, producing a 66 MB "executable" that Windows rejected with &lt;em&gt;"not a valid application for this OS platform."&lt;/em&gt; The PE header was valid and the machine type was correct; the file was truncated. Diagnosing that took longer than installing ffmpeg should have.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A third failure worth naming: I spent a deadline-night attempt adding a local Gemma 3 270M model to write the field brief in plain English. It ran, and every single output was invented - weather forecasts at 35 C, links to websites that do not exist, and not one mention of the bird it was supposed to describe. I deleted the feature rather than ship a birder being sent to check a website. The detection and the species filter are the project. The prose was decoration, and bad decoration is worse than none.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Overall&lt;/strong&gt; - this is what I am actually aiming for&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Best Use of Entire&lt;/strong&gt; - the project was built end to end in an agent session, the session above is embedded, and the write-up is the account of where that help stopped being useful&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I considered claiming DigitalOcean and Render and deliberately did not. Deploying a deliberately-offline tool to a cloud runtime to win a hosting prize would contradict the entire premise of the project. Same reasoning for Sentry Agent Tracing - this is deterministic DSP with an ONNX model, no LLM calls, no tokens, no spans to trace.&lt;/p&gt;

&lt;h2&gt;
  
  
  Full write-up
&lt;/h2&gt;

&lt;p&gt;The complete case study, including the control methodology and every non-local species the model proposed, is in the repo: &lt;a href="https://github.com/Emanuelmsjv/chidambaram-birdnudge/blob/main/docs/case-report.md" rel="noopener noreferrer"&gt;docs/case-report.md&lt;/a&gt;&lt;/p&gt;

</description>
      <category>hf26challenge</category>
      <category>opensource</category>
      <category>birds</category>
      <category>devchallenge</category>
    </item>
    <item>
      <title>The Bricks</title>
      <dc:creator>Melwin Siril Joel V</dc:creator>
      <pubDate>Thu, 13 Aug 2026 02:19:02 +0000</pubDate>
      <link>https://dev.to/cadets_atease/the-bricks-3h3e</link>
      <guid>https://dev.to/cadets_atease/the-bricks-3h3e</guid>
      <description>&lt;h2&gt;
  
  
  Meet the Builder: Melwin Siril Joel
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Building open source, one mobile commit at a time.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Who I Am
&lt;/h2&gt;

&lt;p&gt;I'm Melwin Siril Joel, a second-year B.E. Computer Science Engineering student at Annamalai University, Chidambaram, Tamil Nadu. Beyond the classroom, I'm an NCC Army Wing Cadet and an active open source contributor — a combination that's taught me as much about discipline and problem-solving as any textbook has.&lt;/p&gt;

&lt;p&gt;What makes my journey a little different: I build almost entirely from my phone.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Mobile-Only Developer
&lt;/h2&gt;

&lt;p&gt;Most tutorials assume you have a laptop. I didn't always have that luxury, so I turned constraint into a workflow. Using &lt;strong&gt;Termux&lt;/strong&gt; and &lt;strong&gt;GitHub Mobile&lt;/strong&gt;, I learned to navigate the full open source contribution pipeline — cloning repos, writing code, running tests, and submitting pull requests — all from an Android device. It's slower than a full IDE setup, but it forced me to understand every step instead of relying on one-click conveniences.&lt;/p&gt;

&lt;h2&gt;
  
  
  Open Source Contributions
&lt;/h2&gt;

&lt;p&gt;My open source journey took shape through real, merged code:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;MapLibre Martin&lt;/strong&gt; — Contributed and got PR #2583 merged, documenting a binary diff process for &lt;code&gt;.mbtiles&lt;/code&gt; files.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;maplibre-agent-skills&lt;/strong&gt; — Opened and worked on PR #31 and PR #30.&lt;/li&gt;
&lt;li&gt;Participated in &lt;strong&gt;FOSShack 2026&lt;/strong&gt;, &lt;strong&gt;GSSoC 2026&lt;/strong&gt; (Open Source Track), and &lt;strong&gt;Nexus: Spring of Code&lt;/strong&gt; — three programs that pushed me to contribute consistently and learn how real-world open source communities operate.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Each of these wasn't just a line on a resume — it was a lesson in navigating unfamiliar codebases, communicating with maintainers, and shipping something that actually got used.&lt;/p&gt;

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

&lt;p&gt;I balance my technical work with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;NCC Army Wing Cadet duties&lt;/strong&gt;, including completing the CATC camp — a reminder that discipline off-screen sharpens focus on-screen.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Competitive chess&lt;/strong&gt;, representing Annamalai University in the Chief Minister's Trophy 2026 (Tamil Nadu) in the College category.&lt;/li&gt;
&lt;li&gt;Early groundwork on &lt;strong&gt;campus community building&lt;/strong&gt; — exploring things like FOSS United Campus Clubs and GDG on Campus to help bring open source culture to my university.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What Drives Me
&lt;/h2&gt;

&lt;p&gt;I'm drawn to open source because it rewards persistence over privilege. You don't need the best hardware or a head start — you need curiosity and the willingness to figure things out. That philosophy is what took me from learning C++ and Python fundamentals as a first-year student to shipping merged pull requests on real projects, all from a phone screen.&lt;/p&gt;

&lt;p&gt;I'm just getting started — and I'm building in public, one commit at a time.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Melwin Siril Joel | B.E. CSE, Annamalai University | Open Source Contributor | NCC Cadet&lt;/em&gt;&lt;/p&gt;

</description>
      <category>learning</category>
      <category>devjournal</category>
    </item>
  </channel>
</rss>
