<?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: Kshitij</title>
    <description>The latest articles on DEV Community by Kshitij (@kernelkain).</description>
    <link>https://dev.to/kernelkain</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%2F3953019%2F39f656d7-121d-4b3f-b768-8b352486b929.jpg</url>
      <title>DEV Community: Kshitij</title>
      <link>https://dev.to/kernelkain</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/kernelkain"/>
    <language>en</language>
    <item>
      <title>Your most polite customers are the ones you’re about to lose.</title>
      <dc:creator>Kshitij</dc:creator>
      <pubDate>Sun, 30 Aug 2026 17:43:23 +0000</pubDate>
      <link>https://dev.to/kernelkain/your-most-polite-customers-are-the-ones-youre-about-to-lose-3i16</link>
      <guid>https://dev.to/kernelkain/your-most-polite-customers-are-the-ones-youre-about-to-lose-3i16</guid>
      <description>&lt;p&gt;Think of the last time you said an app was “fine.”&lt;/p&gt;

&lt;p&gt;You still have it on your phone. You still open it when you’re tired. You would not recommend it to a friend. You also would not write to support. Support is for a missing order. “Fine” is quieter than that. “Fine” means you order less, then you stop.&lt;/p&gt;

&lt;p&gt;This review is that moment:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“It’s not bad but I’m comparing every food order to getting downstairs 10 floors. The convenience tax is getting loud.”&lt;/p&gt;

&lt;p&gt;— 3 stars&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In plain English: skipping 10 floors of stairs used to be worth the extra fee. Now walking is starting to win. The person still has manners. They even left stars in the middle.&lt;/p&gt;

&lt;p&gt;A normal sentiment tool reads “not bad,” sees 3 stars, and calls it okay. Maybe even positive. Green on the dashboard.&lt;/p&gt;

&lt;p&gt;What happens next is not a complaint. It is fewer orders. Then the app comes off the phone.&lt;/p&gt;

&lt;p&gt;That is the whole product: the review that looks okay and means goodbye.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Resonance is
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Resonance&lt;/strong&gt; reads a sheet of reviews and tells you what people felt, not what they performed. It scores eight emotions. It notices when the words and the feelings disagree. It names the groups hiding in the 3- and 4-star pile. It writes a &lt;strong&gt;Hidden Ask&lt;/strong&gt; — the need nobody filed as a ticket. Then it waits. It will not invent a product roadmap until you say yes.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Try it live:&lt;/strong&gt; &lt;a href="https://graphics-newsletters-usr-simplified.trycloudflare.com" rel="noopener noreferrer"&gt;https://graphics-newsletters-usr-simplified.trycloudflare.com&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Code:&lt;/strong&gt; &lt;a href="https://github.com/kernelKain/resonance" rel="noopener noreferrer"&gt;https://github.com/kernelKain/resonance&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Watch a run:&lt;/strong&gt; &lt;a href="https://www.youtube.com/watch?v=QnLD8gl54OU" rel="noopener noreferrer"&gt;https://www.youtube.com/watch?v=QnLD8gl54OU&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;  &lt;iframe src="https://www.youtube.com/embed/QnLD8gl54OU" width="710" height="399"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;Two minutes. Then keep reading — the rest is what the clip doesn’t show.&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/kernelKain" rel="noopener noreferrer"&gt;
        kernelKain
      &lt;/a&gt; / &lt;a href="https://github.com/kernelKain/resonance" rel="noopener noreferrer"&gt;
        resonance
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      
    &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;Resonance&lt;/h1&gt;
