Skip to content

Generate the privacy page from the app repo's PRIVACY.md - #8

Merged
ericgriffin merged 1 commit into
mainfrom
ericgriffin/legal-single-source
Sep 22, 2026
Merged

ericgriffin merged 1 commit into
mainfrom
ericgriffin/legal-single-source

Conversation

@ericgriffin

@ericgriffin ericgriffin commented Sep 22, 2026 •

Copy link
Copy Markdown
Member

Summary

The privacy policy existed in two places with nothing keeping them in step:
PRIVACY.md in submersion-app/submersion, and a hand-maintained
privacy/index.html here. They had drifted badly.

The app repo's policy was rewritten to disclose Dropbox, S3, iCloud, Garmin,
Adobe and roughly fifteen coordinate services, to correct claims about
encryption that is off by default, and to disclose that dive buddy photos,
phone numbers and certification card scans leave the device. This page was
still serving the 2026-03-06 text, which names Google Drive as the only
destination.

That is not cosmetic. The Play Store listing links this page, and Google checks
the Data safety declaration against the hosted policy. A page that contradicts
the declaration is a policy violation.

PRIVACY.md is now the single source.

How it works

tools/render_legal.py converts the Markdown and replaces only the region
between the legal:meta and legal:body markers. The head, navigation, intro
paragraph, back link and footer stay hand-owned. The renderer keeps this page's
conventions: tables wrapped in legal__table, and a bolded term followed by a
dash rendered as <strong>Term:</strong>.

It is dependency-free on purpose, so the Actions job needs no install step.

.github/workflows/sync-legal.yml regenerates the page on a daily schedule, on
manual dispatch, on a repository_dispatch the app repo can send, and when the
renderer or template changes. It commits only when the output differs, so the
push trigger cannot loop. On a pull request it runs --check instead of
writing, so a hand edit inside the generated region fails the PR rather than
being silently reverted by the next sync.

Verification

  • The page is the current policy, rendered from the live PRIVACY.md and
    verified with --check against a fresh fetch from the workflow's own URL
  • Rendering twice is byte-identical
  • The HTML parses with balanced tags, and section counts match the source

Follow-up

Terms of Service has the same duplication, and generating it revealed that the
first version of this renderer would break existing anchors. Both are handled
in the follow-up PR.

The policy existed twice: PRIVACY.md in submersion-app/submersion and a
hand-maintained privacy/index.html here. Nothing kept them in step, and they
had drifted badly. The app repo's policy was rewritten to disclose Dropbox,
S3, iCloud, Garmin, Adobe and roughly fifteen coordinate services, to correct
claims about encryption that is off by default, and to disclose that dive
buddy photos, phone numbers and certification scans leave the device. This
page was still serving the 2026-03-06 text, which names Google Drive as the
only destination.

That gap matters beyond tidiness: the Play listing links this page, and
Google checks the Data safety declaration against the hosted policy. A page
contradicting the declaration is a policy violation.

PRIVACY.md is now the single source.

- tools/render_legal.py converts the Markdown and replaces only the region
  between the legal:meta and legal:body markers, so the head, navigation,
  intro, back link and footer stay hand-owned. Dependency-free so the
  Actions job needs no install step, and deliberately limited to the
  constructs the policy actually uses.
- The renderer keeps this page's existing conventions: h2 ids matching the
  old hand-written anchors so inbound links still resolve, tables wrapped in
  legal__table, and `**Term** - description` bullets rendered as
  `<strong>Term:</strong> description`.
- sync-legal.yml regenerates on a daily schedule, on manual dispatch, on a
  repository_dispatch the app repo can send, and on template changes. It
  commits only when the output differs, so the push trigger cannot loop.
- On a pull request the same workflow runs --check instead of writing, so a
  hand edit inside the generated region fails the PR with an explanation
  rather than being silently reverted by the next sync.

The page in this commit is the current policy, regenerated and verified
against the live PRIVACY.md.

Terms of Service has the same duplication. The renderer already handles it;
wiring terms/index.html needs only its markers and a second workflow step.
@ericgriffin
ericgriffin merged commit 1934ac9 into main Sep 22, 2026
2 checks passed
@ericgriffin
ericgriffin deleted the ericgriffin/legal-single-source branch September 22, 2026 23:51
@ericgriffin ericgriffin changed the title Generate the privacy page from the app repo's PRIVACY.md Generate the privacy and terms pages from the app repo's Markdown Sep 22, 2026
@ericgriffin ericgriffin changed the title Generate the privacy and terms pages from the app repo's Markdown Generate the privacy page from the app repo's PRIVACY.md Sep 22, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant