My sites were writing notes nobody read
What this is about. I asked my AI to build Sentinel, a small tool that reads my whole codebase and tells me where it's unsafe, copied or too clever. Security comes first: risky patterns, routes nobody guards, HTML that g
What this is about. I asked my AI to build Sentinel, a small tool that reads my whole codebase and tells me where it's unsafe, copied or too clever. Security comes first: risky patterns, routes nobody guards, HTML that goes onto a page unchecked. On the first day it found six websites lovingly maintaining files that no code ever reads. It also found a bug that wasn't one.
Why. If you run several sites from one template, your copies drift. The question is whether you find out from a tool or from a customer.
The brief
My words, typos and all: "I want you to make a Sentinel, a lightweight code quality tool, which checks the current architecture, looks for where code is multilied and what could be made simpler."
Before writing a line, the AI checked what already exists. Claude Code's own review commands only look at a diff, so they never see what's already in the tree. jscpd finds copies, Semgrep finds risky patterns and knip finds dead code, but none of them knows my rules. One of those rules is that the logged-in user carries a list of roles, never a single role. So Sentinel became one zero-dependency Node script that knows the house rules, finishes in about two seconds, and keeps a baseline file where every accepted finding needs a written reason.
Bark one: the wrong burglar
The first report flagged a "real authorization bug": an admin page checking user.role, which on my sessions is always undefined. It sounded very serious. It was wrong. That user came from a different API, which really does return a single role. The AI traced it, apologised, and narrowed the rule so it only fires on the session user.
The same report announced 152 "stale" template copies. That was wrong too. The sync manifest lists every template file, including the ones a site changed on purpose, so it can't tell a forgotten copy from a deliberate one. Git history can. The real count was 27.
A watchdog that barks at the postman is worse than no dog, so both got fixed before anything else.
Bark two: the drawer
The 27 were real. The script that copies shared files into each site skipped any file that already existed, forever. Fix a template and the fix stopped at the first site that had ever synced. A better login error message had been in the template for a while and had reached one site out of six.
Now the sync remembers a hash of what it last wrote. If a site's copy still matches that hash, nobody touched it, so sync updates it. If the hash differs, it's the site's own version and it's left alone. The first real run carried a fix to all six sites with no --force.
Then the drawer. Every site had its own folder of translation files, about 350 of them across the six. Nothing imported them. The sites read their texts from the shared package, so the copies were decoration. Someone had still been editing them faithfully. One site said "We're out kayaking right now. Please come back a bit later." Another said they were out playing guitar. Nobody ever saw either, because the page that should show them displayed the raw key home.fallback_title instead.
The folder is gone. The missing texts moved to the one place that's actually read, and Sentinel now checks every translation key the code asks for. It found 25 more that pointed to the wrong place, plus a T-lab label defined twice in the same object, where the second silently wins. The size readout lost its percentage that way.
What happened, and how else to do it
- Copies froze at first sync. Fixed: sync records hashes and updates untouched copies.
- Dead translation folders, edited by hand. Deleted, and the live texts recovered.
- Missing and misrouted translation keys. Fixed, and now a check.
- Two false alarms on day one. Rules narrowed, with tests for both.
- The security findings. Checked one by one, and the real ones fixed. I'll spare you the details.
| Option | Better at | Costs |
|---|---|---|
| Claude's diff review commands | Catching problems in each change | Blind to everything already merged |
| jscpd + Semgrep + knip | Mature, precise, big rule libraries | Three configs, no idea of your house rules |
| A home-made Sentinel | Knows your rules, records decisions | You maintain it, and it starts out wrong |
Rule of thumb: if a file is copied, something must own updating it. If nothing does, you've built a drawer.
Rebel Kayaks, one of the six, is at rebelkayaks.eu. After its next deploy, its fallback page says something human.
Originally published at idunworks.com.
Originally published by Dev.to Security. Aggregated on AIWithGhost for educational purposes — full credit and traffic to the original publisher.