{"breach":{"notes":"Art 33 GDPR \u2014 Processor notifies Controller without undue delay (no hard SLA imposed by this DPA). The Customer (Controller) has an independent 72h obligation to notify the supervisory authority if risk warrants; that is the Controller's own obligation, not the Processor's.","notify_controller_sla":"without undue delay"},"changelog":[{"date":"2026-06-18","summary":"Initial registry. Slack canon. Anthropic + OpenAI + GHL disclosed. Erasure 'without undue delay'. GHL 4-year retention.","version":1},{"date":"2026-06-18","summary":"Centralised privacy lockup. Added meta.canonical_url + canonical_version + canonical_route_source. Added data_lanes section (Lane A = LL service customer, Lane B = DPA member processing, Lane C = John's lead-gen marketing). All surfaces (extension, MRR Leak Finder quiz, Skool Traffic Finder, growth/heat reports, README) now point at single canonical /privacy. Lane C surfaces add point-of-collection notice. Stripe added as Lane A sub-processor. Canonical policy bumped to v2.0 (3-lane).","version":2},{"date":"2026-06-18","summary":"Phases 3-6 \u2014 registry-as-source closes the loop. tools/privacy_sync.py renders DPA-lite + GHL DPA template + about-our-data + worker /privacy HTML from registry. Worker exposes /privacy/spec.json + /privacy/changelog.json + /privacy/spec.schema.json (ETag = registry fingerprint, CORS, 304 support). tools/privacy_query.py CLI. .claude/hooks/privacy-drift.sh pre-commit hook fails on drift OR registry-mod-without-bump. ghl_contact retention text restored ('on the next periodic purge').","version":3},{"date":"2026-06-18","summary":"privacy_mod.py pipeline shipped \u2014 single-command modification (DESCRIPTION + PRECISE modes) with rollback, hook integration, launcher tile","version":4},{"date":"2026-06-18","summary":"v1.5 DPA + SaaS-pattern e-sign: standard notify-on-update + continued use = acceptance, replaces re-sign-on-drift. Worker /dpa/sign idempotent; new routes /dpa/current + /dpa/changelog; new tools/notify_dpa_update.py CLI + email template.","version":5},{"date":"2026-06-19","summary":"Phase 0.5 Block 2 extension registry diffs. Added DC-07 install_telemetry; OP-07 ext_telemetry_engagement, OP-08 ext_uninstall_feedback, OP-09 ext_owner_pain_inbox, OP-10 ext_referral_chain; HD-08 owner_authored_text_allowed_lane_a; retentions for ext_install/user/admin_group/message/pain/sprint_signal (term of DPA), ext_telemetry (90d), ext_uninstall (2y), ext_referral_code (indefinite for attribution). DPA bumped v1.5 \u2192 v1.6. No new sub-processors.","version":6},{"date":"2026-06-19","summary":"Phase 1 ship: OP-11 dpa-update notification (owner Controller) with click-to-ack audit row; audited retention rules per compliance bundle 2026-06-19 (telemetry 90d \u2192 2y rolling, pain inbox DPA-term \u2192 1y rolling, new ext_dpa_ack 2y rolling). DPA bumped v1.6 \u2192 v1.7. No new sub-processors.","version":7},{"date":"2026-06-19","summary":"bumped DPA \u2192 v1.8","version":8},{"date":"2026-06-19","summary":"v1.9 DPA bundle (22 fixes): expanded-DPA claim removed; single-page claim removed; DPA acronym defined; admin-session updated (own OR Processor-as-admin); heat reports \u2192 reports; churn/signups \u2192 engagement+revenue metrics; Tier 1 requires DPA; avatars/bios \u2192 Tier 2 may-collect; Tier 1 anon-token clause; Sprint cohort clause; 14d \u2192 30d sub-processor notice; audit 14d \u2192 30d; Supabase AU primary; Google AI/Workspace added; GHL CRM desc updated; Cloudflare AU/EU/US; EU-only-region line removed; locally-on-John's-machine line removed; canonical URL updated; save-where \u2192 except-where; plain English rewritten. F22 location note in meta.notes.","version":9},{"date":"2026-06-19","summary":"Changed meta.canonical_url to custom domain privacy.ascendalliance.com.au (CF custom domain on leverage-lab-score worker, cert provisioned 2026-06-19)","version":10},{"date":"2026-06-19","summary":"DPA v2.0 \u2014 F1 asymmetric notice (LL\u2192Customer 7d sub-processor; Customer\u2192LL 30d audit); F2 governing law QLD AU + narrow consumer-protection carve-out only; F3 tied-to-identifier tier classification baked into DPA as explicit clause; F4 avatar-pool statistics \u2192 Tier 1 aggregate (shipped in error, reverted in v12). New registry fields: dpa.sub_processor_notice_days, dpa.audit_notice_days, dpa.tier_classification_note, identity.governing_law_consumer_note.","version":11},{"date":"2026-06-19","summary":"DPA v2.1 \u2014 revert F4: avatars always Tier 2. No Tier 1 avatar-pool exception. Avatars inherently identifying in practical use. DC-02 notes updated; tier_classification_note updated; DPA text updated.","version":12},{"date":"2026-06-19","summary":"bumped DPA \u2192 v2.2","version":13},{"date":"2026-06-19","summary":"v2.2 field updates: HD-06 desc + OP-06 notes \u2192 identifier-tied verbatim blocked, de-identified permitted (sentiment etc.); breach.notify_controller_sla_hours \u2192 notify_controller_sla='without undue delay' (no hard SLA; schema updated); dpa.anonymised_sharing_permitted=true + note; dpa.sub_processor_notice_note (asymmetric 7d/30d clarified); templates updated; schema updated.","version":14},{"date":"2026-06-19","summary":"bumped DPA \u2192 v2.3","version":14},{"date":"2026-06-19","summary":"bumped DPA \u2192 v2.4","version":15},{"date":"2026-06-19","summary":"Phase 2 Chunk 3-5: scraper public API endpoints + anon T0 telemetry (OP-12, OP-13, DC-06 extension)","version":16},{"date":"2026-06-19","summary":"appended to operations: {'id': 'OP-13', 'name': 'anonymous_install_telemetry', 'description': 'Phase 2 T0 anonymous telemetry: extension fires panel events (drawer opens, lock-clicks, action completions on generic BBs, stage scores derived in-browser) via POST /telemetry. install_token_hash = SHA-256 trunc-24 of an opaque random 32-hex token issued by GET /install/token. Token is a rate-limit lever \u2014 never identity-bound. Payload structurally rejects (worker + DB CHECK) any group/user identifier: group_slug, slug, admin_groups, user_id, skool_user_id, handle, display_name, email, group_id, gid, member_id, author_handle.', 'gate': 'none', 'requires_dpa': False, 'data_categories': ['DC-07'], 'notes': 'Lane Public / operational. No DC tie to a natural person at write time. Becomes correlated personal only if joined server-side with DC-05 (not done in T0). Retention 2y rolling per retention.ext_t0_telemetry. See apps/skool-scraper/sql/04_ext_t0_telemetry.sql.'}","version":17},{"date":"2026-06-19","summary":"bumped DPA \u2192 v2.5","version":18},{"date":"2026-06-22","summary":"Item B (Compliance verdict 2026-06-22 PM): added dpa.revocation_anonymisation_clarification \u2014 Recital 26 wording (once salt destroyed, data is no longer personal). Operational clarification only \u2014 NO DPA version bump, NO registry version bump (same data scope, clearer language). Replaces earlier Art 6(1)(f) framing flagged as category error.","version":18},{"date":"2026-06-22","summary":"Lane A retention_ref clarified for Watchtower auto-roll: active billing cycles + 6mo grace post-cancellation + 7y invoice/tax records (AU Income Tax Assessment Act). Operational clarification \u2014 no new data flow, no DPA bump.","version":19},{"date":"2026-06-22","summary":"Domain cutover: canonical surface URLs moved from privacy.ascendalliance.com.au \u2192 ascendalliance.com.au/{dpa,privacy,uninstall}/* (apex root, path-scoped). meta.canonical_url updated to https://ascendalliance.com.au/privacy. Marketing site at apex root continues to serve via CF Pages (only those path prefixes hit the worker). Old privacy.* subdomain remains live and 301-redirects to apex preserving full path + querystring, so all existing signed DPA links (/dpa/view/<token>?sig=...) keep working. New DPA mints use the apex domain. No data flow change, no DPA version bump (URL surface only).","version":20},{"date":"2026-06-22","summary":"Revocation split into SOFT (default) vs ERASE (explicit GDPR Art 17): /dpa/revoke is now SOFT \u2014 marks consent_log.revoke_type='soft', pauses Lane B collection, PRESERVES anon mapping; same-email re-sign reattaches historical data via UPDATE-not-INSERT on /dpa/sign. NEW /dpa/erase endpoint = irreversible Art 17 hard-delete (cascade purge + de-id + revoke_type='erase'). /api/dpa/status surfaces revoke_type + can_reattach. Migration patch34 adds consent_log.revoke_type CHECK ('soft','erase'); legacy revoked rows backfilled to 'erase' (their cascade-purge already ran). Behaviour change to data lifecycle; DPA wording change deferred (Compliance lane).","version":21},{"date":"2026-06-22","summary":"v22 Compliance bundle (REVIEW-compliance-overview-2026-06-22.md, 12 items). Shipped: Item 2 (Art 13 transparency disclosure block on /dpa/sign \u2014 Path B chosen, telemetry gated on sign event); Item 3 /me/erase endpoint (Owner Hat-2 self-erasure, Path B hard-delete, accepts email+slug OR ext-attested owner_id+slug+hmac; cascades consent_log revoke + Lane B purge + de-id + best-effort GHL contact delete); Item 11b URL canonicalisation (canonical link tag + default PUBLIC_BASE_URL fallback in score.js migrated from privacy.ascendalliance.com.au \u2192 ascendalliance.com.au; old subdomain 301 redirect preserved for existing signed DPA links); Item 11c structural T2 gate (_qmmRequireT2MemberNotice helper + stub /qmm/t2 endpoint that 403s with reason='member-notice-needed' if consent_log.member_notice_url is NULL); Item 12 schema migration patch35 (consent_log.owner_id nullable TEXT + identity_proof_type ENUM('email','ext_attested','manual_mint') DEFAULT 'email' + member_notice_url nullable TEXT + CHECK constraint at least one of owner_id/signer_email present; legacy rows backfilled identity_proof_type='email'). No DPA version bump (additive \u2014 same data scope + clearer compliance posture).","version":22},{"date":"2026-06-24","summary":"v24 \u2014 Request C (sanitised group description summaries) shipped. OP-14 notes extended: group description sanitised + PII-stripped (7 classes: email, phone, URL [skool.com self-refs preserved], social handle, payment keywords, street address, billing data) before any public surface; full original text never persisted to public surface; internally cached pre-scrub only for re-process. New engine tools/sanitise_description.py (scrub_pii + sentence-boundary truncate \u2264200 chars + ellipsis only on truncation). Quality gate tools/test_privacy_scrubber.py (13 PII strip cases + 3 false-positive preserve cases + skool.com whitelist \u2014 pre-commit hard-blocks on failure). tools/test_sanitise_description.py (12 boundary cases). Visible 'Condensed by Leverage Lab' stamp + hover tooltip on every render (apps/scoreboard-v2/group_template.html + build_group_pages.py \u2014 never presented as owner-direct copy). Granular sub-objection: new column suppress_description BOOLEAN on skool_group_audit (patch41) \u2014 NULL in export when set, separate from slug-level suppressed (sister kindness, owners can keep listing while hiding description). CLI tools/suppress_group.py to flip per slug. sync_directory_to_supabase.py writes description_summary + honours suppress_description in export. View v_skool_group_directory rebuilt to include description_summary with NULL-on-suppress. No DPA version bump (same data scope, same lawful basis Art 6(1)(f) \u2014 additive sanitiser layer).","version":24},{"date":"2026-06-24","summary":"v24 \u2014 DC-06 (public_group_metadata) examples extended with owner_social_urls: owner-authored public social links (instagramUrl, twitterUrl, linkedinUrl, websiteUrl, youtubeUrl) surfaced on the public Skool /about page (no login). T0 public group-level metadata, owner-published, not a member identifier. Wired into scoreboard-v2 pipeline (build_data union already preserves them; T0_FIELDS allowlist in build_group_pages.py extended), Supabase skool_group_audit (patch41 adds instagram_url/twitter_url/linkedin_url/website_url columns + v_skool_group_directory view), sync_directory_to_supabase upsert, and scoreboard-v2 UI (per-group page socials row + detail panel links, straight URLs, rel=noopener noreferrer nofollow, no affiliate params). No new lawful basis (still legitimate_interest, DC-06). No DPA version bump (additive public-metadata field, same data scope).","version":24},{"date":"2026-06-23","summary":"v23 \u2014 public directory lane (Lane D) + OP-14 publish_public_directory. directory.ascendalliance.com.au deploy bundle. Rulings 1-8 (REVIEW-compliance-public-deploy-directory-2026-06-23.md) + Rulings 9-13 (REVIEW-compliance-supabase-persistence-2026-06-23.md) shipped: Lane D (data_categories DC-05/DC-06/DC-01, lawful basis legitimate interest, no DPA, objection_endpoint, blocklist + suppression flag); OP-14 (publish_public_directory, cross_group allowed, gate none, Recital 30 B2B aggregate + Recital 47 commercial legit interest); Supabase skool_group_audit table (append-only, RLS service-role-only, CHECK constraint banning member identifiers, suppressed boolean for soft-delete on objection, indefinite retention via retention.group_aggregate). Mitigations M1-M5 (Compliance Supabase REVIEW) all landed in-cycle: registry entry (M1), CHECK constraint (M2), RLS lockdown (M3), suppressed flag (M4), sync .declare.yaml (M5). Pre-deploy B1/B2/B3 (privacy template extended for Lane D, per-page footer + Remove-listing link + canonical fix). Post-deploy P1-P5 (blocklist stub, robots.txt training-crawler block, Art 30 register row, est. prefix + methodology link, no comparative leaderboards). Sub-processor cf_pages_static added to lane_d storage list.","version":23},{"date":"2026-06-24","summary":"v25 \u2014 identity.contact_email moved from john@ascendalliance.com.au \u2192 privacy@ascendalliance.com.au (alias forwarding to john@). Anti-spam protection for scraped public surfaces (Lane D + scoreboard-v2 footer + per-group pages). Alias routed via Cloudflare email routing. DPAs + signed legal docs (delivered post-signing, not scraped) continue to use real John contact via per-document mailto. No new lawful basis, no DPA version bump (operational contact-channel change, same controller/processor identity Tinker Electric Pty Ltd). All ~2989 scoreboard-v2 group pages + index footer regenerated. Worker PRIVACY_HTML + UNINSTALL page swap handed off to ext-repo sister Builder session via outreach/HANDOFF-worker-email-alias-2026-06-24.md.","version":25},{"date":"2026-06-24","summary":"v26 \u2014 P1 self-service report scaffold (Builder under REVIEW cc0a82b \ud83d\udfe1 CONDITIONAL GREEN authorisation, \u00a7117-136). Adds Lane C surface row apps/scoreboard-v2/report.html (T0 self-service report form). Adds four new operations: OP-15 report_generation_t0 (Lane C, DC-05+DC-06, consent + legitimate-interest, GHL+Supabase EU sub-procs, audit_log retention); OP-16 report_generation_t1 (Lane B, DC-01+DC-05, contract via DPA, GHL+Supabase EU sub-procs, audit_log retention); OP-17 audit_log_retention (internal Art 28(3)(h) accountability log, 24mo rolling cap, 90d email-redaction window per C-c2); OP-18 email_transactional_ghl (Path C bridge per Q-d-2 \u2014 GHL transactional email, no new sub-processor; John chose Path C over SES Path B / CF Email Path A on 2026-06-24). Adds retention.audit_log (24mo rolling, automated purge via patch44 Supabase scheduled functions). Welcome-member variant honours C-b1 opt-in requirement: consent signal = signup-question Skool group field; consent_source = ghl_signup_question_skool_group recorded per generation. No DPA version bump (consistent with REVIEW \u00a7126 \u2014 same lawful basis, same sub-processors as currently disclosed for Lane B/C). No sub-processor change (Path C chosen, GHL already disclosed). Migration patch44_audit_log.sql applied to Supabase (audit_log table, RLS enabled, two scheduled functions). t0_purity_check.py + declare-schema \`tier:\` enum key + per-tool tier tagging shipped same bundle (structural enforcement of T0/T1 separation per C-a1/C-a2). Shared infrastructure: tools/report_shared/{template,email_ghl,pdf_storage,audit}.py. P2 (T0 lane) + P3 (T1 lane) + welcome variant follow in separate dispatches. Plan: outreach/PLAN-self-service-reports-P1-2026-06-24.md. As-Built: outreach/AS-BUILT-self-service-reports-P1-2026-06-24.md.\n","version":26},{"date":"2026-06-26","summary":"v28 \u2014 DPA Annex A 'Data items' table (JSON sidecar outreach/dpa-data-items.json + worker mirror): drop \`field\` key (programming endpoint names like 'group.name') AND \`source_endpoint\` key (URL paths like 'GET /{slug}/about (community.price)'). Owner-facing DPA artefact describes data in plain English only \u2014 endpoint surface + internal field-name leak both removed. Generator change in tools/privacy_sync.py _build_dpa_data_rows() \u2014 both keys removed from row dicts; docstring updated. Markdown table in outreach/dpa-lite.md \u00a73f unchanged \u2014 Field/source_endpoint were never rendered there. Internal apps/skool-tier-debugger/field_catalog.py still holds endpoint names (used for tier/DC lookups, etc.) \u2014 only the customer-facing DPA artefacts stop exposing them. No data flow change, no DPA version bump (presentation-layer cleanup, same data scope, same lawful basis). Compliance lane (Builder dispatched 2026-06-26 STOPPED + handed off to Compliance per outreach/DISCUSSION-builder-plan-deviation-dpa-annex-a-field-col.md + COMPLIANCE-TRIGGERS.md halt on privacy-registry.yaml edit).","version":28},{"date":"2026-06-26","summary":"v29 \u2014 DC-08 collector_identity added (plan-approved-collector-identity, outreach/PLAN-collector-identity-2026-06-26.md). Threads collector_user_id (Skool user id ONLY of the ext-running owner/admin) end-to-end: ext content.js (reuses existing users/me id, no new fetch) \u2192 harvester payload top-level body key (NOT inside fields \u2014 never PII-stripped) \u2192 worker /qmm/t1/admin-ingest passthrough \u2192 Supabase qmm_t1_admin_snapshots.collector_user_id (migration 20260626_patch46). Audit-trail provenance only: 'snapshot collected by user X under owner Y signed DPA'. Id-only, minimal-scope subset of DC-05 (no email/name/handle). legal_basis contract, requires_dpa true (collector = owner/admin on own granted house, within signed DPA scope; worker 403s pre-DPA). Client-asserted + server-side id-shape validated (provenance-grade, NOT authz-grade \u2014 no server-side HMAC/per-install auth added; existing no-HMAC finding documented separately, out of scope). data-source-registry.yaml NOT touched (runtime operator identity, not a Skool endpoint/field). No new sub-processor, no new worker route, no DPA version bump (additive id-only column under existing contract basis).","version":29},{"date":"2026-06-27","summary":"v30 \u2014 collector handle via PSEUDONYMISATION MAP (plan-approved-collector-handle, outreach/PLAN-collector-handle-map-2026-06-27.md). John explicitly chose the map design over the earlier per-row handle build, reasoning the GDPR trade-off himself (traceability vs data-minimisation). The earlier per-row collector_handle column build is CANCELLED \u2014 qmm_t1_admin_snapshots stays id-only (collector_user_id, NO handle column). The readable Skool handle is now stored ONCE per collector in a new tiny lookup table ext_collectors (user_id PK, handle, first_seen, updated_at \u2014 migration 20260627_patch47). Worker /qmm/t1/admin-ingest: snapshot insert UNCHANGED (id-only); ADDITIONALLY best-effort UPSERTs ext_collectors(user_id, handle, updated_at=now()) when a valid collector_handle (lowercase ^[a-z0-9-]{1,64}$) + collector_user_id are present \u2014 a map-upsert failure NEVER fails the snapshot ingest. Ext threads the handle transiently: content.js (me.handle, already resolved, no new fetch) \u2192 background.js setCollectorHandle \u2192 harvester payload top-level collector_handle key (sibling to collector_user_id, NOT inside fields). Viewer (tools/qmm_incoming_viewer.py) JOINs collector_user_id \u2192 ext_collectors.handle for display, with id fallback. GDPR basis: Art 4(5) pseudonymisation + Art 5(1)(c) minimisation; erasure of a collector = drop one ext_collectors row \u2192 every historical snapshot reverts to opaque id-only. legal_basis/requires_dpa UNCHANGED (still contract, still within signed DPA scope \u2014 collector = owner/admin on own granted house). data-source-registry.yaml NOT touched (runtime operator attribute, not a Skool endpoint/field). No new sub-processor, no new worker route, no DPA version bump (additive pseudonymisation map under existing contract basis, strictly data-min-improving over per-row storage).","version":30},{"date":"2026-06-28","summary":"v31 \u2014 Metabase registered as a SUB-PROCESSOR (plan-approved-client-embed-secure, outreach/PLAN-client-embed-secure-2026-06-28.md + DISCUSSION-compliance-client-embed-2026-06-28.md C1.5). Self-hosted Metabase (dashboard.ascendalliance.com.au, CF-fronted) now processes the Customer's OWN-GROUP AGGREGATE metrics to render a client dashboard surfaced via a short-TTL (\u2264300s), group-slug-LOCKED, HS256 signed embed JWT. Owner-safe aggregate views ONLY (vw_group_latest / vw_group_aaemr / vw_group_mrr_timeseries / vw_group_members_timeseries / vw_group_levels / discovery_rank) \u2014 NO member-level PII, NO cross-group, NO vw_sprint_signals (excluded at metabase_ro role grant). Access gate = signed DPA (worker /client/embed-link reads canonical consent_log via findExistingSignature; revoked \u2192 403). Lane B (post-consent owner-own-group analytics). New worker route reads consent_log (read-only, no schema change). Public-by-CF-bypass /embed/* path serves only signed-JWT-bound single-owner aggregate. Sub-processor 7-day LL\u2192Customer notice applies. No DPA version bump (additive analytics surface under existing contract basis, no new member-level processing \u2014 owner already sees their own aggregate in Skool admin).","version":31},{"date":"2026-06-29","summary":"v32 \u2014 DPA transparency completeness fix (REVIEW-dpa-data-alignment-2026-06-29.md). Added previously-undisclosed aggregate counts + collector identity to the customer-facing DPA data-items table via field_catalog.py additions: (1) engage.daily_active / engage.weekly_active / engage.monthly_active (DAU/WAU/MAU \u2014 T1/DC-01); (2) members.paying / members.free / members.cancelling / members.churned_status (MEMBER_STATUS cluster \u2014 T1/DC-01); (3) discovery.rank / discovery.category_rank (DISCOVERY cluster \u2014 T1/DC-01); (4) growth.visitors_30d (GROWTH cluster \u2014 T1/DC-01); (5) collector.user_id + collector.handle (DC-08 collector identity \u2014 T1/DC-08, already in registry but absent from customer-facing DPA table). No new data collection \u2014 disclosure completeness only. Same scope, same DC-01/DC-08 basis. banned count CONFIRMED not collected (harvester MEMBER_STATUS filters = active/cancelling/churned/free/paid only). DC-08 surfaced in DC_TO_DPA_SECTION + DC_TO_RETENTION_KEY + DC_STORED maps in privacy_sync.py. No DPA version bump.","version":32},{"date":"2026-06-29","summary":"v33 \u2014 entity-not-person fix for the public privacy policy. Removed every narrative 'John'/'John's' reference where John-the-person stood in for the company across the privacy pipeline; replaced with the legal entity (Tinker Electric Pty Ltd) / trading brand (Leverage Lab) per the legal-vs-product rule. Touched: privacy-html.j2 Lane C heading + Lane C body + Section 8 prospect notice (was 'a prospect or lead of John's', 'John's quiz', 'John acting as Controller', 'used by John to follow up'); about-our-data.html.j2 ('1:1 work with John' \u2192 trading_as, 'groups John owns' \u2192 legal_entity); registry data_lanes lane_c.who ('John's prospects' \u2192 entity) + meta.notes Lane C description. Added trading_as to render ctx in privacy_sync.py (ident.trading_as, default 'Leverage Lab') so templates resolve {trading_as}. NOT changed: contact_email (privacy@ascendalliance.com.au alias forwards to john@; functional routing) and identity.director 'John Missikos' (legally-required named director/authorised signatory \u2014 the human behind the entity, not a stand-in for it). data_lanes lane_c.label 'john_marketing_leadgen' left (code identifier, never rendered). Historical changelog summaries left verbatim (audit record). No data flow change, no new lawful basis, no DPA version bump (presentation/wording-only entity correction).","version":33}],"data_categories":[{"description":"Group-level metrics (MRR, member count, churn, signups, structure, traffic mix)","examples":["mrr","member_count","paid_count","free_member_count","churn_rate","signups_7d","signups_30d"],"id":"DC-01","legal_basis":"contract","name":"owner_group_aggregate","personal":false},{"description":"Member identifiers (handle, display name, level, join date) + engagement counts within recency window + derived heat score + public profile data (avatar URL, bio)","examples":["handle","name","level","joined_at","post_count","comment_count","like_count","heat_score","avatar_url","bio"],"id":"DC-02","legal_basis":"contract","name":"member_handle_and_engagement_counts","notes":"Avatars are Tier 2: avatars are inherently identifying in practical use (even without an explicit handle tie, they are recognisable); no Tier 1 exception. Public bios are inherently identifying and stay Tier 2 regardless. Not collected at Tier 0 or Tier 1. Not an Art 9 special category.","personal":true,"requires_dpa":true},{"description":"Verbatim text bodies (posts, comments, DMs) tied to a specific member","id":"DC-03","name":"member_post_content_verbatim","never_collected":true,"notes":"Hard-denied by gate (HD-01) regardless of DPA. Truncated to 200 chars if leaked.","personal":true},{"description":"Member email, phone, IP, payment data, billing address","id":"DC-04","name":"member_contact_identifiers","never_collected":true,"notes":"Hard-denied by gate (HD-02). Permanent block.","personal":true},{"description":"Owner name, email, Skool handle, contact preferences (GHL CRM record)","examples":["name","email","skool_handle","phone"],"id":"DC-05","legal_basis":"contract","name":"owner_identity","personal":true},{"description":"Group /about + /plans + public post metadata (post_id, posted_at, like_count, comment_count, pinned, is_question) \u2014 all public on Skool, no cookie needed. NEVER includes author_handle, author_name, or verbatim post body.","examples":["group_name","niche","member_count","about_text","tier_stack","post_id","posted_at","like_count","comment_count","pinned","is_question","owner_social_urls"],"id":"DC-06","legal_basis":"legitimate_interest","name":"public_group_metadata","notes":"Phase 2 Chunk 5: post-metadata fields added \u2014 author identifiers structurally banned (see public_post_metadata DO block + ext_t0_telemetry CHECK constraint in apps/skool-scraper/sql/). owner_social_urls = owner-authored public links (instagramUrl, twitterUrl, linkedinUrl, websiteUrl, youtubeUrl) shown on the public Skool /about page, no login needed \u2014 group-level public metadata, not a member identifier.","personal":false},{"description":"Extension install_id, browser_ua, panel engagement events (panel_open/close, panel_visible_pct, bb_done, bb_skip), uninstall pings. Counts only \u2014 no member content.","examples":["install_id","browser_ua","panel_open","panel_close","panel_visible_pct","bb_done","bb_skip"],"id":"DC-07","legal_basis":"contract","name":"install_telemetry","notes":"Standalone non-personal. Becomes correlated personal data when joined server-side with DC-05. Lane A.","personal":false},{"description":"Skool user id of the owner/admin running the extension who collected a T1 admin snapshot. Id ONLY \u2014 no email, name, or handle. Reuses the already-fetched users/me id (no extra fetch). Audit-trail provenance: links each qmm_t1_admin_snapshots row to the collecting account under the owner's signed DPA.","examples":["collector_user_id"],"id":"DC-08","legal_basis":"contract","name":"collector_identity","notes":"Minimal-scope owner/admin self-identity (a strict subset of DC-05 owner_identity: id only, no contact fields). Collector = the owner/admin acting on their own granted house, so same contract basis + within their signed DPA scope. Stored on qmm_t1_admin_snapshots.collector_user_id. Client-asserted + id-shape validated server-side \u2014 provenance-grade, not authz-grade. Never collected at T0. Not an Art 9 special category. PSEUDONYMISATION MAP (v30, plan-approved-collector-handle 2026-06-27): the readable Skool handle is stored ONCE per collector in the ext_collectors lookup table (user_id PK \u2192 handle), NEVER per snapshot row \u2014 snapshots remain id-only (collector_user_id). The viewer JOINs id \u2192 handle for display. This is Art 4(5) pseudonymisation + Art 5(1)(c) minimisation: facts reference the opaque user_id; the re-identifying handle lives in a single separate map. Erasure of a collector = drop the one ext_collectors row \u2192 every historical snapshot reverts to opaque id-only (no row-by-row scrub of the fact table). The handle is transmitted transiently in the ingest payload (collector_handle, top-level body key, lowercase ^[a-z0-9-]{1,64}$ validated) and best-effort upserted to the map; a map-upsert failure never fails the snapshot ingest.","personal":true,"requires_dpa":true}],"data_lanes":[{"controller":"Tinker Electric Pty Ltd","data_categories":["DC-05"],"id":"lane_a","label":"ll_service_customer","lawful_basis":"contract","policy_section":"Section 2 (Lane A) + Section 3 row A + Section 9","processor":"Tinker Electric Pty Ltd","retention_ref":"ghl_contact","storage":["ghl_us","stripe_us"],"who":"LL service customers (owner signups for extension / Sprint / paid Lab)"},{"controller":"Customer (group owner)","data_categories":["DC-02"],"id":"lane_b","label":"customer_member_processing","lawful_basis":"contract_via_customer","policy_section":"Section 2 (Lane B) + Section 3 row B + Section 7","processor":"Tinker Electric Pty Ltd","retention_ref":"member_level_dpa","storage":["supabase_eu"],"who":"Members of Customer's groups, under signed DPA"},{"controller":"Tinker Electric Pty Ltd","data_categories":["DC-05"],"id":"lane_c","label":"john_marketing_leadgen","lawful_basis":"consent_plus_legitimate_interest","point_of_collection_notice":"required","policy_section":"Section 2 (Lane C) + Section 3 row C + Section 8","processor":"Tinker Electric Pty Ltd","retention_ref":"ghl_contact","storage":["ghl_us"],"surfaces":["apps/Money-models-quiz (MRR Leak Finder)","apps/skool-traffic-finder","GHL landing pages (audit required)","apps/scoreboard-v2/report.html (T0 self-service report form)"],"who":"Tinker Electric Pty Ltd (trading as Leverage Lab) prospects \u2014 quiz responders, contact form fills, mailing list signups"},{"controller":"Tinker Electric Pty Ltd","data_categories":["DC-05","DC-06","DC-01"],"id":"lane_d","label":"public_directory","lawful_basis":"legitimate_interest","notes":"Public-directory lane. Aggregate B2B group metadata + owner public identity\n(handle, display name) published on directory.ascendalliance.com.au with\nper-group SEO pages. Lawful basis = GDPR Art 6(1)(f) legitimate interest;\nRecital 30 B2B aggregate. Owner objection honoured via blocklist + suppression\nflag (soft-delete) on next nightly build. No member-level data; structurally\nenforced by skool_group_audit CHECK constraint. See OP-14.\n","objection_endpoint":"https://directory.ascendalliance.com.au/object?slug={slug}","policy_section":"Section 2 (Lane D) + Section 3 row D + Section 11","processor":"Tinker Electric Pty Ltd","retention_ref":"group_aggregate","storage":["cf_pages_static","supabase_au"],"surfaces":["apps/scoreboard-v2 (directory.ascendalliance.com.au)","supabase.skool_group_audit (server-side mirror)"],"who":"Public Skool community owners (group + owner publicly self-advertised on skool.com/<slug>)"}],"dpa":{"anonymised_sharing_note":"Identity-stripped, aggregated data with no re-identification path may be shared in benchmarks, reports, or examples at the Processor's discretion. Only figures tied to the Customer's identity are subject to the sharing restriction.","anonymised_sharing_permitted":true,"audit_notice_days":30,"current_date":"2026-06-19","current_version":"2.5","revocation_anonymisation_clarification":"After consent withdrawal, we cryptographically anonymise historical data series.\nThe salt enabling re-identification is destroyed at the moment of withdrawal.\nOnce anonymised, the resulting data is no longer personal data under GDPR\n(Recital 26) and may be retained for product improvement. We cannot\nre-identify you from this data. Re-signing creates a new data series with no\nlink to your previous history.\n","sub_processor_notice_days":7,"sub_processor_notice_note":"sub_processor_notice_days is LL\u2192Customer notice when adding/replacing a sub-processor (7 days, or less where urgency requires). audit_notice_days is Customer\u2192LL notice for audit requests (30 days). Asymmetric by design.","tier_classification_note":"Tier classification depends on whether data is structurally tied to a member identifier.\nTier 1: aggregated counts, level distribution, engagement clusters \u2014\nanonymous tokens (e.g. MEMBER_001) that cannot be back-resolved to a real handle.\nAvatars are always Tier 2: inherently identifying in practical use; no Tier 1 exception.\nTier 2: any member-level data tied to a real member identifier (handle, display name,\navatar, biography). Requires DPA signed + privacy notice in the Customer's group.\nThe moment data becomes identifier-tied, it moves to Tier 2 regardless of which feature surfaced it.\n","variants":[{"audience":"Skool owners \u2014 quick read, GHL Documents flow","file":"outreach/dpa-lite.md","id":"dpa_lite"},{"audience":"DEPRECATED \u2014 superseded by dpa_lite","file":"outreach/dpa-template.md","id":"dpa_full"},{"audience":"GHL Documents & Contracts template body","file":"outreach/ghl-dpa-template.md","id":"ghl_dpa"}],"versions":[{"date":"2026-06-10","summary":"Initial DPA-lite. Skool owner = controller, Leverage Lab = processor.","version":"1.0"},{"date":"2026-06-17","summary":"Added Tinker Electric entity, AU governing law.","version":"1.1"},{"date":"2026-06-18","summary":"Dropped unregistered trading-as claim.","version":"1.2"},{"date":"2026-06-18","summary":"2-stage value flow. Owner-side metrics allowed under DPA. Member content hard floor.","version":"1.3"},{"date":"2026-06-18","summary":"Slack canon. Sub-processors disclosed (Anthropic/OpenAI/GHL). Erasure 'without undue delay'. GHL contact retention 4y.","version":"1.4"},{"date":"2026-06-18","summary":"Switched from re-sign-on-bump to standard SaaS notify-on-update pattern; continued use = acceptance; clarified erasure rights as termination path (Section 11 rewrite).","version":"1.5"},{"date":"2026-06-19","summary":"Block 2 extension features added: identity capture (Lane A), telemetry events (Lane A), uninstall ping (operational), owner pain inbox (Lane A, owner-authored text only), Skool affiliate passthrough (existing Lane A), short ref_code referral chain (Lane A/legitimate interest). SaaS notify-on-update fires to all signed owners.","version":"1.6"},{"date":"2026-06-19","summary":"Phase 1 ship \u2014 OP-11 dpa_update_notification operation added (cross-tier, notifies group owner Controller on registry/DPA material bump; explicit click-to-ack writes ack row to consent_log with ack_timestamp + acknowledged_dpa_version + registry_fingerprint_at_ack). Audited retention rules per compliance bundle 2026-06-19: ext_telemetry 90d \u2192 2y rolling; ext_pain DPA-term \u2192 1y rolling; new ext_dpa_ack 2y rolling. No new sub-processors.","version":"1.7"},{"date":"2026-06-19","summary":"v1.8: Drop lite naming (title + body); honest never-collects floor (3b rewrite); add Tier 0/1/2 scope clarification section (3e).","version":"1.8"},{"date":"2026-06-19","summary":"v1.9 bundle (22 fixes): drop expanded-DPA claim + single-page claim; DPA acronym defined on first use; admin-session wording updated (own session OR Processor-as-admin); heat reports \u2192 reports generalised; churn/signups \u2192 engagement and revenue metrics; Tier 1 requires DPA clarified; avatars/bios moved to Tier 2 may-collect; Tier 1 anonymous-token clarification added; Sprint/cohort cohort-sharing clause added; sub-processor 14d \u2192 30d notice; audit notice 14d \u2192 30d; Supabase AU primary; Google AI / Workspace added; GoHighLevel CRM desc updated to include telemetry; Cloudflare regions = AU/EU/US; EU-only-region-on-request line removed; locally-on-John's-machine line removed; leverage-lab.com/about-our-data \u2192 canonical worker URL; save-where \u2192 except-where; plain English block rewritten; gdpr-register.md location noted as historical/cleanup deferred.","version":"1.9"},{"date":"2026-06-19","summary":"v2.0 \u2014 F1: asymmetric notice periods (LL\u2192Customer 7 days for sub-processor changes; Customer\u2192LL 30 days for audits); F2: governing law narrowed to QLD AU + consumer-protection-only carve-out; F3: tied-to-identifier tier classification rule baked in as explicit clause. (F4 avatar-pool Tier 1 carve-out shipped in error \u2014 reverted in v2.1.)","version":"2.0"},{"date":"2026-06-19","summary":"v2.1 \u2014 revert F4: avatars always Tier 2 (no Tier 1 anonymous-stat exception). Avatars are inherently identifying in practical use regardless of whether they are explicitly tied to a handle. Removes 'avatar-pool statistics' from Tier 1 list in DC-02, tier_classification_note, DPA text, and template.","version":"2.1"},{"date":"2026-06-19","summary":"v2.2 \u2014 F1: clarify asymmetric notice (7d sub-proc LL\u2192Customer, 30d audit Customer\u2192LL); F2: HD-06 + OP-06 updated \u2014 identifier-tied verbatim blocked, de-identified permitted (sentiment etc.); F3: breach SLA = 'without undue delay' not hard 72h (customer retains own 72h regulator obligation); F4: anonymised sharing explicitly permitted (identity-stripped aggregated data at Processor discretion).","version":"2.2"},{"date":"2026-06-19","summary":"v2.3 \u2014 no unbacked email promises found in DPA text (sign-confirmation is code TODO only, not a DPA promise). Add honest termination-HOW sentence to \u00a711: email now, self-serve link on roadmap. No other changes.","version":"2.3"},{"date":"2026-06-19","summary":"v2.4 self-serve revoke: GET/POST /dpa/revoke worker routes (revoke-intent HMAC), sign-confirmation email with permalink + revoke link, cascade Lane B data purge on revoke, consent_log.revoked_via column added, Section 11 rewritten.","version":"2.4"},{"date":"2026-06-19","summary":"v2.5 \u2014 Phase 2 (scraper public API): DC-06 extended with public_post_metadata fields (post_id, posted_at, like_count, comment_count, pinned, is_question \u2014 author identifiers structurally banned); retention.ext_t0_telemetry added (2y rolling); OP-12 serve_anonymous_group_score + OP-13 anonymous_install_telemetry shipped earlier in this version (Lane Public, legitimate interest, no identity binding stored).","version":"2.5"}]},"hard_deny_rules":[{"code_symbols":["VERBATIM_MAX_CHARS","_strip_verbatim_tied_to_identifier","_VERBATIM_FIELDS"],"constraint_refs":["DC-03"],"description":"Verbatim text > N chars in a record that also carries a member identifier","id":"HD-01","name":"verbatim_member_content_tied_to_identifier","threshold_chars":200},{"code_symbols":["_HARD_DENY_FIELDS","_strip_hard_deny"],"constraint_refs":["DC-04"],"description":"Contact / payment / IP identifier fields are hard-denied regardless of context","fields":["email","phone","mobile","ip","ip_address","payment_method","card_last4","stripe_id","payment_token","address","billing_address","raw_email","hashed_email"],"id":"HD-02","name":"hard_deny_contact_identifiers"},{"code_symbols":["_check_cross_group"],"description":"Records from multiple distinct group slugs in one batch are denied by default","exempt_operations":["OP-01","OP-03"],"id":"HD-03","name":"cross_group_join_forbidden_on_cookied","notes":"OP-01 (anonymous /about) + OP-03 (leaderboard) are explicit exemptions \u2014 both are public, no member identifiers."},{"code_symbols":["require_dpa","dpa_status","GDPRPendingDPA"],"description":"Cookied scrape against a group requires either own-ownership or a signed DPA","id":"HD-04","name":"cookied_lane_must_be_own_or_dpa_signed"},{"code_symbols":["_load_dpa_registry","dpa_status"],"description":"An opt-out / erasure request blocks all subsequent processing for the identifier","id":"HD-05","name":"opt_out_blocklist_overrides_all_lanes"},{"code_symbols":["filter_external_llm_payload","_HANDLE_PATTERNS","_EXTERNAL_LLM_PATTERNS"],"constraint_refs":["DC-03","OP-06"],"description":"External LLM payload containing verbatim text tied to a member identifier (handle pattern + > 200 chars) is blocked. De-identified verbatim (handles stripped, names tokenised to MEMBER_001, no back-resolution path) may be sent for analysis such as sentiment classification.","id":"HD-06","name":"external_llm_no_member_identified_verbatim","threshold_chars":200},{"code_symbols":["filter_outbound"],"description":"Publishing a named report publicly requires explicit consent on owner's own group","id":"HD-07","name":"public_publish_requires_consent_and_own_group","notes":"Public-by-consent doctrine. See PUBLISH-DOCTRINE.md."},{"constraint_refs":["OP-09","DC-05"],"description":"Owner pain-inbox text is OWNER-authored under Lane A contract. Allowed. Does NOT cross HD-01 (verbatim member content) because authorship is the owner themselves.","id":"HD-08","name":"owner_authored_text_allowed_lane_a","notes":"Bind via RLS author check \u2014 only the authoring owner may submit/read their own pain entries."}],"identity":{"abn":"83 660 188 278","contact_email":"privacy@ascendalliance.com.au","controller_role":"Data controller for product analytics and CRM contacts","director":"John Missikos","governing_law":"Queensland, Australia","governing_law_consumer_note":"except where consumer-protection laws of the Customer's place of residence cannot be excluded by contract \u2014 in which case those specific consumer-protection provisions apply","jurisdiction":"Australia","legal_entity":"Tinker Electric Pty Ltd","processor_role":"Data processor for owner-shared group/member-level metrics under DPA","trading_as":"Leverage Lab"},"meta":{"canonical_route_source":"apps/leverage-lab-chrome-ext/worker/score.js (PRIVACY_HTML)","canonical_url":"https://ascendalliance.com.au/privacy","canonical_version":"2.0","last_updated":"2026-06-29","notes":"Privacy + DPA docs ALWAYS state the slackest defensible posture \u2014 never tighter\nthan the GDPR statutory floor. Slack canon = we meet it trivially + GDPR satisfied.\nThe canonical_url is the single source of truth for ALL surfaces (extension,\nMRR Leak Finder quiz, Skool Traffic Finder, growth reports, GHL landing pages).\nNo per-tool duplicate privacy policies \u2014 point at canonical.\nv2.0 (3-lane canonical) covers Lane A (LL service customer), Lane B (DPA member\nprocessing) and Lane C (Tinker Electric Pty Ltd / Leverage Lab lead-gen marketing) in distinct sections.\nCLEANUP NOTE (F22): outreach/gdpr-register.md lives under outreach/ for historical\nreasons. Do not move it \u2014 too many cross-references. Future cleanup: consolidate\nto a top-level compliance/ directory. Tracked here so it is not forgotten.\n","registry_version":33,"source_of_truth":true},"operations":[{"cross_group":"allowed","data_categories":["DC-06"],"description":"Public /about page scrape \u2014 no cookie, no member identifiers","id":"OP-01","name":"scrape_anonymous_about_page","requires_dpa":false},{"cross_group":"forbidden","data_categories":["DC-01","DC-02"],"description":"Cookied scrape using primary or secondary lane on owner's own group or granted group","id":"OP-02","name":"scrape_cookied_own_or_granted","requires_dpa":true},{"cross_group":"allowed","data_categories":["DC-01","DC-06"],"description":"Skool Games leaderboard public scrape \u2014 group-level aggregates across categories","id":"OP-03","name":"scrape_leaderboard_games_host","notes":"Leaderboard is public group aggregates with no member identifiers. The /games/<category> host context legitimately surfaces many groups in one fetch \u2014 cross_group is intentional and harmless.","requires_dpa":false},{"data_categories":["DC-02"],"description":"Member engagement heat report \u2014 counts only, never verbatim content","gate":"own_group_or_dpa_signed","id":"OP-04","name":"heat_report_member_engagement","requires_dpa":true,"verbatim_truncation":200},{"data_categories":["DC-01","DC-02"],"description":"Owner-facing growth report PDF \u2014 owner consent required","gate":"owner_consent_explicit","id":"OP-05","name":"publish_growth_report_owner_consent","requires_dpa":true},{"data_categories":["DC-01"],"description":"Payload sent to external LLM API (Anthropic / OpenAI / etc.) for diagnostic generation","gate":"aggregate_only","id":"OP-06","name":"external_llm_payload","notes":"Verbatim content tied to a member identifier is hard-denied by HD-06. De-identified verbatim (handles stripped, names tokenised to MEMBER_001) may be sent for analysis (e.g. sentiment classification) \u2014 HD-06 permits this as the identifier link is broken.","requires_dpa":false},{"data_categories":["DC-01","DC-07"],"description":"Extension panel engagement events (panel_open, panel_close, panel_visible_pct 0-1, bb_done, bb_skip). Counts only, no member content.","gate":"own_install","id":"OP-07","name":"ext_telemetry_engagement","notes":"Under owner Lane A contract. Retention 90d rolling (see retention.ext_telemetry).","requires_dpa":true},{"data_categories":["DC-07"],"description":"Anonymous uninstall ping with install_id only (no skool_user_id).","gate":"own_install","id":"OP-08","name":"ext_uninstall_feedback","notes":"Operational. Becomes correlated personal only if server-side joined to DC-05. Retention 2y rolling.","requires_dpa":false},{"data_categories":["DC-05"],"description":"Owner-authored pain messages via in-extension dialog. Owner identity + owner-authored text.","gate":"own_install","id":"OP-09","name":"ext_owner_pain_inbox","notes":"Lane A contract. Owner-authored text only; never member content (see HD-08). Retention: term of DPA.","requires_dpa":true},{"data_categories":["DC-05"],"description":"Short 6-char ref_code in install URLs for attribution chain.","gate":"own_install","id":"OP-10","name":"ext_referral_chain","notes":"Lane A / legitimate interest. ref_code never carries skool_user_id; resolved server-side only. Retention indefinite for attribution chain.","requires_dpa":false},{"data_categories":["DC-05","DC-07"],"description":"Notifies group owner Controller when registry or DPA version bumps materially. Owner explicit click-to-ack writes ack_timestamp + acknowledged_dpa_version + registry_fingerprint_at_ack to consent_log. Cross-tier \u2014 fires for any tier with a signed DPA.","gate":"own_install","id":"OP-11","name":"dpa_update_notification","notes":"Lane A. Notification target is the group OWNER (Controller of their members' data), NOT members; members are notified separately by the owner via their group privacy notice if Lane B is active. Click-to-ack pattern per bundle G6/C3 recommendation. Auto-purge OP-11 events 2y rolling (see retention.ext_dpa_ack).","requires_dpa":false},{"cross_group":"allowed","data_categories":["DC-06"],"description":"Phase 2 T0 public API: serve cached server-computed Money Model Score for a group_slug via POST /group/<slug>/score. Score computed from anonymous-lane scrape of public /about + /plans only (DC-06). No member identifiers in payload; no install\u2194slug binding stored. group_slug is the explicit T0 quasi-identifier surface (Recital 30 \u2014 B2B aggregate use, lawful basis legitimate interest, disclosed in install notice per bundle \u00a7 L1). Rate-limited per IP / per anonymous install token.","id":"OP-12","name":"serve_anonymous_group_score","notes":"Lane Public. Lawful basis legitimate interest. group_slug is quasi-identifier per Recital 30 but B2B aggregation use \u2014 not personal data of a natural person. No install identity stored anywhere. See apps/skool-scraper/.","requires_dpa":false},{"cross_group":"allowed","data_categories":["DC-05","DC-06","DC-01"],"description":"Publish public Skool community directory on directory.ascendalliance.com.au \u2014 per-group SEO pages naming owner + group + estimated MRR derived from public price \u00d7 member count. Source: public Skool /about + public leaderboard. No member-level data. Server-side mirror in supabase.skool_group_audit (append-only, RLS service-role-only, CHECK constraint banning member identifiers, suppressed flag honours owner objection). Lawful basis: GDPR Art 6(1)(f) legitimate interest + APP 3 + APP 6.","gate":"none","id":"OP-14","name":"publish_public_directory","notes":"Lane D. Recital 30 + 47 \u2014 public B2B aggregate + owner public identity used\nunder legitimate interest. NOT consent-based (Art 6(1)(f), not Art 6(1)(a)).\nOwner objection honoured via outreach/directory-blocklist.json + suppression\nflag (soft-delete). Hard-delete escalation on explicit demand.\nMRR-estimation structurally flagged \"est.\" in every render (see Ruling 8.1).\nNo comparative leaderboards (Ruling 8.3). No member-level data\n(Ruling 2 + structural CHECK constraint per Ruling 9.2).\nSkool ToS posture: tolerated grey (skool-finder.com precedent +\nskool-tos-DOA-verdict). robots.txt blocks training crawlers.\nGroup description sanitised + PII-scrubbed BEFORE publish (7 PII classes:\nemail, phone, URL [skool.com self-refs preserved], social handle, payment\nkeywords, street address, billing data); full original text never on public\nsurface; internally cached pre-scrub only for re-process. Display includes\nvisible \"Condensed by Leverage Lab\" stamp + hover tooltip pointing at\nskool.com/<slug>. Granular sub-objection: suppress_description column on\nskool_group_audit honoured at view layer (NULL in export when set), separate\nfrom slug-level suppressed flag. See Request C / C-cond-1..5\n(outreach/REVIEW-compliance-t0-expansion-bundle-2026-06-23.md).\n","requires_dpa":false},{"data_categories":["DC-07"],"description":"Phase 2 T0 anonymous telemetry: extension fires panel events (drawer opens, lock-clicks, action completions on generic BBs, stage scores derived in-browser) via POST /telemetry. install_token_hash = SHA-256 trunc-24 of an opaque random 32-hex token issued by GET /install/token. Token is a rate-limit lever \u2014 never identity-bound. Payload structurally rejects (worker + DB CHECK) any group/user identifier: group_slug, slug, admin_groups, user_id, skool_user_id, handle, display_name, email, group_id, gid, member_id, author_handle.","gate":"none","id":"OP-13","name":"anonymous_install_telemetry","notes":"Lane Public / operational. No DC tie to a natural person at write time. Becomes correlated personal only if joined server-side with DC-05 (not done in T0). Retention 2y rolling per retention.ext_t0_telemetry. See apps/skool-scraper/sql/04_ext_t0_telemetry.sql.","requires_dpa":false},{"data_categories":["DC-05","DC-06"],"description":"Generate T0 (public-data-only) self-service report for any requester via public form. Inputs limited to anonymous /about + public group metadata (DC-06). Requester email captured for delivery only (DC-05). No DPA required (no member-level data touched).","gate":"none","id":"OP-15","name":"report_generation_t0","notes":"Lane C (lead-gen marketing surface) + Lane D (public group data input). Lawful basis = consent (Art 6(1)(a) \u2014 explicit click on public form) + legitimate interest (Art 6(1)(f) \u2014 Recital 30 B2B aggregate already covers Lane D source data). Sub-processors: GHL (US, already disclosed) for email delivery + CRM upsert; Supabase EU for audit_log row. Retention_ref: audit_log (24mo rolling, 90d email redaction). Welcome variant: same OP, consent_source = ghl_signup_question_skool_group (signal = signup-question field populated). Honours [[outside-only-data]] + [[scrape-privacy-default]] (no member identifiers). Outside-report T0 surface (directory.ascendalliance.com.au/group/<slug> \"Email me the full PDF\" CTA): adds surface-level honest_attest_checkbox (self-declared owner/admin \u2014 anti-abuse + greenlight alignment, NOT a lawful-basis substitute; operation-level gate stays none). PDF generated from public /about + /plans (DC-06), stored in R2 private bucket OUTSIDE_REPORTS_R2 (Cloudflare sub-processor, already disclosed \u2014 object storage purpose added to sub_processors.Cloudflare), fetched only via signed-URL /r/<token>, 24h expiry, HMAC-bound to request_id, 410 Gone + debounced (1/d/email/slug) re-issue on replay. Rate-limit floor: 3/h/IP (CF-Connecting-IP), 10/d/email, 50/d/slug. NOT a publish event (skoolcore.publish_gate not on path \u2014 PDF private to requester). Point-of-collection notice rendered inline on form (Art 13). Earlier draft name \"outside_report_lead_capture\" REJECTED as a separate OP \u2014 absorbed here per REVIEW-compliance-OP-15-wordings-2026-06-24.md \u00a71.\n","requires_dpa":false},{"data_categories":["DC-01","DC-05"],"description":"Generate T1 (insider/admin data) self-service report for DPA-signed owners via extension drawer. Inputs: cookied admin dashboard via SkoolClient (DC-01 owner_group_aggregate). Owner identity DC-05. Delivered via signed-URL email to DPA signer_email.","gate":"own_group_or_dpa_signed","id":"OP-16","name":"report_generation_t1","notes":"Lane B (DPA member processing). Lawful basis = contract (Art 6(1)(b), DPA v2.5+). Sub-processors: GHL (US) for email delivery; Supabase EU for audit_log row. Retention_ref: audit_log (24mo rolling, 90d email redaction). Layer-2 worker re-checks DPA via require_dpa(slug, soft_fail=False). Email body carries Controller-reminder boilerplate per REVIEW cc0a82b C-e1. BCC privacy@ascendalliance.com.au per C-e2. Signed-URL delivery (revoke-aware) per C-e3.\n","requires_dpa":true},{"data_categories":["DC-05"],"description":"Internal accountability log of T0/T1 report generations. Append-only, 24-month rolling window with automated purge, requester email redacted to SHA-256 after 90 days. Not customer-facing.","gate":"none","id":"OP-17","name":"audit_log_retention","notes":"Internal infrastructure. Purpose: Art 28(3)(h) DPA accountability + Art 30 ROPA evidence of processing activities. Retention_ref: audit_log. 24mo rolling cap matches ext_telemetry + ext_dpa_ack precedent. 90d email-redaction window per REVIEW cc0a82b C-c2 \u2014 once active dispute window closes, only SHA-256 hash retained for accountability. Automated via Supabase scheduled function nullify_old_emails() + purge_old_audit_log().\n","requires_dpa":false},{"data_categories":["DC-05"],"description":"Deliver generated reports + welcome/onboarding emails via existing GHL transactional email sub-processor relationship. Bridge sender for OP-15 + OP-16. No new sub-processor disclosure required.","gate":"none","id":"OP-18","name":"email_transactional_ghl","notes":"Lane B + Lane C bridge. Path C per REVIEW cc0a82b Q-d-2 (chosen by John 2026-06-24 over SES Path B + CF Email Path A). Sub-processor: GoHighLevel (US, already disclosed under \"GoHighLevel CRM contact data\" purpose since v1.4 \u2014 transactional email is within disclosed scope). No DPA bump. No 30-day sub-processor notice required. Same lawful basis as the originating OP (consent/LI for OP-15, contract for OP-16). Footer auto-inject: viral_kit \"Powered by Leverage Lab\" + back-link + privacy@ contact (per [[viral-by-default]] + [[footer-entity-disclosure]]).\n","requires_dpa":false}],"publish_rules":{"amber_on":["named individual content (words attributed to a person)","sentiment/intent reading on named comments"],"consent_tokens":{"description":"Consent must be explicit, per-report, and revocable","storage":"outreach/consent-log.json"},"red_on":["named teardown of a stranger's group with no consent","cross-group member profiling","publishing member verbatim content"]},"retention":{"audit_log":{"notes":"T0/T1 report-generation audit trail (OP-17). 24mo rolling \u2014 automated purge via Supabase scheduled function purge_old_audit_log(). Requester email field redacted to SHA-256 hash at 90 days via scheduled function nullify_old_emails() per REVIEW cc0a82b C-c2 (Art 5(1)(c) data-minimisation). Hash field requestor_email_hash retained for full 24mo window. Migration patch44_audit_log.sql.\n","value":"2 years rolling"},"erasure_response":{"notes":"Article 12 GDPR. No hard SLA in days \u2014 slackest defensible posture.","value":"without undue delay"},"ext_admin_group":{"notes":"Owner's admin group membership record (Lane A). Deleted on DPA termination.","value":"for the term of this DPA"},"ext_dpa_ack":{"notes":"DPA-update click-to-ack rows (OP-11). 2y rolling window \u2014 automated purge.","value":"2 years rolling"},"ext_install":{"notes":"Extension install record (Lane A). Deleted on DPA termination.","value":"for the term of this DPA"},"ext_message":{"notes":"Owner\u2192owner messages via extension (Lane A). Deleted on DPA termination.","value":"for the term of this DPA"},"ext_pain":{"notes":"Owner-authored pain inbox entries (OP-09, HD-08). 1y rolling window \u2014 automated purge. Bundle 2026-06-19 M6 audited retention.","value":"1 year rolling"},"ext_referral_code":{"notes":"Short 6-char ref_code (OP-10). Indefinite for attribution continuity; non-personal standalone.","value":"indefinite for attribution chain"},"ext_sprint_signal":{"notes":"Sprint engagement signals (Lane A). Deleted on DPA termination.","value":"for the term of this DPA"},"ext_t0_telemetry":{"notes":"Anonymous T0 telemetry from extension Phase 2. install_token_hash is SHA-256 trunc-24 of opaque token (no identity binding). See apps/skool-scraper/sql/04_ext_t0_telemetry.sql.","value":"2 years rolling"},"ext_telemetry":{"notes":"Panel engagement events (OP-07). 2y rolling window \u2014 automated purge. Bundle 2026-06-19 M6 audited retention.","value":"2 years rolling"},"ext_uninstall":{"notes":"Uninstall pings (OP-08). 2y rolling window \u2014 NOT indefinite.","value":"2 years rolling"},"ext_user":{"notes":"Extension user identity (Lane A). Deleted on DPA termination.","value":"for the term of this DPA"},"ghl_contact":{"notes":"Lane A owner contact + Watchtower active-billing data retained while subscription active; +6mo grace after final cancellation (matches Lane A floor); +7y for invoice/tax records per AU Income Tax Assessment Act. Watchtower auto-roll continuity = ongoing legitimate processing under DPA scope until cancellation. Quarterly purge cadence runs post-grace.","value":"active billing cycles + 6 months grace post-cancellation + 7 years for invoice/tax records"},"group_aggregate":{"notes":"Group-level aggregates are not personal data and may be retained for benchmarks.","value":"indefinite for trend continuity"},"member_level_dpa":{"notes":"Per-DPA term, deleted on termination.","value":"for the term of this DPA"},"member_level_non_dpa":{"notes":"Without a DPA, member-level data is not collected \u2014 so there is nothing to retain.","value":"purged regularly"}},"rights":[{"art":"Art 17 GDPR","id":"R-01","mechanisms":["HMAC-signed footer link on any report we publish for you","Opt-out form at the privacy contact page","Extension per-group Revoke control (Settings \u2192 Manage DPA)","Email privacy@ascendalliance.com.au"],"name":"erasure","notes":"None of the four mechanisms is exclusive.","sla":"without undue delay"},{"art":"Art 15 GDPR","id":"R-02","mechanisms":["Email privacy@ascendalliance.com.au"],"name":"access","sla":"without undue delay"},{"art":"Art 20 GDPR","id":"R-03","mechanisms":["JSON export via extension Settings \u2192 Export"],"name":"portability","sla":"without undue delay"},{"art":"Art 21 GDPR","id":"R-04","mechanisms":["Opt-out form","Email privacy@ascendalliance.com.au"],"name":"objection_opt_out","sla":"without undue delay"}],"sub_processors":[{"country":"AU","country_note":"AU primary, US available","dpa":"see provider DPA","name":"Supabase","purpose":"Database, hosted AU primary"},{"country":"Global","country_note":"Regions across AU, EU, and US","dpa":"see provider DPA","name":"Cloudflare","purpose":"Worker compute, CDN, edge network"},{"country":"US","dpa":"see provider DPA","name":"Skool","purpose":"Source platform \u2014 owner-authorised data extraction"},{"country":"US","dpa":"see provider DPA","name":"GoHighLevel","purpose":"CRM contact data for the Customer: name, email, Skool handle, products purchased, products of interest, and service-usage telemetry (e.g. extension activity, report runs)"},{"country":"US","dpa":"see provider DPA","name":"Anthropic","purpose":"LLM API for diagnostic generation (aggregate, non-identified inputs)"},{"country":"US","dpa":"see provider DPA","name":"OpenAI","purpose":"LLM API for diagnostic generation (aggregate, non-identified inputs, alternate)"},{"country":"US","dpa":"see provider DPA","name":"Google","notes":"No-train data policy via Google Workspace enterprise agreement.","purpose":"AI-assisted features via Google AI / Google Workspace Gemini; no-train policy applies via Workspace agreement. No member-level verbatim content is sent."},{"country":"AU","country_note":"Self-hosted on Cloudflare-fronted infrastructure (dashboard.ascendalliance.com.au)","dpa":"see provider DPA / self-hosted under LL operational control","name":"Metabase","purpose":"Analytics dashboard rendering the Customer's OWN-GROUP aggregate metrics (counts, percentages, time-series, AAEMR, discovery rank). Owner-safe aggregate views only \u2014 no member-level PII, no cross-group, no sprint/leak data. Surfaced to the owner via a short-TTL, group-locked, signed embed (10-min JWT; access gated by signed DPA)."}]}