Zeus Change Control
How to get a change into Zeus (a React Native Bitcoin/Lightning wallet) without losing user funds, corrupting user data, or getting your PR closed. Zeus moves money; process rules here exist because each one was paid for by a real incident.
Glossary used throughout (defined once):
- PR — GitHub pull request. CI — continuous integration; the automated checks GitHub runs on every PR.
- Lightning — Bitcoin's payment-channel network; Zeus is a wallet for it. LND / CLN — the two major Lightning node implementations Zeus talks to. Macaroon — LND's bearer-token auth credential (a secret; leaking one can drain a node).
- Keychain — the OS-level secure credential store (iOS Keychain / Android Keystore) where Zeus persists ALL wallet secrets in one JSON blob under key
zeus-settings-v2.
- Squash / fixup — git operations that fold review-fix commits into the original commit before merge.
- Backend — one of the 7 node implementations Zeus can drive (embedded LND, LDK Node, remote LND REST, Lightning Node Connect, CLNRest, LndHub, Nostr Wallet Connect).
When to use / When NOT to use
USE this skill for: change classification and approval gates, commit-message style, PR template and review process, CI-check expectations, dependency policy, locale rules, revert policy, docs/license/signing house rules.
Do NOT use this skill for — go to the sibling instead:
| Need |
Sibling skill |
| HOW to write a storage migration, keychain contract details |
zeus-storage-and-migrations |
| yarn verify internals, jest traps, check-styles.test.ts trick, how to add tests |
zeus-validation-and-qa |
| zeus_modules vendoring mechanics, postinstall chain, native builds |
zeus-build-and-env |
| Full incident narratives with evidence chains |
zeus-failure-archaeology |
| Backend capability matrix, adding an RPC |
zeus-backends-and-capabilities |
| Release operations, reproducible builds in practice |
zeus-run-and-operate |
| Adding a settings axis (defaults, options) |
zeus-config-and-flags |
Authoritative in-repo documents this skill summarizes (read them for full text; nothing here overrides them): CONTRIBUTING.md, CODE_REVIEW.md, .github/PULL_REQUEST_TEMPLATE.md.
1. The four maintainer non-negotiables (UNWRITTEN rules)
These four rules are maintainer-stated (2026-07-06) and appear in NO repo document. They bind anyway. Each has a paid-for rationale.
Rule 1 — Storage/keychain changes are gated
Anything touching the zeus-settings-v2 blob, keychain keys, storage/index.ts, or migrations (utils/MigrationUtils.ts, stores/SettingsStore.ts persistence paths) requires maintainer sign-off plus a written migration plan, always — before you write code. Never route around this by "just changing the format".
- WHY: every wallet's seed, macaroon, and PIN live in one keychain JSON blob. A bad write or migration bricks wallets or leaks seeds; there is no server-side undo.
- INCIDENTS: the iCloud keychain saga — PR #3307 (merged as
5f533bb12, 2025-11-10) was reverted the same day (7d8678457, via revert PR #3354); the proper fix took two more PRs (merges e808fd71a + ed161541a, 2025-12-01) and STILL left stale iCloud-synced wallet copies on new devices, requiring a third migration (46f2bac00, 2026-01-14). Separately, a settings migration passed a JSON.stringify'd object to setSettings, corrupting MobX observables — issue #4150, fixed by 7ed901a10 (2026-06-09). Recipes and the safety protocol: zeus-storage-and-migrations; full narratives: zeus-failure-archaeology.
Rule 2 — Revert-first near releases
A regression found during release testing gets reverted the same day, never forward-fixed under pressure. If your merged change is implicated, expect a revert-<PR#>-<branch> PR with an empty body; don't argue for a hotfix, re-land properly later.
- WHY: forward-fixes under release pressure ship untested code into a funds-handling app.
- INCIDENTS: NWC txlist fix #3432 merged and reverted (#3444) on the same day, 2025-12-15 (
28bc50f5e); iCloud #3307 reverted same day 2025-11-10; sat-rounding #1568 (2023-08-04) reverted next day by #1587; app-lock-timeout #1679 reverted by #1773 (2023-10).
- Practical consequence: before trusting any merged fix as final, check
git log --grep='revert-<PR#>'.
Rule 3 — No refactors of payment paths
Changes to send/receive/payment-handling code (views/Send.tsx, views/PaymentRequest.tsx, stores/TransactionsStore.ts, backends/*, utils/BackendUtils.ts dispatch) must be minimal diffs. No drive-by refactoring, renaming, or "cleanup" inside a funds-touching change.
- WHY: stores, views, components, and backends have zero automated test coverage — only
utils/, models/, and lndmobile/ have tests (plus the root check-styles.test.ts; see zeus-validation-and-qa). A refactor there is reviewed and safety-netted by human eyeballs alone, across 7 backends.
- INCIDENT (refactors bite even outside payment code):
fdad118ed (2025-10-24), a "replace UNSAFE React lifecycle methods" refactor, caused an infinite-loading regression fixed only 3 weeks later by 93227029e (2025-11-12, which cites the offending hash in its subject).
Rule 4 — Manual two-platform testing is mandatory
No merge without hands-on testing by the author on both iOS and Android, regardless of green CI.
- WHY: PR CI runs only unit tests, lint, formatting, and type-check on Linux (Section 5) — it never builds or launches the mobile app. Rendering, native modules, and navigation differ per platform; CI green proves almost nothing about runtime behavior. CONTRIBUTING.md says "when possible"; the maintainer standard is stricter: do it.
- The PR template's platform and backend checkboxes (Section 3) are how you attest to this.
2. Change classification and gates
Classify every change before starting. When a change spans classes, the strictest gate applies.
| Class |
What counts |
Gate before coding |
Gate before merge |
| Funds-touching |
Sending/receiving payments, invoice creation/decoding, channel open/close, fee logic, seed/key handling: views/Send.tsx, views/PaymentRequest.tsx, stores/TransactionsStore.ts, backends/*, utils/BackendUtils.ts, swap/Cashu/NWC payment flows |
Open an issue / discuss approach first (CONTRIBUTING "Share Early, Share Often") |
Minimal diff (Rule 3); manual test on iOS + Android (Rule 4); test on every backend the code path can reach, recorded in the PR template matrix; regression test if it's a bug fix |
| Storage-touching |
zeus-settings-v2 blob shape, any keychain key, storage/index.ts, migrations, changed defaults for existing users |
Maintainer sign-off + migration plan, always (Rule 1) |
Migration follows the gated pattern in zeus-storage-and-migrations; manual test on both platforms including upgrade-from-previous-version |
| UI-only |
Screens/components with no store-shape or payment-logic change |
None beyond checking for an existing issue/PR |
Manual test on both platforms (CONTRIBUTING is explicit: rendering differs); screenshots/video in the PR; theme check (styling violations fail the Lint CI job — see zeus-validation-and-qa); new user-facing strings go in locales/en.json only (Section 7) |
| Docs-only |
README.md, CONTRIBUTING.md, CODE_REVIEW.md, docs/* |
None |
docs: commit prefix; no drive-by doc edits inside code PRs — known stale text (e.g. the PR template "Transfix" typo) is fixed via dedicated docs commits, not opportunistically |
| Dependency |
Any package.json addition/major bump |
Discuss with maintainers first (Section 6) |
PR template third-party-deps section filled; verify yarn.lock updated and both platforms still build |
| Locales |
Translation strings |
— |
Only locales/en.json (Section 7) |
3. PR process
The template is sacred
.github/PULL_REQUEST_TEMPLATE.md — never delete or replace it; fill in every section (CONTRIBUTING.md states this explicitly). Its required sections, as of 2026-07-06:
- Description — issue reference (
ZEUS-0000 placeholder), description + screenshots.
- Category checkboxes — new feature / bug fix / code refactor / configuration change / locales update / quality assurance / other.
- Checklist — you ran
yarn run tsc, yarn run lint, yarn run prettier, yarn run test (i.e. everything yarn verify runs).
- Testing — did you add unit tests for modified utility files (options: "No, I'm a fool" / Yes / N/A).
- Platform matrix — Android and iOS checkboxes, with OS version and phone model/VM. This is where Rule 4 is attested.
- Backend testing matrix — which of the 7 node types you tested against, with node/API versions: On-device: LDK Node, Embedded LND; Remote: LND (REST), LND (Lightning Node Connect), Core Lightning (CLNRest), Nostr Wallet Connect, LndHub.
- Locales — new translatable text flagged; acknowledgment that translations happen on Transifex, not in-repo. (The template's "Transfix" spelling is a known typo — leave it.)
- Third-party dependencies — whether contributors must re-run
yarn, whether package.json/yarn.lock changed, both-platform install verified.
- Other — README or onboarding updates needed?
First-time contributors: proof of work
Per CONTRIBUTING.md: first-time contributors submitting features or UI changes must attach screenshot or video evidence that the change works, directly in the PR description. PRs without it are closed within 24 hours; repeat offenders are blocked. Also: no trivial typo/whitespace first PRs; issue assignment is team-only — just comment that you've started.
Review vocabulary (Bitcoin-Core style, defined in CODE_REVIEW.md)
| Term |
Meaning |
ACK |
Full approval: code reviewed AND changes tested. Usually cites the commit hash: ACK 3a4b5c6 |
tACK |
Tested the changes, but no full code review |
cACK |
Concept ACK — agree with the approach, didn't review the implementation |
NACK |
Recommend against merging; must include detailed reasoning |
Nitpick/nit |
Minor, non-blocking suggestion |
Review flow
- Fetch a PR locally:
git fetch origin pull/<N>/head:pr-<N> then git checkout pr-<N> (from CODE_REVIEW.md).
- During review, push fixup commits (easy to re-review); squash before merge. Rebase on master; no merge commits in the branch.
- Merge requirements (CONTRIBUTING.md): all CI checks pass, ≥1 maintainer approval, no unresolved conversations, up to date with base.
- Review checklist highlights (full list in CODE_REVIEW.md): no sensitive data (keys, macaroons, seeds) logged or exposed; inputs validated on payment paths; no potential fund-loss scenarios; no unnecessary
any types; works across themes/locales/font sizes; commits atomic. Separately, CONTRIBUTING.md ("Test Coverage") requires that bug fixes include a test that would have caught the bug.
4. Commit style
CONTRIBUTING.md prescribes component: prefixes (views:, stores:, backends:, utils:, build:, docs:, tests:) — that is the written rule and this skill does not override it. Master history additionally shows conventional-commit-ish prefixes being accepted in practice (122 of the last 200 commit subjects at c5fd094fb use them; most of the rest are merge commits), so either observed style is tolerated in review — but absent a maintainer statement authorizing otherwise, default to the CONTRIBUTING.md component prefixes. Real examples from git log:
fix(migrations): pass object to setSettings to avoid MobX observable corruption (#4150)
fix(utxo-picker): restore UTXO labels and keep Set button above gesture bar
ui: Receive: prevent input field flash on initial load via initialLoad state
refactor: Receive: extract skipOnchain into helper
docs: fix NWC service link in README (#4179)
chore(deps): bump concurrent-ruby from 1.3.3 to 1.3.7
Rules:
- Subject ≤ ~50 chars where possible; body wrapped at 72, explaining problem + why this approach (CONTRIBUTING.md).
- Atomic commits; each should ideally pass
yarn verify independently.
- Version bumps are exactly
Version bump: vX.Y.Z[-alpha|-beta1] (e.g. Version bump: v13.1.3-alpha) — maintainer-only.
- Branch names:
feature/..., fix/..., refactor/....
- When citing hashes in commit messages or discussions, use first-parent master hashes:
git log --all contains duplicated/grafted merge hashes (e.g. PR #3444 appears as both 28bc50f5e and f47ef1acf).
5. CI reality: green PR = exactly 4 checks
Verified in .github/workflows/ at c5fd094fb: exactly four workflows trigger on pull_request —
| Check name |
Workflow file |
Runs |
| Test |
test.yml |
yarn run test (jest) |
| Lint |
lint.yml |
yarn run lint (eslint + the styles test) |
| Prettier |
prettier.yml |
yarn run prettier (format check) |
| Typescript Check |
tsc.yml |
yarn run tsc |
All four = yarn verify locally (package.json: concurrently "yarn test" "yarn prettier" "yarn tsc" "yarn lint"). Run yarn verify before every push. Details of each job's traps (check-styles trick, Prettier pinned at 2.4.1, jest transform whitelist): zeus-validation-and-qa.
What PR CI does NOT do: no mobile build, no dependency scan — build-android.yml and dependency-scan.yml are workflow_dispatch-only (manually triggered); telegram.yml is a push/release notifier, not a check. This is exactly why Rule 4 (manual two-platform testing) exists.
CI runs on ubuntu-latest, Node 24.x, yarn install --frozen-lockfile.
6. Dependency policy
- Discuss before adding any new library (CONTRIBUTING.md "Discuss new dependencies"): there may be an existing in-repo solution or a preferred alternative, and every dependency is supply-chain surface in a funds-handling app.
- Zeus vendors some packages under
zeus_modules/ (some via file: refs, some imported by relative path and deliberately NOT in package.json). Never yarn add something that lives there. Mechanics: zeus-build-and-env.
- If a PR modifies dependencies: tick the PR-template third-party section, confirm
package.json + yarn.lock are consistent, and verify install on both iOS and Android.
7. Locales
- Only
locales/en.json may be edited in-repo. The other 33 locale files (34 total in locales/ as of 2026-07-06) are managed through Transifex (https://explore.transifex.com/ZeusLN/zeus/) and must never be modified directly — such PRs get rejected.
- All user-facing strings must go through the localization system; no hardcoded UI text.
- Want to translate? Request a language role on Transifex, not a PR.
8. Docs house rules
- In-repo docs inventory:
README.md (project overview, feature list, integration guides), CONTRIBUTING.md (contribution process — source of truth for everything in Sections 2–4 here), CODE_REVIEW.md (review process and vocabulary), docs/Bounties.md (bounty program; reportedly partially stale — check open bounties against the issue tracker before relying on it), docs/RemoteConnections.md (node-connection guides), docs/ReproducibleBuilds.md (Android-only reproducible builds).
- External user docs of record: https://docs.zeusln.app/ — README links there for all user-facing feature documentation. User-behavior changes may need updates there (out-of-repo), plus README/onboarding per the PR template's "Other" section.
- License: AGPLv3 (see
LICENSE). All contributions must be AGPLv3-compatible; submitting a PR is agreement to that (CONTRIBUTING.md).
- Signing: all releases and all maintainer commits since 2021-10-20 are PGP-signed with key
AAC48DE8AB8DEE84 (full fingerprint 96C225207F2137E278C31CF7AAC48DE8AB8DEE84, Zeus LN zeusln@tutanota.com); public key in PGP.txt (README.md "Release + Commit Verification" section). Contributors are not required to sign.
- Writing style for docs changes: match existing docs;
docs: commit prefix; don't bundle doc fixes into code PRs.
Pre-PR checklist (condensed)
- Classified the change (Section 2)? Storage-touching → maintainer sign-off FIRST. Funds-touching → minimal diff, discussed first.
yarn verify green locally.
- Manually tested on iOS AND Android (Rule 4); backends exercised and recorded.
- New strings in
locales/en.json only; no other locale files touched.
- Commits: CONTRIBUTING.md component-prefix style (conventional-commit-ish prefixes are tolerated in practice), atomic, rebased on master.
- PR template fully filled in — not deleted; screenshots for UI changes (mandatory for first-timers).
- If a dependency changed: was it discussed first?
Provenance and maintenance
Facts verified 2026-07-06 against master c5fd094fb (v13.1.3-alpha). Maintainer-stated rules (Section 1) confirmed verbally 2026-07-06 — they appear in no repo document; everything else was verified by reading the cited files or running the commands below.
Re-verify volatile facts:
| Fact |
Command |
| HEAD / version |
git log -1 --format='%h %s' |
| PR CI = exactly 4 workflows |
grep -l 'pull_request:' .github/workflows/*.yml (expect lint, prettier, test, tsc) |
| build/scan not in PR CI |
grep -A2 '^on:' .github/workflows/build-android.yml .github/workflows/dependency-scan.yml (expect workflow_dispatch) |
yarn verify composition |
grep '"verify"' package.json |
| CI Node version |
grep node-version .github/workflows/test.yml (24.x as of 2026-07-06) |
| PR template sections |
cat .github/PULL_REQUEST_TEMPLATE.md |
| Locale file count / en-only rule |
ls locales | wc -l (34); CONTRIBUTING.md "Internationalization" |
| Proof-of-work rule |
CONTRIBUTING.md "Proof of Work for First-Time Contributors" |
| ACK vocabulary |
CODE_REVIEW.md "Review Approval Terminology" |
| Commit-style drift |
git log --format='%s' -200 | grep -Ec '^(fix|ui|refactor|feat|chore|docs)[:(]' |
| Version-bump format |
git log --format='%s' --grep='Version bump' -5 |
| Incident hashes |
git log -1 --format='%h %ad %s' --date=short <hash> for 5f533bb12, 7d8678457, 7ed901a10, 46f2bac00, e808fd71a, ed161541a, fdad118ed, 93227029e, 28bc50f5e |
| Revert-of-a-PR check |
git log --first-parent --grep='revert-<PR#>' |
| PGP key |
gpg --show-keys PGP.txt; README.md "Release + Commit Verification" |
| License |
grep -m1 'GNU AFFERO' LICENSE |
| Docs inventory |
ls docs/ |
1---2name: zeus-change-control3description: How changes get classified, gated, reviewed, and merged in Zeus. Load BEFORE writing a commit message, opening/filling a PR, reviewing a PR, deciding whether a change needs maintainer sign-off, adding a dependency, editing locale files, or editing docs. Triggers/symptoms - "can I refactor this payment code", "which CI checks run on PRs", "how do I format my commit", "PR template", "ACK/tACK/NACK meaning", "why was my locale/de.json PR rejected", "do I need approval to touch keychain/settings storage", "first PR to Zeus", "revert policy", "version bump commit", "license/PGP key questions".4---56# Zeus Change Control78How to get a change into Zeus (a React Native Bitcoin/Lightning wallet) without losing user funds, corrupting user data, or getting your PR closed. Zeus moves money; process rules here exist because each one was paid for by a real incident.910Glossary used throughout (defined once):1112- **PR** — GitHub pull request. **CI** — continuous integration; the automated checks GitHub runs on every PR.13- **Lightning** — Bitcoin's payment-channel network; Zeus is a wallet for it. **LND / CLN** — the two major Lightning node implementations Zeus talks to. **Macaroon** — LND's bearer-token auth credential (a secret; leaking one can drain a node).14- **Keychain** — the OS-level secure credential store (iOS Keychain / Android Keystore) where Zeus persists ALL wallet secrets in one JSON blob under key `zeus-settings-v2`.15- **Squash / fixup** — git operations that fold review-fix commits into the original commit before merge.16- **Backend** — one of the 7 node implementations Zeus can drive (embedded LND, LDK Node, remote LND REST, Lightning Node Connect, CLNRest, LndHub, Nostr Wallet Connect).1718## When to use / When NOT to use1920USE this skill for: change classification and approval gates, commit-message style, PR template and review process, CI-check expectations, dependency policy, locale rules, revert policy, docs/license/signing house rules.2122Do NOT use this skill for — go to the sibling instead:2324| Need | Sibling skill |25|---|---|26| HOW to write a storage migration, keychain contract details | zeus-storage-and-migrations |27| yarn verify internals, jest traps, check-styles.test.ts trick, how to add tests | zeus-validation-and-qa |28| zeus_modules vendoring mechanics, postinstall chain, native builds | zeus-build-and-env |29| Full incident narratives with evidence chains | zeus-failure-archaeology |30| Backend capability matrix, adding an RPC | zeus-backends-and-capabilities |31| Release operations, reproducible builds in practice | zeus-run-and-operate |32| Adding a settings axis (defaults, options) | zeus-config-and-flags |3334Authoritative in-repo documents this skill summarizes (read them for full text; nothing here overrides them): `CONTRIBUTING.md`, `CODE_REVIEW.md`, `.github/PULL_REQUEST_TEMPLATE.md`.3536## 1. The four maintainer non-negotiables (UNWRITTEN rules)3738These four rules are **maintainer-stated (2026-07-06) and appear in NO repo document**. They bind anyway. Each has a paid-for rationale.3940### Rule 1 — Storage/keychain changes are gated4142Anything touching the `zeus-settings-v2` blob, keychain keys, `storage/index.ts`, or migrations (`utils/MigrationUtils.ts`, `stores/SettingsStore.ts` persistence paths) requires **maintainer sign-off plus a written migration plan, always** — before you write code. Never route around this by "just changing the format".4344- WHY: every wallet's seed, macaroon, and PIN live in one keychain JSON blob. A bad write or migration bricks wallets or leaks seeds; there is no server-side undo.45- INCIDENTS: the iCloud keychain saga — PR #3307 (merged as `5f533bb12`, 2025-11-10) was reverted the **same day** (`7d8678457`, via revert PR #3354); the proper fix took two more PRs (merges `e808fd71a` + `ed161541a`, 2025-12-01) and STILL left stale iCloud-synced wallet copies on new devices, requiring a third migration (`46f2bac00`, 2026-01-14). Separately, a settings migration passed a `JSON.stringify`'d object to `setSettings`, corrupting MobX observables — issue #4150, fixed by `7ed901a10` (2026-06-09). Recipes and the safety protocol: **zeus-storage-and-migrations**; full narratives: **zeus-failure-archaeology**.4647### Rule 2 — Revert-first near releases4849A regression found during release testing gets **reverted the same day**, never forward-fixed under pressure. If your merged change is implicated, expect a `revert-<PR#>-<branch>` PR with an empty body; don't argue for a hotfix, re-land properly later.5051- WHY: forward-fixes under release pressure ship untested code into a funds-handling app.52- INCIDENTS: NWC txlist fix #3432 merged and reverted (#3444) on the same day, 2025-12-15 (`28bc50f5e`); iCloud #3307 reverted same day 2025-11-10; sat-rounding #1568 (2023-08-04) reverted next day by #1587; app-lock-timeout #1679 reverted by #1773 (2023-10).53- Practical consequence: before trusting any merged fix as final, check `git log --grep='revert-<PR#>'`.5455### Rule 3 — No refactors of payment paths5657Changes to send/receive/payment-handling code (`views/Send.tsx`, `views/PaymentRequest.tsx`, `stores/TransactionsStore.ts`, `backends/*`, `utils/BackendUtils.ts` dispatch) must be **minimal diffs**. No drive-by refactoring, renaming, or "cleanup" inside a funds-touching change.5859- WHY: stores, views, components, and backends have **zero automated test coverage** — only `utils/`, `models/`, and `lndmobile/` have tests (plus the root `check-styles.test.ts`; see zeus-validation-and-qa). A refactor there is reviewed and safety-netted by human eyeballs alone, across 7 backends.60- INCIDENT (refactors bite even outside payment code): `fdad118ed` (2025-10-24), a "replace UNSAFE React lifecycle methods" refactor, caused an infinite-loading regression fixed only 3 weeks later by `93227029e` (2025-11-12, which cites the offending hash in its subject).6162### Rule 4 — Manual two-platform testing is mandatory6364No merge without hands-on testing by the author on **both iOS and Android**, regardless of green CI.6566- WHY: PR CI runs only unit tests, lint, formatting, and type-check on Linux (Section 5) — it never builds or launches the mobile app. Rendering, native modules, and navigation differ per platform; CI green proves almost nothing about runtime behavior. CONTRIBUTING.md says "when possible"; the maintainer standard is stricter: do it.67- The PR template's platform and backend checkboxes (Section 3) are how you attest to this.6869## 2. Change classification and gates7071Classify every change before starting. When a change spans classes, the strictest gate applies.7273| Class | What counts | Gate before coding | Gate before merge |74|---|---|---|---|75| **Funds-touching** | Sending/receiving payments, invoice creation/decoding, channel open/close, fee logic, seed/key handling: `views/Send.tsx`, `views/PaymentRequest.tsx`, `stores/TransactionsStore.ts`, `backends/*`, `utils/BackendUtils.ts`, swap/Cashu/NWC payment flows | Open an issue / discuss approach first (CONTRIBUTING "Share Early, Share Often") | Minimal diff (Rule 3); manual test on iOS + Android (Rule 4); test on every backend the code path can reach, recorded in the PR template matrix; regression test if it's a bug fix |76| **Storage-touching** | `zeus-settings-v2` blob shape, any keychain key, `storage/index.ts`, migrations, changed defaults for existing users | **Maintainer sign-off + migration plan, always** (Rule 1) | Migration follows the gated pattern in zeus-storage-and-migrations; manual test on both platforms including upgrade-from-previous-version |77| **UI-only** | Screens/components with no store-shape or payment-logic change | None beyond checking for an existing issue/PR | Manual test on **both** platforms (CONTRIBUTING is explicit: rendering differs); screenshots/video in the PR; theme check (styling violations fail the Lint CI job — see zeus-validation-and-qa); new user-facing strings go in `locales/en.json` only (Section 7) |78| **Docs-only** | `README.md`, `CONTRIBUTING.md`, `CODE_REVIEW.md`, `docs/*` | None | `docs:` commit prefix; no drive-by doc edits inside code PRs — known stale text (e.g. the PR template "Transfix" typo) is fixed via dedicated docs commits, not opportunistically |79| **Dependency** | Any `package.json` addition/major bump | **Discuss with maintainers first** (Section 6) | PR template third-party-deps section filled; verify `yarn.lock` updated and both platforms still build |80| **Locales** | Translation strings | — | Only `locales/en.json` (Section 7) |8182## 3. PR process8384### The template is sacred8586`.github/PULL_REQUEST_TEMPLATE.md` — **never delete or replace it**; fill in every section (CONTRIBUTING.md states this explicitly). Its required sections, as of 2026-07-06:87881. **Description** — issue reference (`ZEUS-0000` placeholder), description + screenshots.892. **Category checkboxes** — new feature / bug fix / code refactor / configuration change / locales update / quality assurance / other.903. **Checklist** — you ran `yarn run tsc`, `yarn run lint`, `yarn run prettier`, `yarn run test` (i.e. everything `yarn verify` runs).914. **Testing** — did you add unit tests for modified utility files (options: "No, I'm a fool" / Yes / N/A).925. **Platform matrix** — Android and iOS checkboxes, with OS version and phone model/VM. This is where Rule 4 is attested.936. **Backend testing matrix** — which of the 7 node types you tested against, with node/API versions: On-device: LDK Node, Embedded LND; Remote: LND (REST), LND (Lightning Node Connect), Core Lightning (CLNRest), Nostr Wallet Connect, LndHub.947. **Locales** — new translatable text flagged; acknowledgment that translations happen on Transifex, not in-repo. (The template's "Transfix" spelling is a known typo — leave it.)958. **Third-party dependencies** — whether contributors must re-run `yarn`, whether `package.json`/`yarn.lock` changed, both-platform install verified.969. **Other** — README or onboarding updates needed?9798### First-time contributors: proof of work99100Per CONTRIBUTING.md: first-time contributors submitting features or UI changes **must attach screenshot or video evidence** that the change works, directly in the PR description. PRs without it are closed within 24 hours; repeat offenders are blocked. Also: no trivial typo/whitespace first PRs; issue assignment is team-only — just comment that you've started.101102### Review vocabulary (Bitcoin-Core style, defined in CODE_REVIEW.md)103104| Term | Meaning |105|---|---|106| `ACK` | Full approval: code reviewed AND changes tested. Usually cites the commit hash: `ACK 3a4b5c6` |107| `tACK` | Tested the changes, but no full code review |108| `cACK` | Concept ACK — agree with the approach, didn't review the implementation |109| `NACK` | Recommend against merging; must include detailed reasoning |110| `Nitpick/nit` | Minor, non-blocking suggestion |111112### Review flow113114- Fetch a PR locally: `git fetch origin pull/<N>/head:pr-<N>` then `git checkout pr-<N>` (from CODE_REVIEW.md).115- During review, push **fixup commits** (easy to re-review); **squash before merge**. Rebase on master; no merge commits in the branch.116- Merge requirements (CONTRIBUTING.md): all CI checks pass, ≥1 maintainer approval, no unresolved conversations, up to date with base.117- Review checklist highlights (full list in CODE_REVIEW.md): no sensitive data (keys, macaroons, seeds) logged or exposed; inputs validated on payment paths; no potential fund-loss scenarios; no unnecessary `any` types; works across themes/locales/font sizes; commits atomic. Separately, CONTRIBUTING.md ("Test Coverage") requires that bug fixes include a test that would have caught the bug.118119## 4. Commit style120121CONTRIBUTING.md prescribes `component:` prefixes (`views:`, `stores:`, `backends:`, `utils:`, `build:`, `docs:`, `tests:`) — that is the written rule and this skill does not override it. Master history additionally shows conventional-commit-ish prefixes being accepted in practice (122 of the last 200 commit subjects at `c5fd094fb` use them; most of the rest are merge commits), so either observed style is tolerated in review — but absent a maintainer statement authorizing otherwise, default to the CONTRIBUTING.md component prefixes. Real examples from `git log`:122123```124fix(migrations): pass object to setSettings to avoid MobX observable corruption (#4150)125fix(utxo-picker): restore UTXO labels and keep Set button above gesture bar126ui: Receive: prevent input field flash on initial load via initialLoad state127refactor: Receive: extract skipOnchain into helper128docs: fix NWC service link in README (#4179)129chore(deps): bump concurrent-ruby from 1.3.3 to 1.3.7130```131132Rules:133134- Subject ≤ ~50 chars where possible; body wrapped at 72, explaining problem + why this approach (CONTRIBUTING.md).135- Atomic commits; each should ideally pass `yarn verify` independently.136- Version bumps are exactly `Version bump: vX.Y.Z[-alpha|-beta1]` (e.g. `Version bump: v13.1.3-alpha`) — maintainer-only.137- Branch names: `feature/...`, `fix/...`, `refactor/...`.138- When citing hashes in commit messages or discussions, use first-parent master hashes: `git log --all` contains duplicated/grafted merge hashes (e.g. PR #3444 appears as both `28bc50f5e` and `f47ef1acf`).139140## 5. CI reality: green PR = exactly 4 checks141142Verified in `.github/workflows/` at `c5fd094fb`: exactly four workflows trigger on `pull_request` —143144| Check name | Workflow file | Runs |145|---|---|---|146| Test | `test.yml` | `yarn run test` (jest) |147| Lint | `lint.yml` | `yarn run lint` (eslint + the styles test) |148| Prettier | `prettier.yml` | `yarn run prettier` (format check) |149| Typescript Check | `tsc.yml` | `yarn run tsc` |150151All four = `yarn verify` locally (`package.json`: `concurrently "yarn test" "yarn prettier" "yarn tsc" "yarn lint"`). Run `yarn verify` before every push. Details of each job's traps (check-styles trick, Prettier pinned at 2.4.1, jest transform whitelist): **zeus-validation-and-qa**.152153What PR CI does **NOT** do: no mobile build, no dependency scan — `build-android.yml` and `dependency-scan.yml` are `workflow_dispatch`-only (manually triggered); `telegram.yml` is a push/release notifier, not a check. This is exactly why Rule 4 (manual two-platform testing) exists.154155CI runs on ubuntu-latest, Node 24.x, `yarn install --frozen-lockfile`.156157## 6. Dependency policy158159- **Discuss before adding** any new library (CONTRIBUTING.md "Discuss new dependencies"): there may be an existing in-repo solution or a preferred alternative, and every dependency is supply-chain surface in a funds-handling app.160- Zeus vendors some packages under `zeus_modules/` (some via `file:` refs, some imported by relative path and deliberately NOT in `package.json`). Never `yarn add` something that lives there. Mechanics: **zeus-build-and-env**.161- If a PR modifies dependencies: tick the PR-template third-party section, confirm `package.json` + `yarn.lock` are consistent, and verify install on both iOS and Android.162163## 7. Locales164165- **Only `locales/en.json` may be edited in-repo.** The other 33 locale files (34 total in `locales/` as of 2026-07-06) are managed through Transifex (https://explore.transifex.com/ZeusLN/zeus/) and must never be modified directly — such PRs get rejected.166- All user-facing strings must go through the localization system; no hardcoded UI text.167- Want to translate? Request a language role on Transifex, not a PR.168169## 8. Docs house rules170171- **In-repo docs inventory**: `README.md` (project overview, feature list, integration guides), `CONTRIBUTING.md` (contribution process — source of truth for everything in Sections 2–4 here), `CODE_REVIEW.md` (review process and vocabulary), `docs/Bounties.md` (bounty program; reportedly partially stale — check open bounties against the issue tracker before relying on it), `docs/RemoteConnections.md` (node-connection guides), `docs/ReproducibleBuilds.md` (Android-only reproducible builds).172- **External user docs of record**: https://docs.zeusln.app/ — README links there for all user-facing feature documentation. User-behavior changes may need updates there (out-of-repo), plus README/onboarding per the PR template's "Other" section.173- **License**: AGPLv3 (see `LICENSE`). All contributions must be AGPLv3-compatible; submitting a PR is agreement to that (CONTRIBUTING.md).174- **Signing**: all releases and all maintainer commits since 2021-10-20 are PGP-signed with key `AAC48DE8AB8DEE84` (full fingerprint `96C225207F2137E278C31CF7AAC48DE8AB8DEE84`, Zeus LN <zeusln@tutanota.com>); public key in `PGP.txt` (README.md "Release + Commit Verification" section). Contributors are not required to sign.175- Writing style for docs changes: match existing docs; `docs:` commit prefix; don't bundle doc fixes into code PRs.176177## Pre-PR checklist (condensed)1781791. Classified the change (Section 2)? Storage-touching → maintainer sign-off FIRST. Funds-touching → minimal diff, discussed first.1802. `yarn verify` green locally.1813. Manually tested on iOS AND Android (Rule 4); backends exercised and recorded.1824. New strings in `locales/en.json` only; no other locale files touched.1835. Commits: CONTRIBUTING.md component-prefix style (conventional-commit-ish prefixes are tolerated in practice), atomic, rebased on master.1846. PR template fully filled in — not deleted; screenshots for UI changes (mandatory for first-timers).1857. If a dependency changed: was it discussed first?186187## Provenance and maintenance188189Facts verified 2026-07-06 against master `c5fd094fb` (v13.1.3-alpha). Maintainer-stated rules (Section 1) confirmed verbally 2026-07-06 — they appear in no repo document; everything else was verified by reading the cited files or running the commands below.190191Re-verify volatile facts:192193| Fact | Command |194|---|---|195| HEAD / version | `git log -1 --format='%h %s'` |196| PR CI = exactly 4 workflows | `grep -l 'pull_request:' .github/workflows/*.yml` (expect lint, prettier, test, tsc) |197| build/scan not in PR CI | `grep -A2 '^on:' .github/workflows/build-android.yml .github/workflows/dependency-scan.yml` (expect `workflow_dispatch`) |198| `yarn verify` composition | `grep '"verify"' package.json` |199| CI Node version | `grep node-version .github/workflows/test.yml` (24.x as of 2026-07-06) |200| PR template sections | `cat .github/PULL_REQUEST_TEMPLATE.md` |201| Locale file count / en-only rule | `ls locales \| wc -l` (34); CONTRIBUTING.md "Internationalization" |202| Proof-of-work rule | CONTRIBUTING.md "Proof of Work for First-Time Contributors" |203| ACK vocabulary | CODE_REVIEW.md "Review Approval Terminology" |204| Commit-style drift | `git log --format='%s' -200 \| grep -Ec '^(fix\|ui\|refactor\|feat\|chore\|docs)[:(]'` |205| Version-bump format | `git log --format='%s' --grep='Version bump' -5` |206| Incident hashes | `git log -1 --format='%h %ad %s' --date=short <hash>` for `5f533bb12`, `7d8678457`, `7ed901a10`, `46f2bac00`, `e808fd71a`, `ed161541a`, `fdad118ed`, `93227029e`, `28bc50f5e` |207| Revert-of-a-PR check | `git log --first-parent --grep='revert-<PR#>'` |208| PGP key | `gpg --show-keys PGP.txt`; README.md "Release + Commit Verification" |209| License | `grep -m1 'GNU AFFERO' LICENSE` |210| Docs inventory | `ls docs/` |