mAInCharacter
Legal

Data Handling Statement

Version
1.2
Effective
Cited as
legal:data-handling@1.2

This platform records real conversations and holds documents about people's careers. That is a strong claim to make on someone's trust, so this document states what the architecture actually does, in enough detail that a reader could disagree with it.

Everything here describes behaviour that is implemented. Where something is a choice rather than a guarantee, it says so and names the choice.

Audio never leaves the device

Recording and transcription happen entirely inside the desktop application on your consultant's own machine. Speech recognition and speaker separation run as local models loaded into that application — there is no cloud transcription provider in the product, and none can be configured.

No audio is ever uploaded to this platform. What the platform receives is text: transcript turns, summaries, and notes. Audio is not among the kinds of material the platform's device interface will accept, so a recording cannot be sent to us even by mistake.

When the recording is deleted

The audio file is deleted from the consultant's machine, and the deletion is then verified — the code re-checks that the file is gone rather than assuming it, and records an error if it is not.

Deletion is triggered by whichever of these comes first:

We would rather describe that window than round it off. The recording does not vanish the instant the transcript is written; it survives for at most fifteen minutes, on that one machine, and then it is removed and the removal is checked.

Local session material is encrypted at rest

While session material waits on the consultant's machine to be checked in, it is encrypted with AES-256-GCM. The key is held in the operating system's own credential store, minted there on first use.

Two properties are worth stating because they are the ones that usually are not true:

What is sealed: the session transcript and its sidecar, the readable session log, and the stored Coaching Mode configuration.

What is deliberately not sealed

Three things on the consultant's machine are plaintext, and a reader should not assume otherwise:

  1. The audio file, during the fifteen-minute export window described above. It is written unencrypted and then purged.
  2. The Obsidian vault export. If a consultant publishes notes into an Obsidian vault, that copy is written in the clear. This is a user-initiated export to a folder the user chose, and Obsidian has to be able to read what is in it — encrypting it would mean handing someone a file their own note-taking application cannot open. Once it is in the vault it is an ordinary file on that person's disk, under their control and their backups, and outside this platform's protections.
  3. The knowledge-base cache, which holds chunks of prepared material and their search vectors.

Identifying details are replaced when material becomes case data

This happens on the platform, on receipt — not on the device before sending. We state the order plainly because it is the part that is easy to imply wrongly: The transcript travels to us encrypted, and it is de-identified here, on receipt, when it is taken into your case: names and identifying details are replaced with consistent stand-ins, so that the same person is the same stand-in every time. The map from a stand-in back to the real detail is held on our side, encrypted per case, and is never sent to a device.

So the pass runs after check-in, over material that has already crossed to us over an encrypted connection. It is not a filter standing between the consultant's machine and this platform, and it should not be read as one.

The pass fails closed. If the detection service cannot be reached, the result is a blocked outcome carrying the reason — never a document that looks as though it contained no identifiers. "Could not check" and "checked and clean" are never allowed to look the same to the code that reads the answer.

Two further properties:

The two places that pass does not stand between you and a third party

Stated here rather than buried, because a guarantee with unnamed exceptions is not a guarantee. In the second of the two, a weaker pass on the device stands there instead — described below rather than counted as equivalent:

PDF extraction. A PDF has no text until a model has read it, so there is nothing for a detector to run over first. Instead of pretending the guard applies, the crossing is made explicit and recorded: a named consultant grants egress on one document with a stated reason, the grant is audited, and nothing can be submitted without it. The extracted text is consultant-only until it has been de-identified. Other document formats are read on our own server and never cross.

Cloud providers selected on a consultant's device. The desktop application can be configured to use a cloud service for live suggestions and for search vectors. The shipped setting is a model running on your consultant's own machine, which reaches nothing outside it. Which providers exist, and what each receives, is named in the subprocessor list — and if you would rather your engagement ran on the local providers, say so.

The platform's own de-identification pass runs after check-in, so it does not stand between the device and such a provider. A second, separate pass on the device does, and it is weaker than the one on the platform. Before any text goes to an outside model, the application replaces the identifying details it already holds — the names on the case and in the material checked out for it, along with email addresses, phone numbers, web links, and runs of six or more digits — and it abandons the request rather than send anything it could not replace. That refusal is enforced at the client boundary rather than at each call site, and a destination that cannot be proved to be on the machine is treated as remote.

It is a protective measure against a list of details we already hold, not a guarantee of anonymity: a person or organisation first mentioned aloud, whom the application has never been told about, is sent as spoken, and so are addresses, dates, ages, job titles, and employers. Nor does it catch an inflected, misspelled, or mis-transcribed form of a name that is on its list. The pass on the platform uses a trained recognition model; the one on the device is literal matching against a list, because the desktop cannot currently load a second inference runtime alongside its speech engines. We would rather name that difference than let the two be read as the same protection.

Consent, withdrawal, and retention

This section restates, word for word, what the consent documents in your portal say. It is here so that the terms are readable before you are asked to agree to anything, and it is kept identical on purpose — a test in this repository fails the build if the two ever drift apart.

Withdrawing

You can withdraw your consent at any time from your portal, and you do not have to give a reason. Each consent you give is a separate agreement, and withdrawal is per category: you can withdraw any one of them without touching the others.

Withdrawal takes effect immediately. From that moment:

Withdrawal is not retroactive. Work that was already done with your material while your consent stood — notes your consultant wrote, preparation already produced — was done with your agreement and is not unmade.

What we keep, and for how long

If you want stored material deleted sooner, say so and we will handle that separately.

One implementation detail worth adding, because it is the difference between a retention policy and a scheduled job: the twelve-month deletion is carried out by a named, audited administrative action, not by an unattended timer. It is always something a person decided to do, and there is a record of who did it.

Consent is versioned

Every consent document is fingerprinted when it is published and cannot be edited afterwards. Changing the wording means publishing a new version, and publishing a new version drops every case whose agreement was against the old text back to pending until the person agrees again. So a consent record always points at the exact text its signer read, and that signer can still read it.

The documents on this site are versioned the same way, and for the same reason: each carries a version and an effective date at the top, and a citation such as legal:data-handling@1.0 that a consent record can store.

Separation of the public site from your material

The public pages and the signed-in application are separate route groups with separate layouts, and the separation is one of data access rather than appearance:

Deletion is verified, not assumed

Where the platform deletes something, it re-reads afterwards and reports what actually went. This applies to the local audio purge, to quarantined session material that reaches its expiry, and to stored files whose case no longer exists. A count that says twelve rows were removed while twelve rows are still there is precisely the failure this discipline exists to prevent.

Deleting a case

The strongest instance of that discipline is the one that deletes a whole case. It is available to a founder and to nobody else, it takes one case per call — there is no way to spell delete everything matching this with it — it will not run without a stated reason, and performing it is itself written to the audit trail.

The list of what to delete is read from the database's own catalogue rather than typed out by hand, so a table added next year is covered on the day it is created instead of the day somebody remembers it. Two things are done explicitly, because leaving them to the database would get them wrong:

Then it proves itself. Every column in the database that could hold one of that case's identifiers is scanned for one — every table, including tables nobody thought about when this was written — and if a single row is still standing, the entire deletion is rolled back rather than reported as a partial success. Files are a separate step, because deleting the database row that names a file does not delete the file: the deletion records which files are still owed, and it is not marked finished until something has re-read the bucket and found it empty.

It can also refuse outright. If another case was merged into this one, or a sealed record elsewhere cites a run belonging to this case, it stops and names what is in the way instead of deleting around it.

What a deletion keeps, and why

Three records survive it. Naming them is the point of this section:

The first two refuse UPDATE and DELETE at the database level, by a rule the application cannot turn off; the third accepts exactly one later change, the stamp confirming the files are gone. That refusal is not incidental to the retention, it is the reason for it. A consent ledger that could be edited entry by entry would be evidence of nothing, and an audit trail that could be pruned would be least trustworthy at precisely the moment it matters most — which is when it records a deletion. The consent record is also what makes holding the material defensible in the first place, so destroying it alongside the material would remove the proof that we were entitled to hold what we just deleted.

The counterweight is disclosure rather than hedging. All three are exported in full when someone asks for a copy of what we hold, so what is kept is at least readable by the person it is about. The privacy policy states the same thing as a retention period.

Asking us anything

Requests to see, correct, export, or delete what we hold — or to ask which providers your own engagement is configured with — go to hello@main-character.me.