read.markets/app/templates/privacy.html
Giorgio Gilestro 47dce1a1a4 compliance: flag-gate AI portfolio + cloud sync + Stripe; de-risk prompts; harden reviewer
Implements docs/read-markets-compliance-changes.md as flag-gated changes
(no deletions) so paused features stay in the tree for future re-enable.
All four flags default False so a fresh deploy is compliance-safe.

- New env flags: PORTFOLIO_AI_ENABLED, PORTFOLIO_SYNC_ENABLED,
  TICKER_UNIVERSE_AGGREGATE_ENABLED, SUBSCRIPTIONS_ENABLED.
- Gates: /api/analyze, /api/portfolio/sync*, /api/stripe/*, /pricing,
  ticker_universe writes, portfolio_analysis.analyse(). is_paid_active()
  returns True for any auth'd user when subscriptions are paused.
- Prompts (PROMPT_VERSION 10): universal _COMPLIANCE_RIDER prepended to
  every system prompt; watch list removed; price-target / close-above-below
  / trigger / forward-state-as-description rules added; SPECULATIVE
  pivoted to regime-only scenarios; daily + weekly digests tightened.
- Reviewer: deterministic regex/lexicon pre-check fail-closed under the
  Haiku call; portfolio rider gated by PORTFOLIO_AI_ENABLED; base prompt
  sharpened for forward-state and MAR forward-opinion patterns;
  ReviewerVerdict audit table; generate_with_review retry helper.
- Migration 0026: purge portfolio_sync + ticker_universe; create
  reviewer_verdicts.
- Copy: MAR cite fixed to Art 3(1)(35) + Art 20 + Del Reg 2016/958;
  portfolio reframed as browser-only viewer in disclaimer / privacy /
  terms / about / pricing / landing (en + it). TODO(legal) marker for
  lawyer sign-off on disclaimer.
- Tests: 13 lexicon + 6 reviewer compliance regressions; conftest enables
  all flags so existing 402 tests still cover their code paths.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-29 19:57:12 +02:00

273 lines
10 KiB
HTML

{% extends "public_base.html" %}
{% block title %}{{ BRAND_NAME }} &middot; Privacy{% endblock %}
{% block main %}
<section class="public-section">
<h1 class="public-section__head">Privacy notice</h1>
<p style="color: var(--muted); font-size: 13px;">
Last updated: 2026-05-24. The operator (data controller) is
{{ LEGAL_OPERATOR }}, {{ OPERATOR_JURISDICTION }}. Registered with
the UK Information Commissioner&rsquo;s Office under reference
<strong>ZC098928</strong>. Questions:
<a href="mailto:{{ OPERATOR_EMAIL }}">{{ OPERATOR_EMAIL }}</a>.
</p>
<p>
This page describes exactly what we collect, what we don&rsquo;t,
where it lives, and how long we keep it. It is written from the code,
not from a template &mdash; every claim corresponds to an explicit
code path we&rsquo;re happy to point a reviewer at.
</p>
</section>
<section class="public-section">
<h2 class="public-section__head">What we collect</h2>
<ul>
<li>
<strong>Your email address</strong>, when you sign in. We use it
only to send one-time login codes.
</li>
<li>
<strong>An argon2 hash of each login code</strong>, plus expiry
and attempt counts. The plaintext code is sent to your inbox and
never written to disk on our side.
</li>
<li>
<strong>A signed session cookie</strong> after you verify a code.
It contains your user id only and is signed so we can detect
tampering. Cookie is marked Secure and HttpOnly.
</li>
{# Cloud sync + server-side per-ticker aggregate union are flag-gated off.
See docs/read-markets-compliance-changes.md and app/config.py
(PORTFOLIO_SYNC_ENABLED, TICKER_UNIVERSE_AGGREGATE_ENABLED). #}
<li>
<strong>Anonymised cost ledger</strong> of AI calls (model, tokens,
cost). No portfolio or personal data is attached to ledger rows.
</li>
<li>
<strong>Referral linkage</strong>: if you signed up via an invite
link, we record which existing user&rsquo;s code you used so we can
apply the agreed referral credit later.
</li>
<li>
<strong>Job-run telemetry</strong>: success/failure timestamps for
the scheduled jobs that fetch market data and generate AI reads.
No user identifiers are attached.
</li>
</ul>
</section>
<section class="public-section">
<h2 class="public-section__head">What we don&rsquo;t collect</h2>
<ul>
<li>
<strong>Your portfolio holdings, in any form, on the server.</strong>
The portfolio feature is a browser-only composition viewer:
uploaded CSVs are parsed and returned to your browser, kept in
<code>localStorage</code>, and never sent back to or stored on
the server. The server records no per-ticker aggregate of what
anyone holds.
</li>
<li>
<strong>Third-party analytics or ad cookies.</strong> No Google
Analytics, no Hotjar, no Segment, no Facebook pixel, no LinkedIn
tag. (You can verify by viewing-source on any page.)
</li>
<li>
<strong>Browser fingerprints.</strong>
</li>
<li>
<strong>IP-address joins to your user identity.</strong> IP
addresses are processed transiently by the reverse proxy for
security and access logging, retained for up to 30 days, and not
linked to your account record.
</li>
</ul>
</section>
<section class="public-section">
<h2 class="public-section__head">Lawful basis (UK-GDPR Art. 6)</h2>
<p>We rely on the following lawful bases:</p>
<ul>
<li>
<strong>Performance of a contract</strong> (Art. 6(1)(b)) &mdash; for
operating your account, the sign-in flow, and any paid features.
</li>
<li>
<strong>Legitimate interests</strong> (Art. 6(1)(f)) &mdash; for the
anonymised cost ledger, job-run telemetry, and reverse-proxy access
logs. Our interest is the secure, abuse-resistant, cost-controlled
operation of a free public service, balanced against the minimal
and de-identified nature of the data.
</li>
</ul>
</section>
<section class="public-section">
<h2 class="public-section__head">Automated decisions and profiling</h2>
<p>
The Service does not make decisions about you that produce legal or
similarly significant effects in an automated way (UK-GDPR Art. 22).
The strategic log and indicator summaries are general editorial
commentary on public market data, not personalised assessments of
you, and you remain the sole decision-maker about anything in your
account.
</p>
</section>
<section class="public-section">
<h2 class="public-section__head">Cookies and local storage</h2>
<ul>
<li>
<strong>Session cookie</strong> &mdash; strictly necessary for keeping
you signed in (PECR reg. 6(4)). No prior consent required.
</li>
<li>
<strong>Local preferences</strong> &mdash; your chosen theme (light /
dark) and reading level (Novice / Intermediate) are stored in
<code>localStorage</code> on your device. They never leave the
browser.
</li>
<li>
<strong>Local portfolio</strong> &mdash; parsed pies live in
<code>localStorage</code> on your device. They are not sent to
or stored on the server.
</li>
</ul>
</section>
<section class="public-section">
<h2 class="public-section__head">Where the data lives, and international transfers</h2>
<p>
The server runs in {{ OPERATOR_JURISDICTION }}. Data is stored in a
MariaDB database on the same host, backed up locally.
</p>
<p>
Two flows can take personal data outside the UK:
</p>
<ul>
<li>
<strong>SMTP</strong> for sending one-time login codes. Operator-hosted,
currently inside the UK; if that changes we will update this notice.
</li>
<li>
<strong>AI provider calls</strong> for the strategic log and
indicator summaries. Where the provider sits outside the UK, we
rely on the UK International Data Transfer Agreement (IDTA) / the
UK Addendum to the EU Standard Contractual Clauses where no
adequacy decision applies. Each outbound request carries an
explicit no-training opt-out header
(<code>X-OR-Allow-Training: false</code> on OpenRouter); see the
Third parties section below for the caveats. None of these
outbound requests contain user holdings or other portfolio data.
</li>
</ul>
</section>
<section class="public-section">
<h2 class="public-section__head">Retention</h2>
<ul>
<li>
<strong>Login codes</strong>: expire after a few minutes; row
remains briefly to enforce single-use, then is purged.
</li>
<li>
<strong>Session cookies</strong>: expire automatically; you can
sign out at any time to revoke.
</li>
<li>
<strong>Account</strong>: held until you ask us to delete it.
Email <a href="mailto:{{ OPERATOR_EMAIL }}">{{ OPERATOR_EMAIL }}</a>.
</li>
<li>
<strong>Cost ledger and job telemetry</strong>: retained for
operational accounting; no personal data attached.
</li>
</ul>
</section>
<section class="public-section">
<h2 class="public-section__head">Third parties</h2>
<ul>
<li>
<strong>SMTP provider</strong>: an operator-hosted Mailu server
sends the one-time login codes. The provider sees your email
address and the code body (the code itself).
</li>
<li>
<strong>AI provider(s)</strong>: DeepSeek (primary) with OpenRouter
as a fallback. They see the prompt for the strategic log and the
indicator summaries. These prompts contain public market data and
headlines &mdash; never any user holdings or portfolio data.
<br>
<strong>No-training opt-out.</strong> Every OpenRouter request
carries the <code>X-OR-Allow-Training: false</code> header, which
signals to OpenRouter and any compatible upstream that the prompt
must not be used to train or improve models. DeepSeek does not
currently expose a per-request opt-out. We do not control
retention or training policies on the provider side beyond the
headers we set &mdash; the provider&rsquo;s own published data policy is
the binding statement on that point.
</li>
<li>
<strong>Market-data sources</strong>: Yahoo Finance and a small set
of public RSS feeds. We request prices and headlines; we don&rsquo;t
send them any user identifier.
</li>
</ul>
</section>
<section class="public-section">
<h2 class="public-section__head">Your rights (UK-GDPR)</h2>
<p>You have the right to:</p>
<ul>
<li>Ask what personal data we hold about you (Art. 15, right of access).</li>
<li>Have inaccurate data corrected (Art. 16, rectification).</li>
<li>Have your account and associated data deleted (Art. 17, erasure).</li>
<li>Export the data you can recognise (Art. 20, portability): your
email and your referral linkage.</li>
<li>Restrict processing (Art. 18).</li>
<li>Object specifically to processing carried out on the basis of
legitimate interests (Art. 21), including any direct marketing.</li>
<li>Withdraw consent at any time where processing is based on
consent (Art. 7(3)), e.g. by disabling cloud sync.</li>
<li>Lodge a complaint with the
<a href="https://ico.org.uk/" target="_blank" rel="noopener">Information Commissioner&rsquo;s Office</a>
if you think we&rsquo;re mishandling your data.</li>
</ul>
<p>
Email <a href="mailto:{{ OPERATOR_EMAIL }}">{{ OPERATOR_EMAIL }}</a> to
exercise any of these.
</p>
</section>
<section class="public-section">
<h2 class="public-section__head">Children</h2>
<p>
The Service is not directed at, and is not intended for use by,
anyone under 18. Do not create an account if you are under 18. If
you believe a child has provided personal data to us, contact
<a href="mailto:{{ OPERATOR_EMAIL }}">{{ OPERATOR_EMAIL }}</a> and we
will delete it.
</p>
</section>
<section class="public-section">
<h2 class="public-section__head">Security incidents</h2>
<p>
If we discover a personal-data breach likely to result in a risk to
your rights and freedoms, we will notify the ICO within 72 hours of
becoming aware of it, as required by UK-GDPR Art. 33, and notify
affected users without undue delay where Art. 34 requires.
</p>
</section>
<section class="public-section">
<h2 class="public-section__head">Changes to this notice</h2>
<p>
Material changes will be flagged in-app and dated above. Trivial
edits (grammar, restructuring) won&rsquo;t.
</p>
</section>
{% endblock %}