# Privacy, profiles, moderation, and retention

This policy describes how xilogs treats combat-log data before open registration.
Invite-beta operators should surface these points in the publish UI and support channels.

## What publishing does

Publishing a parse makes it readable by anyone with the link and by public discovery
surfaces (public parse list, player directory, player profiles).

A published parse can expose:

- character names and server names observed in the recording
- combat event summaries and timelines derived from those observations
- the uploader’s chosen title and labels

Participant names are **unverified observations** from the uploader’s client. They are
not claimed identities. Profiles are labeled unverified in the API and UI.

## Consent model

- Only the account that owns a parse can publish it.
- Participants who appear in someone else’s recording are not asked for consent before
  publication. Operators must treat this as an informed-upload trade-off and keep
  registration invite-gated until moderation capacity exists.
- Owners can unpublish at any time. Unpublish removes anonymous access immediately for
  subsequent requests; caches must not retain private responses (`Cache-Control: no-store`
  on authenticated routes).

## Takedown and reporting

Anyone may submit a report via the in-app form at `/privacy` or `POST /api/public/reports`
(parse id and/or server+character name, plus a short reason).

Report metadata retention:

- Report bodies (kind, target fields, message, status) are retained until closed and then
  purged after `REPORT_RETENTION_DAYS` (default 30).
- Client network identifiers are **not** stored in cleartext. When
  `REPORT_CLIENT_HASH_PEPPER` (or `OPS_METRICS_TOKEN`) is set, a keyed HMAC of the
  rate-limit client id may be stored for abuse analysis; otherwise `client_key` is null.
- Per-client duplicate suppression uses the shared rate limiter (24h), not a global
  lockout of the target. Independent reports from other clients are stored separately.

Administrators may:

- force-unpublish a parse and set `publication_blocked` so the owner cannot republish
  (`POST /api/admin/parses/{id}/unpublish` or `python -m app.admin parses unpublish <id>`)
- clear a publication block after review (`POST /api/admin/parses/{id}/allow-publish`)
- list/resolve/dismiss reports (`GET/POST /api/admin/reports...`)
- suspend an account (`python -m app.admin accounts suspend <id>` or admin HTTP)

Force-unpublish and suspend actions are audited. Operators should acknowledge takedown
requests within a documented SLA (recommended: 72 hours for invite beta).

## Retention and backups

- Source uploads live under `UPLOAD_ROOT` until the owner deletes the parse and the
  delete worker succeeds.
- Session rows keep truncated `ip_prefix` only (IPv4 `/24`, IPv6 rough `/48`).
- Audit retention is controlled by `DELETE_AUDIT_RETENTION_DAYS`.
- Database dumps and upload-volume backups may retain published and unpublished parse
  data until those backups age out. A takedown that only changes live visibility does
  **not** erase existing backup copies; operators must expire or rewrite backups after
  a confirmed privacy incident according to the retention schedule in `docs/cloud-ops.md`.

## Acceptable use

Do not upload or publish recordings for harassment, doxxing, or intentional
impersonation of other players. Accounts that abuse publishing or upload quotas may be
suspended. Open registration remains unsupported until moderation tooling and this
policy are operationally staffed.
