<?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: EazyHood</title>
    <description>The latest articles on DEV Community by EazyHood (@eazyhood).</description>
    <link>https://dev.to/eazyhood</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%2F4059300%2Fc073d3f1-31e0-436b-a478-e94296e9d9cc.png</url>
      <title>DEV Community: EazyHood</title>
      <link>https://dev.to/eazyhood</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/eazyhood"/>
    <language>en</language>
    <item>
      <title>Cambio: update the plan without losing its source</title>
      <dc:creator>EazyHood</dc:creator>
      <pubDate>Tue, 20 Oct 2026 02:46:14 +0000</pubDate>
      <link>https://dev.to/eazyhood/cambio-update-the-plan-without-losing-its-source-1mhp</link>
      <guid>https://dev.to/eazyhood/cambio-update-the-plan-without-losing-its-source-1mhp</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for the &lt;a href="https://dev.to/challenges/hacktoberfest-week3-2026-10-19"&gt;Hacktoberfest Open-Source AI Challenge: Week 3 — Slow and Steady&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

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

&lt;p&gt;The plan says Room 4 at 10:00. A later message says Room 7 at 10:30. Another asks for an extension cable &lt;em&gt;if you have one&lt;/em&gt;. Lunch has not changed.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Cambio turns an original instruction list and later updates into a reviewed plan.&lt;/strong&gt; An open-weight model finds related instructions. The person chooses &lt;strong&gt;Replace&lt;/strong&gt;, &lt;strong&gt;Add&lt;/strong&gt;, or &lt;strong&gt;Ignore&lt;/strong&gt;. The final plan keeps the exact selected wording.&lt;/p&gt;

&lt;p&gt;The fictional workshop is included. Cambio supports low-stakes English plans: 20 instructions per list, 300 characters per line.&lt;/p&gt;

&lt;p&gt;“Slow and Steady” shaped the interaction: bring likely source lines to the reviewer, saving a repeated search through the plan. Review stays deliberate. A brief highlight follows each changed line and respects reduced-motion preferences. Time saved has not been measured.&lt;/p&gt;

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

&lt;p&gt;&lt;a href="https://eazyhood.github.io/cambio/" rel="noopener noreferrer"&gt;Try Cambio in your browser&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%2Fhsi93uspgqth4tot134o.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%2Fhsi93uspgqth4tot134o.png" alt="Cambio in a real browser: the original meeting time of 10:00 appears beside the 10:30 update, with the unchanged plan and review controls visible." width="800" height="416"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;A suggested match, before any decision. The original plan remains unchanged.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Choose &lt;strong&gt;Try an example&lt;/strong&gt;, then &lt;strong&gt;Find related instructions&lt;/strong&gt;. In the workshop example:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Check and replace the meeting time.&lt;/li&gt;
&lt;li&gt;Replace the room assignment.&lt;/li&gt;
&lt;li&gt;Add the cable instruction, preserving “if you have one.”&lt;/li&gt;
&lt;li&gt;Ignore the repeated lunch announcement.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Unaffected instructions stay intact. Revisit decisions or undo the last one, then export plain text or a JSON review record.&lt;/p&gt;

&lt;p&gt;No account or API key is needed. After downloading its assets, the model runs locally. Matching failures leave manual review available. Reloading discards unsaved work.&lt;/p&gt;

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

&lt;p&gt;&lt;a href="https://github.com/EazyHood/cambio" rel="noopener noreferrer"&gt;Source code and evaluation&lt;/a&gt;. The MIT-licensed repository includes tests, a dependency lockfile, and model provenance. Model weights are not committed; they retain their Apache-2.0 license.&lt;/p&gt;

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

&lt;p&gt;Cambio runs a pinned &lt;code&gt;Xenova/all-MiniLM-L6-v2&lt;/code&gt; revision through Transformers.js 3.8.1, using q8 ONNX weights in a WebAssembly worker. Cosine similarity between normalized sentence embeddings ranks candidate source lines.&lt;/p&gt;

