Blog · Building Hellofew, week by week, part 2 of 8

Week of 31 August 2026: everything that touches money or the account, first

Adarsh Mamgain · 31 October 2026

The second week of the build was one day, Sunday 6 September, and it had the highest fix-to-feature ratio of any week in the log: three features, five fixes to them, all before dinner. I think that ratio is the honest shape of a week where you wire up the two things you cannot get wrong, taking money and holding somebody's LinkedIn session, and then find out what you got wrong.

The three features

The first commit is the foundation: a real auth library, billing through Dodo Payments, the LinkedIn connection through Unipile, and the first thing the product writes, an ideal customer profile generated from a product page. That last one is still the first thing a new customer sees, and it is still free, because reading somebody's product page and telling them who to sell to is the cheapest possible way to let them judge whether the model has understood their business before they pay $49/month to find out.

The second feature is observability: structured logs, incidents with a severity tier, and an admin page to read them on. I built this before the product could send a single message, which looks like procrastination from the outside. It was not. A product that acts on a customer's LinkedIn account while they sleep has to be able to say what it did and why, and the first time it does something wrong, the log is the only witness.

The third is a command-line tool for registering the provider's webhooks, the notifications that say an account's session changed or a message arrived. Dull, and the kind of thing that gets done by hand once and then wrong forever. It has been run after every change to the webhook routes since.

The five fixes, and the one that mattered

  • A status webhook from the provider could clear the gate that decides whether an account is allowed to send. Fixed so that no webhook can ever open the gate; a webhook can only close it.
  • The model was being asked for JSON without being shown the schema, and the tests were raising real incidents that paged me. Both fixed in one commit, because they were found in the same hour.
  • The billing webhook wrote an audit row, and when that row failed to write, the customer's entitlement was rolled back with it. A paying customer could lose access because of a logging failure. Fixed by separating the two: the entitlement is written first and alone.
  • The LinkedIn connection was not being recorded after the provider confirmed it, and the connection count was read from the wrong object in the provider's response. Both found by connecting my own account and watching nothing happen.

The billing one is the one I still think about. Nothing in the test suite would have caught it, because the audit row never failed in a test. It failed in the shape of a real webhook with a field I had not expected. The lesson is older than this product: the write that decides whether somebody is a customer must not share a transaction with anything that can fail for an unrelated reason.

What the sending gate is, since it came up

From this week on, the question of whether an account may send is answered by one pure function that takes facts about the account and returns a decision. It refuses anything it cannot confirm: a connection count it could not read, a status it does not recognise, an account under 150 connections. The ramp is in the same file: 5 invitations a day to begin with, 20 at most after three weeks, and the ceiling of 20 a day and 80 a week sits beside it as a constant. There is no setting anywhere in the product that raises it, and there is no column in the database for one. The limits page is that file, rendered.

The warm-up rampA new account sends 5 invitations a day for three days, then 10, 15, 18, and 20 from the fourth week. The ceiling is 20 a day.5101520 5 a day from day 110 a day from day 415 a day from day 818 a day from day 1520 a day from day 22day 0day 7day 14day 21day 28 Invitations a day since the account connected. The ceiling is 20; a reconnect after a checkpoint starts the staircase again.
The staircase the gate hands the planner, drawn from the constant that defines it. It has not changed since this week. A reconnect after a checkpoint starts it again from 5.

The reason the first webhook bug mattered so much is that the gate is the whole safety argument. A limit that can be opened by a stray notification is not a limit. The fix that week was small; the rule it established, that nothing external can ever make an account more permissive, only less, has been applied to every status path since.