diff options
Diffstat (limited to 'CLAUDE.md')
| -rw-r--r-- | CLAUDE.md | 55 |
1 files changed, 54 insertions, 1 deletions
@@ -28,7 +28,9 @@ meshbay/ ├── packages/ │ ├── meshbay-common/ # Shared crypto + protocol — python3-meshbay-common RPM │ ├── meshbay-hub/ # Hub server (FastAPI + PostgreSQL) — meshbay-hub RPM -│ └── meshbay-node/ # Node daemon + local UI — meshbay-node RPM +│ ├── meshbay-node/ # Node daemon + local UI — meshbay-node RPM +│ ├── meshbay-client/ # Desktop client (Electron) +│ └── meshbay-android/ # Android client (WebView shell, Kotlin) — README.md ├── poc/ # POC spike scripts (reference, not production) ├── docs/ # Architecture drafts and POC plans ├── packaging/ # RPM spec files, DEB control files, systemd units @@ -882,6 +884,43 @@ do. Read them before writing anything that touches the same mechanism. message later by `update_groups`, which assigned its list verbatim. A limit enforced on one path is not enforced +- **Chromium freezes a hidden page sixty seconds after hiding it**, in an + Android WebView as in a tab, and nothing about the *process* changes that: a + media-playback foreground service, a partial wake lock, a Wi-Fi lock and + `setRendererPriorityPolicy` all failed to keep a casting page alive with the + screen off (spike, measured by a heartbeat and the page's own `freeze` + event). What works is the shell telling the WebView its window is still + visible (`ShellWebView.keepVisible`) — set while a cast runs and only then. + Audible audio also exempts a page; a phone humming in the room is not a fix + +- **A first chunk is not a header.** The relay took the page's first decrypted + chunk as the stream's header. On a real film that chunk was by turns 64 KB + (header plus film), 28 bytes (the ftyp alone, the moov in the next push), or + the header exactly — depending on when the node read ffmpeg's output — so the + same film cast on the third try and not the first. The header is everything + before the first moof; boxes, not chunks, are the unit + +- **A seek's first segments came during its own landing and were thrown away.** + `reinitAt` waits on the SourceBuffer; the new stream's first segments arrived + in that gap and the `awaitingInit` flag dropped them as the old film's. The + local player never showed it — its SourceBuffer kept the header from the + start of the film — and a cast relay restarted at that landing received a + stream with no header. Ordering, not the flag, says which stream a segment + belongs to: everything after `stream_init` is held and replayed + +- **A drop threshold sized for small chunks drops whole segments.** The relay + dropped a fragment once 8 MB waited for a receiver; at a film's bitrate one + fragment is 5–10 MB, so a receiver simply reading at playback speed lost + fragments and the picture froze for each. Nothing logged it until a drop + counter was added. The lead now waits in a spool file + +- **When a receiver stops answering, prove which leg failed before reading code.** + A first cast failed every time and two code fixes changed nothing; the cast + framework's own log said `onSocketConnectionFailed … IO Error` to the + receiver's port 8009, and the phone could not ping the receiver while this + machine could. The receiver was half-crashed; a power cycle fixed it. A + machine that reaches the receiver proves nothing about the phone + **Corrections that used to live here** — `punch_nat()` is not a traversal stack, the node keystore's Argon2id parameters, what group chat actually uses, and what is sealed on the wire — are now design statements in `docs/MESHBAY_DESIGN.md` @@ -989,6 +1028,20 @@ here are kept only where they are a rule about *editing* the code. | Node page | `node-page.js` | §6.7 | | i18n | `i18n.js`, `locales/*.js` | `en.js` is the source; **ten catalogues, and a new key goes in all ten** | +### Android (`packages/meshbay-android/`) + +Built with `./gradlew assembleDebug` / `assembleRelease` (JDK 17+, an Android +SDK); `./gradlew testDebugUnitTest` runs the JVM tests, which pytest also runs +when `ANDROID_HOME` is set (`test_android_shell.py`). + +| Need | File | Note | +|---|---|---| +| The shell, the asset loader, the CSP | `MainActivity.kt`, `shell/UiAssets.kt` | the CSP is `main.js`'s, held equal by `test_android_shell.py` | +| The bridge | `assets/bridge/meshbay-bridge.js` (the preload's counterpart), `bridge/Bridge.kt`, `Channels.kt`, `KeyChannels.kt` | **absent, not refusing**, for what a phone lacks; every channel the shim names is the preload's | +| Keys | `keys/Kdf.kt`, `Keyring.kt`, `Transcripts.kt`, `SecretStore.kt`, `DeviceKey.kt` | **held to `meshbay-hub/tests/vectors/keyring.json`**; regenerate it with `gen_keyring_vectors.js` only for a deliberate format change | +| Downloads | `save/SaveSinks.kt`, `SaveNames.kt` | `OPENABLE` is `downloads.js`'s, compared by `test_android_downloads.py` | +| Casting | `cast/CastRelay.kt`, `CastControl.kt`, `CastChannels.kt`, `CastService.kt`, `shell/ShellWebView.kt` | `MeshBayCast` in logcat says what the receiver and the relay did | + ### Test harnesses that drive the real thing | Need | File | |