For very large districts: at 25,000 students the risk you are buying is contractual, not functional
Every serious vendor at this scale can send a message to sixty thousand households. What separates them is what the agreement says about year four, what happens when the vendor changes hands, and whether a corrupt roster file can withdraw half your families on a Tuesday morning.
| Failure mode | What it looks like | Mechanism | Addressed? |
|---|---|---|---|
| Renewal shock | Year-four quote arrives 45% above year three, after switching cost has compounded | §3.2: rate fixed 36 months, then capped at the lesser of CPI-U or 5% annually | Yes, numerically |
| Acquisition | Vendor is rolled up; data terms, roadmap and support change under a new owner | §11.2: district terminates within 90 days with export and prorated refund | Yes, district holds the right |
| Feature paywalling | The capability you deployed on moves into a higher tier at renewal | One tier. Everything included at every band, contractually | Yes |
| Data hostage | Exit quoted as a professional-services engagement with a five-figure number | §7.1: machine-readable export of everything, any time, no fee, no notice | Right yes, tooling no — we run it on request; there is no self-serve export |
| Roster corruption | A truncated export withdraws 60% of active families mid-year | Sync aborts with aborted_guardrail above a 50% withdraw ratio and records the run as aborted | Yes |
| Uptime opacity | A decorative status page and no contractual availability commitment | — | No. We are pre-launch, publish no uptime figures, and have no operating history to publish |
The two we do not address, stated first
Operating history. Kastr is pre-launch in August 2026. No customers, no reference calls, no SOC 2 audit, no published uptime, no availability SLA. At 25,000 students and above, that is a legitimate disqualifier and we would rather you reach that conclusion in ten minutes than in month four of a procurement.
Measured scale. We publish no load-test figures because we have not run a load test we would be willing to have audited. Every "40,000 families in under 90 seconds" number in this category is a marketing artefact unless the vendor will show you the methodology. Ask them for it. Ask us when we have one.
The delivery queue, described without numbers we have not measured
What can be said about the dispatch path is mechanical rather than statistical.
- Workers claim delivery rows with
SELECT … FOR UPDATE SKIP LOCKED, so adding workers adds throughput without two of them claiming the same row. A five-minute claim TTL means a worker that dies mid-batch releases its rows automatically rather than stranding them. - Network I/O happens outside the database transaction. A slow carrier API cannot hold a Postgres transaction open, which is the single most common way a delivery system at scale takes its own database down.
- Idempotency is enforced at the row level, keyed on
broadcastId:personId:channel. A retried dispatch, a redelivered queue message or a double-submitted send cannot produce a second text to the same household on the same channel for the same broadcast. - SMS that fails terminally triggers a voice attempt, linked to the original by a
failover_fromreference, so the record shows the substitution rather than hiding it. - Quiet hours default to 21:00–07:00 at dispatch, bypassed only by an emergency-flagged send, which is gated on a distinct capability.
What we will not tell you is how many messages per second that produces on your infrastructure, because we do not know. See idempotency keys for why the third bullet is the one that actually determines whether parents get duplicate alerts.
Cost at scale, with the three-year number
| Enrolment | Annual | 36-month locked total | Year-four worst case (5% cap) | Per-student, per-month |
|---|---|---|---|---|
| 25,000 | $75,000 | $225,000 | $78,750 | 25.0¢ |
| 40,000 | $120,000 | $360,000 | $126,000 | 25.0¢ |
| 60,000 | $180,000 | $540,000 | $189,000 | 25.0¢ |
No implementation fee, no per-message fee, no modules, no emergency-notification add-on. Text and voice are included in the per-student rate rather than passed through, which at this scale is the line that most often doubles a quote after signature. The composer shows a live per-channel cost estimate as you tick channels, which exists mainly so a communications team can see what a district-wide voice blast costs before sending it rather than in a quarterly reconciliation.
Isolation, and why it matters more at this size
A district of 60,000 with 90 buildings has a large internal permission surface, and the failure that actually happens is not a breach from outside but a building administrator seeing another building's families. Isolation in Kastr is enforced in Postgres via row-level security, applied inside every transaction under a non-owner, DML-only database role — which matters because a table's owner is exempt from its own RLS policies unless explicitly forced, and running application queries as the owner is the most common way RLS is silently defeated in production.
It is hierarchy-aware: a district sees itself and its child schools and never a sibling district. It fails closed: with no organisation context set on the session, policies evaluate against NULL and return zero rows rather than all rows. And it is tested rather than asserted — a cross-tenant leakage suite runs in continuous integration against real Postgres 16, including an owner-bypass regression check. The general shape of the question is at row-level security.
Where large districts will find us short
Beyond operating history: no single sign-on of any kind, which for a district standardised on Entra ID or Google Workspace is frequently a hard requirement we simply fail. No native connectors to PowerSchool, Infinite Campus, Skyward, Aeries or Synergy — roster data reaches us because a job you own POSTs it. SCIM provisioning is beta and will not survive a strict identity provider's pagination. Rate limiting is per-process and in-memory rather than coordinated across instances. Audience targeting by grade, school or route does not resolve. Auto-notice rules do not fire. Retention defaults are documented, not purged. There are no attachments, no push notifications and no AI drafting.
Set against that: 28 org-scoped REST endpoints, signed outbound webhooks with a DNS-resolving SSRF guard and exponential retry, and an MIT-licensed CLI and MCP server that keep working if the commercial relationship ends. At this scale the ability to script against a vendor without asking permission is worth more than most of the feature list.
Questions people actually ask
What is the price at 40,000 students?
$3.00 per student per year, so $120,000 annually and $360,000 across the locked 36-month term. Everything is included — text, voice, email, translation, emergency sends — with no implementation fee and no per-message pass-through. Year four is capped at the lesser of CPI-U or 5%, a worst case of $126,000.
How does the delivery queue avoid double-sending at scale?
Row-level idempotency keyed on broadcast, person and channel, combined with SELECT … FOR UPDATE SKIP LOCKED row claiming and a five-minute claim TTL. A crashed worker's rows return to the pool rather than being lost or re-sent, and a retry cannot produce a second delivery row for the same recipient and channel within a broadcast.
What are your published uptime figures?
We do not publish any, because we are pre-launch and have no operating history. Any uptime number we printed today would be fabricated. If a vendor at this scale shows you a 99.98% figure, ask what period it covers, who measures it, and whether it appears in the agreement as a credit-bearing commitment or only on a marketing page.
What happens to our contract if Kastr is acquired?
Clause §11.2 gives the district a 90-day window to terminate with a full machine-readable export and a prorated refund, with no penalty, on acquisition or on any material change to data terms. The right belongs to you and does not require our agreement. It is the clause that makes the family-monetisation prohibition in §9.4 durable rather than dependent on current ownership.
Can a bad roster file wipe out our family records?
The sync aborts before applying if the diff would withdraw more than 50% of active records, recording the run as aborted_guardrail. That is aimed squarely at the truncated-export failure, where a nightly job produces a partial file and the platform faithfully withdraws everyone missing from it. The diff engine hashes payloads with SHA-256 and classifies every record as add, change, unchanged or withdraw, so an aborted run is inspectable rather than opaque.
One price. Every feature. Locked for three years.
$3.50 per student per year under 5,000 students. No tiers, no add-on modules, no per-message fees. Published on the site because you should not have to book a call to learn a price.