Legal-document accuracy SOP¶
Critical process. Privacy, Terms, and the public legal changelog must stay accurate as infrastructure, security, and processors change. This SOP is what Cursor (or anyone) does every time a legal doc needs correcting.
The ship checklist (validate, sync, commit, deploy, smoke) is LEGAL_RELEASE.md. This SOP is what to say and how to say it. Run this first. Then ship with LEGAL_RELEASE.md.
Founder gate. Legal text is not effective until Ryan reviews and approves it. Draft in the working tree. Do not commit, push, or deploy until he signs off.
1. Trigger¶
Any of these means: check the legal docs (Privacy, Terms, changelog) before the change is treated as done.
- Infrastructure or hosting change (provider, location, control model: single-tenant vs multi-tenant, self-controlled vs third-party-hosted)
- Security posture change (encryption, access control, database-level controls)
- Processor, subprocessor, or BAA change
- A material claim in the docs no longer matches reality
- A verification pass (including
/positions,/claims, or a code/ops audit) catches a legal-doc inaccuracy
If you changed how or where health data is stored, processed, or protected, you are in this SOP. Do not "fix it later."
2. The opsec rule (critical)¶
Legal docs describe the nature of infrastructure and security, not the specific stack.
Describe:
- Single-tenant vs multi-tenant
- Self-controlled / dedicated vs third-party-hosted
- BAA-governed vendor relationships where they process PHI
- Multi-layer access control
- Encryption at rest and in transit
Do not name in Privacy, Terms, the public changelog's new language, /positions Block 4 ("What we're doing"), /meridian (including content/meridian-eval.json, which ships in the public page bundle), or any other public-facing "what we're doing" copy:
- Specific server models or hosts
- Specific vendors beyond what is legally required to disclose
- Specific table names
- Specific tool names (vaults, object stores, databases)
- Encryption internals (algorithms, key-wrapping, master-key location)
- Which tables or data classes have which control, mapped as an inventory
- IPs, regions-as-fingerprints, or anything that maps the attack surface
The opsec rule is not limited to Privacy and Terms. /positions Block 4 is a dated operational record, and /meridian is a public eval board. Both are recurring surfaces for the same leak (hosts, runtime, LAN/IP, model-serving stack). Dated and true is not enough. Dated, true, and functional. Never dated, true, and stack-mapped. Model-family is the ceiling on /meridian if a model is named at all.
Correct an inaccuracy with an accurate functional description. Never by substituting a different specific disclosure.
Example of the wrong fix: "We no longer use vendor A, we now use [named replacement stack]." That trades one over-disclosure for another.
Example of the right fix: "Production health records run on dedicated, single-tenant infrastructure that we control. Where a vendor processes health data on our behalf, that relationship is covered by a Business Associate Agreement."
When a BAA or processor must be named for legal disclosure, name the minimum required: the relationship and its BAA coverage, not the architecture. Cloudflare (public-site hosting, no health records) and Apple (app distribution) are already in that class. Do not add a vendor to the named list unless the law or the policy's own disclosure duty requires it.
Archives of prior versions keep their original wording. Historical accuracy is not a new disclosure. Do not rewrite archived v1.0 / v1.1 / v1.2 text to hide what we used to say.
3. The process (every time)¶
a. Identify every claim affected by the change¶
Search Privacy, Terms, and the changelog for the stale claim. Typical hits: processor names, hosting location, encryption, access-control guarantees, BAA coverage.
List each claim with its section number before you edit.
b. Draft accurate, functional replacement language¶
Nature, not stack. No claim stronger than reality (see §4). Propose the language to Ryan. Do not treat the draft as live.
c. Archive the current version¶
Copy the live markdown before editing it:
content/legal/privacy-vX.Y.mdcontent/legal/terms-vX.Y.md
Add archive routes under app/(site)/privacy/archive/ and terms/archive/ that look up the superseding changelog entry's previousVersion (same pattern as existing archive pages). Add the routes to app/sitemap.ts.
d. Changelog entry¶
New entries at the top of content/legal-changelog.json, one per document. Include:
- What changed (section numbers)
- Why (inaccuracy vs reality, or a real change)
- Effective date (and
effectiveDateDisplay) retrospectiveDisclosure: truewhen the underlying change already happened- Categories:
material,strengthening, orcorrection
The changelog may name the prior disclosed processor so a reader can see what was corrected. The new language stays functional.
e. Material-change assessment¶
If the change is material under the policy's own terms, issue the required notice.
Material includes: processor change, PHI location / control model, security guarantee that veterans relied on.
Privacy §10: notify via email and in-app at least 30 days before a material change takes effect.
When the infrastructure change already happened (same class as the Railway-to-third-party-cloud disclosure in v1.1), there is no way to give advance notice of the move itself. Disclose immediately, label it material, set retrospectiveDisclosure: true, and use a timing note that says so. Going forward, announce intended material changes here, and by email, before they take effect.
Non-material clarifications that do not reduce protections may publish immediately with notice, as v1.2 did.
f. Bump version and effective date¶
- Privacy / Terms headers: Version, Effective Date, Last Updated
- Those headers must match the new changelog entry (
validate-legal-release.mjswill fail the build otherwise)
g. Ryan reviews the language before it is effective¶
This is legal text. Founder approves.
Until approval: working-tree only. No commit, no push, no legal:smoke against production as a "release," no last.vet-api push.
After approval: follow LEGAL_RELEASE.md (npm run legal:release, commit/push web, commit/push API JSON, redeploy API so notice emails match, smoke).
h. Related surfaces¶
One inaccuracy usually appears in multiple places. Check and fix or flag:
README.md/positionsBlock 4 (dated operational record: same opsec rule. Nature, not stack. Do not name servers, vaults, object stores, table names, or encryption internals. Functional dated actions only.)/meridianandcontent/meridian-eval.json(same opsec rule. Eval notes are public. No hosts, IPs, runtimes, or serving-stack names. Model-family at most.)/claims/compliance- Marketing, decks, investor copy
docs/legal/LEGAL_RELEASE.mdand PR templates (process docs: functional, not a second stack disclosure)last.vet-apiuser-facing strings if they repeat the claim
Internal ops docs may keep tool names when they are instructions (how to rotate a secret). They must not become a substitute public legal disclosure.
i. Verify ALL public surfaces (no leftover old version)¶
A truth-focused legal update is not done if any surface still serves or links the prior version.
Canonical text lives in last.vet-web (LASTVET_PRIVACY_POLICY.md, LASTVET_TERMS_OF_SERVICE.md, content/legal-changelog.json). How each hostname uses it:
| Surface | Model | What must be true after ship |
|---|---|---|
| https://last.vet | Serves its own copy (canonical Pages project last-vet-web) |
/privacy and /terms show the new version |
| https://my.last.vet | Serves its own copy from the same repo (separate Pages project last-vet-my, npm run build:my) |
Same new version. Do not assume last.vet being current is enough. This is the disparity that has already happened. |
| https://provider.last.vet | Links to canonical https://last.vet/privacy and /terms (does not host a third copy) |
Footer/legal links still point at last.vet, and last.vet is the new version |
After deploy, check all three live:
- last.vet
/privacyand/terms: new version header; stale claims gone (except in archives). - my.last.vet
/privacyand/termsand every privacy/terms link on that host: new version, not a mix. - provider.last.vet privacy/terms links: still
https://last.vet/..., and those URLs are the new version. - Archives of the prior version still show the old text (historical accuracy).
npm run legal:smoke covers last.vet + my.last.vet version headers and provider.last.vet canonical links. If any surface is still on the old version, stop. Do not send the notice email until every surface matches.
4. The accuracy bar¶
Same honest-claims discipline as /claims and /positions, applied to legal docs.
- No claim stronger than reality. Do not say "cannot bypass" if controls are partial. Do not say "every table" if they are not on every table.
- No location or processor that is not current. If production health records are not on the named host, the named host must come out.
- No compliance claim beyond what is actually true. HIPAA-eligible, BAA-covered, encrypted: only if that is the current fact. Prefer "where applicable" / "where they process PHI" over a blanket that overreaches.
- Functional over specific. If a weaker, accurate sentence exists, use it. Do not paper over a gap by naming a different vendor.
If you cannot write an accurate sentence without inventing a processor or a guarantee, stop and ask Ryan.
Quick sequence¶
- Trigger fires.
- List affected claims (section numbers).
- Draft functional replacement (opsec rule).
- Ryan reviews.
- Archive current version + archive routes.
- Changelog (material assessment + notice plan).
- Bump version / dates in markdown to match JSON.
- Sweep related surfaces.
- After approval:
LEGAL_RELEASE.mdship checklist. - Verify last.vet, my.last.vet, and provider.last.vet all serve or link the new version. No surface left on the old one. Then send notice.