InstaBrain iQ users manual
Version 0.5.0, 09-25-26. For the people who operate iQ: David, Frank, Meteena, Evan. Dates in this document are MM-DD-YY. Times are UTC unless a zone is named. Every statement below comes from the code in this repository or from docs/BUILD-CONTRACT.md; where the contract says a thing is not built, this manual says "not built yet". The technical companion is docs/DEVELOPER-HANDOVER.md; the short checklist is docs/operator-guide.md.
1. What iQ is, and what it is not #
InstaBrain iQ is the autonomous agent and client communication platform. Its first product is the payment-failure alert to the writing agent: when a client's premium payment fails, the agent who wrote the policy gets one clear message with the client's three fix paths and the agent's next steps, and every autonomous send and every reply is visible on an internal dashboard.
Law D governs every word iQ sends: the carrier (Fidelity Life) bills, decides and insures. InstaBrain is the technology platform. Every iQ email carries the footer line "InstaBrain is the technology platform. Policy decisions, billing and coverage are the carrier's." Status words and dates in an alert are the carrier's own, as stated at notice time; iQ never infers a status and never uses coverage words other than the carrier's.
What iQ is not:
- It is not a billing system and does not know whether a client has since paid. Every alert says so: "the client may already have paid."
- It does not read the raw carrier mail (which carries the insured's name and phone in clear). It reads the FraudBrain ledger, which hashes them.
- It writes nothing to the carrier, the FLEX portal, the FraudBrain project, the oversight project or the application database. Its only writes are to its own Firestore project, instabrain-iq.
- It is not live to any agent or client today. Every channel is in shadow (section 9).
2. The two audiences and the four channels #
Two audiences: agents (the writing agent of record for a policy) and clients (the insured). Four channels, each with its own mode in iq/config.modes:
| Channel | State on 09-25-26 | What exists |
|---|---|---|
agent_email | shadow | Built. Immediate alert for card failures; one morning brief per agent for EFT returns and ledger reversals. The only channel the code allows to go live in v1. |
agent_sms | shadow | Built as a would-be send, opt-in required. A short text is composed next to each immediate card alert ONLY for a writing agent who signed up on the opt-in page (section 14) with the email they use for the agent portal AND confirmed the sign-up from that email (A43); the number is the one they gave there. No opt-in, or an unconfirmed one, no row, counted. No live path yet. |
client_email | shadow | Not built yet. The mode exists; there is no template and no send path. |
client_sms | shadow | Built as a would-be send for card failures, opt-in required (David 09-25-26). A short text is composed next to each immediate card alert ONLY when the policy owner's number on the application owns an opt-in on the opt-in page (section 14) that passed the policy number check (A43), and only inside 08:00 to 21:00 in the owner's state; the incident is left untouched otherwise and nothing is deferred to the morning. EFT returns ride the agent's morning brief and reach no client. Inbound STOP and HELP handling on the iQ toll-free number is built (section 11). No live path yet. |
The consent rule for both text channels (David 09-25-26, option A): a text goes only to a person who opted in on the iQ opt-in page for their audience. The checkbox in the application flow stays an argument in the carrier filing and is never a send gate. Emails are transactional and are not gated by the opt-in page.
Frank's spec also asked for an in-portal alert. That is not built: the Portal is dev-owned, and the ask is gated on David deciding whether to raise it (contract A16).
3. Where the signals come from #
iQ reads three sources, all read-only, and folds them into one case per policy.
- Carrier return-EFT notices, through the FraudBrain ledger. BigQuery table
fraudbrain-prod.postsale.notices, rows withnotice_type = return_eftonly. The ledger is filled hourly from the carrier's "Customer Service Notification" mail. First Reminder Notice and Credit Card Maintenance Letter classify as "other" in the ledger and are not triggers (the letter-name ask is open with the FraudBrain lane). - The FLEX book, the FraudBrain lane's tap of the FLEX Agent Viewer (Firestore
instabrain-oversight/flex-book, four runs a day from the office Mac). Two uses: a document whose last event reads "Credit Card Failure Day N" is a card failure, and FLEX is the only source for card failures (the carrier mails nothing); a document whose last event reads "EFT Payment Overdue Day N" is a backstop EFT event, accepted only when no notice exists for that policy within 24 hours. - Commission ledger reversals.
tblCommissionsrows with a negative premium or a reversal, read through the DCC SQL proxy. A late trigger, the money truth one to three days after the event.
Two more reads enrich a case but never trigger one: the application database by policy number (insured name, verified phone, email, state, the application's creator) and the portal agent directory (creator id to agent email). Policy numbers are padded to ten digits everywhere because the ledger drops the leading zero.
FLEX is a scraper and goes dark. While dark, iQ has no card coverage. The dashboard has a "card lane: FLEX dark since ..." line, but the functions do not yet write the freshness fields it reads, so the line does not appear today. The operator signal is the "FLEX distress docs read" tile staying at zero across a day's ticks.
4. The one-touch-per-incident promise #
An agent hears about a failure once, with the fix paths, not once per ladder step and not as a 3 AM duplicate of the carrier's own notice. The code keeps that promise four ways:
- One case per policy. Every event on a policy folds into the same case.
- One touch per incident per channel (data contract invariant 15). An incident opens on the first alertable event on a policy and closes when the labeler marks the case cured or lapsed, or after 60 quiet days. While it is open, each channel (agent email, agent text, client email, client text) may reach its recipient once; a second card failure months later is a new incident and may alert again. The older 24-hour class dedup (invariant 3) still runs underneath. A text that is skipped for missing consent or quiet hours is not a touch: the channel stays open for that incident.
- A FLEX ladder step is not a new failure. FLEX re-dates a policy's last event on every step (card Day 1/4/6/10/15/20/28, EFT overdue Day 5/10/20). Only the first step (card day 2 or below, EFT day 5 or below, or an unnumbered step) can alert. Later steps are recorded on the case ladder and counted as
ladderOnly. - EFT returns and reversals for one agent are consolidated into one morning brief per day. Card failures, where the carrier mails nothing, alert at once.
The case drawer on the dashboard shows the incident (opened, touches per channel, closed and why); the morning brief skips a case whose incident was already touched.
5. How an alert flows #
- A tick reads each source from its watermark (first run: from the program floor, 09-24-26 00:00 UTC).
- Rows become events (class
eft_return,card_failure,ledger_reversal), deduplicated by source id and appended to the event ledger. An event older than 72 hours at ingest is stale: observed on the case, never alerted. - Events fold into the case for the policy. A fresh case is marked pending resolution before anything else happens, so a tick that dies leaves work for the next tick, not orphans.
- The recipient is resolved: the application's creator, looked up in the portal directory, is the address. The notice's agent email is a cross-check. Same private domain (an agency mailbox versus the writing agent) resolves to the directory address with the notice mailbox kept as a cc candidate. A different domain, a public mail provider, an inactive directory row, an unknown or ambiguous address: held for review.
- Card failures render the agent email at once (template
agent-card-failure), pass the vocabulary lint and the mode gate, and dispatch. EFT returns and reversals are queued for the agent's morning brief.
5a. Texts, card failures only, each behind the consent gate (invariants 24 and 25). Agent text: the agent's opt-in row is looked up by the resolved email and must be confirmed from that email (section 14); without one, or with an unconfirmed one, the text is skipped and counted ("agent texts with no text consent on file" on the command center). Client text: the owner's number from the application is hashed and must own a client opt-in that passed the policy number check; then quiet hours in the owner's state (a miss is counted as "inside quiet hours", nothing is deferred). After consent: the STOP list for that number, one touch per incident, the lint, then dispatch. The row records the consent version and time it was sent against; the number sits in a private subdocument.
- The morning brief (template
agent-morning-brief) lists every queued policy for the agent once, with the three client paths and the agent steps, and dispatches under theagent_emailmode. - Dispatch writes a shadow row (shadow) or sends once through iq@ and records the outcome (live).
- Replies are captured by the subject token; the labeler marks outcomes; the digest reports the night.
The copy is Frank's sentence, Megan's three client paths, the agent steps and the Fidelity contacts, on the design-system email shell. Subjects pass the 40-character test. A banned word is a refusal, never a substitution.
6. What an operator sees on the dashboard #
https://instabrain-iq.web.app/ , sign in with a Google account on instabrain.io. The dashboard is read-only: it has no buttons that change state. Control actions go through the operator CLI (section 10). Dates on the dashboard are MM-DD-YY; times are shown in America/Phoenix.
Layout (0.4.0). A left sidebar carries the iQ mark, the build stamp, the section list with loaded-row counts, the Operator Guide (this manual), a link to the review site (/iQreview) and a feeds block. From 1100 px wide the sidebar is fixed at 240 px; from 700 to 1099 px it becomes an icon rail with tooltips; below 700 px it is a drawer behind the top-left menu button (Escape or the backdrop closes it). No width hides a section. The top bar holds one search box (policy number, agent email or name, writing number, product name or code, client state; Escape clears; the count reads in words such as "3 of 14 cases match"), the four channel modes as text (collapsed to "N of 4 channels live" when narrow), a PAUSED badge when the kill switch is on, the zone, a sources toggle and who is signed in.
Feeds block (sidebar foot). Notices, FLEX book and ledger with the newest event time each, read from iq/status.sources. "Feeds live" means every source was read inside its 45 minute budget; otherwise the worst feed is named in words ("FLEX 9 h late"). Beneath: last tick, shadow nights, template version.
Command center (the landing section), top to bottom:
- Results window line: from the start of shadow to today, when the labeler last computed the figures, and the shadow phase note (nothing has been sent; figures are observed on cases iQ would have alerted, not caused by iQ).
- Four tiles from
iq/metrics: cases recovered on their own (with alerted, lapsed and still-open counts), premium on those policies (latest modal premium x 12, monthly assumption, with how many policies were read), commission protected (75% heaped advance on that premium) and recovery rate by class. Once a channel is live the same tiles read as cases alerted and recovered by iQ. - Latest run decisions: the last 24 hours summed over every tick (
iq/status.decisions24h): immediate alerts, morning briefs queued, held for a human, stale observed only, ladder steps folded, deferred or deduped; beneath the tiles, the texts skipped in words (agent or client texts with no text consent on file, client texts inside quiet hours, suppressed by STOP). - Channel reporting: one row per channel with its current mode, shadow-only rows (never handed to a provider), sent, delivered, opened, clicked, replied. A cell that cannot exist yet says so in words ("not live yet", "not tracked" for text, "no opt-ins yet" for a text channel with no matched opt-in); the dashboard never shows N/A.
- Strip: channels live, last run, shadow nights, holds unresolved, last run errors, template and labeler age.
Cases: one row per policy with product, last class, ladder, incident, resolved recipient, outcome and last update; the search box and the product chips filter it (Final Expense and Guaranteed Issue are never collapsed). Clicking a row opens the drawer: the case document, its incident, its messages, its review rows, its outcome document, its replies.
Agent messages and Client messages: shadow and live rows in one table each, labelled in text by mode, with channel, address (clients and text rows show a hash, never the number), state, subject, template, a Delivery column (sent, delivered, opened, clicked, bounced, in words) and a reply count. A shadow row never reached a provider. A live row is real only in state sent; the state column says which. Smoke-test rows (section 9) are marked test and are excluded from the metrics.
Replies: channel, classification (stop, help, cured, question, other), sender, matched policy, snippet, and the HubSpot ticket id when one was opened.
Review queue: reason, policy, class, notice email, directory email, FLEX agent name, created, resolved.
Outcomes: labelled cured, labelled lapsed, still open, and the cured share of decided outcomes by days to outcome, as bars and as a table.
Health: last run errors, inbound mail poll, labeler, digest, watermarks, last read, sources, config (paused, quiet hours, minimum shadow nights, template version, event floor, max event age, first-step days), and the operator alerts table (control actions, lint refusals, smoke tests, needs-human).
Runs: one row per tick with what it read, events, cases, queued, held, deduped, errors and mode. A run with mode paused is not a tick.
Operator Guide: this manual, rendered at /guide inside the same shell and sign-in.
7. The daily rhythm #
| When | What |
|---|---|
| 02:01 to 04:12 | The carrier's nightly batch mails land; the FraudBrain ledger ingests them hourly (p95 64 minutes later). |
| Every 5 minutes, 02:00 through 06:55 | Batch ticks (iqPollBatch). |
| Every 15 minutes, other hours | Off-window ticks (iqPoll). A single-flight lock keeps two ticks from overlapping. |
| Hourly at :03 | Brief pass (iqBrief). An agent is due when their local hour is 8 through 11 and they have not been briefed that local day. The directory carries no state, so today every agent is on the Phoenix clock: briefs compose 08:00 to 12:00 Phoenix (15:00 to 19:00 UTC). Agent-local timing is the design, not the live behaviour. |
| :07 :22 :37 :52 | Reply poll of helpdesk@ and iq@ (iqInboundMail), three-day lookback. |
| 13:30 | Outcome labeler (iqLabeler), after the 13:00 directory refresh and the morning FLEX tap. |
| 07:05 America/Phoenix (14:05 UTC) | Digest to david@ (iqDigest), subject "iQ shadow digest: N would-be, M live". |
The digest lines, in order: would-be sends by channel and class; the ticks' decisions (immediate, brief queued, held, stale, ladder steps folded, deferred, deduped); what was read (notices, FLEX distress documents, ledger reversals, new events, ticks, errored and paused ticks); live sends by state; holds by reason; replies by class; shadow nights, last run, errors on the last run.
8. The review queue: reasons and what to do #
A hold is a decision iQ refused to make. Resolve it by reading the notice and the directory, never by editing a template on the spot. The dashboard has no resolve button in this version; a row is marked resolved through the Admin SDK by the operating terminal, and stays open until then.
| Reason | Meaning | What to do |
|---|---|---|
policy-not-in-app-db | A FLEX-only policy with no application row in the app database (or not an InstaBrain product). The row carries the FLEX agent name and writing number. | Check the policy in the FLEX Agent Viewer. If it is a real InstaBrain policy, the app-database join is the defect to report; otherwise close the row. |
missing-agent-email | No creator path and no agent email on the event. | Look the policy up by hand; decide whether an agent should be reached manually. |
agent-email-mismatch | The directory address for the application's creator and the notice's address differ on different domains or on a public mail provider. Both addresses are on the row. | Decide who wrote the policy; a stale carrier address can point at an ex-agent. Reach the right one by hand. |
agent-inactive | The creator's directory row is inactive, disabled or terminated. | Route to the agency or upline by hand. |
ambiguous-agent | The notice's address matches more than one directory agent. | Identify the writing agent from the writing number; reach by hand. |
notice-email-not-in-directory | No creator path and the notice's address is unknown to the directory. Never mailed. | Confirm the agent with the carrier or the agency; consider a directory correction. |
lint-refused | Rendered copy hit a banned word (the vocabulary lint). An operator alert row is written too. | This is a template defect: fix the composer in code and redeploy. Never edit copy on the spot. |
two-unconfirmed-sends | Live only. Two send attempts ended unconfirmed; the message is quarantined needs-human, never a third attempt. | Search iq@'s Sent folder for the subject token. If truly not sent, send by hand and record it. |
Holds piling up after a source or directory change is usually a resolution defect, not agent work: on the first shadow night every case held because the directory reader assumed one document (contract A9). Compare held to immediate + briefQueued on the run before treating the queue as real.
9. Shadow mode versus live, and the GO procedure #
Shadow: the message row is written to the shadow collection with state shadow; the transport is never called (a test asserts zero calls). Live: the row is written to the live collection and the provider is called once; the states are pending, sending, sent, ambiguous, needs-human. Health, freshness and success rate never read shadow rows.
Shadow nights are counted per UTC date on which a tick read at least one return-EFT notice. The count is in the header and in the digest. Night 1 was 09-25-26 (UTC).
Go-live for agent_email, in order:
- At least 3 shadow nights recorded (
iq/config.minShadowNights). - The review queue understood; the golden trace, policy 0101893044, reproduced on the dashboard; one shadow brief opened and read end to end; the Fidelity and eFinancial feed thread acknowledged (
docs/operator-guide.md). - Frank's sign-off. This is a procedural gate; the code does not enforce it. Record it on the config note.
- David's GO, one decision.
- The command
go-live agent_email GO-LIVE <templateVersion>, where the template version must equal the deployed composer's (2026-09-24.1 today). The control refuses a wrong confirm word, too few nights, a version mismatch, or any channel other thanagent_email. The activation is recorded oniq/config.liveActivationwith who, when, the template version and the night count.
Agent SMS and both client channels stay shadow until a dedicated verified number, STOP handling proven end to end and the consent basis exist (David's ruling, contract A1).
10. Pause and resume #
The operator CLI is scripts/control.js; it needs the operator key in IQ_API_KEY.
node scripts/control.js status
node scripts/control.js pause
node scripts/control.js resume
node scripts/control.js set-mode agent_email shadow
node scripts/control.js tick
node scripts/control.js brief
node scripts/control.js go-live agent_email GO-LIVE <templateVersion>
pause is the kill switch: every tick writes a run with mode paused and reads nothing; the brief pass skips; the header shows PAUSED. resume clears it. set-mode <channel> shadow is the one-step rollback from live; set-mode accepts only shadow (live goes through go-live). Every control action records who and when on the config document and appends an operator alert row.
11. How replies flow #
Email. Every live email carries a token like [iq-xxxxxxxx] in its subject. The sender is iq@instabrain.io (unattended); the Reply-To is helpdesk@instabrain.io, which is a channel account of the HubSpot Help Desk inbox, so an agent's reply lands where the help desk already works. Every 15 minutes iQ searches both mailboxes for the token, matches it to a live message row, and writes a reply with a classification: stop, help, cured (words like "paid", "all set", "updated the card"), question (a question mark), other. During shadow no live rows exist, so every reply shows as unmatched; that is expected. An email STOP is classified, counted, and the address is written (hashed) to the iQ suppression list so no later email goes to it.
Text. Two providers, one flag. Once an operator sets smsProvider to telnyx in iq/config, production texts come from +1 877 451 0084, InstaBrain's verified toll-free line on Telnyx, and replies to it post to iqInboundSmsTelnyx (the Telnyx signature is checked first). Until then, and for smoke tests on the A2P test path, texts come from the iQ number on the InstaBrain Twilio account (+1 888 563 8680), and inbound texts post to iqInboundSms. The Twilio signature is checked first. Whichever number a text arrives on, the same rules apply: STOP (also unsubscribe, cancel, end, quit) writes the phone's hash to the iQ suppression list and answers "You are opted out of InstaBrain iQ texts." HELP answers with the Fidelity Life Customer Service number. Anything else is stored as a reply. A text is matched back to the message it answers by the phone hash on the sent row; a text from a number iQ never wrote to shows as unmatched. The raw number sits in a private subdocument nobody reads from a client. Toll-free verification is staged for David and not filed; no text goes out. A client text that is not STOP or HELP becomes one HubSpot Help Desk ticket (Support Pipeline, stage New, owner Evan since 09-25-26, configurable) once client text is live, or earlier when an operator sets hubspotTicketsOnReplies in iq/config; the reply row carries the ticket id.
12. When something looks wrong #
Errors on a run. Health shows the last run's errors as text, one per source ("notices: ...", "flex: ...", "ledger: ...") or per policy. The tick continues on the other sources and a failed source keeps its watermark, so nothing is lost. The same error on consecutive ticks is a source or permission problem: hand it to whoever runs the functions with the exact text. Contract A9 and A11 record a misdiagnosis to avoid: a "dataset not found in location US" error is the BigQuery location, not the deny policy.
Holds piling up. Read them by reason (section 8). A mass hold with one reason after a change is a defect.
ladderOnly dwarfing alerts. Normal. The book carries many multi-week failures and every step re-dates them. The line between a new failure and a step is iq/config.firstStepDays, a David decision recorded on the config document.
Watermark held. ingest.watermarkHeld naming a source, or ingest.skipped above zero, on consecutive runs means the tick cannot ingest its sources inside its 200-second budget; read.carriedCases at 150 means the same on the resolution side. Nothing is dropped; it is late. Raise it as capacity.
Stale dominating. A night that is mostly stale means a source delivered history (a re-scan, a late feed). Not agent work.
flexComplete false on two ticks in a row. The FLEX book is changing faster than 20,000 documents per tick.
Zero notices on a weeknight. The carrier batch or the ledger ingest did not run; that is the FraudBrain lane.
No digest at 07:05 Phoenix. Check iq/status.digest on Health and the function logs.
Night 1 numbers. The first night's brief count (646) is cold-start inflated: FLEX Day 5 backstops fired for policies whose notices predate the floor. Do not read it as the daily rate.
13. The review site #
https://instabrain-iq.web.app/iQreview (also /iqreview) is where the team reads every staged template and decision, scores it and leaves comments, so David can finalize the copy and start the smoke tests. Same sign-in as the dashboard: a Google account on instabrain.io.
- What is on it: the twelve rendered templates (agent emails, the morning brief, agent texts, client emails, client texts) with their subject lines and character counts and the plain-text version of each; the fifteen copy decisions from the copy review with their options; three go-live asks (toll-free verification, the billing account, the Portal alert); the team note; the six dev-group questions; this manual and the developer handover, read-only.
- Scoring: 1 to 5 (1 Send it back, 2 Needs work, 3 Fine with changes, 4 Good, 5 Ship it), a verdict (Approve, Change, Discuss), a choice on decisions, and a comment. One row per person per item in
iq-review-feedback/{itemId}__{email slug}, written by the browser with the signed-in email; the rules let a person create or update only their own rows and let nobody delete. Every save carries the template version. - Filters: "Unscored by me" and "Needs discussion" (any reviewer chose Discuss).
- Summary: per item average score, verdict tallies, choice tallies on decisions, every comment with author and time, and a coverage matrix of reviewers by items. It updates live as people score.
- Rebuild:
node scripts/build-review.jsreads the staged sources, writespublic/review/manifest.json, copies the renders intopublic/review/previews/and renders these two documents intopublic/review/docs/. Ids come from file names and decision numbers, so scores survive a rebuild.
Dates on the site are MM-DD-YY; times are the browser's zone.
14. Text opt-in #
https://iq.instabrain.io/optin (also served at https://instabrain-iq.web.app/optin) is the public sign-up page for iQ texts. No sign-in. It is the consent record US carriers require before an application texts a person, and a screenshot of it is the evidence attached to the toll-free verification filing for the iQ number (+1 888 563 8680). Nothing on this page sends a payment alert; it records permission to receive one. Since 09-25-26 it is also the GATE for both text channels: an agent text goes only to an agent with a row here (matched on the portal email they entered), a client text only to a policy owner whose application number has a row here. No row, no text, in shadow as in live; the command center counts the skips.
Since 09-25-26 (A43) a row counts only once the person behind it is VERIFIED. Two checks, one per audience:
- Writing agents confirm from their agent portal email. When the email entered is on the InstaBrain agent roster, the sign-up is recorded as "awaiting email" and iQ sends ONE email from iq@instabrain.io to the roster address (the one in the agent directory, never a variant typed on the page) with the subject "Confirm your InstaBrain iQ text alerts" and a gold button "Confirm my number ending NNNN". The email says in words what pressing the button does (the number is confirmed, a short confirmation text goes to it, payment-problem texts follow) and that ignoring it means nothing is confirmed and no texts are sent. The button opens
https://iq.instabrain.io/v/..., a page that shows the number ending and one more gold button; pressing THAT confirms the number (a mail scanner opening the link confirms nothing). Links work for 48 hours; a second sign-up on the same number replaces the earlier link. Until the button is pressed, the row is not consent: no agent text is composed against it, in shadow or live. Why: before A43 anyone who knew an agent's roster email could sign up their own number under it and would have received policy-number alerts about that agent's clients. - Policy owners give the 10 digit policy number (required) and the mobile number Fidelity Life has on file for that policy. The page checks the number entered against the policy's contact record (formatting does not matter). A match is recorded as "verified, policy number matched" and proceeds as before. A number that does not match is refused in words: "That mobile number does not match the one on file for this policy. Use the number Fidelity Life has, or call Fidelity Life Customer Service at 800-369-3990 to update it." A policy number iQ cannot find is refused too. The number on file is never shown. If the policy lookup cannot answer (the database proxy is down or slow), the sign-up is recorded as "policy check unavailable" and nothing is sent; the person reads "a confirmation text will follow once the number is verified" and can sign up again later. Why: before A43 anyone who knew a policy owner's number could sign up as that owner.
Smoke personas are the exception: an agent email on iq/config.testRecipients, or a policy owner number on iq/config.testNumbers, is recorded as a test persona and skips both checks (the command center says so). Sign-ups recorded before 09-25-26 carry neither check and do not count; those people sign up again.
- Who uses it: a writing agent who wants texts about payment problems on policies they wrote, or a policy owner who wants them on their own policy. The person picks one, enters a US mobile number (formatted as they type), first and last name, an email (agents give the address they use for the agent portal; optional for policy owners) and, for policy owners, the 10 digit policy number (required since A43).
- The consent: one checkbox, unchecked until the person checks it, with this text: "I agree to receive text messages from InstaBrain iQ at the number above about payment problems on a life insurance policy I wrote or own (returned drafts, declined cards) and how to fix them. Message frequency varies by account activity. Message and data rates may apply. Reply STOP to stop, HELP for help. Consent is not a condition of any purchase. InstaBrain is the technology platform; policy decisions, billing and coverage are the carrier's (Fidelity Life)." The text carries a version (2026-09-25.1). If the words ever change, the version changes and an older copy of the page is refused with "This page is out of date."
- The button: gold, the one primary element, disabled until the number has 10 digits and the box is checked. The audience, the names, the email shape and the policy number are checked on the page and again by the function, and every refusal is a sentence in words, never a code.
- What is stored:
iq-optins/{hash}with the last four digits, the audience, the consent text and version, name, email (and a lowercase copy the agent lookup uses; for a roster-matched agent this is the roster address), policy number, the roster check and the policy check results, the email verification state (requested, sent, verified when), when (first and latest), and a history of repeat submits (20 kept). When a text is later composed against the row, the message record carries the consent version and time from it. The full number sits in a private subdocument that no browser can read. The Health section of the dashboard shows the count by audience, how many are verified, and the newest ten rows with the verification state in words ("verified by email", "awaiting email", "verified, policy number matched", "policy check unavailable at sign-up, not verified", "test persona", "not verified, signed up before ..."). - A verified opt-in ends a STOP. If that number had replied STOP to an iQ text, a sign-up that passes its check (a policy owner at submit, an agent when the email button is pressed) removes it from the iQ suppression list, records when, and writes an alert row (Health, Alerts, kind "Optin ended stop") so the reversal is visible to an operator. An unverified sign-up leaves the STOP in place. The other direction holds too: a STOP after an opt-in blocks every text to that number even though the opt-in row still exists, because the tick checks the STOP list right after consent.
- The confirmation text ("InstaBrain iQ: you are signed up for payment-problem texts. Msg frequency varies. Msg & data rates may apply. Reply STOP to stop, HELP for help.") goes out only once the check has passed, and only when an operator sets
iq/config.optinConfirmTextto true and the function holds a text sender. Until then the page says "A confirmation text will follow once the number is verified." The page never says a text was sent unless the server sent one; when the carrier refuses (the toll-free number is not verified yet) the row waits in the client or agent messages view (split by who was signing up) as a text in state "Needs a human", and the person still reads "will follow". An agent who has just signed up reads "Check your agent portal email" instead, and the confirmation page reads "Your number is confirmed" once the button is pressed. - Limits: ten sign-ups per connection per hour; sixty confirmation-link attempts per connection per hour; three verification emails per number per day and one hundred per day in all; a larger submission is refused; every refusal is a sentence in words.
15. Glossary #
- Case: iQ's record for one policy (
iq-cases/{policy10}), with its ladder, alerts, hold and outcome. - Incident: one failing-payment episode on a policy (
iq-cases.incident): opened by the first alertable event, touched at most once per channel, closed on cure, lapse or 60 quiet days. A new episode later is a new incident. - Event: one normalized fact from one source (a notice, a FLEX document, a ledger row), with a source id. Append-only; never carries insured PII.
- Class: what kind of event:
eft_return,card_failure,ledger_reversal. - Ladder, ladder step: the carrier's Day N sequence on a failing payment as FLEX shows it. A step is not a new failure.
- First step: the step that may alert (card day 2 or below, EFT day 5 or below, or unnumbered).
- Stale: an event older than the age guard (72 hours) at ingest. Observed on the case, never alerted.
- Observed: a case that has seen only stale events or only later ladder steps. History, not open work.
- Backstop: a FLEX EFT-overdue event accepted as an EFT event because no notice reached the ledger for that policy within 24 hours.
- Hold: a review-queue row; iQ refused a decision and a human makes it.
- Shadow night: a UTC date on which a tick read at least one return-EFT notice.
- Watermark: where a source was last read to. A source with skipped rows keeps its watermark.
- Tick: one run of the poll. Reads, ingests, resolves, decides, writes a run record.
- Brief: the one-per-agent morning email consolidating overnight EFT returns and reversals.
- Dedup window: one alert per policy per class per 24 hours.
- policy10: the policy number as ten digits with the leading zero kept.
- Subject token: the
[iq-xxxxxxxx]key in every live subject; the reconcile key for replies. - Template version: the composer's version stamp (2026-09-24.1); go-live is bound to it.
- Mode:
shadoworlive, per channel. - needs-human: a live message with two unconfirmed attempts; quarantined, never retried.
- Cured, lapsed, open: the labeler's outcome for a case, from the FLEX book, advisory only.
- Opt-in: a person's recorded consent to receive iQ texts (
iq-optins/{hash}, from the/optinpage), with the consent text and its version. It counts only once verified (agents by the email link, policy owners by the policy number match, section 14); a verified opt-in ends a STOP for that number. - Verified (opt-in): an agent row whose email link was pressed ("verified by email"), or a policy owner row whose number matched the policy record ("verified, policy number matched"); test personas count as verified.