feat: add EleBook offline individual browser - #33
Conversation
|
/gemini review |
|
@BMichaelJ Feedback from Astra. Just one issue: Returning from a profile resets catalog scroll position. off-grid-mobile/src/screens/IndividualBrowser/hooks.ts Lines 23 to 33 in 3fec524 clears its individuals, and switches to loading. This unmounts the catalog’s FlatList; returning from an individual therefore creates a fresh list at the top. Keep the list mounted while refreshing an unchanged pack, or restore its position. A regression test confirms the unmount. |
|
@JasonWildMe Thanks to you and Astra for catching this. Fixed in 7909eeb. A same-pack focus refresh now keeps the ready catalog and its existing FlatList mounted instead of clearing it, preserving native scroll state. Pack identity changes and failed refreshes still hide stale data. The real-navigation regression pauses the return refresh and asserts that the identical catalog instance survives, then covers both success and failure. It reproduced the unmount before the fix. Commit hooks passed: TypeScript, lint, and 1,008 tests across 67 Jest suites. The updated PR is running CI. The previously tested field.3 APK is unchanged and does not contain this follow-up; a new signed tester APK will be needed to validate this fix on device. |
|
/gemini review |
|
/gemini review |
Sign-in completed at Microsoft but storing the tokens failed on Android 9 with "Wrapped error: Keystore operation failed". The keychain service name embedded all six URL-encoded deployment fields (246 chars for the live config). Android 7-11 keep each Keystore key in a file named <uid>_USRPKEY_<alias> with most punctuation escaped to two characters, so the blob filename reached 289 bytes, over Linux NAME_MAX (255), and key generation failed with "could not rename blob". Sign-in could never complete on those devices. Digest the deployment key with SHA-256 instead. The alias is now a fixed 90 characters, tokens stay isolated per deployment, and the same deployment still maps to a stable service name. Devices that never stored a token (all Android <= 11) are unaffected; iOS and Android 12+ testers sign in once more after upgrading, matching the documented "legacy tokens are not reused" behaviour. Adds a regression test that models the Android keystore filename encoding and asserts a long deployment stays within 255 bytes. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
|
Pushed a fix for a sign-in blocker found while testing field.4 on Android 9 (BlueStacks "Pie64", live deployment config). Symptom. Microsoft sign-in completes, then the app shows "Sign-in failed: Wrapped error: Keystore operation failed". Logcat from the keystore daemon: Root cause. Fix ( Compatibility. Nothing changes for Android <= 11 (no token was ever stored there). iOS and Android 12+ testers who signed in on an earlier build get one fresh sign-in after upgrading; their previous entry stays in secure storage, matching the existing "legacy tokens are not reused" note. docs/setup.md updated accordingly. Tests. New regression test models the Android keystore filename encoding and asserts a long deployment stays within 255 bytes (fails at 338 bytes on the previous code), plus a pinned service-name fixture for the example deployment so the derivation cannot drift silently. Existing isolation/stability tests unchanged and passing. Reviewed independently with Codex (no Critical/Major findings; its two Minor notes on the test helper and docs wording are included). Version left at 0.1.0-field.4 for you to bump as you see fit for the next tester build. |
On BlueStacks (Android 9 on an x86_64 host, running the arm64 app through its ARM translation layer) detection failed with ONNX Runtime reporting "Load model from <path> failed. File doesn't exist", although the same file passed react-native-fs exists/stat checks and pack validation. The detector path was 290 bytes. The identical commit built for x86_64, which needs no translation, loads the model, so the translation layer fails native open() on that long path where the Java file APIs succeed. The length came from the pack directory keys: the project ID and pack version were UTF-16 hex encoded (4 characters per code unit, up to 40 code units each) and the full 64-digit artifact SHA was appended, so a single version folder was 147 characters here and could reach 227, close to the 255-byte component limit as well. Use a 16-hex-digit SHA-256 prefix per level instead, computed over the lossless UTF-16 encoding of the identity (plus the artifact SHA for the release level): `p-<digest>` and `v-<digest>`. Isolation per project and per (version, artifact) is unchanged, the identity length limits are kept, and the detector path is now about 100 bytes plus the model filename on Android and 150 plus the filename on iOS. Installed packs keep working because records store absolute paths; new downloads use the shorter directories. The pack format documents a 64-character detector filename budget. Tests: maximal 40-code-unit identities yield directory segments of at most 34 characters; look-alike labels and a different artifact of the same label get distinct unsuffixed directories; the derived names for the example inputs are pinned. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
|
Pushed a second fix from field.4 testing on BlueStacks (Android 9 on x86_64, arm64 app running through the ARM translation layer). Symptom. After sign-in and a successful pack download and validation, the first detection failed: The pack still re-validated as ready after an app restart, so the file existed and the Java file APIs saw it. Only ONNX Runtime, native arm64 code running through the translation layer, could not open it. The path was 290 bytes. Building the identical commit for x86_64 (no translation) made detection work, which pins the failure to native Cause. The extract directory keys encoded the project ID and pack version as UTF-16 hex (4 characters per code unit, identities up to 40 code units) and appended the full artifact SHA: the version folder was 147 characters for a 20-character version and could reach 227, close to the 255-byte component limit regardless of emulator. Fix ( Tests. New: maximal 40-code-unit identities yield directory segments of at most 34 characters (was 162 for the project level); look-alike labels and a different artifact of the same label get three distinct unsuffixed directories; the derived names for the example inputs are pinned so the derivation cannot drift silently. Reviewed independently with Codex; its Minor notes (lossless encoding for malformed UTF-16, repair-suffix masking in the test, filename budget, claim wording) are included. CI note for maintainers. The |
Summary
Add a pack-local, offline individual browser to EleBook. This is a scoped new feature, not full PWA parity.
No backend endpoint, model, pack publishing, profile editing, location history, PWA enrichment, or WhiskerBook reconciliation is added.
Type of Change
Screenshots / Screen Recordings
Android
Signed field.3 screenshots from the Pixel 9a. Device chrome, pack labels, names, and IDs are redacted. These are attachments, not files committed to the repository.
iOS
The CI native suite passed 45 tests on an iOS simulator. The new browser UI and a physical iPhone have not been field-validated; simulator unit results do not establish field parity.
Checklist
General
Testing
npm testincluding iOS on macOS CIReact Native Specific
Performance & Models
Security
Related Issues
New PR against
wildlife-reid, based on83c80149325e2670eb1bfae494db23a116da3d4b. PR #32 was merged by JasonWildMe and is not reused.Additional Notes
Review follow-up (9 September)
Jason/Astra's catalog-scroll finding is addressed in
7909eeb. A same-pack return refresh preserves the ready catalog and its mounted FlatList; pack identity changes and refresh errors still hide stale data. The actual-navigation regression asserts that the same list instance survives a delayed refresh and covers both success and failure.Local commit gates passed: TypeScript, lint, and 1,008 tests across 67 Jest suites. Follow-up CI is green on attempt 2: typecheck, lint, test, and Android debug/release builds passed. The first test-job attempt passed Jest and Android tests, then reported an unexpected iOS test-process exit during the existing
DownloadManagerModuleTests.testCompletedDownloadEntryPersistsUntilMovedtest. Retrying only that failed job succeeded with no source or native-test changes. Reply to Jason.Field.4 tester build
The field.4 version-only commit
919c516de9a1e207966a07dc93f99d9555a2bd76is pushed and is now the PR head. It matches the source used for the prepared signed0.1.0-field.4/1787551545ARM64 APK, which includes the scroll fix. Version-commit CI passed all four jobs on the first attempt: typecheck, lint, test, and android-build.APK SHA-256:
6b202a4e2ee361a4689f724cdadee78531a2728e7148585516801d6c52dfe9ed. Signature/certificate compatibility, version, architecture, non-debuggable status, alignment, bundled JavaScript/fixed hook, and approved deployment configuration were verified. The APK, checksum, TXT guide, and ZIP remain local and are not distributed.Field.4 has not been installed or device-tested. The field.3 bundle and historical device evidence below remain unchanged; field.3 does not contain
7909eeb.Existing tester APK
APK/device-tested commit:
3fec5243ca74de9265130b2eea9081156ace1b73.Signed APK:
0.1.0-field.3/1787551544,org.ganesha.elebook, ARM64, non-debuggable, bundled JavaScript; signing certificate matches field.2.APK SHA-256:
21f2a737b7abe1522d66f27e7ea5af2a7efee4ae8dfdc16fd2eeee1cdb0ee22f.Validation of the existing field.3 APK commit:
npm ci: all three version-pinned patch-package patches applied.npm run typecheck: passed with explicit configuration; commit hook also passed.npx eslint .: passed with two pre-existing warnings.npx jest --coverage --forceExit --maxWorkers=50%: 67 suites, 1,007 tests passed; 89.26% statements, 82.99% branches, 92.36% functions, 89.45% lines.npm run test:android: 18 tests, 3 suites, zero failures/errors/skips.npm run lint:android: passed, no new issues; 42 warnings filtered by baseline.typecheck,test,lint,android-build), including debug/release Android builds and 45 iOS simulator native tests. The CI release uses an ephemeral CI key; the field.3 tester APK uses the established release key.Remaining validation: iOS browser UI/physical field checks; observation-bearing legacy upgrade; exhaustive 189-reference image traversal; large-text/landscape and pinch gesture checks; physical pack replacement/removal, missing-file and multi-project matrices (automated coverage exists); failure/retry upload and other devices. This is not fleet acceptance or an identification-accuracy claim.
JasonWildMe is requested as reviewer. His scroll-retention finding is addressed as noted above; review approval remains pending. Gemini review was requested, but has not responded at the latest check; no review approval is implied.
npm cireported 30 existing dependency vulnerabilities (2 low, 18 moderate, 9 high, 1 critical). Dependency remediation is outside this feature and remains a separate approval decision.APKs, bundle, raw device evidence, and test fixtures remain ignored/local. Only the reviewed screenshots are attached above. This PR is a draft for Jason's review; no release publication, merge, auto-merge, force-push, or history rewrite is authorized.