AICRO

The weekly client report, and why you can trust its numbers

Every Monday, each active client gets a draft report. AICRO reviews and edits it, then publishes it. This page explains what each section is for, exactly where its data comes from, and the rules that stop the report from ever quietly lying to a client.

Written for Anderson · 13 July 2026 · Live on staging, cron still held

The trust model

Two rules hold the whole thing up

A weekly report is only worth sending if the client believes the numbers. Both rules below are enforced in code, not by convention, because the failure they prevent is silent.

1. A number is never invented

Metrics are computed from cortex. The model is forbidden from authoring a figure, and a reviewer cannot hand-type one either. Captions and labels are editable; values are not.

A hand-typed number is indistinguishable from a real one. One invented figure puts every other number in the report in doubt, so the edit path strips values server-side and keeps the computed ones.

2. Qualified leads have one definition

The leads section reads client.qualified_lead_board, the same canonical view behind the portal's Qualified Leads report. One person, one row.

It used to read warm_lead_board, which is one row per message. A lead who replied five times appeared five times, and the section claimed "8 qualified" when there were four people. Reading the canonical view makes that impossible by construction.

The report

What a client actually sees

Real output for Lucra Sports, week of Jul 6. The numbered pins map to the explanations underneath.

portal.aicro.co  /  Strategy › Notebook
Draft, visible to AICRO only. Click any field to edit it. Refresh data Publish to client
1Reporting period Mon Jul 6 to Sun Jul 12, 2026
Weekly update, Jul 6 to Jul 12
Data as of Jul 13, 11:42 AM
2Lucra Sports booked 12 meetings between Jul 6 and Jul 12, up 35% versus the prior 30-day average, with 11 positive replies at a 12% positive reply rate across 6,041 sends.
6,041 ↑ +7%
Sent
email + LinkedIn, Jul 6 to 12
11 ↑ +5%
Positive replies
12% of replies, Jul 6 to 12
12 ↑ +35%
Meetings booked
Jul 6 to 12
3Values are computed and read-only. Captions are editable.
Recommendations 4
Shift attention to LinkedIn sequencing LinkedIn produced 7 of 11 positive replies from 91 sends, a 32% positive reply rate against 6% on email.
Audit the three zero-return email campaigns before any relaunch They account for 4,642 of the period's sends and produced effectively nothing.
Qualified leads 5 8 qualified
NameCompanyCategoryNext step
DeVone ClaybrooksYoubetmeWonClosed, nurture for expansion
Jason VanderburghIn pipelineAdvance the Putting Edge deal
Aram FuchsBuzztime.comMeeting bookedConfirm the meeting held; log the outcome
Chris KleinMeeting bookedConfirm the meeting held; log the outcome
All qualified leads →
Campaigns 6
CampaignStatusContactedPositivesRate
LI | Core | SE USA ExpansionCompleted78810%
EM | Q2 Rate Teaser | BanksCompleted1,50020%
All campaigns →
What’s next 7
Expand the two LinkedIn sequences producing at 10%AICRO
Confirm the ICP definition for the Banks segmentClient
1

The reporting period

The report covers the last complete week (Mon to Sun), is generated the following Monday, and may be presented at a Tuesday or Wednesday client call. So it states both endpoints and when it was generated. It never says "this week" or "last 7 days".

Computed week_startreport_title()
Never: the model does not author the title. That is exactly how the first version shipped "week of Jul 6", which a client reading it on the 14th reasonably took to mean the wrong week. A model must not decide what dates a report covers. Relative time language is banned in the prose for the same reason: it ages into a lie the moment the reader opens it late.
2

The headline

One or two sentences, metric first. The thing a busy founder reads and nothing else.

LLM Editable written from the computed payload only
Never: a figure that is not in the payload. The model is given the numbers and forbidden from producing new ones.
3

The three headline metrics

Sent, positive replies, meetings booked, each against the prior 30-day average so direction reads before magnitude. Positive Reply Rate is positives over replies, never over sends.

Computed outreach.v_client_daily_metrics summed per channel over the period
Never: a hand-typed value. The edit endpoint accepts a tile's label and caption and silently carries the computed value over. Meetings come from intelligence.meetings, a different source from the leads board, so a duplicate lead cannot inflate the meeting count.
4

Recommendations

Two or three, each one backed by a number that appears above it. Add, edit, reorder or delete before publishing.

LLM Editable grounded in the computed payload
5

Qualified leads

One row per person, with a real lifecycle (Won, In pipeline, Meeting booked, Qualified) and one concrete next action. The link goes to the full Qualified Leads report, which reads the same view, so the two can never disagree.

Computed client.qualified_lead_board, deduped on coalesce(crm_contact_id, lower(reply_email))
Never: a raw CRM artifact. A placeholder deal name ("Unknown Company – Kate Brown") is suppressed rather than published back to the client as if it were their pipeline.
6

Campaigns

What ran in the period, with real contacted and positive counts. Links out to the full campaign history.

