<?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: Srishti Pandey</title>
    <description>The latest articles on DEV Community by Srishti Pandey (@srishti_pandey_18fdfe4cdf).</description>
    <link>https://dev.to/srishti_pandey_18fdfe4cdf</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F2617099%2Fc62ac7e6-2735-439c-a32c-49dd07dbec61.gif</url>
      <title>DEV Community: Srishti Pandey</title>
      <link>https://dev.to/srishti_pandey_18fdfe4cdf</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/srishti_pandey_18fdfe4cdf"/>
    <language>en</language>
    <item>
      <title>CODEOWNERS Is a Lie. I Built a Graph to Prove It.</title>
      <dc:creator>Srishti Pandey</dc:creator>
      <pubDate>Sun, 18 Oct 2026 16:11:09 +0000</pubDate>
      <link>https://dev.to/srishti_pandey_18fdfe4cdf/codeowners-is-a-lie-i-built-a-graph-to-prove-it-c6</link>
      <guid>https://dev.to/srishti_pandey_18fdfe4cdf/codeowners-is-a-lie-i-built-a-graph-to-prove-it-c6</guid>
      <description>&lt;p&gt;Every code repository has a file that says who owns each part of the code. Nobody fully trusts that file, and there’s a good reason. People change teams. People leave projects. The file never updates itself when that happens.&lt;/p&gt;

&lt;p&gt;I wanted to know how wrong that file actually is, and whether a graph database could measure the gap instead of just storing data.&lt;/p&gt;

&lt;h2&gt;
  
  
  The setup
&lt;/h2&gt;

&lt;p&gt;I took every pull request merged into Home Assistant’s core repository over 180 days. About 10,000 pull requests, 1,600 modules, 1,500 contributors. I loaded all of it into FalkorDB: people, modules, pull requests, and decisions as nodes. The connections between them (who wrote what, who reviewed what, which modules depend on which, and who’s listed as the owner) became edges.&lt;/p&gt;

&lt;p&gt;The first thing I checked was simple: when a pull request touches a module, does the listed owner actually review it?&lt;/p&gt;

&lt;p&gt;Across the whole dataset, the listed owner was the real reviewer only about 14% of the time. That’s not a small error. That means the ownership file is wrong most of the time.&lt;/p&gt;

&lt;h2&gt;
  
  
  Making the graph do the thinking
&lt;/h2&gt;

&lt;p&gt;A normal database can answer “who reviewed pull request #4512.” It struggles with “what breaks if this person stops reviewing,” because that question needs several steps: find the modules this person maintains, find who else has touched those modules recently, find the ones with nobody left, then find everything that depends on those.&lt;/p&gt;

&lt;p&gt;That’s a few lines of Cypher in FalkorDB. I used variable-length path matching to trace dependencies several steps deep, and FalkorDB’s built-in PageRank to rank which modules matter most based on how much depends on them.&lt;/p&gt;

&lt;p&gt;I also ran into a real bug along the way. Binding a loop variable inside a MATCH pattern silently returned zero rows instead of giving an error. No warning, nothing. It just looked like there was no data, when the data was actually there. I only caught it by building a tiny test graph and checking the query by hand. The fix was switching to a WHERE key IN $list filter instead.&lt;/p&gt;

&lt;h2&gt;
  
  
  The result I didn’t expect
&lt;/h2&gt;

&lt;p&gt;I ran the “what if this person leaves” query against the most active reviewers in the dataset. For one contributor, removing them left 21 modules with no remaining reviewer who had touched them in the past 90 days. Those 21 modules have 751 other modules depending on them, directly or through a chain.&lt;/p&gt;

&lt;p&gt;None of this shows up in the ownership file. That file still lists this person as relevant to modules they haven’t touched in months.&lt;/p&gt;

&lt;h2&gt;
  
  
  Making sure the answers can be trusted
&lt;/h2&gt;

&lt;p&gt;I didn’t want to just print numbers and hope they’re right. So every answer the system gives is built from small facts, and each fact is tied to the exact query that produced it. Before showing anything to a user, a separate piece of code reruns that query and checks the number still matches. If it doesn’t match, the claim gets dropped, not shown with a warning next to it.&lt;/p&gt;

