Skip to content

chore: a count in a sentence is checked, or it stops being a count - #222

Merged
productdevbook merged 1 commit into
mainfrom
chore/a-count-in-prose-is-a-bug-waiting
Aug 20, 2026
Merged

chore: a count in a sentence is checked, or it stops being a count#222
productdevbook merged 1 commit into
mainfrom
chore/a-count-in-prose-is-a-bug-waiting

Conversation

@productdevbook

Copy link
Copy Markdown
Owner

The architecture answer to "why does this keep finding gaps, and how do we get ahead of it". Measured before it was built.

What the measurement said

This workspace is a third prose by line: 10,939 of 31,615 non-blank source lines are doc comments — before CLAUDE.md, the changelog, the register and the skills. The compiler has an opinion about none of it.

Of twelve defects found in one day's own work: eight were prose, three were code, one was process. All three code defects were caught within minutes — by the compiler, by an existing test, by a new one. None of the eight was caught by anything but somebody reading.

And corrections rot faster than original writing. Every long-standing count in this repository verified; the three wrong ones were written the day before, by the changes that were correcting something else. A small local edit gets less scrutiny than new code.

scripts/counts.py

Reads the source for a fact and the prose for the claim. CI runs it.

It is deliberately small — three facts, each with a history of rotting — and it earned its place while it was being written, catching three stale citations in sequence, including one in a role file that the change fixing CLAUDE.md had not reached.

Its --self-test calls the production comparison rather than a copy. That is the mistake coverage.py's self-test makes: recomputing the two set differences inline proves the copy works and says nothing about the original.

The larger half: stop writing the number

Most of these should not be numbers at all. "A change here reaches every adapter" carries what "five adapters" carried and cannot go stale. Four became words — including conformance.rs's "all six clients", now "every client in the roster", and the roster is latched.

Why the list is hand-kept, and why that is the right call here

Measured, not assumed: 112 (number + countable noun) pairs live in this repository's prose, and almost all are rhetorical — "four ways of reaching green", "six currencies iyzico settles in", "one provider". A check over all of them is ninety false positives, which is a check people learn to route around.

So the list is small, every entry has a reason, and per ratchets it may only shrink: a count that becomes a word, or a command, leaves it and does not come back.

money-safety §5

Gains the marker the other four carry. It named two shipped defects — #168's inverted refund-key rule and #187's refunds summing to nothing — without saying so in the form the rest use. That is why the count disagreed with the file rather than the file disagreeing with itself.

The rule, in CLAUDE.md

One claim, one home. A checkable claim becomes a check. A number is a word or it is in counts.py. An unverifiable claim goes in UNVERIFIED.md. And measure a rule before you write it — twice in one day a fix that sounded right was refused by its own measurement, the sharpest being that widening the doc-seam detector to skip a blank /// matches 380 comments, because that is the correct shape for one.

CI decides.

The architecture answer to a question worth asking: why does an audit keep
finding gaps, and how does it stop.

Measured first. This workspace is a third prose by line — 10,939 of 31,615
non-blank source lines are doc comments, before CLAUDE.md, the changelog, the
register and the skills — and the compiler has an opinion about none of it. Of
twelve defects found in one day's own work, eight were prose and three were
code. All three code defects were caught within minutes, by the compiler, by an
existing test, and by a new one. None of the eight was caught by anything but
somebody reading.

And corrections rot faster than original writing. Every long-standing count in
this repository verified; the three wrong ones were written the day before, by
the changes that were correcting something else. A small local edit gets less
scrutiny than new code.

So: scripts/counts.py reads the source for a fact and the prose for the claim,
and CI runs it. It is deliberately small. The three facts in it are the ones
with a history of rotting, and it caught three stale citations while it was
being written — including one in a role file the change that fixed CLAUDE.md
had not reached.

Its `--self-test` calls the production comparison rather than a copy of it,
which is the mistake coverage.py's makes: recomputing the two set differences
inline proves the copy works and says nothing about the original.

The larger half is that most of these should not be numbers. "A change here
reaches every adapter" carries what "five adapters" carried and cannot go
stale. Four such counts became words, including conformance.rs's "all six
clients", which now says "every client in the roster" — and the roster is
latched.

Why the list is hand-kept, measured rather than assumed: 112 (number +
countable noun) pairs live in this repository's prose, and almost all are
rhetorical — "four ways of reaching green", "six currencies iyzico settles in",
"one provider". A check over all of them is ninety false positives, which is a
check people learn to route around. So the list is small, every entry has a
reason, and it may only shrink.

money-safety §5 gains the marker the other four carry. It named two shipped
defects — #168's inverted refund-key rule and #187's refunds summing to nothing
— without saying so in the form the rest use, which is why the count disagreed
with the file rather than the file disagreeing with itself.

CLAUDE.md gains the rule the whole thing is for: one claim, one home; a
checkable claim becomes a check; a number is a word or it is in counts.py; an
unverifiable claim goes in UNVERIFIED.md; and measure a rule before writing it.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Aug 20, 2026

Copy link
Copy Markdown

Warning

Review limit reached

@productdevbook, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 6 minutes

Limit details: You’ve used all 10 included reviews currently available.

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

Wait for the limit to reset, then comment @coderabbitai review or push new commits to the PR.

An organization admin can change what happens after included review limits in Billing.

How do review limits work?

CodeRabbit enforces per-developer PR review limits within each organization.

For paid Pro and Pro+ reviews, CodeRabbit uses a developer's included PR review attempts over the past 7 days to set the current hourly allowance. At typical activity levels, the full plan allowance applies. Higher sustained activity can lower the allowance until earlier attempts leave the 7-day window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: f35e2ccd-af89-42be-afd8-818a54961d16

📥 Commits

Reviewing files that changed from the base of the PR and between 293f613 and 10fef8d.

📒 Files selected for processing (8)
  • .claude/agents/kasapay-core.md
  • .claude/agents/kasapay-provider.md
  • .claude/agents/kasapay-review.md
  • .claude/skills/money-safety/SKILL.md
  • .github/workflows/ci.yml
  • CLAUDE.md
  • crates/kasapay/tests/conformance.rs
  • scripts/counts.py

Comment @coderabbitai help to get the list of available commands.

@productdevbook
productdevbook merged commit 812139d into main Aug 20, 2026
8 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant