ProofPack closed on 26 October 2026. This page is kept as the record of how we handled data while it ran. Read the closure notice.
Data processing agreement
Version dpa-2026-10-11, in effect from 11 October 2026.
Changes from version dpa-2026-09-24 (11 October 2026). Section 6 now says where the quote PDF and the database are held. Since 7 October 2026 the quote PDF sits in Cloudflare Workers KV, not in a Supabase storage bucket, and the database is Cloudflare D1, not a Supabase project; the sub-processors page and the privacy notice have said so since then. Nothing else in this agreement changed.
This agreement is part of the terms of service and applies whenever we process personal data on your behalf. At card checkout and on the quote acceptance page it is called the Data Processing Addendum; it is the same document. It is written to UK GDPR Article 28. It starts from a fact that shapes everything else: ProofPack runs inside your environment, and your data does not reach us.
1. The parties and their roles
You are the customer named on the order, the controller of any personal data in the data you analyse with ProofPack.
We are Global Phoenix Solutions Ltd, company number 14855822, registered in England and Wales, registered office Ground Floor Flat, 259 Chichester Road, Bognor Regis, West Sussex, PO21 5AH, United Kingdom. Contact: Joshua Sandhu, director, joshua.sandhu@globalphoenix.co.uk.
What we are not. We are not a processor of your test-set data, model outputs or patient data, because the engine runs on your infrastructure and none of that leaves it. There is no upload endpoint, no licence server and no agent.
What we are. We are a processor of the small amount of data the engine may send us, and we are the controller of the commercial data about your company and its staff that we hold in order to sell and support the licence. The privacy notice covers that controller role.
2. What may reach us, exhaustively
2.1 Runner telemetry. At the end of a run, unless you run with --offline or set egress.telemetry: false, the engine may send one record containing exactly these fields and no others:
schema, licence_id, run_id, engine_version, platform, manifest_sha256, duration_s, halt_code, row_count_bucket, timestamp.
No column name, no metric value, no count below the bucket level (<1k, 1k-10k, 10k-100k, >100k), no row-level value and no free-text field is in the record. The engine checks the record against its telemetry definition before sending and does not send a record that fails the check, and our receiver refuses any record that carries a field outside the ten. The definition is published on /trust. The copy there comes from an earlier engine version whose rules for individual values differ in detail from the ones the engine and our receiver now apply; it names the same ten fields and no others. The engine makes one HTTP request after run.json is written, a 5 s socket timeout on the connect and a 5 s deadline on the reads and writes after it, a redirect answer not followed, and a failed send prints one line and changes nothing else about the run. Our receiver (POST /api/telemetry on this site) stores the ten fields with a receipt time and nothing else: no IP address, no user-agent string, no header. The record is kept for 24 months from receipt, or 30 days after the last licence under the terms ends if that is sooner, as /trust states and clause 8 sets out; the purge that enforces the 24 months is not built yet, and until it is we delete by hand. The two switches are --offline and egress.telemetry: false; with either, no record is built and no connection is opened.
2.2 Commerce data. What you and your staff give us to buy and use the licence: the legal entity, billing address, buyer name and email, an accounts-payable email, the model name, a PO number, the plan and model count, which procurement documents you need, and, when a quote is accepted, the name and role of the person who accepts, their confirmation that they are authorised to bind you, and the IP address and user-agent of the acceptance. Also the licence file we issued, the versions of these terms and this agreement you accepted, and the Stripe identifiers that tie the records together. We hold this as controller; it is listed here so the whole picture is on one page.
2.3 Support email. Whatever your staff choose to write to us. We never ask for test data or patient data in a support conversation, and if a conversation heads towards it we stop it. When we run the digest described in section 3 of the privacy notice, it can quote the first 60 words of such an email to our director, through Resend.
3. Personal data: not intended, and the residual-risk mitigations
ProofPack is not intended to process personal data on our behalf, and the runner is built so that none reaches us. We do not say “never” as an absolute, because an absolute is not something a test can check. What can be checked is each of the following, which the engine’s published egress schema states as the rules every channel out of the engine must satisfy:
- No row-level field exists in the telemetry record. Nothing that describes an individual row can be serialised, because the definition has no place for it and admits no field beyond the ten above.
- Small-cell suppression before anything is serialised. Any aggregate cell with fewer than 10 subjects, fewer than 5 events or fewer than 5 non-events is serialised as suppressed with null values. You may tighten those thresholds and may not loosen them.
- Pseudonymisation of every level of the site, device and protocol columns and of every
attr_column, other than the engine’s ownUnknown/missinglabel, to “Site A”, “Device A”, “Protocol A”, “Level A” and so on, before egress; the map back to your labels is written only to a file on your machine. A level of any other attribute column is pseudonymised only when it is not a short token. A short token (at most 16 characters, starting with a letter or digit, using only letters, digits and_ . + -, for exampleF,Maleor40-65) is serialised as it is, whatever it records: one of the engine’s tests feeds1987-03-04as a level of asexcolumn and reads it back unchanged. - A header allow-list. Only canonical column names matching
^[a-z][a-z0-9_]{0,31}$may appear in any aggregate payload. For an attribute column whose header startsattr_, the canonical name is that header, so it can appear. - Free-text fields never leave. The
justification,descriptionandsourcefields you write, and raw dates, are on the never-serialised list. --offlineopens zero sockets. In the engine’s tests, the calls that open a network connection are made to fail while each command runs with--offline. The engine’s public continuous integration also runs a whole analysis inside a network namespace with no network, with and without--offline, on every push to the engine’s repository, and the result of each run is public.- The aggregate rules above apply to features that do not exist yet. The only channel the engine has is the telemetry record in clause 2.1, which carries no aggregate. The channels that would carry aggregates are an optional narrative feature for the runner and for the demo, both deferred past version 1.0 with no code path; the rules are published in the schema, and built into the engine, so that they exist before either feature does.
If, despite all of that, personal data reaches us, we treat it as a personal data breach under clause 7: we tell you, we delete it, and we tell you what we changed so it cannot happen the same way again.
4. Processing details
| Subject matter | Operation of the ProofPack licence: runner telemetry, licence issue, billing and support |
| Duration | The licence term and the retention periods below |
| Nature and purpose | Receiving and storing telemetry for support triage and licence usage; issuing and emailing licence files; billing; answering support questions |
| Categories of data subject | Your staff who buy, accept, install or run ProofPack, and who write to support |
| Categories of personal data | Business contact data (name, role, work email), acceptance audit data (IP address, user-agent), support correspondence. Telemetry contains no personal data by design |
| Special category data | None, and none is to be sent to us |
| Retention | Telemetry: 24 months from receipt, or 30 days after the last licence under the terms ends if that is sooner. Commercial records: the life of the relationship and then for as long as UK company and tax record-keeping law requires. Support email: until you ask us to delete a thread, and then we delete it |
5. Our obligations as processor
Where we process personal data on your behalf we will:
- process it only on your documented instructions, which are these terms and the engine’s configuration as you set it, and tell you if we think an instruction breaks the law;
- make sure the one person with access, the director, is bound by a duty of confidentiality;
- apply the security measures in clause 6;
- use only the sub-processors listed at /legal/sub-processors, under written terms that impose the same obligations, and remain responsible for them;
- help you respond to data subject requests, within the limits of what we hold, which is little;
- help you with security, breach notification and impact assessments so far as what we hold is relevant;
- delete or return the personal data at the end of the licence, as clause 8 says;
- make available the information needed to show we are meeting these obligations, and allow an audit, as clause 9 says.
6. Security measures that exist today
Each measure below is in the site’s code as it stands on 24 September 2026, except the bullets on the quote PDF and the database, which describe the code as it stands on 11 October 2026. Where an automated test that runs on every change checks the measure, the bullet says “tested”; where the measure is a property of the code that no test checks, or of a provider account that the code cannot check, the bullet says that instead. Measures that are not in place are listed on /trust, and this page does not describe a planned control as an existing one.
- No user accounts and no logins anywhere in the product: there is no session to steal and no password to leak. (A property of the code: the site has no login route and no session store.)
- Card details are handled entirely on Stripe’s hosted checkout page; no card number reaches our code or our logs. (A property of the code: the checkout endpoint creates a Stripe Checkout Session and redirects to it.)
- Transport security and security response headers on every route, including the server endpoints. (Tested.)
- Payment webhook signatures verified before the request body is parsed, with a replay window, a constant-time comparison and every event id recorded so a retry cannot issue a licence twice. (Tested.)
- Licence files signed with Ed25519; the signing key is read from an environment variable only and exists in no file in any repository. (Tested: a check runs before every deployment and fails while a stand-in key is published.)
- Quote acceptance links are signed and expire after 30 days; the quote PDF is held in a private file store (Cloudflare Workers KV since 7 October 2026) and served through our own route, never from a public object address. (Tested.)
- The database (Cloudflare D1 since 7 October 2026) is reached only from the server functions, through a binding that Cloudflare gives them; no page of this site carries a database key. (A property of the code. How the database is configured in our Cloudflare account is not set by our code and no test checks it: [unverified: project configuration].)
- No web font, analytics or cookie on any page of this site, and no third-party script on any page except
/demo, which loads the Pyodide runtime from cdn.jsdelivr.net. (A property of the built site; on/demo, an automated browser test checks that every request is a GET to this site or to cdn.jsdelivr.net with no body.) - Every dependency open source and installed from the public registry. (A property of the package manifest.)
- A published vulnerability disclosure route at
/.well-known/security.txt, with 90-day coordinated disclosure. (Tested.)
Not in place, stated plainly. No third-party penetration test has been performed. We hold no SOC 2 report, no ISO 27001 certificate and no Cyber Essentials certificate. Automated security scanning of the site and a per-release software bill of materials are specified and not yet running. The reasons and what we will do are on /trust.
7. Personal data breaches
If we become aware of a personal data breach affecting personal data we process for you, we will tell you without undue delay and in any case within 72 hours of becoming aware, by email to the contact on your account, with what we know at that point: what happened, what data and roughly how many people are affected, what we have done, and who to talk to. We will update you as we learn more. We will not tell a regulator about a breach of your data on your behalf unless you ask us to.
8. Deletion at the end of the term
Within 30 days of the end of the last licence under the terms, we delete the telemetry records for your licences and any support correspondence you ask us to delete. We keep the commercial records for as long as clause 4 says, because company and tax law requires it, and delete them when that period ends. On request we confirm the deletion in writing.
9. Audit
You may audit our compliance with this agreement by written questionnaire, once in any twelve months and additionally after a breach, and we answer within 30 days from the documents on /trust and this page. If a written answer is not enough for a specific, stated reason, we will discuss a remote review of the relevant system with you. We do not offer on-site audits: there is one person, no office, and nothing of yours to see.
10. International transfers
Where a sub-processor processes personal data outside the United Kingdom, the transfer is made under the sub-processor’s data-processing terms, as stated per provider on /legal/sub-processors. Where that page marks a mechanism as [unverified], it has not yet been confirmed from the provider’s terms, and we will confirm it on request before you rely on it.
11. Sub-processor changes
We give 30 days’ notice of a new sub-processor by updating /legal/sub-processors and emailing the contact on your account. If you object on reasonable data-protection grounds and we cannot resolve it, you may end the licence and we refund the unused part of the term.
12. General
This agreement is governed by the law of England and Wales. If it conflicts with the terms of service on a data-protection point, this agreement wins. Annual licensees may ask for a countersigned copy, and we will provide one.
Other legal pages: Terms · Privacy · Sub-processors · Outreach privacy notice · Legitimate interests assessment