Files
flamenet-messenger-android/CONTRIBUTING.md
T
Paul HittandClaude Fable 5.1 8a7f40fb13 Second pass with the avoid-ai-writing detector
The skill's detector scored the README, PARITY.md and the extracted
comment prose. Fixed what it flagged: hollow intensifiers, "in order
to", "additionally", "the whole point", bold sentences in docs, and
bold that had wrapped across comment lines. Comment prose scores a
maximum of 4 out of 100 across the repo.

One sweep rule mangled four comments ("which is the entire point of X"
lost its clause); repaired, and the rule now keeps the clause.

Comments and strings only. 1208 tests pass, counted from the XML.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-08 19:20:07 -04:00

73 lines
3.1 KiB
Markdown

# Contributing
The Android client for Flamenet Messenger, in Kotlin and Compose. Three modules:
`engine` (the encryption primitives), `client` (protocol and transport), `app`
(UI). Feature parity with iOS is tracked in [PARITY.md](PARITY.md), read it
before assuming something is missing by accident.
## Security bugs do not go in an issue
Email **security@flamenetmessenger.com**. See [SECURITY.md](SECURITY.md).
## Building
JDK 21 and the Android SDK. On a machine with no default Java, which is the
usual state of a Mac. Gradle reports "Unable to locate a Java Runtime" rather
than anything about JDKs, so set it explicitly:
```bash
export JAVA_HOME=/opt/homebrew/opt/openjdk@21
export ANDROID_HOME=$HOME/Library/Android/sdk
./gradlew :engine:test :client:test :app:testDebugUnitTest
```
Those three suites are the merge gate.
JVM crypto tests prove nothing about Android. The JVM's JCA and Android's
Conscrypt are different providers with different opinions. X25519/X448 need DER
key specs and API 33 on device, and code that passes `:engine:test` on the JVM
can throw on a handset. Anything touching key agreement or signatures needs an
instrumented test, which is why `interop/` exists.
Instrumented tests are not in the gate: they need an emulator and a local relay.
## What a change needs
- **Touching the wire?** iOS and the relay move with you. A field this client
required and the relay never sent broke groups completely while every unit
test stayed green. **Diff the wire types first.**
- **Touching state that arrives incrementally**: avatars, rosters, device
lists, merge, never replace. Absent from a fetch means "not loaded yet", not
"deleted".
- **Touching WebRTC callbacks?** Never let an exception escape one. It does not
surface as a caught error, it `SIGABRT`s the process. Calls have crashed this
app twice that way.
- **Adding a permission?** Declare it *and* verify on device. A missing
`ACCESS_NETWORK_STATE` presented as a dead button, not as a permission error.
- **Writing KDoc that mentions a path like `/e2e/*`?** Kotlin does not nest
block comments, so `*/` inside one closes it and the compiler reports
"Unclosed comment" at the end of the file, hundreds of lines from the cause.
## Releases
The signed release APK is built with a keystore that is **not in this
repository and never will be**, it is public. Signing keys are permanent for
the life of an installed app: a key change means every existing user must
uninstall and lose their local history, so the certificate identity is not
something to fix later.
## House rules
- Fail closed. Unverifiable signatures, unknown versions and unpinned identities
are refusals, and the user is told which.
- Never log message contents, keys, or tokens.
- No secrets, keystores, or passphrases in the repository.
- Match the surrounding style. Comments explain why a line exists, usually,
which attack or which platform quirk it accounts for.
## Comments and prose
Plain text. No emoji or symbol markers, no markdown bold inside code comments,
no em-dashes. Say what the code does and why, briefly; the history of how it
got that way belongs in the commit message, not in the file.