Six commits landed on the working branch since the last entry. The full security audit the owner ordered has run from end to end over the exact commit that closed the last one, and no critical finding came out of it. The one high finding was closed the next morning: issuing a new set of recovery codes now asks for a live code first. And the rate limits on the live site were checked against the real server rather than taken on trust.
An audit that runs to the end
The audit ran over the commit the last entry closed on, with everything built so far in scope: the web application, the website, the theme behind this news site, and every control the threat model declares. The shape of the run is the part worth reporting. Reconnaissance first, across every dynamic route and twelve subsystems. Then ten hunting passes, then a check on what those passes had actually covered, then four more aimed only at the gaps that check named. 83 units of work in total, and nothing was called a finding until it had been reproduced a second time, independently of the reasoning that first proposed it. Seven duplicates were merged before that stage, so a thing found twice is counted once.
How the results would be handled was settled before the run started. The run’s own directory is ignored by git before its first file is written. What is committed is a counts table, and a finding’s title and severity join that public log once its fix has shipped, not before. Nothing is filed as a public issue. And each confirmed finding became its own slice of work that starts from a reproduction test written to fail, because a fix with no failing test in front of it is a claim rather than a repair.
A new set of recovery codes asks for a code first
An account with a second factor holds ten recovery codes, shown once and meant to be printed, and a control that issues a fresh set. A fresh set cancels the printed one, and it hands whoever asked for it a code that satisfies the very check guarding the two most serious things an account can do. So it now asks for the same proof as those two: the current code from the authenticator app, or one of the remaining recovery codes, which is spent by the asking.
Two details carry the reasoning. Offering nothing gets its own sentence rather than the wrong-code one, because a missing code is not a mistyped code and the person reading the refusal needs to know which of the two they are looking at. And every refusal leaves the printed sheet exactly as it was: a failed attempt can never cost somebody the codes they already hold.
One rule behind four doors
Four routes now demand a live credential: turning the second factor off, issuing a new set of recovery codes, the second step of signing in, and deleting the account. All four run the same function, so the fourth was added to a list rather than to the code, and the rule cannot drift between the doors it guards.
The test that asserted a bare request was answered with a new sheet was asserting the defect. Its requirement changed on the record first, in the screen specification, and only then in the test: red observed, then green. The module’s suite went from 40 to 42 tests and the browser suite ran 1,456 of 1,456. In the threat model’s table, the row for an account’s deletion leaving its credentials behind reads in place again, because a new sheet can no longer mint the proof that deletion demands.
The limits are on, and the check ran against the live server
One question could not be answered from the repository at all: does the live site see a visitor’s address? If it does not, every per-address limit is off in production, whatever the code says, and a rate limit nobody has watched work is a belief rather than a control.
The owner answered it by running it. 21 wrong-password sign-ins from one address against gymai.coach: 401 twenty times, then 429. The limits are on. The question is closed with that evidence written beside it, and the owner’s answers went into the plan the same night rather than staying in a chat window, where a fact of that kind survives exactly as long as somebody remembers it.
51 checks, 10,146 unit tests and 1,456 browser tests
The gate reads 51 checks, all green, and the last full run read 10,146 unit tests and 1,456 browser tests, the same figures as the last entry: this week moved the shape of the product rather than its volume. The standing counts, each written by the check that derives it: 55 routes, 27 rate-limited; 1,871 rule citations resolving by number; documented coverage across 251 modules; 81 artboards; Node pinned at 22.23.2.
What comes next
More of the same discipline, each slice starting from a failing test, and the work towards opening the free gym listing carries on behind it.
If you would rather be told when GymAI opens than keep checking, the waiting list is on gymai.coach.
No comments yet
Nobody has written anything here. You can be the first.