&lt;p&gt;This is a matching model, not a contradiction detector. “Bring the charger” and “Do not bring the charger” concern the same thing; a strong similarity score cannot decide which instruction to follow.&lt;/p&gt;

&lt;p&gt;The model can suggest a source but cannot apply a replacement. Weak or competing matches, duplicates, and some conditional or negative wording trigger closer review. These heuristics miss ambiguities; all original lines remain available for comparison.&lt;/p&gt;

&lt;p&gt;The engine binds decisions to both exact input lists. Edited sources invalidate old decisions. Two updates cannot replace the same original. Export requires every update to have a decision; no paraphrase is generated.&lt;/p&gt;

&lt;h3&gt;
  
  
  What I tested and what remains unknown
&lt;/h3&gt;

&lt;p&gt;The 32 automated tests passed locally, covering stale decisions, conflicting replacements, recovery, navigation, and exports. Some use DOM and Worker doubles; browser inference was checked separately.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/EazyHood/cambio/actions/runs/39358087890" rel="noopener noreferrer"&gt;GitHub Actions&lt;/a&gt; passed its checks and deployed the static demo from commit &lt;code&gt;7c6cc8d&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;On the public demo in Edge, real inference and four review decisions produced six exact lines. The conditional cable update showed a warning without preselecting a source. The downloaded JSON identified the pinned q8/WASM model as executed. Manual fallback separately produced correct exports with no model execution. Review and completion had no horizontal overflow at a 390 × 844 viewport.&lt;/p&gt;

&lt;p&gt;Separately, real CPU inference was evaluated on 20 synthetic English list pairs. An AI agent authored the labels before inference; they are &lt;strong&gt;not independent human validation&lt;/strong&gt;. Ten pairs were reserved until the policy was fixed.&lt;/p&gt;

&lt;p&gt;On the reserved split, MiniLM ranked the expected source first for &lt;strong&gt;18/21&lt;/strong&gt; single-target updates; simple token overlap scored &lt;strong&gt;19/21&lt;/strong&gt;. MiniLM did not outperform it. The model highlighted an unrelated source for &lt;strong&gt;3/6&lt;/strong&gt; new updates; heuristics warned on &lt;strong&gt;5/8&lt;/strong&gt; ambiguous updates. These small, constructed counts cannot estimate real-world accuracy. Every prediction is in the &lt;a href="https://github.com/EazyHood/cambio/blob/main/evaluation/README.md" rel="noopener noreferrer"&gt;evaluation report&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;One successful browser example does not establish parity with the entire CPU evaluation or full offline operation. No user study or time-saving result is claimed.&lt;/p&gt;

&lt;p&gt;Cambio cannot verify authority, omitted context, or dates. Avoid high-stakes instructions. Text stays off an application server, but hosting and asset downloads expose connection metadata. JSON contains both full inputs: check before sharing.&lt;/p&gt;

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

&lt;p&gt;Open weights make a small, local matching tool possible without a paid inference service. Open code makes the boundary between suggestion and action inspectable: the model ranks; the engine records a person's choices.&lt;/p&gt;

&lt;p&gt;Others can replace the model or reuse the engine. Publishing the baseline comparison also makes weak results visible.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;AI assistance:&lt;/strong&gt; Jhonatan del Rio Mejia directed this project. OpenAI Codex generated the implementation, design, fixtures, tests, documentation, and this article under that direction. The workshop example is fictional; no real attendance or user feedback is implied.&lt;/p&gt;

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

&lt;p&gt;&lt;strong&gt;Best Use of GitHub Copilot&lt;/strong&gt;, through the GitHub Actions option explicitly listed in &lt;a href="https://dev.to/challenges/hacktoberfest-week3-2026-10-19"&gt;this challenge&lt;/a&gt;. Actions runs the tests and production build, then deploys the static demo. The successful run is linked above. No GitHub Copilot tool was used to author the code.&lt;/p&gt;

</description>
      <category>devchallenge</category>
      <category>hf26challenge</category>
    </item>
    <item>
      <title>SweepSheet: turn cleanup voice notes into reviewed counts</title>
      <dc:creator>EazyHood</dc:creator>
      <pubDate>Wed, 07 Oct 2026 14:26:23 +0000</pubDate>
      <link>https://dev.to/eazyhood/sweepsheet-turn-cleanup-voice-notes-into-reviewed-counts-2f29</link>
      <guid>https://dev.to/eazyhood/sweepsheet-turn-cleanup-voice-notes-into-reviewed-counts-2f29</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;A cleanup has two different jobs: picking things up and keeping track of what was collected. SweepSheet puts the bookkeeping after the outdoor part.&lt;/p&gt;

&lt;p&gt;Use your usual voice recorder to leave a short note: “Three plastic bottles and two cans.” Put the phone away. When you’re back, import the recording into SweepSheet. An open speech model transcribes it on your device, and a small parser proposes quantities in six categories. Listen, correct anything necessary, and confirm. Only then do the numbers enter your notebook and CSV.&lt;/p&gt;

&lt;p&gt;The person I designed for is someone keeping the tally for a small cleanup, with several voice memos to turn into a table. This is a working prototype for that task, not a report of a cleanup I have already conducted. The examples are synthetic speech and are labeled that way throughout.&lt;/p&gt;

&lt;p&gt;The most revealing test was a mistake. The sentence “Twenty three wrappers and twelve cans” came back as &lt;strong&gt;“23 rappers and 12 kids.”&lt;/strong&gt; SweepSheet did not try to rescue it with another model. It left the counts for a person to enter after listening.&lt;/p&gt;

&lt;p&gt;That decision shapes the whole application: speech recognition can help with transcription, but it does not get to approve the record.&lt;/p&gt;

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

&lt;p&gt;&lt;strong&gt;&lt;a href="https://eazyhood.github.io/sweepsheet/" rel="noopener noreferrer"&gt;Open SweepSheet&lt;/a&gt;&lt;/strong&gt; — no account or API key needed.&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%2F77hx9rkrk2b6vuclcn4p.jpg" 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%2F77hx9rkrk2b6vuclcn4p.jpg" alt="SweepSheet in Edge after real local transcription and confirmation of the synthetic canal note: three plastic bottles, two cans, total five." width="800" height="586"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;A real browser run with a clearly marked synthetic recording. The total is five because one note has been confirmed; the other two are still pending.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Choose &lt;strong&gt;Try the example notebook&lt;/strong&gt;, then open &lt;strong&gt;Along the canal&lt;/strong&gt;. The initial example transcript comes from the saved model test. &lt;strong&gt;Transcribe again&lt;/strong&gt; runs Whisper on your own device; the first use downloads the model.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Play the note and check &lt;strong&gt;3 plastic bottles + 2 cans&lt;/strong&gt;. Confirm: the total becomes &lt;strong&gt;5&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Review &lt;strong&gt;By the footbridge&lt;/strong&gt;: &lt;strong&gt;4 wrappers + 6 cigarette butts + 1 glass bottle&lt;/strong&gt;. Confirm: &lt;strong&gt;16&lt;/strong&gt; in total.&lt;/li&gt;
&lt;li&gt;Open &lt;strong&gt;An uncertain count&lt;/strong&gt;. Its transcript says “Maybe 4 or 5 rappers.” The app holds the proposal; it adds nothing.&lt;/li&gt;
&lt;li&gt;Correct a confirmed quantity and explain why. The total changes by replacement, while the previous quantities remain in the review history.&lt;/li&gt;
&lt;li&gt;Download the confirmed CSV and the JSON review history. The latter includes the audio file’s SHA-256 identifier, original model output and corrections, but not the audio bytes.&lt;/li&gt;
&lt;/ol&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%2Fuvnl7q7lld2n9m0xebcp.jpg" 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%2Fuvnl7q7lld2n9m0xebcp.jpg" alt="The uncertain synthetic recording is held for review, with zero suggested counts and the previously confirmed total unchanged." width="800" height="416"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Uncertainty stays visible. Opening this note does not change the confirmed total.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Your own short audio files work too. Keep them below 60 seconds and 10 MB. A printable field card lists the six categories and a short recording example. There is no requirement to keep this app open outdoors or rely on a web recorder with a locked phone.&lt;/p&gt;

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

&lt;p&gt;&lt;strong&gt;&lt;a href="https://github.com/EazyHood/sweepsheet" rel="noopener noreferrer"&gt;Source, setup and evidence on GitHub&lt;/a&gt;&lt;/strong&gt; · &lt;a href="https://github.com/EazyHood/sweepsheet/blob/main/evidence/model-run.json" rel="noopener noreferrer"&gt;All ten test inputs and observed outputs&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The app and repository were started on October 7 for this challenge. The application code is MIT licensed. Model and library licenses are credited separately in the README.&lt;/p&gt;

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

&lt;p&gt;The pipeline is small enough to inspect:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Audio file → browser decoding → Whisper tiny.en in a worker
           → editable transcript → conservative count proposal
           → explicit human confirmation → totals and CSV
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I used Transformers.js 3.8.1 and the quantized &lt;code&gt;Xenova/whisper-tiny.en&lt;/code&gt; ONNX conversion, pinned to revision &lt;code&gt;79fb389fc764e7c395bd330e9531d9d32ada7049&lt;/code&gt;. The browser runs inference through ONNX Runtime WASM. A worker keeps that computation away from the interface. The app stores recordings, transcripts and review history in IndexedDB; there is no transcription server or application backend.&lt;/p&gt;

&lt;p&gt;The parser supports exact quantities in six categories. It holds corrections, vague amounts, negation and unsupported numbered categories. “Bottles” alone needs a material. The parser does not silently repair “rappers” to “wrappers.” These are inspectable, intentionally limited rules, not a claim to understand every sentence.&lt;/p&gt;

&lt;p&gt;Every imported note starts pending. Exact-byte reimports are detected with SHA-256, so importing the same file twice does not double the tally. Corrections replace a note’s quantities instead of adding them again. Excluded notes remain available for reference. The CSV contains confirmed records only; the JSON also retains pending and excluded notes. Spreadsheet-sensitive text is escaped.&lt;/p&gt;

&lt;h3&gt;
  
  
  What the tests actually showed
&lt;/h3&gt;

&lt;p&gt;I generated eight short spoken fixtures locally with Microsoft Zira Desktop, plus digital silence and deterministic white noise. The &lt;a href="https://github.com/EazyHood/sweepsheet/blob/main/evidence/README.md" rel="noopener noreferrer"&gt;full method&lt;/a&gt; distinguishes synthetic speech, CPU inference and browser execution.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Test group&lt;/th&gt;
&lt;th&gt;Observed result&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Four unambiguous count sentences&lt;/td&gt;
&lt;td&gt;Three produced the intended quantities; one was held after a recognition failure&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Four correction, uncertain, vague or not-collected sentences&lt;/td&gt;
&lt;td&gt;All held for manual review&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Silence and white noise&lt;/td&gt;
&lt;td&gt;Neither proposed counts; noise was transcribed as “(water splashing)”&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The noise result matters too: even a speech model can invent a plausible description. Nothing about that output establishes that there was water, much less collected litter.&lt;/p&gt;

&lt;p&gt;The tests also check that pending and excluded notes never affect totals, corrections retain the earlier values, invalid quantities are rejected, and CSV text cannot become a spreadsheet formula. These checks protect the recording workflow; they do not establish outdoor ASR accuracy.&lt;/p&gt;

&lt;p&gt;The current limits are practical. It is English-only. Browser audio-format support varies. Model preparation needs internet, and offline page reload is not supported in this version. Browser storage can be cleared, so keep original recordings and export your work. Wind, real voices, accents and mobile performance still need field testing. I have not measured a reduction in screen time or claimed environmental impact from these example counts.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;AI assistance:&lt;/strong&gt; Codex substantially assisted with implementation, tests, documentation and this write-up. The synthetic demo voice is disclosed separately. No field experience, interviews or user metrics have been invented to fill in the story.&lt;/p&gt;

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

&lt;p&gt;The useful open component here is the transcription model, not a logo beside a text field. Without it, the user must type the recording into the notebook. With it, audio can be transcribed on the same device, without uploading cleanup recordings or obtaining an inference API key.&lt;/p&gt;

&lt;p&gt;The pinned weights and readable pipeline also make the failure above reproducible. Someone can try another open speech model against the same WAV files, or adapt the parser to another cleanup vocabulary, while keeping the confirmation rules intact. The application does not depend on a remote provider continuing to offer a particular model or pricing tier.&lt;/p&gt;

&lt;p&gt;A closed API could also transcribe these notes. The reason to use open weights is control over where inference happens and the ability to inspect and replace the component. It does not make recognition magically reliable.&lt;/p&gt;

&lt;p&gt;Cleanup logging itself already exists—&lt;a href="https://oceanconservancy.org/work/plastics/cleanups-icc/clean-swell-app/" rel="noopener noreferrer"&gt;Clean Swell&lt;/a&gt; is one example—and a voice memo plus a spreadsheet is a reasonable manual alternative. SweepSheet’s contribution is narrower: keep the recording beside a proposed tally, make uncertainty visible, and preserve what changed after review. The next useful test is taking that complete workflow to a real cleanup and finding out whether the bookkeeping is actually easier.&lt;/p&gt;

</description>
      <category>devchallenge</category>
      <category>hf26challenge</category>
    </item>
    <item>
      <title>A mano: remember the place, find the thing</title>
      <dc:creator>EazyHood</dc:creator>
      <pubDate>Fri, 02 Oct 2026 13:48:00 +0000</pubDate>
      <link>https://dev.to/eazyhood/a-mano-remember-the-place-find-the-thing-115</link>
      <guid>https://dev.to/eazyhood/a-mano-remember-the-place-find-the-thing-115</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;I built &lt;strong&gt;A mano&lt;/strong&gt; around a practical problem affecting Lucía, a designer who works from home. &lt;strong&gt;Lucía is a pseudonym for a real person who prefers to keep her identity private.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;She sometimes remembers what an object does more easily than its name or where she stored it. Connecting a laptop to a television becomes a search for the thing that puts the computer screen on the TV, rather than for “USB-C to HDMI.”&lt;/p&gt;

&lt;p&gt;A mano connects that remembered purpose to a saved record. Each object has a name, room, precise location and optional description. Ordinary keyword search works immediately. An optional open-weight model runs in the browser and finds additional matches from descriptions of what someone needs to do. It suggests existing records; it cannot invent locations.&lt;/p&gt;

&lt;p&gt;The useful result is deliberately simple: an editable card saying where to look. Users can update a location after moving an object, mark favorites, filter rooms and export a backup.&lt;/p&gt;

&lt;p&gt;The public demo contains ten synthetic records, separate from personal collections. Its adapter example reproduces a technically tested search; it is not evidence of Lucía's possessions, feedback or measured time savings.&lt;/p&gt;

&lt;p&gt;Personal records stay in the browser, without synchronization or encryption. The model needs an initial download and can return incorrect suggestions. Objects must first be recorded, and their locations kept current. Those limits remain visible alongside the working demo.&lt;/p&gt;

&lt;p&gt;The Spanish interface uses a compact catalogue layout, self-hosted Archivo and original SVG objects. Card transitions preserve context when filtering, while keyboard navigation and reduced-motion preferences remain supported.&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%2Frovqdhl69adqsgh77x4y.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%2Frovqdhl69adqsgh77x4y.png" alt="The A mano interface, showing synthetic demonstration objects" width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

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

