Story Android rehearsal¶
CANCELLED 2026-10-25 (owner).
~/.local/share/story-android(25 GB) and~/.cache/story-androiddeleted;~/.android(adb key) and~/story-publisherkept. Rebuilding needs the SDK/AVD set up from scratch. Was: PAUSED 2026-10-16 (Facebook/Instagram). Flag~/.config/social-paused; resume steps in content-pipeline "Social pause". Website notes keep publishing.
User-space Android tooling for Story publisher.
Source repository /home/angel/story-publisher, branch sandbox (the branch cron runs; private remote github.com/EmbeddedEra/story-publisher, corrected 2026-10-14).
SDK/JDK, AVD and Appium extension state live in ~/.local/share/story-android.
Downloads live in ~/.cache/story-android. Owner-authenticated Google/Meta session state is retained only in the private AVD.
Dedicated API 35 AVD story_rehearsal_api35, 480×800, 1536 MiB explicit lowram,
Intel host graphics, Vulkan disabled. rehearse_android.py creates only a
transient user service story-android-rehearsal.service: 2300 MiB max, zero swap,
150% CPU, 256 tasks and a default 480-second hard deadline.
--observe-seconds accepts 60–900 seconds (default240); the hard deadline adds240seconds. Foreground monitor adds an
available-RAM start gate and abort floor. No timer or boot autostart exists.
start_appium.sh creates transient story-appium-rehearsal.service: 512 MiB,
zero swap, 100% CPU and 600-second deadline. Appium listens on 127.0.0.1:4727;
UiAutomator2 uses port 8299. Emulator serial/console port is emulator-5580.
ADB's user daemon uses loopback 5037. Source android_env.sh for tool PATH;
no global shell profile was modified.
If you change this¶
Keep production social queues and ownership untouched until the approved pilot.
Recheck host available memory and the actual cgroup limits before every run.
Do not silently raise caps: initial API 35 boots without lowram hit the cap.
Stop only the two rehearsal units on failure. ADB may be shared by another
Android task; check before killing its server. Runtime metrics and screenshots
are ignored under the local source repository's runtime/ directory.
Media/link and Play Store rehearsal — 2026-09-22¶
Added Android platform 35 build stubs and a local offline test APK, built with existing Java/aapt2/d8/zipalign/apksigner tools. The fixture has no requested permissions and no Internet access. It displays a packaged PNG, stores an HTTPS URL, persists it across app restart and forwards it to an internal Activity after a native click. This is not a provider upload or browser destination check.
Added the official Google Play API 35 revision 9 image and separate AVD
story_playstore_api35. It uses the same resource limits and cannot run alongside
the original profile on the shared port. Real Play Store version 41.3.25 resolves
Instagram's market URI and reached the unauthenticated sign-in screen. No Google
or Meta account was signed in. Existing EmbeddedEra accounts are the chosen test
target; actual publications still require existing approval.
The Play image is not accepted for unattended operation at 1536 MiB: ADB was intermittently offline and guest lowmemorykiller killed a Google services process. Host cgroup OOM is distinct from guest pressure; the observed Play run did not hit host cgroup OOM. Prefer adequate host RAM/normal guest allocation before a production pilot; see the machine card's 32 GB recommendation and unverified module layout. Both profiles remain bounded, manually invoked development tests.
Normal-memory Play retry — 2026-09-22¶
After the owner stopped ERP sandbox, Play profile uses 2560 MiB guest RAM without
lowram, 3584 MiB cgroup cap and 4600 MiB MemAvailable start gate. Original profile
limits unchanged. Both retain zero host swap, 700 MiB sustained host abort floor
and bounded automatic teardown. Source commit 2cdde2d.
The Play profile passed the offline media/URL/restart fixture and 18 consecutive ADB probes. Official Play Store 41.3.25 still requires Google sign-in; no account login, Meta app installation or publication performed. Background Android service reclamation was observed, so fixture success is not unattended social-app acceptance.
Phone account setup — 2026-09-22¶
~/android-login (also ~/.local/bin/android-login) starts transient
story-android-login.service; stop and status subcommands are available.
Procedure: SOP-041. Source: ~/story-publisher/android_login.py and browser_auth.py.
Runtime: separate Xvfb :91, official scrcpy 4.1, x11vnc Unix socket only,
noVNC 1.7.0/websockify 0.13.0 on 127.0.0.1:6089. No X/desktop sharing or TCP VNC.
4608 MiB/no swap, 150% CPU, 30 minutes, host start gate 5200 MiB; early cgroup
and host memory guards. Shared AVD lock excludes rehearsals. No boot startup.
https://android.embeddedera.com/vnc.html routes through the plex tunnel with
Administration-only Google Access app EmbeddedEra Android; onboard admin
mapping includes it. cloudflared validates the app AUD and browser_auth verifies
JWT signature/issuer/audience/expiry/email and websocket Origin. Private origin
config: ~/.local/share/story-android/browser-access.json. Owner login state
is retained in the AVD, never version controlled. No input/frame recording.
User-space dependencies, checksums and local browser verification are documented
in ~/story-publisher/docs/LOGIN.md. Google/Meta owner login is pending.
2026-09-22 owner Google Play login succeeded. Official Meta apps now installed via com.android.vending: Instagram448.0.0.52.84 and Facebook579.0.0.52.74. Native launches observed; Meta account authentication and Story capabilities remain unverified. Owner phone session remains bounded and no account input is recorded.
2026-09-22 evening: owner logged into Instagram; own professional embedded_era profile verified. Native Story menu exists; photos permission/media/link-sticker rehearsal remains pending. Facebook owner login is next. No posts or Story submissions.
2026-09-22 evening: Facebook owner login completed and active EmbeddedEra Page identity verified via native menu and Professional dashboard. Both Instagram/Facebook identities authenticated; login service stopped after verification, AVD retained. Session persistence across restart and clickable Story capability remain to be tested. No publication.
Native Story composition — 2026-09-22¶
Current headless Play profile: 2560MiB guest, 4096MiB cgroup cap, 4800MiB host
start gate; zero swap, 700MiB sustained host floor and shared device lock retained.
Browser login profile remains separately capped at4608MiB/start5200MiB.
Both Meta sessions persisted across restart. Instagram's native Link sticker and
Facebook Page Custom link accepted the website URL in unpublished test editors.
Drafts discarded; emulator stopped. Facebook full image/video permission was
revoked after testing; selected-photo permission remains. Technical results and
limitations: ~/story-publisher/docs/META-REHEARSAL.md. This is not proof of a
published link or unattended reliability. No real Story was submitted.
Draft-only driver — 2026-09-22¶
~/story-publisher/rehearse_meta.py --platform instagram|facebook --account NAME
uses native ADB/UIAutomator with the separately supervised headless Play AVD.
It holds runtime/meta-driver.lock, refuses a running phone viewer, verifies the
known app version/own account/fixture, and stops at unpublished composition and
discard. No new service, timer, listener or public repository. Temporary media
permissions are restored and verified; camera/audio requests are denied. Per-run
reports and editor screenshots stay in ignored private runtime/meta-rehearsals/.
Final cold-boot composition/discard runs passed on both platforms; emulator is off.
Source 4dce262; procedure/limits docs/META-REHEARSAL.md. No live publication.
2026-09-22 handoff check: rehearsal, browser login and Appium units all inactive. No runtime configuration changed during the memory/notes update. Public Story content rules and real-note pilot readiness belong in ../../../projects/story-publisher and ../../../projects/story-publisher-pilot; the fixed-fixture runner remains unchanged.
Real-note previews and session independence — 2026-09-23¶
The real-note draft mode and evidence belong in ../../../projects/story-publisher
and ../../../projects/story-publisher-pilot. Runtime limits remain unchanged.
Foreground tool monitor/driver processes received external SIGTERM during this
session; the sender was not established. Temporary user units
story-android-pilot-monitor, story-android-pilot-instagram and
story-android-pilot-facebook completed the final drafts independently of the
calling session. They are created on demand with systemd-run --collect, not
installed/enabled services or timers. No boot autostart or publishing schedule.
Monitor:128MiB/no swap,64tasks,840-second hard limit; it runs the existing
600-second bounded Play observation, retaining the4096MiB emulator cap and
4800MiB start gate. Drivers:128MiB/no swap,64tasks,450-second limit and95-second
stop allowance. The existing device lock still excludes concurrent drivers/viewers.
SIGTERM handling and atomic private draft checkpoints preserve the original
permission baseline for recovery. Procedure: story-publisher/docs/REAL-NOTE-PILOT.md.
Final drafts explicitly discarded; known fixture JPEG restored. Both apps'
READ_MEDIA_IMAGES and READ_MEDIA_VIDEO were verified false before shutdown.
Facebook began its final run with full grants true, so final cleanup explicitly
restored the documented restricted baseline rather than claiming that was its
starting state. Selected-photo grants were not changed. One earlier zero-byte
interrupted media file was quarantined outside the gallery, not assumed valid art.
Private evidence: story-publisher/runtime/pilot-2026-09-23/final-cleanup.json.
Rehearsal/login/Appium units inactive and pilot units stopped/collected at handoff;
host available5019MiB. No live Story was submitted.
Resized for 40 GiB host — 2026-09-25¶
Measured after the RAM upgrade (source 152e431, branch sandbox). Old Play profile sat
on its 4096 MiB cap from 80 s and on the 150% CPU quota for ~2.5 min; guest had ~1.1 GB free.
Current limits, all zero swap, 700 MiB host abort floor unchanged:
| Profile | Guest | cgroup cap | Start gate | CPU | Measured peak / boot |
|---|---|---|---|---|---|
Play story_playstore_api35 |
4096 MiB | 7168 MiB | 8000 MiB | 200% | 6.1 GB / 24 s (was 35 s) |
Plain story_rehearsal_api35 |
2560 MiB, no lowram | 5120 MiB | 5900 MiB | 200% | 4.3 GB / 24 s |
| Browser login | 4096 MiB | 7680 MiB (early guard 7300) | 8500 MiB | 200% | not run; needs owner session |
200% matches -cores 2; the guest stays CPU-bound for minutes after boot either way (Play
services settling), so more CPU would need -cores 3 on a 4-thread host — not done.
Guest am_kill counts (2-4 per run) persisted with 2 GB free: normal cached-process trimming,
not a pressure signal. Earlier sections' numbers are history.
GPU check 2026-09-26: every run logs "Your GPU cannot be used for hardware rendering" yet the
renderer is Mesa Intel HD Graphics 630 via gfxstream — the warning is cosmetic. A/B on the
Play profile: -gpu host boot 24 s / peak 6.1 GB vs swiftshader_indirect boot 50 s / peak
7.2 GB (hit cap). Keep -gpu host; the post-boot CPU load is Play services, not rendering.
Quick-boot snapshot — 2026-09-26¶
Source story-publisher commit after 152e431 on sandbox. -no-snapshot removed from
rehearse_android.py and android_login.py: the emulator saves default_boot on a graceful
exit (adb emu kill, waited up to 90 s; unit TimeoutStopSec 90 / login 120) and resumes from
it. Play AVD: resume 9 s vs 24 s cold, avg CPU 29% vs 86%; save ~8-10 s; snapshot 3.8 GB in
.../story_playstore_api35.avd/snapshots/default_boot. Account/app state already persisted on
disk, so behaviour is unchanged except running-app RAM state now carries over too.
Fallbacks: a changed -memory/GPU/cores flag or a failed load means one cold boot; a hard kill
skips the save and the next start resumes the older snapshot. Save briefly pushes the cgroup to
~7.0 GB of the 7168 cap (page cache, reclaimable). Login profile shares the same flags so the
snapshot should load there too; not yet run with the owner. To force a clean cold start,
delete the default_boot folder while the emulator is stopped.
Cron needs the user bus — 2026-09-27¶
The first unattended Story from cron failed: story-publish-due ran every 15 min from 09:15 with Could not start the bounded emulator: Failed to connect to bus: No medium found. Cron has no login session, so systemd-run --user had no XDG_RUNTIME_DIR / DBUS_SESSION_BUS_ADDRESS. Fixed in ~/.local/bin/story-publish-due (untracked file) with os.environ.setdefault to /run/user/<uid> and its bus. This works because Linger=yes keeps the user manager up. The 27 Sep Facebook Story was posted at 10:00 after the fix. Anything else started from cron that calls systemd-run --user or systemctl --user needs the same two variables.
2026-10-14 blocked slot and collision fixed¶
18:15 Instagram slot blocked on 'Expected screen not established: Profile' (4th time): wait_drawn returns on the first app window and the old four quick looks for 'Profile' gave up before the tab bar drew. 18:30 retry failed: monitor unit still active ('already loaded'). 18:40 hq-retry posted it (story 18478460029119045, ~35 min late). Fixed in story-publisher 222cddd: Profile waits up to APP_DRAW_SECONDS; a blocked untouched slot stops both rehearsal units; the settle wait checks the monitor unit too.