platform: accounts, plans, and the Stripe billing that charges for them - #57
Merged
Merged
Conversation
§3 was "tailored, not blasted" and argued restraint from the schema. Migrations
023 and 026-032 landed and the first contact harvest ran, so it can now argue it
from evidence: contact_route went from 1 row to 2,351 across email, phone and
form, 439 counterparties became reachable, seven sites' robots.txt refused us and
the agents stopped, and zero of 1,622 harvested addresses were fabricated. A
refusal on screen beats a sentence about being responsible.
Telegram and WhatsApp are named, and the wording is load-bearing: "where Telegram
and WhatsApp land when a label needs them". That is a claim about the model and
it is true — `channel` already admits `social`, the consent boundary is one SQL
predicate in `sender._prepare`, and a DM channel is a column value plus an
adapter rather than a second compliance regime. What may not be said is in "What
must not be said": no messenger logo on screen, no implication that we message
anyone on either platform, and no naming of a statute. There are zero `social`
routes and no adapter, and a judge reads a logo as an integration.
The "distributed" claim is the honest one: the route predicate lives in SQL
"rather than in Python so that no caller can forget it", so every worker inherits
it regardless of which agent runs. There is no rogue agent that forgot the rule,
because the rule is not in the agent.
Two corrections found while writing it:
- §3 has told the shoot, since this file was written, to film a `contact_route`
row in `opted_out`. That state has never held a row — measured today, 2,350
unverified and 1 verified. It was true of the design and never of the table.
Now a gate in the pre-shoot checklist.
- §4 also said "one open thread per counterparty is a partial unique index",
which §3 now says. Cut from §4: twice is four seconds the runtime does not
have, and the second mention sounds like a point that could not find a home.
Runtime 2:55 against the 3:00 cap: §3 grew 0:30 -> 0:44, fourteen seconds from
the existing headroom and four from that cut. Genre precision moved to §2, where
the vector index is already on screen.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…tion Two things, because they divide along the runtime cap. **SUBMISSION.md** is new: the who / what / where / when / why-CockroachDB / how rundown, with no 3:00 budget forcing it to choose. It is the narrative of record for a judge and for a model reading the repository, and it sits under the adversarial sponsor audit rather than over it. Every hard figure in it was executed against the cluster on 2026-08-14 and checked again before this commit: 14,170 counterparties, 66,103 live facts, 14,169 roles classified, 2,351 contact routes, 439 reachable, 55,569 agent runs, $0.12 all time, 3,180 country facts. The centrepiece SQL is now `agents.shortlist_as_of` in shape rather than a plausible-looking query — `<=>` not `<->`, `party@party_shortlist`, all four predicates in the index prefix. Writing it out surfaced a detail that belonged in the submission and was not in it: past `gc.ttlseconds` the function *raises* rather than retrying without the clause, because retrying would return the current ranking presented as the historical one — a true answer to a question nobody asked, offered as the justification for having emailed somebody. A system that can say "I cannot tell you why, and here is exactly why I cannot" is more accountable than one that always has an answer. The "global label, thousands of conversations" framing is stated as the design and immediately labelled with its N, because the cluster holds one thread, one send, one region and US-only counterparties. The argument is not that we ran thousands; it is that every guarantee making thousands safe is a constraint, and a constraint holds identically at one and at a hundred thousand. A dedicated section lists the seven things this submission does not claim. **DEMO_SCRIPT.md §3** was a replacement and should have been an addition. The lines cut in the last commit are back — blast radius, `opted_out` as a state no discovery stage can overwrite, the sender refusing an inferred address, and "sustainable outreach is a schema property here, not a policy document" — now carrying the contactability evidence underneath rather than instead. Only the genre line stayed moved, because §2 says it better with the vector index already on screen. That costs four seconds over the cap, so §1 gets a marked trim that returns five: it was already 0:26 in a 0:20 slot, and it no longer needs to name the sources now that §3 shows them. Cut runs 2:59. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Adds the account and billing layer: an accounts module, a plan catalogue, a Stripe integration with webhook signature verification, and the 033 schema migration that backs them. Settings learns to read the Stripe mode off the key prefix rather than a second flag, so test and live cannot disagree. Console and landing surfaces are reworked to show plan state. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The account and billing layer, plus the console and landing surfaces that show it.
accounts.py,plans.py,billing.py— accounts, the plan catalogue, and Stripe with webhook signature verificationplatform/schema/033_account_billing.sql— the migration behind themplatform/bin/stripe_setup.py— one-shot product/price setup, refuses ansk_live_keytest_accounts.py,test_billing.pyStacked on #56 — that one should merge first. Once it does, this diff narrows to the billing work alone.
Not test-verified. Merged at the author's explicit direction without running the suite;
mainwas green at 610 passed beforehand.🤖 Generated with Claude Code