The repository has Forgejo and GitLab remotes but no GitHub remote, so
nothing under .github/workflows ever ran - including the daily Payple
renewal job, which means Payple subscriptions were not being renewed.
- Port payple-renew (daily cron + manual dispatch) to Forgejo. Requires the
Forgejo secrets SUPABASE_URL and CRON_SECRET.
- Port the CI checks (quality incl. version:check and contract:check, build,
mobile quality, edge functions, API tests) to .forgejo/workflows/ci.yml.
macOS and Android emulator jobs are dropped: no macOS runner here, and the
signed Android release stays on GitLab mobile-production-release.
- Keep one site deploy workflow (Linux, Cloudflare Pages); remove the
manual Windows duplicate. The mobile release boundary self-test runs there.
- Release verifiers read the Forgejo/GitLab workflows, fail if .github
workflows come back, and check the rewritten site offers no mobile package.
Policy: docs/REFACTOR_POLICY.md Wave 3, W3-7 and W3-8.
The feed publisher overwrote whatever version-specific assets it found, so a
re-run of an old release tag could quietly replace the installer that
customers already downloaded under that version number.
Publication now compares the bytes already in the version-specific registry
path and stops when they differ, while still allowing an identical re-run to
finish. The metadata verifier gained a negative case so the guard cannot be
removed unnoticed.
Desktop clients had two competing update sources: the runtime pointed at a
legacy GitLab registry while the Forgejo packages were filled in by
hardcoded, version-pinned scripts. Operators could not tell which feed was
authoritative, and no release could be reproduced from a tag.
Auto-update now reads a single canonical Forgejo registry feed, updated by
a version-agnostic publisher that runs from the tag on Forgejo, GitLab, and
GitHub CI alike. Channel, minimum supported version, forced install,
full-versus-delta thresholds, staged rollout, and a remote kill switch come
from one policy file the client fetches alongside the feed. Tag creation is
gated on a clean tree, matching version surfaces, and a changelog section.