&lt;p&gt;&lt;a href="https://eazyhood.github.io/a-mano/" rel="noopener noreferrer"&gt;Open A mano&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Try this route:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Keep &lt;strong&gt;Explorar demo&lt;/strong&gt; selected. Search &lt;code&gt;estuche gris&lt;/code&gt;; the adapter appears because that exact place is recorded.&lt;/li&gt;
&lt;li&gt;Clear the field and choose &lt;strong&gt;Activar&lt;/strong&gt;. The first activation downloads approximately 160 MB of public model and runtime assets. No account or paid inference key is needed.&lt;/li&gt;
&lt;li&gt;Search &lt;code&gt;quiero mostrar la pantalla del computador en el televisor&lt;/code&gt;. The model suggests the USB-C to HDMI adapter even though that sentence is not its title. Open its card to inspect the recorded location.&lt;/li&gt;
&lt;li&gt;Switch to &lt;strong&gt;Mis cosas&lt;/strong&gt;, add a harmless test object, edit its place and export a backup. The fictional and personal collections stay separate.&lt;/li&gt;
&lt;/ol&gt;

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

&lt;p&gt;&lt;a href="https://github.com/EazyHood/a-mano" rel="noopener noreferrer"&gt;Repository, reproducible checks and evidence&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;This is new source written during the event window, with OpenAI Codex assistance. Earlier projects informed design decisions; their code was not repackaged as this entry. The repository records authorship, third-party licenses, synthetic test data and current limitations.&lt;/p&gt;

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

&lt;p&gt;React and TypeScript handle the interface. Transformers.js 3.8.1 loads a pinned, quantized ONNX conversion of &lt;strong&gt;paraphrase-multilingual-MiniLM-L12-v2&lt;/strong&gt; in a Web Worker. Mean-pooled, normalized embeddings let cosine similarity rank existing names, descriptions and tags. Literal matches are retained and placed first, so activating AI does not make exact locations disappear.&lt;/p&gt;

&lt;p&gt;The asynchronous details matter: stale queries and collection versions are ignored, clearing a query restores the ready state, and room filters operate on all qualifying candidates rather than a prematurely shortened result list. The model cannot write or delete records.&lt;/p&gt;

&lt;p&gt;The app passed 55 unit tests, production compilation and browser checks for add/edit/favorite/reload, export/delete/restore, narrow layouts and actual ONNX inference. A loaded session could also search with the network disabled. This does not establish offline page reload support.&lt;/p&gt;

&lt;p&gt;In eleven synthetic target queries against the ten-object demo, literal search found two target records and the hybrid approach found nine. Two absent-object examples produced no result. The model still missed an Allen-key paraphrase and a sofa-measuring paraphrase. A second open model and a fragmented index did not improve the tradeoff, so neither was shipped. These are small reproducible examples, not a user study or an accuracy guarantee. &lt;a href="https://github.com/EazyHood/a-mano/blob/main/docs/ai-evaluation.md" rel="noopener noreferrer"&gt;Read the evaluation and its failures&lt;/a&gt;.&lt;/p&gt;

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

&lt;p&gt;Open weights and a browser runtime let the semantic search happen on the device without sending household descriptions to a hosted inference API. They also make it possible to pin the model, compare alternatives and publish the actual evaluation, including failures.&lt;/p&gt;

&lt;p&gt;That choice has costs: a noticeable first download, device computation and imperfect suggestions. Browser storage is not encrypted or synchronized, and the hosting services still receive ordinary asset requests. The design makes those boundaries visible instead of implying that local inference solves every privacy or reliability problem.&lt;/p&gt;

