# Week of 7 September 2026: the loop closes, on a fake LinkedIn first

> 51 commits: search, score, draft, approve, plan, send, accept, message, follow up once, reply, stop. Run for fourteen simulated days against a fake LinkedIn before a real account saw it, and the bugs the fake one found.

By Adarsh Mamgain, 31 October 2026. From the Hellofew blog at https://hellofew.com/blog.

Part 3 of Building Hellofew, week by week. Every part: [Week of 24 August 2026: the schema before the product](https://hellofew.com/blog/building-week-1-the-schema-before-the-product.md), [Week of 31 August 2026: everything that touches money or the account, first](https://hellofew.com/blog/building-week-2-money-and-the-account-first.md), [Week of 7 September 2026: the loop closes, on a fake LinkedIn first](https://hellofew.com/blog/building-week-3-the-loop-closes.md), [Week of 14 September 2026: read the person before writing to them](https://hellofew.com/blog/building-week-4-read-before-you-write.md), [Weeks of 21 September 2026 to 5 October 2026: the quiet weeks, and the first two replies](https://hellofew.com/blog/building-week-5-the-quiet-weeks.md), [Week of 12 October 2026: the launch week, a name, and 94 commits](https://hellofew.com/blog/building-week-6-the-launch-week.md), [Week of 19 October 2026: writing that reads like a person, and the first fourteen replies](https://hellofew.com/blog/building-week-7-writing-that-reads-like-a-person.md), [Week of 26 October 2026: the week the replies came, and what broke on the way](https://hellofew.com/blog/building-week-8-the-week-the-replies-came.md).

51 commits in six days, the busiest week until the launch. By Friday the whole loop existed: find people who match the profile, score them, write a message for each, put them in a queue for the customer to approve, plan the sends across working hours, send, notice an acceptance, send the first message the next working day, follow up once, notice a reply, cancel everything else for that person. It also got a deploy, a digest email, comparison pages and a legal section. It was a lot. Some of it was good.

*Figure: Find, read, write, approve, send, accepted, message, follow up once; a reply cancels everything queued for that person.*

*The loop as it was drawn that week and as it still runs. The approve step is the customer's; everything else is the worker's. The dashed line is the check that runs again in the seconds before any send.*

## A fake LinkedIn, and what it found

Before any of this touched a real account I built a fake one: a small server that behaves like the provider's API, accepts invitations on a schedule, replies to some messages, and refuses things the real one refuses. Then the loop was run against it for fourteen simulated days, and the baseline from that run is in the repository as a document.

The fake found three bugs that the real one would have found on a customer. The acceptance path marked a lead accepted when the provider had merely listed the invitation as sent. The reconciler counted the week from the database's clock rather than the one it was handed, so a test and production disagreed about what a week was. And the row-level policies from week one had been written for the original tables and never applied to the four added since, which the fake found because its two accounts could see each other's leads. That last one is the reason the suite now asks Postgres which tables exist rather than trusting a list.

## One follow-up, and a reply that stops everything

The follow-up rule was decided this week and has not changed: one message after somebody accepts, one follow-up 4 days later if they have not answered, and nothing after that. There is no setting for a second follow-up and no column for one. The reasoning has [its own post](/blog/one-follow-up-never-a-sequence); the short version is that every product with the setting ends up being run with it turned up.

A reply cancels everything queued for that person, and it is checked twice: when the reply lands, and again in the moment before any send goes out, because a reply can arrive in the minutes between the queue being planned and the message leaving. That double check is the single line of code I would keep if I had to throw the rest away. A follow-up arriving at somebody who answered yesterday is the one output that would make a customer stop trusting the product, and it must not depend on an inbox write succeeding or a webhook arriving in time.

## The breaker, and the blind window

The accept-rate breaker also arrived this week: if too few of the invitations that have had a fair chance to be answered were accepted, the daily cap halves; lower still, inviting stops. The first version had no minimum sample and stopped an account on its first morning because three invitations and no acceptances reads as zero percent. The fixed version needs 20 invitations each 7 days old. That fix created a window: for the first ten days of an account's life the breaker cannot fire at all, which is exactly when a bad profile does its damage.

*Figure: From day four a blunt check on 10 invitations 3 days old; from day ten the settled check on 20 invitations a week old.*

*The second tier was added on Saturday 12 September, the last working day of this week. It halves the cap under 20% and stops under 10% on a smaller, younger sample, and hands over to the settled check as soon as there is one. The thresholds are the constants the sender reads.*

So on the Saturday the second tier went in, the first search was made to run the minute an account connects rather than the next morning, approving the first three people became the thing that starts sending rather than a switch on a settings page, and a rule was added that one LinkedIn flag in an account's first day of sending stops it until a person restarts it. Those three commits are the activation and safety story of the product in one afternoon, and they came out of watching a real account for the first time.

## The deploy, honestly

The first deploy took eight commits on the Tuesday. Two migrations were invisible to the migration tool because they had never been registered. The mock loader was in the ignore file, so no clean clone could build. The build read environment variables that production did not have at build time. The migration script exited with code one and no message. The platform hid a one-shot job's logs, so migration moved to worker boot where its output could be read. Postgres became its own resource rather than a container beside the app. None of this is interesting and all of it is why I distrust any week with no fixes in it.

The week also produced the first comparison pages, the sitemap, the markdown twin of every page and the llms.txt that lets a model read the site, and the first version of the landing page. The limits that page published are the constants from week two, unchanged: 20 a day, 80 a week, the ramp from 5. They are on [the limits page](/limits), and what the real accounts have done under them is on [the numbers page](/numbers).