&lt;p&gt;I also built a plain text-search version on the same data, on purpose, to check whether the graph was really adding value or whether I was just convincing myself it was better. The graph wins at picking the top three likely reviewers. The text-search version wins when there’s almost no history to work from. I kept both results instead of only showing the one that made the graph look better.&lt;/p&gt;

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

&lt;p&gt;Right now, ownership and dependency connections are snapshots, not dated, so I can’t yet ask “who owned this module back in March.” Adding dates to those connections is the next real improvement. I’d also like to combine the graph ranking with the text-search ranking, since each one wins under different conditions.&lt;/p&gt;

&lt;p&gt;The code, setup steps, and full graph structure are linked below if you want to try it yourself or check the numbers.&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/srishtipandey1" rel="noopener noreferrer"&gt;
        srishtipandey1
      &lt;/a&gt; / &lt;a href="https://github.com/srishtipandey1/provenance" rel="noopener noreferrer"&gt;
        provenance
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      A graph-powered tool for understanding code ownership, reviewer expertise, and project risk.
    &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;Provenance&lt;/h1&gt;
&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;See who owns the code and who actually knows it.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;a rel="noopener noreferrer" href="https://github.com/srishtipandey1/provenance/docs/screens/hero.png"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fsrishtipandey1%2Fprovenance%2FHEAD%2Fdocs%2Fscreens%2Fhero.png" alt="Dashboard"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Why&lt;/h2&gt;
&lt;/div&gt;
&lt;p&gt;I built Provenance to show where a repository's listed owners differ from the people doing the work.&lt;/p&gt;
&lt;p&gt;When ownership records fall behind, reviews go to the wrong people and expertise gaps stay hidden. In Home Assistant, if &lt;code&gt;epenet&lt;/code&gt; stops reviewing, 21 modules lose expert coverage, affecting 751 dependent modules.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;How it works&lt;/h2&gt;
&lt;/div&gt;

  &lt;div class="js-render-enrichment-target"&gt;
    &lt;div class="render-plaintext-hidden"&gt;
      &lt;pre&gt;flowchart LR
  A[Public GitHub data] --&amp;gt; B[FalkorDB graph]
  B --&amp;gt; C[8 typed deterministic tools]
  C --&amp;gt; D[Evidence facts]
  D --&amp;gt; E[Claim]
  E --&amp;gt; F[Plain-code verifier]
  F --&amp;gt;|replay matches| G[Verified answer and UI]
  F --&amp;gt;|mismatch| H[Reject claim]
&lt;/pre&gt;
    &lt;/div&gt;
  &lt;/div&gt;
  &lt;span class="js-render-enrichment-loader d-flex flex-justify-center flex-items-center width-full"&gt;
    &lt;span&gt;
      &lt;span class="sr-only"&gt;Loading&lt;/span&gt;
&lt;/span&gt;
  &lt;/span&gt;


&lt;p&gt;&lt;strong&gt;Architecture&lt;/strong&gt;&lt;/p&gt;

  &lt;div class="js-render-enrichment-target"&gt;
    &lt;div class="render-plaintext-hidden"&gt;
      &lt;pre&gt;flowchart LR
  GH[GitHub data and local architecture records] --&amp;gt; ING[Resumable ingestion]
  ING --&amp;gt; DB[(FalkorDB)]
  DB --&amp;gt; TOOLS[provenance/tools]
  TOOLS --&amp;gt; AGENTS[Router, verifier, and workflow agents]
  LLM[Optional Groq or Gemini planner] -. typed tool selection .-&amp;gt; AGENTS
  AGENTS --&amp;gt; API[Read-only FastAPI]
  API --&amp;gt; UI[React and TypeScript dashboard]
&lt;/pre&gt;
    &lt;/div&gt;
  &lt;/div&gt;
  &lt;span class="js-render-enrichment-loader d-flex flex-justify-center flex-items-center width-full"&gt;
    &lt;span&gt;
      &lt;span class="sr-only"&gt;Loading&lt;/span&gt;
&lt;/span&gt;
  &lt;/span&gt;


&lt;p&gt;&lt;strong&gt;Graph schema&lt;/strong&gt;&lt;/p&gt;
&lt;div class="js-render-enrichment-target"&gt;&lt;div class="render-plaintext-hidden"&gt;…&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/srishtipandey1/provenance" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