Computed outreach.campaign_daily_activity summed over the period
Known gap: inbound carries a campaign name, not an id, so a campaign can show positives against zero contacted. The report surfaces the source data faithfully rather than hiding it. See handoff item 10.
7

What’s next

Actions split by owner, AICRO or the client. This is the one section that is not yet right, and it is the main open question in this handoff.

LLM Editable
This currently violates our own rule. The legacy weekly brief is explicit: "NEVER fabricate tasks from lastCall summaries, campaign data, or general knowledge." What's Next is meant to be a projection of the Task Hub, fed by Fireflies → the n8n Post Call Analysis → Josh's approval. Today the report generates it. It should project from the locked source instead. See handoff item 4.
Lifecycle

Nothing reaches a client without a human

The report is an internal draft until someone publishes it. Editing is admin-only and draft-only; a published report is immutable.

Monday

Generate

A cron drafts a report for every active client, covering the last complete week.

Any time before the call

Review and edit

Every section is editable in place, with an AI refine on the prose. Numbers are not.

On demand

Refresh

Recomputes the metrics. A section you edited is pinned and survives; the rest recompute.

Explicit

Publish

Only then does the client see it. Drafts are absent from the client's payload, not merely hidden.

The cron cannot fail silently

A weekly report that is quietly absent is as bad as one that is wrong, and Slack alerts do not fix it (the bot can be out of the channel, the message can go unread). So the failure surfaces in the product: /admin/weekly-reports shows every client's state, with a loud banner when the job itself is dead. A dead cron is detectable only by the absence of a run, because a cron cannot report its own death. Each client's Notebook also carries a "not generated yet" card with a one-click Generate, so a failure is an inconvenience, not a fire drill.

Handoff

What is left, and who owns it

Ordered by what unblocks the most. Items 1 and 2 are small and high-leverage; 4, 5 and 6 need a decision from Josh before anyone writes code.

ItemWhy / evidenceSize
1 Map Contract Status → client.clients.status
Blocks the cron
Cortex says 15 clients are active; Airtable says 8. The other 7 are churned. Root cause: the n8n Clients sync never writes status (Airtable has no field called "Status", it has Contract Status), so status is the stale insert default while contract_status is current. One mapping makes cortex correct and fixes ~10 consumers at once. Until then the cron would report on 7 churned clients. S
2 Fireflies recording URL crm_record_url is the de-facto "link to the recording" column and Granola and Fathom both set it. Fireflies never does, because _TRANSCRIPT_QUERY does not request transcript_url. Two-line fix, and it is what stands between us and attaching the week's call to the report. S
3 Fireflies binding gap integrations.connections is keyed by anon_id (the onboarding browser session), with no anon-to-client binding. AICRO's connection reports 731 transcripts; only 21 landed for the client. The connection is orphaned. M
4 What’s Next: project, stop generating
Needs Josh
Violates the standing "never fabricate tasks" rule. It should render the same set the Weekly Strategy Doc does (On Us / On Them), sourced from call-extracted tasks union open Task Hub tasks, gated on the Lock In Strategy approval Josh already owns, so nothing reaches a client he has not locked. M
5 Automated recap replacing the post-call flow
Needs Josh
Today the post-call flow costs roughly 30 minutes per call of cleanup; the target is 5 minutes of approving. The n8n extraction already exists, so the recap would replace the manual doc edit and the copy-paste into Slack. Depends on 2, 3, 4 and 6. Any automated Slack post must go through the n8n slack-post webhook (the AICRO bot), never the Slack MCP, which posts as Josh personally. L
6 Resolve the action-items doc conflict Two committed docs disagree. The meeting-transcripts PRD says Airtable Client Calls is the source of truth and to "not migrate". The newer Airtable-to-cortex plan says Client Calls → intelligence.meetings. The recap design cannot start until one wins. S
7 Per-campaign deep links Doug asked for a link from each campaign row into that campaign's background. Not buildable yet: the portal campaigns page is keyed on Airtable record ids while cortex keys on a uuid, only 25 of 1,189 cortex campaigns carry airtable_campaign_id, and there is no per-campaign route (the detail is a local-state modal). Needs an identifier decision plus a ?campaign= param. M
8 client.qualified_lead_funnel has no migration The RPC exists in the live database only. A fresh db reset will not have it, so CI and any new environment are one step from breaking. S
9 qualified_lead_board is not canonical enough It lives in the legacy migration tree, not the canonical bootstrap, and it inlines a predicate that disagrees with is_qualified_reply_v2 (missing the delegated_to_dm referral fix and the newer classifier vocabulary). The canonical definition is not actually canonical. M
10 Inbound campaign_id is NULL Per-campaign inbound is mapped by name, so a campaign can show positives against zero contacted, and a cross-client name collision mis-attributes positives. M

The question for Josh

Should "What's Next" project the same set the Weekly Strategy Doc renders (On Us / On Them), gated on your existing Lock In Strategy approval? That would make the weekly report a surface on the flow you already own, rather than a second, LLM-invented list that can contradict it.