You are browsing as a guest. Sign up (or log in) to start making projects!

7h 31m 7s logged

Devlog - how I accidentally almost shipped a lie detector that couldn’t detect lies: So Ellery already told you what was true about your data. Findings, plain English, click one and it peels open down to the exact rows. Nice. The problem was how it did that.Every finding carried a loose bag of numbers called evidence. And then, three separate times, a file called pull.js squinted at that bag and tried to reverse-engineer what the detector had been thinking. Three parallel switch (detector) statements. One to figure out which rows mattered, one to write the explanation sentence, one to write the derivation. Add a detector, edit four files, pray. Worst part: to figure out which rows a finding covered, pull.js re-ran the detector’s filter from scratch. Two copies of the same logic, living in different files, free to disagree. The finding says “3 records are low on stock,” the highlight lights up 4, and nobody notices for six months.The fix, and the part where I was wrongReplace the bag of numbers with an actual graph. Each finding now carries the computation that made it - max over a column, count over classified statuses - as nodes that hash to their own content, bottoming out at fingerprinted cells.I’d designed the graph nodes to include their computed value in their identity. Claude pushed back: separate identity from evaluation. The node names the computation; the value is what you get when you run it against data. Fine, sure, whatever - except it turns out that’s the entire ballgame, because now you get two fingerprints. One for the reasoning, one for the reasoning-applied-to-this-data. Which means the app can now tell you “your numbers changed but the logic didn’t” versus “the logic itself moved.” That’s a genuinely different product capability and it fell out of a definition change.Second thing I got wrong: I’d let the graph carry rowIndices. Row indices! In the evidence layer! That’s render state wearing a trenchcoat. Now it carries a witness - records addressed by content fingerprint - and the renderer figures out where they currently sit. Also, a haunting: Spent a solid while convinced the trace had 1,200px of unreachable content. Built a control experiment. Scrolling was fine. The real culprit was scroll-behavior: smooth - I was setting the scroll position and reading it back mid-animation, watching it clamp at 61.5px, and concluding the layout was broken. There was no bug. I nearly “fixed” a phantom. Small indignity: While all this was happening we discovered npm run lint was pointed at public/js, a directory that hasn’t existed since the frontend moved to the repo root. It had been linting nothing. For a while. Repointed it, and it immediately snitched on a pile of dead imports. Shipped: the derivation graph, two-fingerprint identity, a verify button that can actually say no, golden tests over the whole truth path, and a linter that lints. Deleted: more than I added, where it counted.

0
31

Comments 0

No comments yet. Be the first!