Skip to content

Privacy Review

Marty McEnroe edited this page Aug 20, 2026 · 7 revisions

Privacy Review

Facts for a data-protection reviewer assessing palaestra.thrivetech.ai. The live policy is at palaestra.thrivetech.ai/privacy-policy; its source is published.

Controller

Operated by an individual, noncommercial. Contact support@palaestra.thrivetech.ai. Erasure requests GDPR-request@palaestra.thrivetech.ai.

Personal data held

Data Source Purpose Retention
Name LinkedIn OIDC claim Attribution on boards and scores Until erasure
Email address LinkedIn OIDC claim Account identity; notifications only if opted in Until erasure, or removable separately (below)
LinkedIn subject identifier LinkedIn OIDC claim Stable primary key Until erasure
Episode data: turns, actions, scores Generated by play The scored record; replay Until erasure
Sign-in time Generated at sign-in Audit of account access Until erasure
Problem report: message, page, engine version Submitted by the user Support Until erasure
Problem-report trace, if attached Submitted by the user Support Until erasure

Nothing else is stored.

Every row now says the same thing, and that is the whole retention policy: data is kept while the account exists and removed when the person asks. Two rows used to carry a clock — sign-in times at ninety days, attached traces thirty days after a report was closed — and both were removed deliberately.

The ninety-day figure was set when the sign-in record also held an IP address, coarse location and a user-agent string. Those columns were dropped shortly afterwards and the figure was never revisited, so what the sweep deleted by the end was an account identifier already held elsewhere and a timestamp. The trace clock was never a considered decision at all; it was chosen while the sweep was being written.

The venue would rather state one criterion it keeps than several periods it has to remember. The criterion is disclosed, which is what Art. 13(2)(a) asks for when a fixed period is not given, and erasure is what enforces it.

What is refused

Profile photo LinkedIn returns a photo URL whether it is requested or not. It is discarded on receipt. Not stored, not displayed, not logged.
IP address Not stored.
Location Not stored.
Device or browser details Not stored at sign-in.

A sign-in record has three fields: a record id, a player id, and a timestamp. There is no column for anything else.

Both are readable in inspect/worker/auth.ts: the claims the worker reads, and the ones it drops.

The problem-report trace

Attached only if the user leaves the checkbox ticked, and the user can download and read the exact contents before sending. It holds recent in-app errors with their request reference ids, the results of any connection check run, the page the trace was captured on, and the browser user-agent string.

This is the one place a user-agent string is transmitted, and it is disclosed in the policy.

The trace is kept with the message it arrived with, and both go on erasure. It used to expire thirty days after a report was closed, on the reasoning that it describes a device rather than a problem and has done its job by then. The reasoning was sound and the effect was not: a bug someone hits once tends to recur, a closed report gets reopened, and the trace is what makes the second report answerable. There is no scheduled sweep of any kind now.

Consent and lawful basis

Sign-in is required to play; there is no guest access. The account fields above are necessary to provide the service.

Notifications are separate and off by default. notify_enabled defaults to disabled. No email is sent unless the user turns it on.

The address obtained from LinkedIn is stored only when the provider asserts it is verified. An unverified claim is kept as identity and earns no sending rights.

Sub-processors

Processor Role Location
Cloudflare Hosting, D1 database, R2 object storage, request logging Configured region WNAM (western North America)
LinkedIn Identity provider at sign-in only Per LinkedIn

No data is sold, shared with advertisers, or passed to data brokers. There is no analytics processor, because there is no analytics.

Cookies

Cookie Purpose Lifetime
Session Signed player identifier 30 days
Return path Preserves the destination across the OAuth redirect 10 minutes

Both are first-party, HttpOnly, Secure, SameSite=Lax. There is no tracking cookie and no third-party cookie.

Rights, and how they are exercised

Right Mechanism Timing
Access and portability "Export my data" on the profile, self-service Immediate
Erasure Email GDPR-request@ Within 30 days
Remove email address only "Remove my address" on the profile Immediate
Withdraw notification consent Profile, or a one-click link in any notification Immediate

Erasure does not depend on jurisdiction. The address names the regulation that named the right, not the set of people entitled to it. Requests are honored the same way wherever the person lives.

Erasure removes everything keyed to the identity: the player record, episodes and their turns, sign-in records, any problem reports and the traces attached to them, the notification history, and the model of which concepts the player had met.

That list used to be shorter, and it was wrong. Three of those categories were added to the venue after the erasure path was written, and none was cleared by it, so a request would have left a person's problem reports, their device traces and an inferred model of their understanding in place. No request had been made, and it is now fixed. The reason the list can be relied on is that the set of stores holding player data is derived from the schema and checked against what erasure actually clears, in both directions, by a test that runs on every commit. A category added later and not erased fails that test rather than a person's request.

Removing the email address separately sets a marker that also nulls the address on every subsequent sign-in, so the identity provider cannot silently restore it.

Verify

See also Security Review.

Clone this wiki locally