{"schemaVersion":"1.0","type":"Article","slug":"my-ledger-said-i-posted-zero-replies-on-a-day-i-posted-two-because-the-tool-was-classifying-rows-by-a-cell-i-type-by-hand-k5bih","url":"https://api.zyvop.com/my-ledger-said-i-posted-zero-replies-on-a-day-i-posted-two-because-the-tool-was-classifying-rows-by-a-cell-i-type-by-hand-k5bih","title":"My ledger said I posted zero replies on a day I posted two, because the tool was classifying rows by a cell I type by hand","subtitle":null,"tldr":"A counter in my own records told me I had posted zero replies on a day I posted two. The classification read a cell I type by hand, and the convention it called constant was honoured by 7 of 17 rows. What the fix was, why the zero went unread, and the loud failure that arrived while fixing it.","keywords":["Programming","Python","developer tools","Case Studies"],"entities":["Mathieu Ades","Founder","Programming","Python","developer tools","Case Studies","ZyVOP"],"keyTakeaways":["I distribute a small browser extension by writing in public.","Everything I do lands as a row in a markdown ledger: publications, replies to people, emails sent.","A handful of scripts read that ledger and tell me what I am still allowed to do today, because I hold myself to caps."],"headings":["How the classification worked","The convention is not constant","Why nobody noticed","The fix is not a better regex","The error log I earned","After","Disclosure"],"outboundLinks":["https://blueticks.io/"],"contentText":"I distribute a small browser extension by writing in public. Everything I do lands as a row in a markdown ledger: publications, replies to people, emails sent. A handful of scripts read that ledger and tell me what I am still allowed to do today, because I hold myself to caps. On the morning of 28 August one of them told me this. My tooling speaks French, so I gloss each line underneath. 9 surface(s) reglee(s), 4 ligne(s) datees du 2026-08-28 lues au tracker, dont 4 publication(s) et 0 reponse(s). Indie Hackers 2 pose(s) aujourd hui, **aucun plafond mesure** Four rows read, four publications, zero replies , two of them posted on one community site. I had posted two replies the night before and no publication there at all. The zero was wrong and so was the two. How the classification worked A reply and a publication both occupy one row under the same platform name. They fall under different caps, so the tools have to tell them apart. They did it by reading the platform cell and looking for a suffix after the first comma. REPONSE = re.compile(r'^(reponse|réponse|commentaire)', re.I) ... morceaux = c[2].split(',') # \"Indie Hackers, reponse a X\" reste = ','.join(morceaux[1:]).strip() if REPONSE.match(reste): repons[cible] = repons.get(cible, 0) + 1 else: faits[cible] = faits.get(cible, 0) + 1 Two separate files did this, and both carried a comment calling the naming convention constant, on a count taken four days earlier: 23 replies and 208 publications. The convention is not constant I wrote twenty lines to check, over the one table in the ledger that contains nothing but replies. journal des reponses : lignes 486 a 507 17 ligne(s) datee(s), dont 10 SANS le suffixe de convention l.490 Indie Hackers l.499 r/GMail l.500 Quora Ten of seventeen rows in the replies table do not carry the suffix. The convention my code called constant is honoured by seven rows out of seventeen, in the table that exists only for replies. Eight of those ten had been miscounted for a month and nothing said so. They only became visible when two of them collided with a URL that already appeared as a publication, which tripped a different check entirely. Why nobody noticed The wrong number never hit a rule. That community site has no measured ceiling in my config, so 2 pose(s) printed next to the words no ceiling measured and went by. On a site with a ceiling it would have been a false overrun, and a false overrun is worse than silence: it teaches you to skip the alert on the exact tool you wrote because a real overrun once slipped past. The fix is not a better regex The real mistake was treating a hand typed cell as an instrument. A cell I type is testimony. It records what I meant. It cannot measure, because the thing being measured is my own typing. The section header above the row is different. It is structure. A row under the replies journal is a reply whether or not anyone wrote the word in the cell, and that is true of all seventeen rows rather than seven. def est_reponse(entete, cellule_plateforme): \"\"\"Either signal suffices. The section settles rows in the journal; the suffix catches replies recorded elsewhere.\"\"\" return sous_journal_reponses(entete) or suffixe_reponse(cellule_plateforme) I kept the regex deliberately. Twenty two replies in my ledger live outside that journal, recorded under other sections, and structure alone would miss every one. Two signals that do not share an assumption, and neither can veto the other: a badly named reply is still a reply, and so is a reply filed somewhere else. The error log I earned My patch inserted the import with a string replace that assumed one import per line. That file declares import io, re, sys . Traceback (most recent call last): File \"verif_tables.py\", line 174, in &lt;module&gt; n, d, expl = doublons('tracker.md') File \"verif_tables.py\", line 72, in doublons ent = sections.entetes(fichier) NameError: name 'sections' is not defined This is the good kind of failure. It arrived in under a second and named the line. The bug it was patching had been quiet for weeks. After The same command, later on the morning of 28 August: dont 2 publication(s) et 2 reponse(s). Indie Hackers 0 pose(s) aujourd hui, et 2 reponse(s) hors cadence Two publications, two replies, zero posted on that site. The duplicate check went from seven explained collisions and two real ones to nine explained and none. A third counter read one effective publication rather than two that morning, and that gap is explained rather than smoothed: one of the two was born with a noindex tag, so it is public but not indexable, and it does not count as effective for me. Every number above is a reading taken at a stated moment, not a standing state. I published again later the same day, and all three counters moved. I did not rewrite the ten cells. Fixing the data would leave the instrument depending on my typing for every row I add next. The tool changed, not the ledger. Disclosure I build BlueTicks for Gmail, a Chrome and Firefox extension that shows WhatsApp style ticks in your Gmail sent list, one tick sent and two blue ticks opened. It costs 4 dollars a year, and the free tier covers 30 emails a month. Everything above comes from distributing it in public and writing down what the tools did. You can find it at blueticks.io . If a check classifies your rows by something a human writes, it is not measuring your rows. It is measuring your discipline, and reporting the result as if it were data.","contentHash":"sha256:ce607e58cd541e0e407696457c878aafec258b5df263f2cb6d5bfca98191926e","authorName":"Mathieu Ades","authorUrl":"https://api.zyvop.com/author/mathieu","authorSameAs":["https://blueticks.io/"],"category":"Case Studies","tags":["Programming","Python","developer tools"],"audience":"Readers researching Case Studies","tone":"Professional, founder perspective","readingTimeMinutes":4,"wordCount":969,"faqs":null,"primaryTopic":"Case Studies","publishedAt":"2026-08-28T15:55:02.046Z","updatedAt":"2026-09-02T09:30:00.134Z","canonicalUrl":"https://api.zyvop.com/my-ledger-said-i-posted-zero-replies-on-a-day-i-posted-two-because-the-tool-was-classifying-rows-by-a-cell-i-type-by-hand-k5bih"}