All checks were successful
Mirror to GitHub / mirror (push) Successful in 6s
Generated by the resolutionflow-legal skill from a code scan of the FastAPI
backend + React frontend on commit 0564646. Each document is a starting
point for attorney review, not legal advice.
Includes:
- privacy-policy.md, terms-of-service.md, cookie-policy.md (public-facing)
- dpa.md (contractual; signed with MSP customers)
- subprocessor-list.md (Railway, Anthropic, Voyage, Stripe, Resend, Sentry,
PostHog, Google Fonts — confirmed live as of scan)
- data-inventory.md + classification.md (Phase 1/2 working files)
- attorney-review-checklist.md (consolidated [LEGAL REVIEW] punch list)
- implementation-verification.md (claim-by-claim audit vs. actual code)
Three blocking issues filed before public publication:
- #175 deletion-on-offboarding (or rewrite retention claims)
- #176 narrow Sentry send_default_pii + Session Replay config
- #177 EU/UK consent for PostHog + Google Fonts
Public-facing documents intentionally route physical-mail requests through
support@ rather than publishing the LLC's registered address.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
11 KiB
11 KiB
Implementation Verification
Generated: 2026-05-14
Scanned commit: 0564646 on feat/public-landing-routing-refactor
This document checks every concrete claim in the generated legal documents against what the code actually does. Each row is marked:
- ✅ Confirmed — code clearly supports the claim
- ⚠️ Partial — the code supports a narrower or related claim; the language is acceptable but tighten if possible
- ❌ Not implemented — the claim is aspirational; either build it or rewrite the claim
- ❓ Cannot verify in scan — depends on a runtime config, deployment posture, or external attestation the scan can't reach
A claim that overpromises is worse than one that underpromises. Anything ❌ must be resolved (built or rewritten) before publication.
Privacy Policy
| Claim | Source in docs | Reality | Verdict |
|---|---|---|---|
| Passwords are bcrypt-hashed with 12 rounds; plaintext never stored | §3.1, §9 | BCRYPT_ROUNDS=12 (config.py:86); User.password_hash (user.py:36) |
✅ |
PSA integration credentials encrypted at the application layer using Fernet (AES-128-CBC + HMAC), key derived via HKDF from SECRET_KEY |
§3.1, §9; DPA Annex B.1 | encryption.py | ✅ |
| TLS for production traffic | §9; DPA Annex B.1 | Hosted at api.resolutionflow.com / resolutionflow.com via Railway with HTTPS |
❓ (depends on Railway domain config; verify) |
| Tenant isolation enforced by PostgreSQL row-level security | §9; DPA Annex B.2 / B.5 | RLS referenced in PROJECT_CONTEXT.md:206 as "Phase 4 RLS"; account_id scoping pervasive |
✅ |
Access tokens stored in localStorage rather than HTTP-only cookies |
§9 | Confirmed in authStore.ts:47-48, OAuthCallbackPage.tsx:100-101 | ✅ |
| 5-minute access tokens, idle 3d / absolute 14d refresh defaults | §6 retention table; Cookie Policy §2.1 | config.py:69-79 | ✅ |
| Account deletion soft-deletes the user and revokes refresh tokens; account-scoped content not automatically purged | §6 (drafted as a [LEGAL REVIEW] flag) |
accounts.py:524-567 — confirms the soft-delete + token revoke; no purge of audit_logs, ai_sessions, etc. |
⚠️ disclosed accurately as a flagged gap; ❌ if you intend to claim "we delete your data" |
| AI flow-builder wizard conversations purged 24h after creation | §6 retention | scheduler.py:118-136, hourly job | ✅ |
| Assistant chat threads retained 90 days OR 100-chat cap (account-configurable), pinned exempt | §6 retention | retention_cleanup.py; defaults in account.py:40-45 | ✅ |
| AI chat sessions auto-archived after 30 days idle | §6 retention | main.py:45-63 | ✅ (note: archived, not deleted — disclosed accurately) |
| Audit logs retention | §6 (flagged) | No purge job — indefinite | ❌ — fix or rewrite |
| Refresh-token row cleanup | §6 retention | Rows persist after expiry/revoke | ❌ — fix or rewrite (data-inventory open item) |
| Email-verification / password-reset token cleanup | §6 retention | Rows persist after expiry/use | ❌ — fix or rewrite |
| File-upload deletion on account deletion | §6 retention | file_uploads rows + Railway Object Storage objects retained |
❌ — fix or rewrite |
| Stripe never sees full card data; we hold only Stripe customer/subscription IDs | §3.4; Subprocessor List Stripe row | @stripe/stripe-js on frontend (Elements pattern); backend stores stripe_customer_id, stripe_subscription_id only (account.py:28, subscription.py) |
✅ |
PostHog initialized with persistence: 'localStorage+cookie'; identified by user.id, grouped by account_id; US instance |
§3.2; Cookie Policy §2.3 | main.tsx:17-23; analytics.ts:34-40 | ✅ |
Sentry: backend send_default_pii=True; replay 1%/100% with text + media unmasked |
§3.2 (disclosed); Subprocessor List | main.py:14-26; instrument.ts:9-12 | ✅ (disclosed accurately; ⚠️ recommend narrowing — see Attorney Checklist A2) |
| Anthropic is the sole live LLM provider | §5.1; Subprocessor List | AI_PROVIDER='anthropic' (config.py:159); user-confirmed Gemini not provisioned |
✅ |
| Voyage AI is the live embedding provider | Subprocessor List | VOYAGE_API_KEY, EMBEDDING_MODEL='voyage-3.5' (config.py:219-221); user-confirmed key set |
✅ |
| No model training on Customer Data (Anthropic, Voyage) | ToS §3.4; Subprocessor List | Public terms commitment of each subprocessor; not enforceable from our side | ❓ — re-verify subprocessor terms before each publish |
Resend is the transactional email provider; address invites@resolutionflow.com |
Subprocessor List | config.py:97-99 | ✅ |
| Google Fonts loaded over CDN → IP exposed to Google | §5.1; Subprocessor List; Cookie Policy §2.5 | index.html:11-13 | ✅ |
| Microsoft Learn MCP retrieves public docs only; no Customer Data egress | Subprocessor List "What is NOT" | ENABLE_MCP_MICROSOFT_LEARN=True (config.py:216); the MCP search query string is the only outbound payload |
⚠️ partial — the query string itself can include AI-session context. Disclosed at a high level; if Customer Data text could be substantively included in a query, consider listing MS Learn as a subprocessor. |
| Backup retention 90 days | §9 backup language; DPA §6.3 | User-stated target; depends on Railway PITR window configuration | ❓ — verify Railway PITR configuration matches |
Terms of Service
| Claim | Source | Reality | Verdict |
|---|---|---|---|
| Owner, admin, engineer, viewer role hierarchy; team-admin gate separately | §2.3 | permissions.py, User.account_role (user.py:25-52) |
✅ |
| Only owner can delete the account; deletion blocked if other members remain | §9.2 | accounts.py:524-548 | ✅ |
| Removed members are moved to a personal account on the free tier | §2.3 | accounts.py:231-254 | ✅ |
| ConnectWise PSA integration available | §1, §3.1, §8 | services/psa/connectwise/; only live PSA provider per user |
✅ |
| AI features integrate Anthropic; outputs may include errors | §4.2 | Code confirms Anthropic integration; honest disclosure | ✅ |
| 30-day export window post-termination | §9.4 | No automated export-window enforcement in code | ❌ — needs implementation or rewrite |
| Stripe handles payment processing | §5.3 | @stripe/stripe-js + STRIPE_* env vars |
✅ |
| Auto-renewal of subscriptions | §5.2 | Stripe Subscriptions semantics | ✅ |
| 30-day notice for price changes | §5.5 | Operational commitment; not code-enforced | ❓ — operational |
| MFA disclosure (not required) | (Privacy Policy §9 — accurate omission) | No MFA code path detected | ✅ |
DPA
| Claim | Source | Reality | Verdict |
|---|---|---|---|
| Application-layer encryption for PSA credentials | Annex B.1 | Confirmed (above) | ✅ |
| RLS for tenant isolation | Annex B.2/B.5 | Confirmed (above) | ✅ |
| Authorized sub-processors list matches reality | Annex C | Matches Subprocessor List (Anthropic, Voyage, Stripe, Resend, Sentry, PostHog, Railway, Google Fonts) | ✅ |
| 72-hour breach notification SLA | §3.7 | Operational commitment | ❓ — define an internal detection-to-notify procedure to make this credible |
| Audit reports (SOC 2) available | §3.8.1 | No SOC 2 today | ⚠️ language says "when available," which is honest |
| Customer Data deleted after 30-day export window | §6.2 | Not implemented — see Privacy Policy table above | ❌ — flagged in Attorney Checklist A1 |
| 90-day backup retention | §6.3 | User-stated; depends on Railway PITR config | ❓ |
| SCC Module 2 / Module 3 incorporation | §5.1 + Annex D | Drafting only — no Customer signed instance yet | ❓ — operational |
Subprocessor List
| Subprocessor | Listed correctly? | Notes |
|---|---|---|
| Railway | ✅ | Hosting + DB + Object Storage all in one entry |
| Anthropic | ✅ | LLM API for FlowPilot and AI features |
| Voyage AI | ✅ | Embedding provider; confirm DPA URL with attorney |
| Stripe | ✅ | Payment processor |
| Resend | ✅ | Transactional email |
| Sentry | ✅ | Error + Session Replay; see A2 about config |
| PostHog | ✅ | Product analytics; US instance |
| Google Fonts | ✅ | Disclosed; consider self-hosting (A3) |
| Gemini / Google AI | Omitted (correct) | Not provisioned in prod |
| OpenAI | Omitted (correct) | Not detected |
| Autotask, HaloPSA | Omitted (correct) | Not live |
| ConnectWise | Disclosed as non-subprocessor (correct) | Customer-controlled data source |
| Microsoft Learn MCP | Disclosed as non-subprocessor | Verified: doc-retrieval only |
Cookie Policy
| Item | Reality | Verdict |
|---|---|---|
access_token and refresh_token in localStorage |
authStore.ts:47-48, 86-87 and others | ✅ |
theme-storage, rf-editor-fullscreen, rf-intended-plan, recentFlows, step-feedback flag, rated-sessions, escalation-queue seen |
All confirmed by grep | ✅ |
ph_* cookie set by PostHog due to persistence: 'localStorage+cookie' |
main.tsx:17-23 | ✅ |
| Sentry described as telemetry-only, not cookie-setting | Default Sentry browser SDK behavior matches description | ✅ |
| Google Fonts disclosed | index.html:11-13 | ✅ |
| Consent mechanism for EU/UK | Not implemented | ❌ — see Attorney Checklist A3 |
Net verdict
Safe to share with an attorney as a starting draft. Do not publish to the public website until the items marked ❌ are resolved by either:
- Building the missing behavior (recommended path for A1 deletion-on-offboarding, A3 consent banner, A2 Sentry config tightening), OR
- Rewriting the relevant paragraph to describe the actual behavior with no overclaim.
The factual scaffolding (subprocessors, encryption posture, retention reality, cookie inventory) is accurate. The remaining work is commercial-risk calibration and a small number of high-priority implementation gaps.