Back to the evidence page

The legal surface

Seven questions a district's counsel asks before this software telephones a parent. FERPA, the TCPA, retention, and which four of them are still open.

Seven questions a school district's counsel would ask before this software telephoned a single parent. Some have an answer in this repository, some have a design position, and some are open. They are written down because silence about them reads as never having asked.

Not among the seven: COPPA. It covers an operator of an online service directed to children collecting personal information from a child under 13, and this software does not do that. It telephones an adult, it asks nothing of a child, and if a child answers the instruction is to say only that the school will call back and end the call (firstbell/domain.py, build_task). Named here because a summary of this document listed it for a fortnight and the document never mentioned it, which is worse than either answering it or leaving it out.

This is not legal advice and it is not a compliance sign-off. It is the list of questions a district's counsel would ask before this software phoned a single parent, written down so that a reader can see which ones have an answer here, which ones have a design position, and which ones are open. Every one of them is a question about a school telephoning a family, not a question about this code, which is why none of them is answered by the tests.

The order is the order they would be asked in.

1. Is an absence call a disclosure of an education record? (FERPA)

The rule. FERPA (20 U.S.C. § 1232g; 34 CFR Part 99) restricts disclosure of personally identifiable information from education records without written consent. A student's attendance record is an education record. Telling a parent about it is ordinarily not a disclosure problem, because a parent is the party with rights under FERPA for a minor.

Where it gets interesting. The call is placed by software operated by a vendor. That makes the vendor's status the question, not the parent's. The usual route is the school official exception at 34 CFR § 99.31(a)(1): an outside party may be treated as a school official where it performs a service the district would otherwise use its own employees for, is under the district's direct control as to the use and maintenance of the records, and does not redisclose.

What this repository can say. The work file carries the minimum that a call needs: a student id, guardian numbers, a locale, a consent flag and an absence date. student_name is present because a call that cannot say the child's name is not a usable call. Nothing else about the student is read, and the receipt records outcomes rather than record contents.

Open. Whether the district's own counsel accepts CALL-E, as the upstream telephony provider, inside the school official boundary, and what its annual notification of rights must say. Neither is answerable here.

2. May we place an artificial-voice call to a parent's mobile? (TCPA)

The rule. The TCPA (47 U.S.C. § 227) restricts calls to wireless numbers using an artificial or prerecorded voice without prior express consent. On 8 February 2024 the FCC adopted a Declaratory Ruling recognising that calls made with AI-generated voices are "artificial" under the TCPA (FCC news release). That ruling is the reason this section exists: it puts a call like this one squarely inside the statute rather than beside it.

What this repository does. consent is a required column and a row without it is SKIPPED before any call is placed, which the demonstration shows as S-1045. The consent gate is implemented, tested, and cannot be bypassed by a flag.

What the parent actually hears, in their own language. The disclosure is a constant in firstbell/domain.py, not a template, so a deployment cannot reword or omit it. A reviewer asked the obvious next question: the constant is English, so is a Tamil-speaking parent disclosed to in English? The answer is on a real call. Work item S-4106, ta-IN, opens:

இது பள்ளி வருகைப் பதிவு அலுவலகத்திலிருந்து வரும் தானியங்கி அழைப்பு.

This is an automated call from the school attendance office.

நீங்கள் ஒரு நபருடன் அல்ல, AI உதவியாளருடன் பேசுகிறீர்கள். எந்த நேரத்திலும் பணியாளர் ஒருவருடன் பேச வேண்டும் என்று கேட்டால்,

You are speaking with an AI assistant, not a person. If at any time you ask to speak with a staff member,

That is the first thing said, before anything is asked, and it is the disclosure the FCC ruling is about. The Tamil is not a translation this project wrote: the locale is one column in the work file, and CALL-E spoke and transcribed the rest. The English under each Tamil line is ours, written afterwards from that Tamil and kept in tools/glosses.json so the page and this document cannot carry two different readings of one sentence. The second line runs on into the next turn, which is why it stops where it does. The recording is on the evidence page, which is where every recording lives and not in this repository, for the reason evidence/README.md gives. The English call opens with the same sentence in English. Whether a district's counsel accepts a machine translation of a disclosure as the disclosure is a question for them, and it is not answered here.

The gap, stated plainly. A CSV column reading yes is a data structure, not a legal record of consent. It carries no timestamp, no evidence of what the parent was told, no record of the channel it was given on, and no revocation path. The software enforces a flag that a district would have to be able to defend, and nothing here helps it defend one.

Half closed, and the open half is still the largest one on this page. The schema half is done: docs/consent-record.md is the shape of a dated consent record, dispatch/consent.py enforces it, and a work file can name one per row in a consent_record column. Eight checks run before a phone rings and every one fails closed: the record must be in the register, be for this student, not be withdrawn, not have expired, not be dated in the future, cover voice rather than text or email, cover attendance rather than general contact, and name every telephone number on the row.

