Skip to content

refactor: give each duplicated rule one home - #104

Merged
GauranshMathur merged 2 commits into
mainfrom
refactor/one-rule-one-home
Sep 1, 2026
Merged

refactor: give each duplicated rule one home#104
GauranshMathur merged 2 commits into
mainfrom
refactor/one-rule-one-home

Conversation

@GauranshMathur

Copy link
Copy Markdown
Owner

Closes finding 9 of the 2026-08-18 architecture review, tracked in #90. Three rules, each written more than once — and each needing a different answer, which is why this wasn't mechanical.

Tags are lowercase — four copies, one of them different

Tag, Post#sync_tags, ApplicationHelper and TagsController each downcased, and only Tag also stripped whitespace. So "#Ruby " reached three of them as a different string from the one the fourth stored. Tag.normalize is now the rule; the other three call it.

What a username is — two definitions that disagreed

user.rb    /\A[a-z0-9_]{3,20}\z/     # what may be stored
routes.rb  /[A-Za-z0-9_]+/           # what may be typed

Nothing said whether the disagreement was intended. It is — and that's the interesting part: the route is deliberately looser so /@ADA reaches the controller, which downcases before looking up. A stricter route would 404 on a handle someone capitalised, which is worse than finding it.

So this isn't "delete one". Both are now derived from one character class and one length range, with that reasoning written where they're defined. Verified /@ada and /@ADA both return 200 against a running server.

The ranking formula — two copies bound by a comment

RankedFeed#score and script/scaling-curve each held the expression, joined only by the words "the ranking, as RankedFeed#score computes it". A comment cannot fail.

It moved to Ranking — a plain module with no Rails dependency, which is precisely what lets the benchmark script require it directly. That dependency was the reason the copy existed.

Cost, stated

config/routes.rb now references a model constant, so the routes file autoloads User at boot. Supported, and verified (bin/rails routes and a live /@ada both work) — but it's a coupling the previous literal didn't have. The alternative, a spec asserting the two regexes agree, would have left two definitions plus a test holding them together, which is the shape this finding is about.

Measured

Rule Before After
Tags are lowercase 4 copies, 1 differing 1
What a username is 2 disagreeing definitions 1 source, 2 derived
The ranking formula 2 copies, bound by a comment 1
Specs guarding any of them 0 9

The guards were checked by mutation, not trusted. Dropping strip, removing digits from the username character class, and changing the decay exponent each failed an example — because nine specs written green prove nothing on their own. Suite 380 → 389, RuboCop clean.

Finding 8 is deliberately not done

Like and Repost are one concept written twice across twelve files. The review's own judgement is that the duplication is stable and worth doing "when a third engagement type appears". Building a shared abstraction for two cases with no third in sight is exactly the scaffolding-ahead this repo forbids — so #90 stays open for finding 8, with that reasoning recorded in the findings table rather than closed by a premature module.


Generated by Claude Code

Tags were downcased in four places and stripped in only one, so the same
hashtag reached three of them as a different string. The username rule
was two regexes that disagreed on case and length with nothing saying
whether that was intended — it is, and both are now derived from one
character class with the reason written down. The ranking formula was
two copies bound by a comment; it moved to a plain module the benchmark
script can require without booting Rails, which is why the copy existed.

Nine guards, each checked by mutation rather than trusted: dropping
strip, removing digits from the username characters and changing the
decay exponent all fail an example.

Finding 8 stays open on the review's own judgement.
@GauranshMathur
GauranshMathur merged commit 4698ed3 into main Sep 1, 2026
7 checks passed
@GauranshMathur
GauranshMathur deleted the refactor/one-rule-one-home branch September 1, 2026 14:09
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.

2 participants