</description>
      <category>devchallenge</category>
      <category>weekendchallenge</category>
      <category>hf26challenge</category>
    </item>
    <item>
      <title>The cache key that only looked at one of its four inputs</title>
      <dc:creator>EazyHood</dc:creator>
      <pubDate>Sun, 02 Aug 2026 15:47:59 +0000</pubDate>
      <link>https://dev.to/eazyhood/the-cache-key-that-ignored-the-question-2g59</link>
      <guid>https://dev.to/eazyhood/the-cache-key-that-ignored-the-question-2g59</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for &lt;a href="https://dev.to/bugsmash"&gt;DEV's Summer Bug Smash: Clear the Lineup&lt;/a&gt; powered by &lt;a href="https://sentry.io/" rel="noopener noreferrer"&gt;Sentry&lt;/a&gt;.&lt;/em&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%2F5xudapwnqmzh9vdxl63n.jpg" 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%2F5xudapwnqmzh9vdxl63n.jpg" alt=" "&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Project Overview
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/Paritok-official/paritok-4b-v1" rel="noopener noreferrer"&gt;Paritok&lt;/a&gt; is a context compressor. You&lt;br&gt;
hand it a blob of text, a query describing what you care about, and a compression level,&lt;br&gt;
and it hands back a shorter version that is supposed to keep what matters &lt;em&gt;for that query&lt;/em&gt;&lt;br&gt;
and drop the rest. Results are cached, because compression is the expensive part.&lt;/p&gt;

&lt;p&gt;I was not looking for bugs in it. I was building an audit harness to measure how much&lt;br&gt;
&lt;em&gt;meaning&lt;/em&gt; compression costs — feeding the same corpus through with different queries and&lt;br&gt;
checking which critical substrings survive: file paths, error types, line numbers,&lt;br&gt;
identifiers.&lt;/p&gt;
&lt;h2&gt;
  
  
  Bug Fix or Performance Improvement
&lt;/h2&gt;

&lt;p&gt;Two rows in my results table were byte-for-byte identical. Different query, different&lt;br&gt;
compression level, same 544 characters:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;query="Fix the IntegrityError on commit"              level=L0  -&amp;gt;  159 tok  cache_hit=False
query="Explain the tax rounding TODO in compute_tax"  level=L3  -&amp;gt;  159 tok  cache_hit=True
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;compress()&lt;/code&gt; takes four things that shape its output — &lt;code&gt;content&lt;/code&gt;, &lt;code&gt;query&lt;/code&gt;, &lt;code&gt;level&lt;/code&gt; and&lt;br&gt;
&lt;code&gt;kind&lt;/code&gt;. The cache was keyed on one of them:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;sid&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;content_hash&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;content&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;cached&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;storage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get_cached_compressed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sid&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So the first caller's answer was served to every later caller with the same input text, no&lt;br&gt;
matter what they actually asked. The second caller got a compression tuned to somebody&lt;br&gt;
else's question, marked &lt;code&gt;cache_hit=True&lt;/code&gt;, with nothing in the response to say so.&lt;/p&gt;

&lt;p&gt;This is worse than a stale cache. A stale cache gives you an old answer to &lt;em&gt;your&lt;/em&gt; question.&lt;br&gt;
This gives you a fresh answer to &lt;em&gt;someone else's&lt;/em&gt;.&lt;/p&gt;
&lt;h2&gt;
  
  
  Code
&lt;/h2&gt;

&lt;p&gt;The fix is open as a PR: &lt;strong&gt;&lt;a href="https://github.com/Paritok-official/paritok-4b-v1/pull/17" rel="noopener noreferrer"&gt;Paritok-official/paritok-4b-v1#17&lt;/a&gt;&lt;/strong&gt; — 2 files, +118/−12.&lt;/p&gt;

&lt;p&gt;The audit harness that surfaced it is at&lt;br&gt;
&lt;a href="https://github.com/EazyHood/paritok-audit" rel="noopener noreferrer"&gt;EazyHood/paritok-audit&lt;/a&gt; (Apache-2.0).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# The compressed result depends on query, level and kind as well as on the
# content -- query is documented as driving keep/drop -- so all four belong
# in the key. Keying on content alone returned the first caller's answer to
# every later caller. `sid` deliberately stays content-only, because
# expand_context resolves originals by content and that behaviour is correct.
&lt;/span&gt;&lt;span class="n"&gt;cache_key&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;content_hash&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\x00&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="n"&gt;sid&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;level&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="sh"&gt;""&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;kind&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="sh"&gt;""&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;query&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="sh"&gt;""&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# 4. Cache check (same content AND same intent gets the same answer)
&lt;/span&gt;&lt;span class="n"&gt;cached&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;storage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get_cached_compressed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cache_key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  My Improvements
&lt;/h2&gt;

