Recorded decision (Simon 2026-08-31): personal data may be stored under
legitimate interest ONLY as business contacts bound to a company/org entity.
Gate enforces it: legitimate_interest requires purpose=business_contact and
entity_linked_only=true; recordStored() requires entity_id (orgnr/rgs/LEI,
hashed) and refuses person-only rows. +1 test; suite 167 pass | 1 skip;
typecheck clean.
PiiGateService makes any future personal-data source (ratsit.se and other
directory domains) technically GDPR-OK before the first byte is stored:
- recorded legal basis (art. 6) with basis_ref evidence, no policy => fail-closed
- data minimisation via field allowlist (art. 5(1)(c))
- storage limitation + enforceRetention purge (art. 5(1)(e))
- sha256-only identity keys + log redaction (art. 25/32)
- accessStatement / erase subject-rights surfaces (art. 15/17)
- robots/rate confirmation required for web+api sources; no stealth/bypass
- audit trail via AUD0 at risk L3 (0pt.pii_*)
- gate enabled by default in SourceQueryService
10 new tests; full suite 166 pass | 1 skip; typecheck (blocking gate) clean.
The previous commit said "nobody has probed the running site". I then probed it,
so the docs should not keep hedging.
curl -sI https://0pt.app/
HTTP/2 402
server: Vercel
x-vercel-error: DEPLOYMENT_DISABLED
strict-transport-security: max-age=63072000
https://0pt.app/api/health -> HTTP 402, body "Payment required / DEPLOYMENT_DISABLED"
Two facts hold simultaneously and the docs now state both: the Coolify deploy hook
fires for real on every push to main, AND the public product domain is dark behind a
disabled Vercel deployment with DNS never cut over. Neither cancels the other.
Still not established, and still marked as such: whether the Coolify app builds and
starts. A deploy endpoint returning 200 means the request was accepted, not that a
container came up healthy.
Side note worth recording for PR #19: the HSTS header on that 402 response is
Vercel's platform default, which is exactly the disappearing-on-cutover risk
next.config.mjs in PR #19 was written to remove.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Six documents on main assert that no Coolify app has been provisioned for 0pt and
that cd.yml's COOLIFY_APP_ID is a literal placeholder whose guard fails the job on
purpose. That is no longer true, and the gap is not cosmetic: it means a merge to
main silently ships to production while the repo's own docs promise it cannot.
Measured, not assumed:
* repo Actions secret COOLIFY_TOKEN exists, created 2026-08-31T11:34:34Z
(GET /api/v1/repos/sax3l/0pt/actions/secrets)
* repo Actions variable COOLIFY_APP_ID exists with a real 24-character value,
not the "TODO-no-coolify-app-provisioned-yet" literal
(GET /api/v1/repos/sax3l/0pt/actions/variables)
* both guards in .gitea/workflows/cd.yml therefore pass; on the push to main at
1ff34410 (2026-09-06) the job "Deploy to Coolify / deploy" (run 11695, job
26295) finished SUCCESS with "coolify deploy HTTP 200" in its log
Deliberately NOT claimed: that the Coolify app builds, starts or serves, or that
0pt.app DNS points at it rather than Vercel. Nobody probed the running site, and
every corrected passage says so explicitly rather than replacing one unverified
claim with another.
Corrected: README.md "Deploy", docs/02-architecture.md hosting callout,
docs/architecture/decisions/0001 (consequence annotated, decision untouched --
an ADR is a historical record), docs/runbook/incident.md (the symptom row is now
inverted: the risk is an unintended deploy, not a red job),
docs/compliance/GOLDEN-STANDARD-REPORT.md D4 (❌ -> ⚠️, not ✅, because "webhook
accepted" is not "app serves"), docs/compliance/INVENTORY.md CI row.
Falsifiable check over all six files (stale claim present without a correction
marker = red):
origin/main -> FAIL (12 findings)
this branch -> PASS
mutation: drop only the README bullet -> FAIL
mutation: drop only the runbook correction -> FAIL
The check initially passed vacuously on docs/02-architecture.md because PR #32 had
already put the string "CORRECTED 2026-09-06" in that file for an unrelated reason;
the marker was made specific so the check could actually fail there too.
Docs only. No workflow files, no .gitignore, no source.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
PR #15 already fixed AGENTS.md/SECURITY.md with a dated, attributed
statement of the account owner's 2026-08-11 decision (Simon Axelsson, via
an interactive decision prompt, responding to this repo's own removal
proposal PR #7 which was verified clean/128 tests and closed unmerged --
no rationale beyond "keep it" was given or is invented). This PR finds and
fixes every other place in the repo that still carried the earlier
unattributed "medvetet anvandarbeslut" / "deliberate user decision" claim
a compliance audit flagged as unverifiable:
- docs/compliance/GOLDEN-STANDARD-REPORT.md: control C6 row + the
"Bypass-undantag" formal section (the two places this doc was explicitly
named to need checking) -- header gains a dated update note, C6 row and
the section body get the same attributed statement as AGENTS.md/SECURITY.md.
- docs/compliance/SLUTRAPPORT.md, docs/compliance/INVENTORY.md: historical
session doc keeps its original text and gains a dated correction
addendum; the INVENTORY.md evidence bullet is corrected in place.
- docs/slo.md, CONTRIBUTING.md, prompts/002-compliance-audit.md,
renovate.json, .gitea/workflows/security.yml: direct/living references
to the exemption get the same attributed, dated pointer instead of the
unattributed phrase.
CLAUDE.md's general §1 anti-evasion policy text is untouched, per instruction
-- this is a scoped exception note, not a change to the normative rule. No
code changes.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Golden Standard §1.4 requires an unresolved blocker to be recorded in
docs/compliance/BLOCKERS.md; this file was confirmed absent in a recent
audit pass, which is itself a delivery defect per the framework's own
rule. Records four blockers, each freshly re-verified against current
main rather than copied from prior findings:
- WAF-bypass/Tor/FlareSolverr stack (services/scrapers/*): the account
owner's decision (keep) is now on record via merged PR #15 as of
today; PR #7 (removal) stays closed/unmerged. Documented as decided,
not left as still-pending.
- No Coolify app / Infisical project provisioned (cd.yml still carries
the TODO placeholder on current main).
- 0pt.app / 0pt.dev DNS still delegated to Vercel nameservers (live NS
lookup today), despite PowerDNS holding shadow zone copies.
- middleware.ts still answers anonymously live even after a merged
auth fix (PR #11) — confirmed with a fresh live probe today, which
sharpens the existing P0-1 backlog item.
Scope: documentation only, this one new file. Does not touch
services/scrapers/*, services/infra/docker-compose.data-stack.yml,
docs/compliance/BACKLOG.md, or PR #7.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>