</description>
      <category>falkordb</category>
      <category>graphdatabase</category>
      <category>python</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Second Take: Whisper counts my brother's filler words, Gemma explains the counts</title>
      <dc:creator>Srishti Pandey</dc:creator>
      <pubDate>Mon, 05 Oct 2026 05:53:52 +0000</pubDate>
      <link>https://dev.to/srishti_pandey_18fdfe4cdf/second-take-whisper-counts-my-brothers-filler-words-gemma-explains-the-counts-1d1b</link>
      <guid>https://dev.to/srishti_pandey_18fdfe4cdf/second-take-whisper-counts-my-brothers-filler-words-gemma-explains-the-counts-1d1b</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for the &lt;a href="https://dev.to/challenges/hacktoberfest-weekend-2026-10-01"&gt;Hacktoberfest Weekend Challenge: Build for a Friend&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

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

&lt;p&gt;My brother is 15 and sometimes has to speak in front of people. I asked him what he thought about a small app that could help him practise. He said: "It's good."&lt;/p&gt;

&lt;p&gt;So I made one.&lt;/p&gt;

&lt;p&gt;Second Take is a small web app that runs on my laptop. You record yourself talking for a short time, and it gives you a few things to look at: speaking pace, pauses of 0.7 seconds or more, and filler words like "um", "uh", "like", "basically", and "you know".&lt;/p&gt;

&lt;p&gt;The filler words and pauses have timestamps, so you can click on one and go back to that part of the recording.&lt;/p&gt;

&lt;p&gt;It also sends the transcript and the measurements to Gemma through Ollama. Gemma gives practice tips based on them. Each take is saved locally, and the app has a chart showing fillers per minute and long pauses across the takes.&lt;/p&gt;

&lt;p&gt;The important part is that Gemma isn't calculating the numbers. Python does that first. The model gets the finished measurements and the transcript and writes the advice.&lt;/p&gt;

&lt;p&gt;I also added a check after Gemma responds. It finds numbers in the response and compares them with the numbers calculated by the app. It caught numbers in several of my test responses, although it also produced some false alarms.&lt;/p&gt;

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

&lt;p&gt;I made five real takes.&lt;/p&gt;

&lt;p&gt;The first take was 23.5 seconds long. It measured 99.5 words per minute, 12.8 fillers per minute, and 3 long pauses.&lt;/p&gt;

&lt;p&gt;The next take was 27.2 seconds long. It measured 119.2 words per minute, 4.4 fillers per minute, and 5 long pauses.&lt;/p&gt;

&lt;p&gt;The app also shows where those pauses happened. In the second recording, for example, it found pauses between "scalability." and "When", "server..." and "What", and "copy." and "It".&lt;/p&gt;

&lt;p&gt;The transcription isn't perfect. One part came back as:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;ThesecondpointIwanttomakeisaboutscalability&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;So there is clearly still work to do there. The timestamps are more reliable than the transcript formatting, which is why the measurements are based on the timestamps.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fpq2sigaze679ex9gdgun.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fpq2sigaze679ex9gdgun.png" alt=" " width="800" height="543"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fcqer7hyjzjqekhur4eqr.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fcqer7hyjzjqekhur4eqr.png" alt=" " width="800" height="725"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fsdnt9j495kbmxyvlnqnx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fsdnt9j495kbmxyvlnqnx.png" alt=" " width="800" height="537"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fbaw5no80a5ttcf7vzy6l.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fbaw5no80a5ttcf7vzy6l.png" alt=" " width="800" height="619"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fbs5a4vigtcs2ve5kl1jf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fbs5a4vigtcs2ve5kl1jf.png" alt=" " width="800" height="535"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;My brother actually tried it. I asked him what he thought.&lt;/p&gt;

&lt;p&gt;He said:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"It's good."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That's the whole review.&lt;/p&gt;

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

&lt;p&gt;&lt;a href="https://github.com/srishtipandey1/second-take" rel="noopener noreferrer"&gt;https://github.com/srishtipandey1/second-take&lt;/a&gt;&lt;/p&gt;

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

