Prospecting for the Owner and for a customer
The Owner and a customer prospect with the same code. There is no Owner-only prospecting feature and no customer-only one. The difference is commercial: a customer's use is bounded by their plan's allowances and recorded against them, and the Owner has no plan and no gates. Anything else that differs is a routing fault, not a product decision.
One body, two doors#
A customer session's requests are rewritten by tenantAdapt into /api/customer/ui/… paths and then checked against the customer_safe allowlist in the middleware. Both audiences arrive at the same prospecting modules underneath. Discovery, evidence, scoring, the no-guessed-address rule and identity resolution are not re-implemented for tenants, and there is no narrower customer version of any of them.
That is enforced rather than promised. tools/test_audience_parity_v1.py reads the route table out of the running application and compares every Owner capability with its customer counterpart. ALIASES records the places where the customer surface simply renames something; KNOWN_GAPS lists what a tenant genuinely cannot reach, each with a reason. That list may shrink and must never grow.
What actually differs#
| Aspect | Owner | Customer |
|---|---|---|
| Discovery, research, evidence, scoring | Same modules | Same modules |
| The no-guessed-address rule | Applies | Applies |
| Identity resolution | Against the Owner workspace's relationships | Against that workspace's own relationships only |
| Allowance on research and sending | None | The plan's, recorded in the ledger |
| Refusal when the allowance is spent | Does not arise | Work is held rather than lost |
| API path | Direct | Rewritten by tenantAdapt, then allowlisted |
| Where the data lives | The owner-jbrh workspace | That tenant's workspace, isolated three times over |
The ledger#
A customer's prospecting draws on the same allowances the rest of their workspace uses: AI work against the plan's budget, outbound messages against the daily send allowance. metering and tenant_entitlements hold the limits and the running total, and Plan & Usage shows both.
- Research that would exceed the AI budget is refused rather than run and billed. The refusal is recorded with its reason.
- Outreach that would exceed the daily send allowance is held, not discarded. It goes when the allowance resets or the plan changes.
- Discovery keeps working when sending is exhausted; the two limits are separate, and researching today what you will write tomorrow is normal use.
- The Owner passes through all of this without a gate, which means an allowance defect is invisible from the Owner account and obvious from a tenant.
When a tenant sees less#
- A prospecting screen 403s for a customer and works for the Owner
- Almost always the routing pair: an Owner path
tenantAdaptdoes not recognise becomes/api/customer/ui/blocked, or a pathcustomer_safedoes not allow. It is a rewrite to add, not a feature to build. - A control is missing rather than refused
- The customer surface may name it differently — a customer's
peopleare the Owner'srelationships. Check the alias before concluding it is absent. - The capability is genuinely unavailable to tenants
- Then it is in
KNOWN_GAPSwith a reason. If it is not there and a tenant cannot reach it, the parity suite fails, which is the point of the suite. - The number of prospects differs wildly between accounts
- Different workspaces, different relationships, different briefs. Nothing about prospecting is shared between them.
Questions#
Does the Owner get better prospecting?
No — the same code runs for both. The Owner's runs are not metered and not gated, which changes how much can be done in a day, not what any single run does or how good it is.
Can a customer's prospect list overlap with another customer's?
Two workspaces can independently discover the same public organisation, because it is a real business either of them may research. Neither can see that the other did, and neither's records touch the other's.
Who verifies that the two audiences really match?
An enumerating test rather than an assertion in a document: the route table is read out of the running application and compared capability by capability, so a new one-audience path fails the suite on the day it is added.