&lt;/div&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Customer emotion archaeology powered by Plutchik's Wheel&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;a href="https://graphics-newsletters-usr-simplified.trycloudflare.com" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/bd57870e4e99ee65279934914c70b8e25412605e595d0afc63c3f7206d181e1a/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f6c6976655f64656d6f2d747279636c6f7564666c6172652d303043374237" alt="Live demo"&gt;&lt;/a&gt;
&lt;a href="https://github.com/kernelKain/resonance/LICENSE" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/c2c54bf8409d6c3e378ad8f666d1a2dbe508be1980c7c54e60dc79ad9a210065/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f6c6963656e73652d4d49542d6379616e2e737667" alt="License: MIT"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Resonance does not classify reviews as positive, negative, or neutral. It scores each review on Plutchik's eight emotions, flags cognitive dissonance, maps an unmet Maslow need, clusters the emotion vectors in a TrueForge sandbox, names psychological archetypes, writes Hidden Asks — then &lt;strong&gt;pauses for a human&lt;/strong&gt; before any product-roadmap recommendation is emitted.&lt;/p&gt;
&lt;p&gt;Built for &lt;a href="https://wemakedevs.org/" rel="nofollow noopener noreferrer"&gt;The Agent Harness Hackathon&lt;/a&gt; on the TrueForge harness (filesystem MCP, Exa web search, Daytona sandbox, &lt;code&gt;ask_user_question&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Live demo:&lt;/strong&gt; &lt;a href="https://graphics-newsletters-usr-simplified.trycloudflare.com" rel="nofollow noopener noreferrer"&gt;https://graphics-newsletters-usr-simplified.trycloudflare.com&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Always-on Oracle Always Free ARM VM in Mumbai. Nothing runs on a laptop. The URL is a Cloudflare Quick Tunnel (&lt;code&gt;*.trycloudflare.com&lt;/code&gt;); it can change if that tunnel process restarts.&lt;/p&gt;

&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Screenshots&lt;/h2&gt;
&lt;/div&gt;
&lt;p&gt;Zomato demo run (Plutchik profile → HITL approval → roadmap).&lt;/p&gt;
&lt;p&gt;
  &lt;a rel="noopener noreferrer" href="https://github.com/kernelKain/resonance/demo_data/Results/Zomato/live-analysis.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%2FkernelKain%2Fresonance%2FHEAD%2Fdemo_data%2FResults%2FZomato%2Flive-analysis.png" alt="Zomato — live analysis workbench"&gt;&lt;/a&gt;
&lt;/p&gt;

&lt;p&gt;
  &lt;a rel="noopener noreferrer" href="https://github.com/kernelKain/resonance/demo_data/Results/Zomato/emotion-profile.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%2FkernelKain%2Fresonance%2FHEAD%2Fdemo_data%2FResults%2FZomato%2Femotion-profile.png" alt="Eight-dimension Plutchik emotion profile" width="48%"&gt;&lt;/a&gt;
  &amp;nbsp;
  &lt;a rel="noopener noreferrer" href="https://github.com/kernelKain/resonance/demo_data/Results/Zomato/segments.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%2FkernelKain%2Fresonance%2FHEAD%2Fdemo_data%2FResults%2FZomato%2Fsegments.png" alt="Psychological archetype segment card" width="48%"&gt;&lt;/a&gt;
&lt;/p&gt;

&lt;p&gt;
  &lt;a rel="noopener noreferrer" href="https://github.com/kernelKain/resonance/demo_data/Results/Zomato/approval.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%2FkernelKain%2Fresonance%2FHEAD%2Fdemo_data%2FResults%2FZomato%2Fapproval.png" alt="Human-in-the-loop approval gate before recommendations" width="48%"&gt;&lt;/a&gt;
  &amp;nbsp;
  &lt;a rel="noopener noreferrer" href="https://github.com/kernelKain/resonance/demo_data/Results/Zomato/recommendations.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%2FkernelKain%2Fresonance%2FHEAD%2Fdemo_data%2FResults%2FZomato%2Frecommendations.png" alt="Roadmap recommendations after approval" width="48%"&gt;&lt;/a&gt;
&lt;/p&gt;

&lt;p&gt;
  &lt;a rel="noopener noreferrer" href="https://github.com/kernelKain/resonance/demo_data/Results/Zomato/unspoken-needs.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%2FkernelKain%2Fresonance%2FHEAD%2Fdemo_data%2FResults%2FZomato%2Funspoken-needs.png" alt="Hidden Asks — unmet needs no review filed as a ticket" width="48%"&gt;&lt;/a&gt;
  &amp;nbsp;
  &lt;a rel="noopener noreferrer" href="https://github.com/kernelKain/resonance/demo_data/Results/Zomato/red-flags.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%2FkernelKain%2Fresonance%2FHEAD%2Fdemo_data%2FResults%2FZomato%2Fred-flags.png" alt="Cognitive dissonance red flags on individual reviews" width="48%"&gt;&lt;/a&gt;
&lt;/p&gt;

&lt;p&gt;
  &lt;a rel="noopener noreferrer" href="https://github.com/kernelKain/resonance/demo_data/Results/Zomato/executive-summary.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%2FkernelKain%2Fresonance%2FHEAD%2Fdemo_data%2FResults%2FZomato%2Fexecutive-summary.png" alt="Executive summary with PDF export" width="48%"&gt;&lt;/a&gt;
  &amp;nbsp;
  &lt;a rel="noopener noreferrer" href="https://github.com/kernelKain/resonance/demo_data/Results/Zomato/light-mode.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%2FkernelKain%2Fresonance%2FHEAD%2Fdemo_data%2FResults%2FZomato%2Flight-mode.png" alt="Light-mode workbench" width="48%"&gt;&lt;/a&gt;
&lt;/p&gt;

&lt;p&gt;Upload a CSV → watch the Plutchik wheel fill in real time → approve the analysis → export a dark-theme PDF.&lt;/p&gt;




&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Sample analysis&lt;/h2&gt;
&lt;/div&gt;

&lt;p&gt;&lt;/p&gt;&lt;div class="table-wrapper-paragraph"&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;table&gt;

&lt;thead&gt;

&lt;tr&gt;

&lt;th&gt;Product&lt;/th&gt;

&lt;th&gt;Dataset&lt;/th&gt;

&lt;th&gt;Report&lt;/th&gt;

&lt;/tr&gt;

&lt;/thead&gt;

&lt;/table&gt;&lt;/div&gt;…&lt;p&gt;&lt;/p&gt;&lt;/div&gt;
&lt;br&gt;
  &lt;/div&gt;
&lt;br&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/kernelKain/resonance" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;br&gt;
&lt;/div&gt;
&lt;br&gt;


&lt;p&gt;Built for &lt;a href="https://www.wemakedevs.org/hackathons/trueforge" rel="noopener noreferrer"&gt;The Agent Harness Hackathon&lt;/a&gt; (WeMakeDevs × TrueForge × Qodo). The live URL is a Cloudflare tunnel on a small always-on VM. If that process restarts, the hostname can change. The repo and the video stay.&lt;/p&gt;

&lt;p&gt;Drop a CSV. Watch the wheel fill. Approve or decline. Download a PDF.&lt;/p&gt;

&lt;h2&gt;
  
  
  The job I gave the agent
&lt;/h2&gt;

&lt;p&gt;A product manager already has a spreadsheet. Their dashboard says “mostly positive.” They need the people hiding in the polite ratings.&lt;/p&gt;

&lt;p&gt;The job, in order:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Read the file. Don’t make me paste reviews into a chat.&lt;/li&gt;
&lt;li&gt;Learn what the product is, so “I love it” on food is not “I love it” on a bank.&lt;/li&gt;
&lt;li&gt;Score every row: eight emotions, whether the words fight the feeling, one unmet need.&lt;/li&gt;
&lt;li&gt;Group similar emotion patterns with real math — not a guess.&lt;/li&gt;
&lt;li&gt;Name the groups. Write the Hidden Asks.&lt;/li&gt;
&lt;li&gt;Ask me before any “you should build X.”&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The eight emotions are Plutchik’s, not happy / sad / meh. Politeness is not joy.&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%2Fe59wwb754g6m5wvcj2jc.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%2Fe59wwb754g6m5wvcj2jc.png" alt="Eight-emotion wheel for the Zomato run. Sadness and anger sit high. Joy is low." width="782" height="868"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;This is the job: a shape of feeling, not a thumbs-up.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  TrueForge: the harness in the middle
&lt;/h2&gt;

&lt;p&gt;A chatbot answers. An agent has to reach a file, run code somewhere safe, and stop before it does something you can’t undo. I didn’t want to spend the week building that machinery. TrueForge is the layer between the model and everything it touches.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;You (browser)  →  workbench  →  TrueForge agent
                                   ├ filesystem (the CSV)
                                   ├ web research (what is this product?)
                                   └ sandbox (the clustering script)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;What the harness handled:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Files&lt;/strong&gt; — the agent reads the upload by name and writes results. It doesn’t get the rest of the disk.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A specialist&lt;/strong&gt; — one helper looks up the product. Scoring and the wait stay on the main agent.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A sandbox&lt;/strong&gt; — grouping runs in a sealed machine, not on my laptop.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A pause&lt;/strong&gt; — after Hidden Asks, TrueForge stops and asks. Roadmap items stay empty until &lt;strong&gt;Approve&lt;/strong&gt;. &lt;strong&gt;Decline&lt;/strong&gt; ends there.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I wrote the screen, the parser, and the PDF. The harness wrote the loop, the tools, the sandbox, and the wait.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;TrueForge paused on &lt;code&gt;ask_user_question&lt;/code&gt; — waiting for Approved or Decline.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F8dzmkvrqgwc14u9js55q.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%2F8dzmkvrqgwc14u9js55q.png" alt="Live analysis after a finished run. The activity log shows TrueForge paused, waiting for Approve or Decline." width="800" height="444"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;The wait is not a fake button. The session actually stops.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What broke
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Stage 1 — the model vanished.&lt;/strong&gt; The first provider ran out of quota. I moved the agent to OpenRouter: one model first, a second if the first turn fails. A run stays on one model until you approve. Unsexy. Why the demo still works.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Stage 2 — the sealed room had no door.&lt;/strong&gt; I told it to run the clustering script on the scored file. The sandbox had never seen that file. I had to copy the script &lt;em&gt;and&lt;/em&gt; the data in. After that, it was just a tool.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Stage 3 — the answer got cut in half.&lt;/strong&gt; Long replies died mid-stream. The UI said done. The wheel was empty. I stopped asking the model to “be complete” and started only drawing what I could actually read.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Stage 4 — the first model got tired.&lt;/strong&gt; Same job, second model, more room. Not a second opinion.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Stage 5 — the small computer had opinions.&lt;/strong&gt; The app had to listen for the real visitor IP behind the tunnel. The harness on that machine had to listen on all network interfaces or Docker couldn’t talk to it. The public URL is a tunnel. The only open door is SSH.&lt;/p&gt;

&lt;p&gt;That’s the messy middle. That’s also why a stranger can click the link.&lt;/p&gt;

&lt;h2&gt;
  
  
  Qodo from the first PR
&lt;/h2&gt;

&lt;p&gt;Every real change went through a pull request. Qodo read it before it landed. That was the way the repo grew, not a polish pass at the end.&lt;/p&gt;

&lt;p&gt;Example: &lt;a href="https://github.com/kernelKain/resonance/pull/4" rel="noopener noreferrer"&gt;PR #4 — the approval step&lt;/a&gt;. The dangerous part of this product is emitting a roadmap. Qodo caught a High bug: if the pause data failed to parse, &lt;strong&gt;Approve would fake a local replay, mark the run done, and never send the answer back to TrueForge.&lt;/strong&gt; The wait would look real. The harness would never hear you.&lt;/p&gt;

&lt;p&gt;I stopped inventing a fake replay id. Approve only continues when the pause is a real TrueForge interrupt.&lt;/p&gt;

&lt;p&gt;I don’t merge because the bot is green. I merge when the note is fixed, or the thread says why we skipped it.&lt;/p&gt;

&lt;p&gt;All merged work: &lt;a href="https://github.com/kernelKain/resonance/pulls?q=is%3Apr+is%3Amerged" rel="noopener noreferrer"&gt;the PR list&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  One Zomato run
&lt;/h2&gt;

&lt;p&gt;I uploaded &lt;code&gt;zomato_reviews.csv&lt;/code&gt;. Fifty reviews. No extra chat window — the file is the input.&lt;/p&gt;

&lt;p&gt;First, the polite ones that don’t mean polite.&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%2Fb5wdull24z8gsfz3l8s0.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%2Fb5wdull24z8gsfz3l8s0.png" alt="Review cards. One says “not bad” and is tagged praise masking pain, 3 stars." width="725" height="576"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Same quote as the opening. Now you can see the tag.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Then the group that still opens the app.&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%2F5o0x2u6v9672xdskynol.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%2F5o0x2u6v9672xdskynol.png" alt="Segment card: Fee-Fatigued Loyalists. 22 reviews. 44% of the set. Esteem." width="723" height="468"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;They stay because discovery still works. One bad bill and they don’t.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Then the need that never became a ticket.&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%2F448wx4127i2z2sjua47x.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%2F448wx4127i2z2sjua47x.png" alt="Hidden Ask card: “A path back to a real human.” Belonging. High." width="720" height="526"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Not “make the bot nicer.” A person who can undo a wrong charge.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Then it waits. The roadmap side is blank on purpose.&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%2Fs7e4tijnqbcchbqu15cv.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%2Fs7e4tijnqbcchbqu15cv.png" alt="Approve recommendations modal, Hidden Asks listed, Decline and Approve buttons." width="657" height="613"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Approve continues. Decline stops here. I tried both.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Only after Approve:&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%2Fwwntffopq8b3mfj6s5wk.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%2Fwwntffopq8b3mfj6s5wk.png" alt="Roadmap card: one-tap “talk to a person” after two failed chat loops." width="720" height="557"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Same ask, now as something you could ship. That sentence did not exist before a human said yes.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Go try it
&lt;/h2&gt;

&lt;p&gt;Open the live link at the top, or clone the repo, and hit &lt;strong&gt;Load demo dataset&lt;/strong&gt;. Approve once. Decline once. The interesting screen is the one where the roadmap is still empty.&lt;/p&gt;

</description>
      <category>hackathon</category>
      <category>ai</category>
      <category>trueforge</category>
      <category>opensource</category>
    </item>
    <item>
      <title>PawSpective: See the World Closer to How Your Dog Sees It</title>
      <dc:creator>Kshitij</dc:creator>
      <pubDate>Mon, 17 Aug 2026 04:44:53 +0000</pubDate>
      <link>https://dev.to/kernelkain/pawspective-see-the-world-closer-to-how-your-dog-sees-it-2k4g</link>
      <guid>https://dev.to/kernelkain/pawspective-see-the-world-closer-to-how-your-dog-sees-it-2k4g</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for &lt;a href="https://dev.to/challenges/weekend-2026-08-13"&gt;Weekend Challenge: Dog Days Edition&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Have you ever bought a bright red toy that looked impossible to miss only to watch your dog struggle to find it on green grass?&lt;/p&gt;

&lt;p&gt;Humans and dogs do not experience color in the same way. That inspired me to build &lt;strong&gt;PawSpective&lt;/strong&gt;, an application that combines a canine-vision approximation, AI-assisted scene understanding, deterministic visibility calculations, and playful narrated videos.&lt;/p&gt;

&lt;p&gt;The central idea is one connected experience:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Capture a scene → explore a canine-vision approximation → discover which objects remain visible → turn the moment into a fictional story.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I also wanted PawSpective to be entertaining without pretending it can read a dog’s mind. It does not claim to determine exact canine vision, gaze, thoughts, feelings, smell, or intent.&lt;/p&gt;

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

&lt;p&gt;PawSpective helps dog owners explore how objects in an everyday scene may appear under a canine-inspired color transformation.&lt;/p&gt;

&lt;p&gt;A user can:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Create a lightweight dog profile.&lt;/li&gt;
&lt;li&gt;Open the &lt;strong&gt;Live Dog Lens&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;compare Human View with a canine-vision approximation.&lt;/li&gt;
&lt;li&gt;Record or upload a short video.&lt;/li&gt;
&lt;li&gt;Let Google Gemini identify visible objects and scene events.&lt;/li&gt;
&lt;li&gt;Review, rename, or remove incorrect AI detections.&lt;/li&gt;
&lt;li&gt;Calculate the relative dog-visible contrast of an object.&lt;/li&gt;
&lt;li&gt;Explore possible attention cues through the &lt;strong&gt;Curiosity Map&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Compare alternative toy colors in the &lt;strong&gt;Toy Color Lab&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Generate and download a fictional narrated &lt;strong&gt;Story Reel&lt;/strong&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Live Dog Lens
&lt;/h3&gt;

&lt;p&gt;The Live Dog Lens uses a browser-based WebGL transformation to provide an immediate Human/Dog Vision comparison.&lt;/p&gt;

&lt;p&gt;The transformation preserves more blue and yellow differentiation while reducing red and green differentiation. A comparison slider makes the effect easy to understand, and a dog-height guide helps users frame the scene from a lower point of view.&lt;/p&gt;

&lt;p&gt;This is deliberately described as a &lt;strong&gt;canine-vision approximation&lt;/strong&gt;, not an exact reconstruction of what a particular dog sees.&lt;/p&gt;

&lt;h3&gt;
  
  
  AI scene analysis
&lt;/h3&gt;

&lt;p&gt;After a user uploads a 5–15 second video, PawSpective sends a normalized, silent version of the clip to Google Gemini.&lt;/p&gt;

&lt;p&gt;Gemini returns structured scene evidence, including:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Visible object labels&lt;/li&gt;
&lt;li&gt;Approximate bounding boxes&lt;/li&gt;
&lt;li&gt;Timestamps&lt;/li&gt;
&lt;li&gt;Object categories&lt;/li&gt;
&lt;li&gt;Confidence values&lt;/li&gt;
&lt;li&gt;Visible evidence&lt;/li&gt;
&lt;li&gt;Coarse motion levels&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The response must pass a strict Pydantic and JSON Schema contract before the application accepts it.&lt;/p&gt;

&lt;p&gt;Users can then remove incorrect events, rename objects, and select which object should be analyzed. These corrections become the source of truth for visibility calculations and Story Reel generation.&lt;/p&gt;

&lt;h3&gt;
  
  
  Visibility Lab
&lt;/h3&gt;

&lt;p&gt;The Visibility Lab measures how strongly a selected object differs from its nearby background.&lt;/p&gt;

&lt;p&gt;The backend:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Seeks to the event timestamp.&lt;/li&gt;
&lt;li&gt;Samples pixels inside the object’s corrected bounding box.&lt;/li&gt;
&lt;li&gt;Samples a surrounding background region.&lt;/li&gt;
&lt;li&gt;Applies the same canine color transformation used by the frontend.&lt;/li&gt;
&lt;li&gt;Converts colors into CIE Lab.&lt;/li&gt;
&lt;li&gt;Measures foreground/background color and luminance separation.&lt;/li&gt;
&lt;li&gt;Produces a relative dog-visible contrast score.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The result is presented as a product score and qualitative visibility band—not as a scientific probability.&lt;/p&gt;

&lt;p&gt;For example:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Dog-visible contrast: High&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
The blue toy remains visually distinct from the surrounding grass after the canine-vision transformation.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Curiosity Map
&lt;/h3&gt;

&lt;p&gt;The Curiosity Map highlights objects that may visually stand out in the scene.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;AI-inferred motion&lt;/li&gt;
&lt;li&gt;Measured dog-visible contrast&lt;/li&gt;
&lt;li&gt;Apparent object size&lt;/li&gt;
&lt;li&gt;A small optional profile-relevance bonus&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Every result explains why it appeared. PawSpective calls these &lt;strong&gt;possible attention cues&lt;/strong&gt;, because the application does not track a dog’s gaze or know what the dog is actually paying attention to.&lt;/p&gt;

&lt;h3&gt;
  
  
  Toy Color Lab
&lt;/h3&gt;

&lt;p&gt;Toy Color Lab compares six screen colors against the measured background around a selected object.&lt;/p&gt;

&lt;p&gt;It keeps the surrounding background unchanged, simulates alternative colors for the object, applies the canine transformation, and ranks the colors by approximate dog-visible contrast.&lt;/p&gt;

&lt;p&gt;The preview is illustrative—it does not claim that a physical toy will look exactly the same or guarantee a dog’s response—but it makes the red-versus-blue-on-grass problem immediately understandable.&lt;/p&gt;

&lt;h3&gt;
  
  
  Story Reel
&lt;/h3&gt;

&lt;p&gt;The final step turns the reviewed scene into an 8–10 second vertical video.&lt;/p&gt;

&lt;p&gt;Google Gemini uses only the user-reviewed scene timeline to generate grounded story and animation direction. ElevenLabs creates the fictional dog narration, and FFmpeg combines the video, narration, captions, overlays, music, watermark, and disclaimer into a downloadable 9:16 MP4.&lt;/p&gt;

&lt;p&gt;The result remains clearly labeled &lt;strong&gt;Just for fun&lt;/strong&gt;.&lt;/p&gt;

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

&lt;p&gt;The application is available at:&lt;/p&gt;

&lt;p&gt;👉 &lt;a href="https://pawspective.onrender.com/" rel="noopener noreferrer"&gt;https://pawspective.onrender.com/&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Demo note:&lt;/strong&gt; [My Gemini API daily usage limit ran out, so I couldn’t publish the complete demo.]&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The interface and deployed application can still be explored through the link above. The complete demonstration will be added to the repository once the provider usage limit is available again.&lt;/p&gt;

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

&lt;p&gt;The complete source code is available on GitHub:&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/kernelKain" rel="noopener noreferrer"&gt;
        kernelKain
      &lt;/a&gt; / &lt;a href="https://github.com/kernelKain/pawSpective" rel="noopener noreferrer"&gt;
        pawSpective
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      See the world closer to how your dog sees it. PawSpective combines canine-vision simulation, AI-powered object visibility analysis, curiosity mapping, and playful narrated story reels.
    &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;PawSpective&lt;/h1&gt;
&lt;/div&gt;
&lt;p&gt;See the world closer to how your dog sees it. PawSpective combines a
canine-vision approximation, reviewed AI scene analysis, deterministic
visibility scoring, color comparison, curiosity mapping, and downloadable
fictional Story Reels.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;What it does&lt;/h2&gt;
&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;Opens a live Human/Dog Vision comparison or accepts a 5-15 second video.&lt;/li&gt;
&lt;li&gt;Detects visible objects with Gemini and lets the user correct the result.&lt;/li&gt;
&lt;li&gt;Measures foreground/background contrast with OpenCV and CIE Lab color.&lt;/li&gt;
&lt;li&gt;Shows possible attention cues in a timestamp-aligned Curiosity Map.&lt;/li&gt;
&lt;li&gt;Compares six screen colors in Toy Color Lab.&lt;/li&gt;
&lt;li&gt;Creates an 8-10 second animated dog-height POV reel with fictional narration.&lt;/li&gt;
&lt;li&gt;Supports a SHA-256-bound controlled demo for offline rehearsals.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;PawSpective labels deterministic calculations as &lt;strong&gt;Research-grounded&lt;/strong&gt;
model interpretation as &lt;strong&gt;AI-inferred&lt;/strong&gt;, and fictional output as
&lt;strong&gt;Just for fun&lt;/strong&gt;. It does not claim exact canine vision, gaze, thoughts,
emotions, smell, intent, or behavioral diagnosis. See the
&lt;a href="https://github.com/kernelKain/pawSpective/docs/AI_DISCLOSURE.md" rel="noopener noreferrer"&gt;AI disclosure&lt;/a&gt; for data flow, limitations, and provider
details.&lt;/p&gt;
&lt;div class="markdown-heading"&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/kernelKain/pawSpective" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;Repository: &lt;a href="https://github.com/kernelKain/pawSpective" rel="noopener noreferrer"&gt;https://github.com/kernelKain/pawSpective&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The repository also contains the product contract, AI disclosure, deployment guide, exported schemas, automated tests, Docker configuration, and release checklist.&lt;/p&gt;

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

&lt;p&gt;PawSpective uses a Next.js frontend and a Python media-processing backend.&lt;/p&gt;

&lt;h3&gt;
  
  
  Frontend
&lt;/h3&gt;

&lt;p&gt;The frontend uses:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Next.js 16&lt;/li&gt;
&lt;li&gt;React 19&lt;/li&gt;
&lt;li&gt;TypeScript&lt;/li&gt;
&lt;li&gt;WebGL for the live color transformation&lt;/li&gt;
&lt;li&gt;Canvas and video APIs for previews and overlays&lt;/li&gt;
&lt;li&gt;Vitest and Testing Library&lt;/li&gt;
&lt;li&gt;Playwright for end-to-end smoke testing&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The browser handles the live Dog Lens, comparison slider, dog profile, recording and upload flow, object-correction interface, visibility results, Toy Color Lab, Curiosity Map, job polling, and Story Reel download.&lt;/p&gt;

&lt;h3&gt;
  
  
  Backend
&lt;/h3&gt;

&lt;p&gt;The backend uses:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;FastAPI&lt;/li&gt;
&lt;li&gt;Pydantic&lt;/li&gt;
&lt;li&gt;Google Gemini&lt;/li&gt;
&lt;li&gt;OpenCV&lt;/li&gt;
&lt;li&gt;NumPy&lt;/li&gt;
&lt;li&gt;ElevenLabs&lt;/li&gt;
&lt;li&gt;FFmpeg and FFprobe&lt;/li&gt;
&lt;li&gt;SQLite&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;FastAPI validates uploaded media, normalizes videos, coordinates AI requests, performs deterministic calculations, and manages background Story Reel jobs.&lt;/p&gt;

&lt;p&gt;SQLite stores job metadata and progress, while generated media is stored on a writable backend volume. Story rendering runs through a bounded background worker so the frontend can submit a job, poll its progress, and download the completed reel.&lt;/p&gt;

&lt;h3&gt;
  
  
  Google Gemini
&lt;/h3&gt;

&lt;p&gt;Gemini is used for three related tasks:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Scene analysis&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Gemini examines the short clip and returns visible objects, approximate bounding boxes, timestamps, motion levels, and supporting visual evidence.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Grounded story generation&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Gemini receives the reviewed event timeline instead of being allowed to invent details directly from the raw video.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Animation direction&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Depending on the configured model and access, Gemini Omni or Veo can create a canine-vision-inspired artistic edit using the source clip or reference frames.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;One of my most important engineering decisions was requiring structured model output. Gemini responses are validated against strict schemas, and malformed coordinates, unsupported fields, impossible timestamps, or ungrounded results are rejected.&lt;/p&gt;

&lt;h3&gt;
  
  
  ElevenLabs
&lt;/h3&gt;

&lt;p&gt;ElevenLabs generates the complete fictional dog narration for the Story Reel.&lt;/p&gt;

&lt;p&gt;Only the finalized narration text is sent to ElevenLabs—the original video is not. The selected voice is intentionally described as a &lt;strong&gt;fictional dog voice&lt;/strong&gt;, rather than an attempt to recreate a real animal’s voice or internal thoughts.&lt;/p&gt;

&lt;p&gt;The application also supports narration failure handling and cached demo output so a temporary voice-service problem does not break the entire user journey.&lt;/p&gt;

&lt;h3&gt;
  
  
  Deterministic computer vision
&lt;/h3&gt;

&lt;p&gt;I did not want an AI confidence value to become a fake scientific visibility score.&lt;/p&gt;

&lt;p&gt;Instead, the Visibility Lab and Toy Color Lab use deterministic OpenCV and NumPy calculations. They sample pixels from the video, apply the documented color transformation, convert the colors to CIE Lab, and measure relative foreground/background contrast.&lt;/p&gt;

&lt;p&gt;This creates a clear boundary between what the model inferred and what the application calculated.&lt;/p&gt;

&lt;h3&gt;
  
  
  Video composition
&lt;/h3&gt;

&lt;p&gt;FFmpeg performs the final media work:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Video normalization&lt;/li&gt;
&lt;li&gt;Portrait 9:16 composition&lt;/li&gt;
&lt;li&gt;Captions&lt;/li&gt;
&lt;li&gt;Narration synchronization&lt;/li&gt;
&lt;li&gt;Curiosity overlays&lt;/li&gt;
&lt;li&gt;Visibility result cards&lt;/li&gt;
&lt;li&gt;Music&lt;/li&gt;
&lt;li&gt;Watermarking&lt;/li&gt;
&lt;li&gt;Final MP4 encoding&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Using a fixed template made the rendering pipeline more reliable and kept the project focused on one polished experience instead of becoming a general-purpose video editor.&lt;/p&gt;

&lt;h3&gt;
  
  
  Reliability and responsible AI
&lt;/h3&gt;

&lt;p&gt;PawSpective separates its output into three categories:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Research-grounded:&lt;/strong&gt; deterministic transformations and calculations&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;AI-inferred:&lt;/strong&gt; visible-object and motion interpretation from Gemini&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Just for fun:&lt;/strong&gt; fictional narration and story framing&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The application includes recovery paths for camera denial, unsupported browsers, malformed AI output, dark footage, empty detections, narration failures, rendering errors, portrait and landscape uploads, and missing profile photos.&lt;/p&gt;

&lt;p&gt;It also supports a controlled rehearsal mode. Cached analysis and media are bound to one exact video using a SHA-256 fingerprint, preventing saved bounding boxes from being incorrectly applied to an unrelated upload.&lt;/p&gt;

&lt;p&gt;This separation became one of the most important lessons from the project: an AI product can be playful while still explaining where every result came from.&lt;/p&gt;

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

&lt;h3&gt;
  
  
  Best Use of Google AI
&lt;/h3&gt;

&lt;p&gt;Google Gemini powers PawSpective’s structured scene analysis, grounded story generation, and optional video-animation workflow.&lt;/p&gt;

&lt;p&gt;Gemini is not used as an unrestricted narrator. Its output is schema-validated, reviewed by the user, and checked against visible scene evidence before it enters later stages of the application.&lt;/p&gt;

&lt;h3&gt;
  
  
  Best Use of ElevenLabs
&lt;/h3&gt;

&lt;p&gt;ElevenLabs converts the grounded fictional script into narration for the downloadable Story Reel.&lt;/p&gt;

&lt;p&gt;Voice generation is integrated into a complete media pipeline rather than presented as an isolated text-to-speech example. The narration is synchronized with captions, scene events, overlays, music, and the final vertical video.&lt;/p&gt;

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

&lt;p&gt;The hardest part was not adding more AI. It was deciding which parts should not depend on AI.&lt;/p&gt;

&lt;p&gt;Gemini is useful for interpreting a scene, but object visibility is better represented by deterministic calculations over measured pixels. Storytelling can be imaginative, but it must remain grounded in events the user has reviewed.&lt;/p&gt;

&lt;p&gt;That led to the design principle behind PawSpective:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Use AI for interpretation and creativity, deterministic code for measurable calculations, and clear labels wherever uncertainty remains.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;PawSpective started as a fun question about how dogs experience color. It became an experiment in building an AI-powered product that combines delight, practical insight, transparency, and responsible storytelling.&lt;/p&gt;

</description>
      <category>devchallenge</category>
      <category>weekendchallenge</category>
    </item>
    <item>
      <title>I Built a Tool to Detect Delayed Access Revocation</title>
      <dc:creator>Kshitij</dc:creator>
      <pubDate>Sun, 09 Aug 2026 20:16:36 +0000</pubDate>
      <link>https://dev.to/kernelkain/i-built-a-tool-to-detect-delayed-access-revocation-427d</link>
      <guid>https://dev.to/kernelkain/i-built-a-tool-to-detect-delayed-access-revocation-427d</guid>
      <description>&lt;p&gt;This weekend, I built &lt;strong&gt;TimeTrap&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;It started with a simple question:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;What if access is revoked, but something that depends on it stays active?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That small delay can become a real security problem.&lt;/p&gt;

&lt;p&gt;🔗 &lt;a href="https://web-2b33.prg1.zerops.app" rel="noopener noreferrer"&gt;Try TimeTrap live&lt;/a&gt;&lt;br&gt;&lt;br&gt;
💻 &lt;a href="https://github.com/kernelKain/timetrap" rel="noopener noreferrer"&gt;View the source code&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The problem
&lt;/h2&gt;

&lt;p&gt;Imagine a user cancels a premium subscription at minute 10.&lt;/p&gt;

&lt;p&gt;The subscription is revoked immediately, but a cached permission remains active until minute 60. The system allows a five-minute grace period.&lt;/p&gt;

&lt;p&gt;So the timeline looks like this:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Time&lt;/th&gt;
&lt;th&gt;What happens&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Minute 10&lt;/td&gt;
&lt;td&gt;Subscription is revoked&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Minute 15&lt;/td&gt;
&lt;td&gt;Allowed grace period ends&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Minute 60&lt;/td&gt;
&lt;td&gt;Cached access finally expires&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The user keeps premium access for 50 minutes after cancellation. Of those, &lt;strong&gt;45 minutes violate the rule&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Each part of the system may look correct by itself. The subscription was revoked, and the cache eventually expired. The problem is the gap between those two events.&lt;/p&gt;

&lt;p&gt;That is what TimeTrap finds.&lt;/p&gt;

&lt;h2&gt;
  
  
  What TimeTrap does
&lt;/h2&gt;

&lt;p&gt;You describe the objects in your authorization flow—subscriptions, caches, sessions, or tokens—and add events such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;issue&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;refresh&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;revoke&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;expire&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Then you choose a rule, such as “cached access must end within five minutes of subscription revocation.”&lt;/p&gt;

&lt;p&gt;TimeTrap checks the timeline and shows:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;whether the scenario is safe;&lt;/li&gt;
&lt;li&gt;the exact time the violation begins and ends;&lt;/li&gt;
&lt;li&gt;how long stale access remains active;&lt;/li&gt;
&lt;li&gt;the events that caused the problem;&lt;/li&gt;
&lt;li&gt;a suggested correction.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For the example above, TimeTrap reports the violation as &lt;code&gt;[15, 60)&lt;/code&gt; and suggests revoking the cached permission when the subscription is revoked.&lt;/p&gt;

&lt;p&gt;You can see the complete flow here:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://web-2b33.prg1.zerops.app/results/d28ecf3d-e28a-4538-a74c-d88d791d57fe" rel="noopener noreferrer"&gt;Unsafe result&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://web-2b33.prg1.zerops.app/results/1998c072-7095-4d5f-a45f-7a520a3d62c8" rel="noopener noreferrer"&gt;Corrected result&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  How it works
&lt;/h2&gt;

&lt;p&gt;The analyzer is written in Go and is fully deterministic. The same input always produces the same result.&lt;/p&gt;

&lt;p&gt;Instead of checking every minute, it checks only the moments where something can change: an issue, refresh, revocation, expiry, or rule deadline. It then joins failed periods into one clear violation interval.&lt;/p&gt;

&lt;p&gt;The rest of the application uses:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;React and TypeScript for the interface;&lt;/li&gt;
&lt;li&gt;Go for the API and analyzer;&lt;/li&gt;
&lt;li&gt;PostgreSQL for saved scenarios and results;&lt;/li&gt;
&lt;li&gt;Zerops for deployment.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Saved results use their own URLs, so they can be refreshed or shared. Applying a fix creates a corrected copy instead of replacing the original unsafe result.&lt;/p&gt;

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

&lt;p&gt;Authorization is not only about &lt;strong&gt;who can access something&lt;/strong&gt;. It is also about &lt;strong&gt;when that access should stop&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;TimeTrap is currently a design-time tool. It checks the scenario you provide; it does not inspect or change a live production system. The model is intentionally small and uses integer-minute timing, but it makes this easy-to-miss problem visible.&lt;/p&gt;

&lt;p&gt;OpenAI Codex helped me with planning, implementation, testing, documentation, and deployment. I still reviewed the code and verified the behavior through tests, builds, API checks, and browser testing.&lt;/p&gt;

&lt;p&gt;I built TimeTrap for the WeMakeDevs challenge and deployed it on Zerops.&lt;/p&gt;

&lt;p&gt;If this kind of authorization problem sounds familiar, try the demo and let me know what you think.&lt;/p&gt;

&lt;p&gt;👉 &lt;a href="https://web-2b33.prg1.zerops.app" rel="noopener noreferrer"&gt;Open TimeTrap&lt;/a&gt;&lt;br&gt;&lt;br&gt;
⭐ &lt;a href="https://github.com/kernelKain/timetrap" rel="noopener noreferrer"&gt;Explore the GitHub repository&lt;/a&gt;&lt;/p&gt;

</description>
      <category>go</category>
      <category>security</category>
      <category>react</category>
      <category>webdev</category>
    </item>
  </channel>
</rss>
