How it works underneath
For the curious. Nothing here is needed to run a campaign; it is here so that when a screen surprises you, you know which part surprised you.
Four ideas carry the whole design, and each one exists because the obvious alternative failed.
One ledger
Every touch is a row in one table: each letter out, each reply in, on email and on WhatsApp alike, against the person it concerns.
flowchart LR
A["The receiver"] --> L["The touch ledger"]
B["The sequencer's webhook"] --> L
C["The chat transport"] --> L
D["An agent logging a call"] --> L
L --> E["The Inbox"]
L --> F["The Pipeline"]
L --> G["A person's timeline"]
L --> H["Every count on every screen"]
One writer, not four. Every path above goes through a single piece of code that writes the row. The alternative was tried: recording spread across four call sites, one of which never ran, and nothing could tell a missing call from a person nobody had written to.
That is why the timeline settles disagreements. It is not a report assembled from several places; it is the place.
The person spine
A person moves through a fixed set of states, and the moves are forward-only.
flowchart LR
A["New"] --> B["Qualified"]
B --> C["Contacted"]
C --> D["Positive"]
D --> E["Meeting"]
E --> F["Proposal"]
F --> G["Won"]
C --> H["Unsubscribed"]
C --> I["Declined"]
C --> J["Invalid"]
Forward-only matters more than it looks. A reply read as positive asks the spine to move somebody forward; if they have already unsubscribed, the spine refuses and the screen reports what actually happened rather than what was asked for.
This is why a label’s effects are described as what they did, not what they mean. A cancelled sequence and a refused move are both real answers.
Vendor logic behind seams
Neutron never speaks a vendor’s language. Each vendor has one entry that translates, and the engine talks to the entry.
flowchart TD
E["The engine<br/>who, what, when, and whether it is allowed"]
E --> S1["The transport seam"]
E --> S2["The classifier seam"]
E --> S3["The drafts seam"]
S1 --> V1["Salesforge"]
S1 --> V2["Neutron's own sender"]
S2 --> M1["The deterministic pass"]
S2 --> M2["A model"]
S3 --> D1["A drafted answer"]
Three seams, and they are three on purpose.
The transport seam is who puts a letter on the wire. Swapping it changes one provider entry, and nothing about who gets written to.
The classifier seam is how a reply is read. Its first pass costs nothing and is not a guess — headers, and the sender’s own words above the quoted thread. Only what is left goes to a model.
The drafts seam is what an answer may say. It is separate from transport for the reason the whole product exists: writing and sending are different permissions.
The reusable message logic — what a message says about itself, where the quoted thread starts, whether a sender is away and until when — lives in a shared module rather than in the engine, so an agent baking it as a tool reads a message exactly as this pipeline does.
What keeps time
Nothing in the engine happens because somebody clicked. Things happen because a date arrived and a set of conditions were all true.
flowchart TD
A["Every minute: what is due?"] --> B{"Five questions"}
B --> C["Is the domain healthy?"]
B --> D["Is the address switched on?"]
B --> E["Is the person schedulable?"]
B --> F["Are we inside the window?"]
B --> G["Is the address suppressed?"]
C & D & E & F & G --> H{"All true?"}
H -->|"yes"| I["It sends"]
H -->|"no"| J["It holds, and records which question failed"]
A held letter names the question that failed. That is the whole of the held-reason vocabulary you meet on the Approvals screen, and it is why “held” is never a mystery.
Two more timed passes run beside it.
The warden checks every domain and mailbox once a day: placement, heat, blocklists, DNS, and whether the vendor’s event feed is still alive. It pauses a domain on evidence, opens an incident, and says so in the room.
A sweep for abandoned work. A reply claimed for reading by a process that then died would sit invisible forever — not unread, because something claimed it; not read, because nothing finished. Anything held longer than ten minutes is given back to the unread pile.
Why a reply acts before anybody reads it
Because the alternative is worse.
Somebody who writes “please take me off this list” at two in the morning must not receive the next letter at nine, and would if the only thing that suppressed them was a person opening the Inbox.
So the reading and its effects run as the reply lands. A person’s correction then runs the same effects again for the new label — and the correction always wins, even against a reading still in flight, because a machine’s answer must never overwrite somebody who has just disagreed with it.
Nothing is undone by a correction. A cancelled sequence stays cancelled and a suppression stays, because lifting a suppression on a second reading is how somebody who asked to be left alone gets written to again.
Where the boundaries are
| The engine decides | A vendor decides | A person decides |
|---|---|---|
| Who is written to | Whether a letter is delivered | Whether a first letter goes |
| What the letter says | What a mailbox’s warm-up looks like | Whether a drafted answer goes |
| When it is allowed to go | What it charges | Whether a paused domain comes back |
| What a reply means | Whether a reading was right | |
| Whether a domain may send | What a deal is worth |
The middle column is the shortest on purpose. A vendor is transport.