The eighth is the one your counsel will care about most. Under the TCPA prior express consent attaches to the number called and not to the person the number belongs to. A row carries a fallback chain, this software works down it, and a record that names a pupil says nothing about which of two numbers may be dialled, so a row carrying any number the record does not name is refused outright rather than refused at the third attempt. A record that names no number at all still dials, because every register written before that field existed names none, and the run counts and prints those rows instead of passing them quietly. --json writes one line per call naming the record that authorised it and whether that record named the number that rang.

A run also prints how many rows it dialled on a record and how many on a boolean, because a column that says yes is not a record and this page will not let that pass quietly.

What stays open is the conversation, and it is the part that matters to you. Where the record lives and who may write one. How a parent withdraws, how fast that reaches the register, and what happens to calls already queued. And whether an unexplained absence is an emergency: the schema has an emergency purpose and this software refuses it, because deciding that an absence is a safety exception is a decision about a child rather than a configuration option. Changing that is two constants in dispatch/consent.py, and it should be changed on purpose with a name attached.

3. May the call be recorded, and is it? (state wiretap law)

The rule. Recording consent is state law and it is not uniform. A majority of US states permit recording with one party's consent; a minority require all parties to consent. Placing a call across a state line can engage both states' rules.

What this repository does. Recordings of these calls exist, on CALL-E's dashboard and on this project's evidence page, and they are of calls between the author and the author's own line made for demonstration. That is said first because the rest of this answer reads like a stronger claim than it is.

This app never records and has no route to a recording: there is no audio field on any of the three production responses captured under tests/data, and /recording, /audio, /recordings and /v1/recordings all return 404. That is a limitation of the platform rather than a decision made here, and it happens to be the safer default. What a district would be relying on, then, is that the software cannot fetch what the platform keeps, which is not the same as the platform not keeping it.

Open. Whether the district's own retention obligations require it to keep a recording it currently cannot fetch, and what its position is in an all-party state.

4. What is kept, for how long, and who deletes it?

What this repository does. A run writes one receipt. It carries outcomes, counts, identifiers and timings. It does not carry a transcript unless --include-transcript is passed, and it never carries an unmasked telephone number: mask() is applied on the way out and tests/test_privacy.py fails the build if a number, a key or a seven-digit run reaches a receipt, a log line or stderr.

Open. Retention is undefined here because it belongs to the district's schedule, not to a tool. A deployment needs a stated life for receipts, a stated life for anything CALL-E holds upstream, and a deletion path that covers both. This software writes files to a path it is given and has no opinion about how long they live, which is a gap and not a feature.

5. What does the data-processing agreement have to say?

The clauses a district would need, none of which this repository can supply:

6. A voice-only service and a guardian who cannot use a voice call

This is the objection that most deserves to be uncomfortable, because the argument for this software is a language-access argument.

Title VI and the 2015 joint Dear Colleague Letter require a district to communicate with families in a language they understand. This app answers that by calling in the family's own language. Section 504 of the Rehabilitation Act and Title II of the ADA require effective communication with a guardian who is deaf or hard of hearing, and a voice call is not that. Solving one duty with a channel that cannot serve the other is not a solution, it is a transfer.

What this repository does about it now. The work file carries an optional voice column. voice=no means the phone cannot reach this guardian, and it is a gate rather than a preference: the row is never dialled, it is not counted among the calls that failed, and it goes to the human queue carrying a reason that says somebody has to reach them another way. The gate is second, behind consent, because a family that refused to be called is not owed an outreach on a different channel either. A value in that column nobody recognises raises instead of guessing, since a spelling mistake there decides whether a person is telephoned.

This closes the record-keeping half of the problem and not the communication half. Before it, a guardian who could not take the call was dialled, reached nothing, and was filed as a failure, which on a report reads as nobody answered. The family was reachable. The channel was not, and the record said the opposite.

The gate is demonstrated rather than described, in the export a district already produces:

python -m firstbell --work-file examples/absences-oneroster.csv

[HUMAN] S-2204       this family is not reachable by a voice call; nothing was
                     dialled and somebody has to reach them another way

For a while it was described and not demonstrated, which is a weaker thing than it reads as. The rule was held by nine tests over CSVs written inside those tests, and no shipped work file carried the column at all, so a reviewer running everything in this repository never saw the refusal happen. A district buyer found that by checking all four files. district-ingest.md has what filling that column costs, because no student information system carries it and no vendor can populate it for a district.

What is still not built. There is no relay support, no TTY path and no SMS fallback. firstbell does not send the other message; it declines to send the wrong one and hands the case to a person. There is also still no stated behaviour when a family's language is outside CALL-E's supported table.

7. Who is accountable for the case the software escalates?

A school cannot delegate its duty of care and this software does not ask it to. The rule is that only an explicit confirmation closes a record, and everything else reaches a person inside a stated window. SAFEGUARDING_CALLBACK_MINUTES is 30.

Open. Thirty minutes is a number chosen to be stated rather than a number negotiated with anybody. A pilot would have to agree it, name the role that owns the queue, and define what happens to an escalation nobody has picked up when that window expires. Software that escalates into an unstaffed queue has moved a problem rather than solved it.

This page is docs/the-legal-surface.md in the repository, rendered at build time. The file is the original and this is a copy of it, so if the two ever disagree the file is right.