&lt;p&gt;Transcription uses faster-whisper with the &lt;code&gt;base.en&lt;/code&gt; model and word timestamps.&lt;/p&gt;

&lt;p&gt;Whisper sometimes removes things like "um" and "uh", which is a problem because those are exactly the things I wanted to count. I turned off the voice-activity filter and gave it a short prompt containing some disfluencies.&lt;/p&gt;

&lt;p&gt;That helped. The test recordings included "uh" and "um" in the transcript, although the transcription itself still wasn't always clean.&lt;/p&gt;

&lt;p&gt;The metrics are just a Python function that takes &lt;code&gt;(word, start, end)&lt;/code&gt; values.&lt;/p&gt;

&lt;p&gt;For pace, it counts words in each 30-second window and converts that to words per minute.&lt;/p&gt;

&lt;p&gt;For pauses, it looks at the gap between one word ending and the next word starting. Anything at least 0.7 seconds counts as a long pause.&lt;/p&gt;

&lt;p&gt;For fillers, it checks the transcript against two lists of words.&lt;/p&gt;

&lt;p&gt;I also wrote a small test using made-up timestamps where I already knew what the answers should be. The test passed.&lt;/p&gt;

&lt;p&gt;For the AI part, I used Ollama with &lt;code&gt;gemma3:1b&lt;/code&gt;. I went with the 1B model because I wanted something that would actually run on my laptop without a GPU.&lt;/p&gt;

&lt;p&gt;The prompt gives Gemma the measurements and transcript and asks for three practice tips with timestamps.&lt;/p&gt;

&lt;p&gt;The app stores takes in a local JSON file. The chart reads from the same file.&lt;/p&gt;

&lt;p&gt;I built the app with GitHub Copilot in agent mode. I gave it the requirements, let it make the first version, then ran it and fixed things that didn't behave the way I wanted.&lt;/p&gt;

&lt;p&gt;One thing I caught was the recording button still looking like it was recording after I stopped a take. I also changed the history so it doesn't make old takes look playable when their audio isn't stored.&lt;/p&gt;

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

&lt;p&gt;Here are the five takes currently in the app:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Take&lt;/th&gt;
&lt;th&gt;Fillers per minute&lt;/th&gt;
&lt;th&gt;Long pauses&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;4.4&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;12.8&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;2.2&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;0.0&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;0.0&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The numbers don't move neatly downward, which is probably what you'd expect from five short recordings.&lt;/p&gt;

&lt;p&gt;The 10:30 take had 12.8 fillers per minute and 3 long pauses. The 10:33 take had 4.4 fillers per minute but 5 long pauses. So there were fewer fillers, but more long pauses.&lt;/p&gt;

&lt;p&gt;The tips from Gemma were mostly about pauses and explaining things more clearly.&lt;/p&gt;

&lt;p&gt;What my brother said after:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"It's good."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;What didn't work: the 1B model isn't particularly good at following the coaching format every time. Some responses are generic, and sometimes it puts numbers in the answer that aren't part of the measurements. In the latest take, the number check flagged 1 and 3.&lt;/p&gt;

&lt;p&gt;The other problem is transcription. Whisper occasionally runs words together or misses things, so the filler count depends on what makes it through the transcript.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Does Open Innovation Matter?
&lt;/h2&gt;

&lt;p&gt;The recordings are a teenager's voice, so I wanted to keep them on my laptop.&lt;/p&gt;

&lt;p&gt;Whisper runs locally. Gemma runs locally through Ollama. There is no account, API key, or audio upload involved. The take history is just a file in the project folder.&lt;/p&gt;

&lt;p&gt;That also made testing easier. I could record something, run it through the app again, change the prompt, and try again without paying for an API call.&lt;/p&gt;

&lt;p&gt;The model name is an environment variable too, so I can swap &lt;code&gt;gemma3:1b&lt;/code&gt; for a bigger model later if the computer can handle it.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;Best Use of Gemma: Gemma writes the practice tips from the measurements calculated by the app, using Ollama locally.&lt;/li&gt;
&lt;li&gt;Best Use of GitHub Copilot: I built the app with Copilot in agent mode and used it to generate the first version from my specification.&lt;/li&gt;
&lt;/ul&gt;

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