&lt;p&gt;Three decisions in this patch are worth explaining, because the obvious fix is wrong.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Don't change &lt;code&gt;sid&lt;/code&gt; — add a key beside it.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The tempting one-liner is to fold the query into &lt;code&gt;sid&lt;/code&gt; and move on. That breaks something&lt;br&gt;
else: &lt;code&gt;expand_context&lt;/code&gt; resolves a compressed reference back to its original &lt;em&gt;by content&lt;br&gt;
hash&lt;/em&gt;. &lt;code&gt;sid&lt;/code&gt; has to stay content-only for that to keep working. So the patch introduces a&lt;br&gt;
separate &lt;code&gt;cache_key&lt;/code&gt; and leaves &lt;code&gt;sid&lt;/code&gt; exactly as it was. Two identifiers, two jobs.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Classify &lt;code&gt;kind&lt;/code&gt; before building the key, not after.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;kind&lt;/code&gt; was being resolved &lt;em&gt;after&lt;/em&gt; the cache check. That meant a caller passing &lt;code&gt;kind=None&lt;/code&gt;&lt;br&gt;
and a caller passing the same kind explicitly would key differently, even though the&lt;br&gt;
compressor would treat them identically — a cache miss on every first call, forever.&lt;/p&gt;

&lt;p&gt;Moving classification above the cache check fixed that, and it fixed a second bug on the&lt;br&gt;
way: only &lt;code&gt;LocalModelStrategy&lt;/code&gt; sniffed &lt;code&gt;kind&lt;/code&gt; internally, so &lt;code&gt;GpuServerStrategy&lt;/code&gt; was&lt;br&gt;
forwarding &lt;code&gt;kind=None&lt;/code&gt; to the server. Central classification means every backend now&lt;br&gt;
receives a real value.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Join the parts with a null byte.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;"\x00".join(...)&lt;/code&gt; rather than &lt;code&gt;"-".join(...)&lt;/code&gt; or plain concatenation. Without a separator&lt;br&gt;
that cannot occur in the inputs, &lt;code&gt;level="L0"&lt;/code&gt; + &lt;code&gt;kind="1code"&lt;/code&gt; and &lt;code&gt;level="L01"&lt;/code&gt; +&lt;br&gt;
&lt;code&gt;kind="code"&lt;/code&gt; collide into the same key. It costs nothing and removes a class of bug that&lt;br&gt;
would be genuinely miserable to track down later.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The test.&lt;/strong&gt; &lt;code&gt;tests/test_cache_key_intent.py&lt;/code&gt; (+92) asserts the property directly: same&lt;br&gt;
content with different queries must not return the same object, and the same content with&lt;br&gt;
the same intent must hit the cache. It fails on the original code and passes on the patch,&lt;br&gt;
which is the only claim about a fix I actually trust.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I took away from it
&lt;/h2&gt;

&lt;p&gt;I found this because my harness printed &lt;code&gt;cache_hit&lt;/code&gt; next to every row. If it had only&lt;br&gt;
printed token counts, two identical numbers would have looked like a compressor being&lt;br&gt;
consistent, which is exactly what you want it to be.&lt;/p&gt;

&lt;p&gt;The bug was invisible in the metric everyone watches and obvious in the one nobody logs.&lt;br&gt;
Since then I print the cache flag next to every cached result I benchmark — the cost is one&lt;br&gt;
column, and it is the column that told me the answer I was measuring wasn't mine.&lt;/p&gt;

</description>
      <category>bugsmash</category>
      <category>devchallenge</category>
      <category>debugging</category>
      <category>python</category>
    </item>
  </channel>
</rss>
