Story publisher¶
Local repository: /home/angel/story-publisher, branch sandbox. No remote or production integration.
Current handoff — 2026-09-23¶
- Today's published feed article is Browser-based firmware flashing without an installer, selected from the current calendar, not a new research queue. Both proposed Stories use its exact public article URL. Review artwork, actual native-editor previews, link policy and proposed times in story-publisher-pilot.
- Angel approved both pilot Stories and their exact times at06:45EDT. The two payloads are in the local approval ledger; no Story was submitted, posted or viewer-link verified, and no publisher is armed. Angel also delegated future routine Story reviews/approvals to the assistant. Perform a distinct Story review and record delegated reviewer identity; do not ask for repeated owner confirmation. Existing feed slots/IDs and all eight canceled Postiz Stories remain unchanged.
- Local source
~/story-publisher, branchsandbox, commita23ad9e.--proposalextends the existing draft/discard runner with strict matching article/day/account, hashed portrait PNGs, exact URL readback and placement-bound review fingerprints. It still has no Share operation. The historical homepage fixture remains available only as a technical fixture. - Final real-note drafts passed on Facebook (
1790159649545225036-facebook) and Instagram (1790159754341839192-instagram). Both were explicitly discarded and the gallery restored. Primary inspected the editor screenshots. Instagram uses the native default centered sticker, clear of all copy; custom drag attempts were rejected during visual review and removed. Facebook's native Custom link was confirmed by exact URL entry/readback and Remove action link; its viewer rendering remains unverified. - Private proposal, final evidence, generated images/prompts and interrupted-run reconciliation:
~/story-publisher/runtime/pilot-2026-09-23/. No raw login input was recorded. Final permission cleanup verified both apps' full image/video grants false; Facebook had begun its final run with them true and was explicitly returned to the documented restricted baseline afterward. - The journal distinguishes
postedfromverifiedand blocks another claim in either uncertain or posted state. Real-note fingerprints include native link placement. 37 offline tests pass; six unchanged browser-auth tests skip under system Python. These tests do not prove a real publication or viewer click. - Android, login viewer, Appium and temporary pilot units are stopped/collected. Temporary systemd monitor/driver units allowed draft runs to survive tool-session interruption without changing the emulator's resource limits or adding a timer/autostart. Runtime facts: ../map/objects/host/story-android.
- Next dependency is technical: complete the controlled live adapter and viewer inspection for the already-approved two-platform pilot. No further content/time approval is required for these unchanged payloads. Establish single-platform sharing scope, record an uncertain attempt before one native submission, identify the resulting Story and click its link as a viewer to verify the exact article. Unknown outcomes must be reconciled before retry. Unattended-production acceptance and public release remain open.
Daily-package correction — September 23¶
The owner clarified the complete daily chain: prepare seven future packages ahead, release one new website note on its assigned day, then its Facebook feed/linked Story and Instagram feed/bio CTA/linked Story. All five outputs use one note/date. Approval is advance readiness, not permission to publish early. Android execution remains owned here.
Read content-pipeline and ~/assistant/docs/daily-content-queue.md. The website approval endpoint now queues an immutable note/date in note_queue within the existing content-approval SQLite ledger; /home/api/content exposes daily_note_queue. No daily-release timer is enabled. Do not call this a working end-to-end pipeline yet.
Prepare reviewed Story media/link payloads ahead even while the article is unpublished; public Story submission must wait for the exact article to be verified live on the assigned date and its platform feed to publish. Bind the parent slug, source digest, assigned date, exact URL, account, image identity, visible text and link placement. Finish the real-note Android pilot and viewer click evidence; connect readiness and outcomes to the parent daily package rather than creating an independent topic/date queue. Do not recreate Postiz media-only Stories or move the existing approved feed dates. Historical September23 website batch publication is an exception, not future buffer coverage.
Cross-chat inputs — 2026-09-23¶
The original handoff added no blanket approval. The later06:45EDT decision above explicitly approved the pilot and delegated future routine Story approvals; it supersedes earlier personal-confirmation requirements. Read content-pipeline, story-publisher-pilot, shared social automation/artwork preferences, SOP-018 and SOP-041 before resuming. Recheck current state rather than copying the September22 schedule snapshot.
The feed pipeline owns research, website-note approvals and Facebook/Instagram feeds. It maintains a rolling seven-day content supply; that count includes drafts and is not seven approved Story days. The Story workflow consumes the same notes and calendar. It must not create a competing research queue, change feed schedules or recreate canceled Postiz Stories.
Inputs to reconcile read-only: published notes in ~/embeddedera-site/src/content/notes/; matching social packages/artwork in ~/embeddedera-content/<slug>/; approved feed identities in ~/.local/state/assistant/content-approval.sqlite3; recent delivery observations in ~/.local/state/assistant/delivery-status.json. Verify the exact article on embeddedera.com is public. Drafts on the apple-style branch are not eligible until published. Record a Story payload with note slug/title, exact URL, source feed date, destination account, image identity, visible text/link label and proposed Story time. Existing feed approval is context, not automatic Story approval.
Use the vivid USB-C/schematic image direction; adapt for a readable vertical Story and native clickable link on each platform. The Android fixed-fixture composer is rehearsal evidence only. Complete the approval-bound real-note path and viewer click verification through the existing pilot process. Record platform, note/date, approval, attempt/Story identity, resulting link and any blockage in this project's existing ledger/notes. Reconcile uncertain submissions before any retry.
Phased execution plan¶
Scope authorized 2026-09-21: execute local development and feasibility work. Public repository release is deferred. Existing editorial approval and scheduling remain in place. No production content or posting time changes are part of this prototype. Account connection and a real test publication need a concrete pilot.
1. Feasibility — PC selected; bounded boot verified¶
On 2026-09-22 the user chose this Linux PC. KVM API 12 is usable without root.
A dedicated Android 15 emulator boots with explicit low-memory mode, 1536 MiB
RAM, 480×800 display and Intel graphics. It is confined to a 2300 MiB memory cap,
zero swap and 150% CPU quota, with a host-memory watchdog and automatic shutdown.
Initial default-memory attempts hit the cap; the emulator had silently raised
RAM to 2560 MiB. The low-memory configuration passed boot and idle observation.
Existing services were not stopped. The local development guide is ~/story-publisher/docs/ANDROID.md.
2. Offline foundation — implemented¶
Local sandbox Git repository, read-only host doctor, SQLite approval contract, duplicate protection, due-time gate, durable uncertainty and transition history. Fixture tests exercise approval changes, duplicate identities, crash/reopen, multiple connections, early/late schedules and missing or incorrect link evidence. No network clients or provider credentials are used in these tests.
3. Android rehearsal — automatic draft composition verified¶
The owner authenticated the existing EmbeddedEra accounts. Official Play installs are Instagram448.0.0.52.84 and Facebook579.0.0.52.74. Sessions persist across emulator restart. The Play profile uses2560MiB guest memory; current host limits are in ../map/objects/host/story-android. No permanent Android service exists.
~/story-publisher/rehearse_meta.py now automatically verifies the own account,
selects a fixed hashed JPEG, enters the exact website URL, applies the native link,
discards the draft and restores temporary media permissions. It has no publishing
operation and does not claim approval-ledger jobs. Both platforms passed the final
cold-boot run. Instagram requires separate screenshot inspection because its
native hierarchy omits sticker text; primary inspected the resulting screenshot.
The runner rejects unknown accounts, changed app versions, unknown gallery media,
ambiguous controls, moving targets and taps overlapping publish controls. Known
camera/microphone prompts are denied. Failed runs remain failed; force-stop is not
proof that a draft was discarded. No automatic retries or background schedule.
Twenty-four local guard/ledger tests pass. Technical guide: docs/META-REHEARSAL.md.
This proves controlled unpublished composition, not publishing, viewer clicks, production reliability or the seven-run/fault-case acceptance gate below.
4. Controlled linked-Story pilot — prepare real note and approved test¶
Use a matching Story image for a real published website note, its exact approved article URL, the intended account and an explicitly approved posting time. The homepage and blue/yellow fixture were technical tests only. Persist an attempt before the publish action, inspect the resulting Story, open its link as a viewer and capture the destination plus timestamp/Story identity. Screenshots alone cannot establish clickability. Validate media matching after platform transcoding.
Test network interruption, app restart, uncertain submission, expired login, wrong account, missing sticker controls and changed UI. Never blindly retry an uncertain post. Establish evidence freshness and reconciliation deadlines. Require seven consecutive successful controlled runs, plus fault cases, before migration. Failures stop that destination and become actionable alerts, not silent gaps.
5. Production integration — pending pilot¶
Reuse existing approval and daily coverage monitoring. Define a durable single owner per account/destination; migrate one destination at a time after checking its Postiz queue. No simultaneous schedulers for the same Story. Read-only shadow comparisons precede cutover. Implement authenticated approval ingress, content hash validation, bounded media intake, device leases, durable attempt/evidence records, stale verification alerts and explicit rollback/reconciliation procedures.
Migration preserves already-approved content/time. Any changed payload or time requires the existing approval process. Document the recurring operation in the canonical social SOP when real operation exists; this plan is not that procedure.
6. Public repository — later¶
Generalize account and brand configuration; retain a thin Postiz adapter. Add reproducible pinned installation, portable examples, CI with fixture-only tests, supported-device/version matrix, license and dependency review, contribution guide and failure-recovery documentation. Audit all history/artifacts for secrets, private media and session state before the owner-approved public release.
Acceptance limits¶
The prototype proves local ledger behavior and bounded Android boot/native UI control. It does not establish Android/Meta automation reliability, automatic clickable-link inspection, production readiness or a guarantee against every missed post. Those require the device phases and ongoing monitoring. Automated security challenges may still need intervention.
Log¶
- 2026-09-21: Executed host feasibility inspection and offline foundation. KVM API 12 works without root; emulator runtime held because available RAM was ~2.7 GiB and swap fully allocated. Twelve local tests pass, including abrupt subprocess exit after durable claim and rejecting observations older than the attempt. No installs, new services, account connections or provider writes. Existing production publishing untouched.
-
2026-09-21: Two bounded tool-free, Landlock-confined reviews requested
gpt-5.6-lunavia the subscription CLI; both completed. CLI did not return a resolved model version (unknown, not inferred). Primary reviewed and corrected evidence timestamp validation, added process-exit verification, and documented that synthetic evidence is not trusted provider proof. Capacity source codex-app-server observed weekly 23% at 2026-09-22 02:26:16 UTC; no API-key fallback. -
2026-09-22: User chose this PC. Installed isolated official Android SDK/JDK plus pinned Appium 3.7.0/UiAutomator2 8.7.0. Boot succeeded with explicit low-memory mode after two memory-capped failed attempts exposed the default 2560 MiB floor. ApiDemos 6.0.17 native menu navigation/back/screenshot and session cleanup passed. Production and sandbox assistant health both returned OK. No account connection, publication, root change or existing service shutdown. Two tool-free Landlock-confined review runs requested gpt-5.6-luna; exact resolved model was not reported. Primary corrected cleanup/failure reporting and added an isolated UiAutomator2 port.
-
2026-09-22 final validation: source commit
3edf9d6, clean sandbox tree; 12 ledger regressions and Python/shell syntax checks pass. Successful repeat cold boot took 34.8s, followed by four minutes of observation including fixture automation. Emulator peak 2070 MiB; minimum sampled host available memory 797 MiB; successful-run cgroup memory events recorded zero OOM/kill. Automatic teardown returned success and both rehearsal units stopped. Screenshot inspected visually. Prior failed capped runs are preserved separately in private runtime reports. -
2026-09-22 media/link follow-up: complete fresh-install fixture test passed after primary corrections for bitmap decoding, exact asset dimensions, strict URL parsing, saved/current input binding and forced reinstall to avoid stale APKs. Verified image rendering, exact URL persistence across force-stop/restart, native click handoff to an internal Activity, HTTP rejection and session cleanup. Twelve ledger regressions plus Python/shell syntax checks pass. The fixture has no requested permissions; it does not prove media upload, browser loading, Meta stickers or publication.
- 2026-09-22 native-app acquisition: installed official Play Store API 35 image in separate bounded profile. Confirmed real Store 41.3.25 market-link handler and visually inspected its Google sign-in screen. No Google/Meta login or publication occurred. EmbeddedEra accounts are the user-selected compatibility target. Low-memory Google process kills and intermittent ADB loss made this Play profile unsuitable for unattended acceptance; no host cgroup OOM was observed. Its failed fixture attempts and deliberate stop are retained as failed/incomplete evidence, not a pass. The original Google APIs profile remains the successful fixture target.
- 2026-09-22 RAM answer: live machine has 16 GiB installed; about 3.1 GiB available before tests. Recommend 32 GB total for this workload. Dell specifies Tower/SFF up to 64 GB (four UDIMMs) and Micro up to 32 GB (two SODIMMs). Occupied slots/module sizes unverified because SMBIOS read needs sudo password; no kit chosen, purchase, RAM change or unrelated service stop. Canonical hardware facts and Dell source are in ../map/objects/host/machine.
-
2026-09-22 delegation: implementation draft and independent review used two confined tool-free subscription runs explicitly requesting gpt-5.6-luna; CLI did not report resolved version. Primary corrected the draft and review findings and executed device tests. Draft initially loaded a resource instead of the required asset; corrected before first build. Reviewer caught a possible null bitmap and evidence overclaim; corrected and retested. Capacity source codex-app-server was fresh at dispatch, 26% weekly used; no paid API fallback.
-
2026-09-22 final state: local sandbox commit
b4c1938, clean tree. Fresh fixture pass completed; final original-profile boot/observation passed with automatic teardown, 34.6s boot, 2125 MiB peak emulator memory and 622 MiB minimum sampled host available RAM. Both rehearsal units inactive, production/sandbox assistant health OK. Official Play profile remains unaccepted; no login or posts. -
2026-09-22 Android continuation: after ERP sandbox shutdown, repeated 1536 MiB Play test still showed guest pressure and incomplete fixture restart. Increased only Play profile to 2560 MiB guest/3584 MiB cgroup with 4600 MiB host start gate. Full offline image/URL persistence/native handoff/invalid URL fixture passed; 18 repeated ADB probes passed. Twelve ledger tests pass. Commit
2cdde2d. Play Store reached unauthenticated sign-in; Google authentication remains required before official Meta app acquisition. No login or publication occurred. -
2026-09-22 Play retry final verification: boot 34.5 seconds, four-minute post-boot observation passed with automatic shutdown. Two full fixture runs passed (second after visiting Play Store); 18/18 ADB checks succeeded. Emulator peak 3163 MiB, minimum sampled host available 1738 MiB. Both rehearsal services stopped; production assistant healthy; ERP sandbox stayed off. Private runtime evidence retained. Google sign-in is the next gate; requested whether owner has direct desktop or remote access to arrange private authentication.
-
2026-09-22 phone login launcher: user requested one command from Easy SSH. Implemented
~/android-login/stop/status, transient bounded 30-minute unit, no boot start, private scrcpy/Xvfb/noVNC screen. Only Android is exposed. Google Access Administration gate created beforeandroid.embeddedera.comDNS/ingress; cloudflared and origin JWT validation enabled, admin mapping added to onboard. Manual stop/restart, actual 390 px browser/VNC touch and text delivery to offline fixture, local auth rejection tests, anonymous origin403 and public302 passed. Twelve ledger plus six authentication tests pass using their documented Python environments. All existing surfaces and Access reconciliation pass. Sourced107051; SOP-041 v1.0 draft published. Actual phone/Google/Meta login remains for owner; no publication or account login performed by agent. -
2026-09-22 independent review: two bounded Landlock-confined/no-tools subscription runs explicitly selected Fable and both returned
claude-fable-5-1. Architecture and code reviewed; primary corrected shutdown timeout handling, stale display recovery through Xvfb, early cgroup memory guard, and independently found/fixed x11vnc's IPv6 listener with explicit-rfbportv6 0. All VNC transport now uses a0600 Unix socket. Capacity source claude-cli-usage reported2%weekly at dispatch (observed1790094050) and postbatch (1790094826); no paid API fallback. Private review artifacts:~/.local/state/story-android-review-20260922/andstory-android-code-review-20260922/. Local test JWKS issuer removed before real origin config; no credentials/screens captured during owner authentication. -
2026-09-22 final lifecycle proof: shortened70-second systemd runtime reached its deadline after readiness, then automatically closed the session within about1second. No6089/VNC/emulator listeners or ready/Xauthority files remained; main production assistant healthy, ERP sandbox still off. Normal command remains30minutes (test override was transient and collected). Session left stopped for owner to start from Easy SSH.
-
2026-09-22 account setup continuation: owner completed Google sign-in; live Play Store catalog accessible. Installed official
com.facebook.katana579.0.0.52.74 andcom.instagram.android448.0.0.52.84; Android package manager reports installercom.android.vendingfor both. Facebook reached its logged-out Activity; closed it to keep one app in focus. Instagram launched and reached ModalActivity, but its accessibility dump exposed no readable labels, so exact visible login state is not verified. No passwords, verification codes, screenshots or account details captured. No Meta login completed by agent and no publication. Existing bounded phone session retained for owner to finish Instagram login; automatic deadline unchanged. -
2026-09-22 follow-up: Instagram accessibility labels finished loading. Selected I already have a profile and verified the existing-account login form (username/email/phone, password, Log in). Left that screen for owner; no field values entered.
-
2026-09-22 13:23 Eastern: Owner reported Android browser timeout. Verified the 12:49:46 bounded session ended at 13:18:58; an immediate owner restart had hit a transient port-in-use error. Restarted the existing launcher successfully at 13:22, verified Android boot completion and active browser unit, then reopened Instagram using its resolved MainTabActivity. Both official Meta packages remain installed; no login fields/screens captured, account authentication inferred, or publication performed. Normal 30-minute expiry remains.
-
2026-09-22 20:12 login recovery: owner screenshot showed noVNC websocket failure. Tunnel logs and unit journal established that the session exited at20:11:34 via the3800MiB early memory guard, not SSH closure or a login error. Host had5473MiB available after shutdown. Raised only login service cap4096→4608MiB, early guard3800→4250MiB, and start gate5000→5200MiB; retained zero swap,700MiB host floor and30-minute deadline. Restarted for owner login.
-
2026-09-22 owner Instagram login verified live: profile username
embedded_era, Edit profile and Professional dashboard controls confirm own professional account. Dismissed optional saved-login-info prompt without storing a password. Create New → Story exists; entry requested photo/video permission. No media selected or uploaded, permission not granted, no Story published. Exited and stopped Instagram to conserve guest RAM, then opened Facebook for owner authentication. Link-sticker availability remains unverified. -
2026-09-22 owner Facebook login verified. Native profile menu offered EmbeddedEra; switched into the Page and verified EmbeddedEra, see your profile, Professional dashboard, and Create story while acting as the Page. Dismissed optional Google Password Manager saving, did not inspect or record credentials. Both requested social identities are now authenticated (Instagram
embedded_era, Facebook EmbeddedEra). No Story media, link sticker, share or publish action taken. Closed temporary login service after verification to release RAM; retained AVD. Next: verify session persistence and rehearse media/link composition with a harmless fixture before any separately approved publication. -
2026-09-22 nonpublishing composition: Instagram448.0.0.52.84
embedded_eraand Facebook579.0.0.52.74 EmbeddedEra Page sessions survived restart. Instagram loaded the180×320PNG with selected-photo access; Link Sticker accepted https://embeddedera.com/ and displayed EMBEDDEDERA.COM. Explicitly discarded. Facebook did not list thatPNG under selected, image-only or full media permissions; a1080×1920JPEG appeared under full access. Native Page Link→Custom link accepted the URL, confirmed “Link added”, and exposed Remove action link. Discard photo returned to picker; closed it and reverified own EmbeddedEra profile. No Share action, publication, viewer click or destination test. Facebook full images/video permissions revoked afterward; selected access retained. Format/dimensions/permission causes not isolated. Source evidence guidedocs/META-REHEARSAL.md; private screenshots/results in ignoredruntime/meta-composition. -
2026-09-22 resource/cleanup: headless Play cap increased3584→4096MiB/startgate4600→4800MiB; guest2560MiB unchanged. Added bounded60–900second observation option, default240. Original profile and browser login caps unchanged. First run boot34.6s/peak3570MiB/minhost1832MiB ended via externalSIGTERM and cleaned up; preserved as interrupted, not an observation pass. Second run completed Facebook editor checks and was deliberately stopped before its deadline; report correctly says emulator_stopped, cleanup succeeded, hostavailable5335MiB. Twelve ledger regressions and Python syntax pass; six browser-auth tests skipped under systemPython (unchanged auth). Tests and small runner adjustment kept local; no new helper this turn. Production posting untouched.
-
2026-09-22 draft automation: source sandbox commit
4dce262adds fixed-fixturerehearse_meta.py, exact account/version/media/URL checks, stable-position taps, native permission denial, explicit discard and verified media-permission restoration. Final cold run passed Facebook then Instagram without operator taps. Primary inspected both final screenshots; Instagram domain visible. Reportsruntime/meta-rehearsals/1790127227194895064-facebook/and1790127356529604778-instagram/; acceptance/visual-review files are private. No Share control, real Story, ledger claim, queue mutation or publishing timer. Earlier blocked development runs retained as failures; initial cold navigation failed before draft entry, then passed after position stability checks. Native UI still can change; no production acceptance claimed. - 2026-09-22 validation/review: twelve XML/interaction guards plus twelve ledger tests pass; six unchanged browser-auth tests skipped in systemPython. Python compile and diff checks pass. Confined Fable and explicitly selected GPT-5.6-Luna review attempts both stopped at changed CLI hash validation; neither model ran, no pin bypass or paid API fallback. Reviewed locally. Capacity source codex-app-server observed1790125320 at dispatch; later1790126522. Claude refresh observed1790125592, subsequently stale. Review failure artifacts remain private in
~/.local/state/story-draft-*-review-20260922/. -
2026-09-22 final runtime: cold boot34.6s, peak3634MiB emulator memory, minimum host available1654MiB. Deliberately stopped after accepted drafts; supervisor correctly records emulator_stopped, not an idle-observation pass. Cleanup succeeded and host available5400MiB. Exact-image pilot proposal is story-publisher-pilot; unapproved, no time selected, nothing queued.
-
2026-09-22 documentation handoff: owner explicitly requires links to each matching published website note. Superseded the homepage/blue-yellow public pilot proposal; retain those only as technical evidence. First live test remains conditional on a selected live note, matching artwork, exact URL/time approval and viewer verification. The runner is still fixed-fixture; no code, queue, publication or runtime change made in this documentation task. Shared preference memory and its vault mirror updated.
-
2026-09-23: Prepared the first real-note Story review package from today's existing WebUSB feed pair, verified the public exact article/canonical/title by browser-agent GET, generated vivid vertical art via the built-in image tool and rehearsed both native links. Final payloads, screenshots and proposed times are in story-publisher-pilot; all remain pending approval. No feed, research-controller, Postiz or public website mutation. Source
a23ad9eadds real-note proposal validation, draft checkpoints, placement-bound fingerprints and separate posted/verified evidence states; 37 offline tests pass, six unchanged auth tests skip. - 2026-09-23 recovery/limits: earlier foreground monitor/driver SIGTERM interruptions and one empty gallery orphan were retained as failed/incomplete evidence. The empty file was quarantined; a later interrupted unedited Instagram draft was explicitly exited and its own profile verified. Bounded transient user services completed final drafts. A swipe covered the subtitle and the held gesture did not move the sticker; both custom-drag approaches were removed in favor of the visually reviewed default center. No submission occurred. Final runtime stopped; host available5019MiB. See private pilot evidence and host card.
-
2026-09-23 delegation: applicable SOP-025/capacity/runner state checked. Both installed Claude and Codex CLI digests differed from the confined runner's validated pins; no worker was launched and no pins/permissions or paid API route were bypassed. Primary Codex implemented/reviewed; built-in image generation produced the artwork. Pure file/XML/SQLite tests made no provider calls; an additional bubblewrap isolation probe failed before test execution and is not counted as an isolated pass.
-
2026-09-23 06:45 EDT: Angel explicitly approved both exact pilot fingerprints/times and delegated future routine Story approvals to the assistant. Saved
runtime/pilot-2026-09-23/approval.jsonand two queued approvals inruntime/pilot-ledger.sqlite3; no claims/submissions or armed dispatcher. Shared preference memory and mirror updated. Approval is no longer a blocker; native publishing/viewer completion remains the technical blocker. Future reviews must be substantive and attributed to the assistant under delegated authority. -
2026-09-23 (Claude, after Codex hit its usage limit at ~08:30): committed the two pieces Codex left finished but uncommitted, and cleared the test-runner regression its previous commit introduced.
7b31b82makesparent_bridge.enqueue_reviewedtake its conflict decision inside aBEGIN IMMEDIATEtransaction instead of a racy read, and adds--supersede-queuedso a revised review cancels a prior handoff only while it is stillqueued— anything claimed, attempted or posted still refuses and demands explicit reconciliation, so a revision can never silently cancel work that may have reached Meta. It also addsmeta_observer.py, a read-only reader of our own Facebook/Instagram profile and Story list using the Postiz credentials already in the local database: fixed account IDs, no caller SQL, path restricted to''or/stories, regex-checked fields, redirects refused so a bearer token cannot follow one off the pinned host, capped response size, returned identity must match the account asked for, andlink_verified: falsebecause seeing a Story exist is not evidence its link works. - 2026-09-23 test runner:
6a0442dputstest_parent_bridge,test_meta_observerandtest_native_submissionback onunittest. They had drifted onto pytest in2d20c09, so the README's ownpython3 -m unittest discovererrored on all three — and with no venv here and pytest present only in an unrelated project's, a fresh clone could not run them at all. Same assertions and fixtures, expressed withsetUp/TemporaryDirectory,assertRaises(Regex)andmock.patch.object. 53 tests pass on the stdlib runner, six browser-auth tests skip as before, and they still pass under pytest. Working tree clean; both commits onsandbox. -
2026-09-23 gotcha:
~/story-publisherhas no git remote and only thesandboxbranch, so nothing here is backed up off-box. Worth fixing before the pilot carries more evidence. -
2026-09-23 first native Story published: Facebook Story
994199873704309went out from the Android emulator with the native article link, for the browser-firmware note. It is the first one this project has ever published; every prior run was draft-and-discard. Ledgerruntime/pilot-ledger.sqlite3, job2026-09-23-facebook-browser-firmware-rescheduled, state posted (not verified). Angel authorised republishing the 09:05 slot that the 15-minute claim window had already missed; the job was re-timed through a fresh proposal so the approval digest still binds the exact payload. - 2026-09-23 the failure that nearly looked like success: the Share tap appeared to do nothing — the Graph API listed no Story, and the post-submission screenshot showed Meta had raised an "Easily add to your story" home-screen-shortcut promo over its own editor. A modal swallows taps anywhere on screen, including a Share button it does not cover. A retry was queued; it blocked at photo selection without submitting. Then the Story appeared at 12:45:06, five minutes after the 12:39:50 tap: Facebook deferred the upload and reopening the app flushed it. The first tap had landed all along. The ledger's refusal to auto-retry an
unknownjob is the only reason this produced one Story instead of two — the retry job was cancelled during reconciliation. Treat "no Story in the API" within the first minutes as unknown, never as "not published". - 2026-09-23 guards added (
68a531f):native_submission.interstitial()runs beforeledger.claim, so a modal costs a run rather than a job that can never be retried;left_editor()runs after the tap, because the editor leaving the screen is the only on-device sign Share took.rehearse_meta --submitdismisses only a known interstitial, viaprotect_point, and stops on an unknown one. Marker list is meant to grow. -
2026-09-23 Story viewer mechanics (measured, previously all guesswork — the worker's pinned selectors were wrong exactly where it flagged LOW confidence): the own-Story entry is on the home feed story tray labelled
Your story/Your story, Unseen, not on the profile. Take the smallest node carrying that label; a larger container's centre lands on someone else's thumbnail. Stories auto-advance in about 5 seconds and Facebook injects sponsored stories, so a tree dump and a screenshot taken seconds apart can show different stories — press and hold to pause before reading anything. The accessibility tree is unavailable for a few seconds right after the viewer opens; retry.rehearse_meta.protect_pointfalse-positives onYour story, because its publish-word regex matches that phrase outside the editor. The link control on our own published Story has not been located in the tree yet;viewer_verification.pyis therefore unproven against a real screen. -
2026-09-23 evening: both platforms published a linked Story from the emulator. Facebook
994199873704309is verified — Angel opened the live Story and the native link took him to the exact article, recorded withobserved_by: owner:angel:manual-viewer-taprather than as a machine inspection. Instagram18173645989456382(https://www.instagram.com/stories/embedded_era/3992855420891135668) is posted, link not yet clicked. That is the project's original goal reached for the first time. - 2026-09-23 the two scheduled runs both failed, for dull reasons worth never rediscovering:
sys.boot_completeddoes not mean the gallery is writable. Measured directly: after the property reads 1, a touch-and-delete in/sdcard/Picturesneeded three probes over 14.7 seconds. Runs beginning 11s and 45s after boot died onrmreturningEFAULT('Bad address') against an existing file; the same command works minutes later, and the Facebook run that succeeded had merely started later.run_publication.storage_ready()now probes the operation instead of trusting the property and refuses to drive the app if the mount never serves writes.Device.remove_mediaadditionally retakes a file with a push before deleting.- The 15-minute claim window was shorter than boot + composition + one retry. It expired twice, and each expiry required hand-building a proposal at a new timestamp because the approval digest binds
scheduled_at. Nowledger.CLAIM_WINDOW_SECONDS = 3600, named, with tests expressed relative to the constant so widening it again cannot disarm the overdue check. - A guard of mine would have blocked Instagram forever:
sharing_scopetreated the presence of a "Close Friends" button as proof the draft targeted close friends. Instagram always shows it beside "Your story". Presence is not selection — it now refuses only when a foreign destination is actuallychecked/selected, and the scope evidence records that state. - The post-tap
left_editorcheck earned its place: on the attempt where the tap did not take, it refused to report success, so the ledger never claimed a Story that did not exist. That job staysunknownand will never retry — which is why one Story went out, not two. A failed submission now saves its screen before cleanup force-stops the app. - 2026-09-23 emulator window raised from 15 to 45 minutes at Angel's call (
rehearse_android --observe-secondsnow accepts up to 2700). Only the time bound moved; the memory cap, swap ban, CPU quota and host-headroom floor are unchanged. A publication plus its diagnosis does not fit in fifteen. -
2026-09-23 nothing is scheduled to publish tomorrow. Both of today's Stories were driven by hand. There are no Story timers and no queued jobs beyond today's expired ones. The remaining work, in order: a daily job that builds and enqueues both platforms' proposals; auto re-timing for a job that was queued and never claimed (safe, unlike
unknown); one emulator session serving both platforms; and provingviewer_verificationagainst a live Story sopostedbecomesverifiedwithout Angel tapping it. -
2026-09-23 late: the two halves are joined and scheduled.
~/.local/bin/story-handoff(daily 07:15) turns a day's approved package into publishable Story jobs — it writes the proposal the native driver loads, copies the artwork beside it and hash-checks the copy, then enqueues throughparent_bridge, which re-derives the digest and refuses anything that does not match the approval. Verified first that the assistant'sdaily_packagestage digest andparent_bridge.stage_digestproduce identical output on the same input; had they differed, every handoff would have been rejected for an obscure reason. Ran for real against 2026-09-27: both Story stages queued, both proposals validated throughproposal.load_proposalrather than by eye. - 2026-09-23 late:
~/.local/bin/story-publish-due(every 15 min) is the runner that was missing. It reads the ledger and only touches the emulator when a job is genuinely inside its claim window; one job per run, because the device is exclusive; never re-runs a claimed job. Simulated at the 09-27 slots: picks Facebook at 09:10, Instagram at 18:10, nothing at 11:30 once the window has closed. Kill switch at~/.config/story-publish.disabled. Both jobs are wrapped bycron-runand tracked bycron-watch(27 jobs green). - 2026-09-23 late:
engineering-deployis wrapped again, withcron-runinside theflock. It had been left bare becauseflock -nexits 1 on ordinary lock contention and would have paged for healthy behaviour; inside the lock, contention stays silent while a real failure of the deploy pages with its log tail. - 2026-09-23 late: everything is off this disk.
EmbeddedEra/story-publishercreated private (it had no remote at all), plusassistantmain and sandbox (11 commits with no upstream) and threeerp-configbranches holding 6 commits that existed nowhere else. Checked for secrets before creating the remote:runtime/,*.sqlite3and.env*are ignored and nothing secret-shaped is tracked. Gotcha: an audit using@{u}..reports zero for a branch with no upstream, silently hiding unpushed work — compare against--not --remotesinstead. -
2026-09-23 still open: nothing publishes before 09-27 because packages exist only for the 27th and 28th;
viewer_verificationremains unproven against a real screen (tonight's Instagram Story isposted, notverified, and expires about 20:20 on the 24th);CONTENT_DAILY_RELEASE_ENABLEDis still off; the artwork library still holds four images until Codex returns on the 28th. -
2026-09-24 both platforms verified, Instagram by machine. The Facebook Story was verified yesterday by Angel tapping it; the Instagram Story
18173645989456382was verified today by driving the emulator: own-Story viewer → "Visit Link" card → Instagram's in-app browser, which rendered the page titled Browser-based firmware flashing without an installer — Engineering Notes — EmbeddedEra. Evidence recorded withobserved_by: assistant:emulator-viewer-inspectionplusobserved_hostandobserved_page_titleverbatim, so the row can be audited rather than trusted. Ledger:facebook_story|verified,instagram_story|verified. - 2026-09-24 the viewer selectors were all wrong, and only a device could show it (
89d3c46): - The link sticker is not in the accessibility tree. It is painted into the story surface, so the original "find a node labelled link sticker" could never have matched.
- The owner's view carries a separate "Visit Link" card, and that is what opens the link; tapping the rendered pill does nothing. Neither is in the hierarchy, so the card is reached by a pinned region on the 480x800 screen — the module says so rather than pretending to find it.
- Instagram's in-app browser exposes only the host (
ig_browser_text_subtitle), never the full URL, so the oldurl_matcheswas checking something unobtainable. The page title is the evidence that the link reached a specific article and not merely the right domain; a test asserts the right host with the homepage title fails. - A first-run "Introducing a better way to browse" interstitial covers the page with a Done button.
- Stories auto-advance in ~5 s — the first tap landed on somebody else's story because a screenshot took too long.
- The tray entry is labelled
<account>'s story, N of M, Seen., far better than "Your story" (a container). On the profile, an "Add to story" plus-badge is smaller than the avatar, so a smallest-node rule opens the camera instead of the Story. That cost a run. - Resource guard worth remembering: the Play profile refuses to start below 4800 MiB available; it declined at 4564 and the failure looks like a hung boot unless the unit's journal is read.
-
2026-09-24 remaining on this project: re-run the rebuilt
viewer_verificationend to end against a live Story (each piece was observed, the assembled flow has not been); and wirestory-publish-dueto call it sopostedbecomesverifiedwithout anyone watching. -
2026-09-26 full login + dress rehearsal on the snapshot emulator. Scheduler-style start (
story-publication-monitor→rehearse_android1200 s) resumed from the quick-boot snapshot:boot_completedin 10 s, gallery writable on the first probe (cold boots needed ~15 s of retries), guest clock matched host, apps still Instagram 448.0.0.52.84 / Facebook 579.0.0.52.74.rehearse_metadraft-only with tomorrow's real handoff proposals (runtime/handoffs/2026-09-27/): Facebook EmbeddedEra 66 s and Instagramembedded_era100 s, bothown_account_verified → link_composed → draft_discarded, permissions and gallery restored. Instagram editor screenshot reviewed by primary: native link stickerEMBEDDEDERA.COMcentred, clear of headline and footer; Facebook Link action added. Graceful stop saved the snapshot in 3.9 s. Nothing submitted. Queued jobs for 09-27 (FB 09:05, IG 18:05) unchanged. - 2026-09-26 API check (scout, Sonnet): Meta Graph API v25 still refuses Story stickers —
ig-user/mediaSTORIES: "Publishing stickers (i.e., link, poll, location) is not supported"; Page Stories API takes onlyphoto_id/video_id. Buffer/Later/Hootsuite/Sprout fall back to phone-reminder flows for link stickers; instagrapi'sStoryLinkis not a visible sticker (issue #1139) and risks bans; Sked Social ($59+/mo) claims unattended link Stories via an undisclosed channel. Unverified lead: Meta Business Suite web scheduling with a link sticker, which would move publishing onto Meta's servers — worth a spike before building more emulator robustness. - 2026-10-13 Stories blocked since 10-12:
Claim differs from composed payload.parent_bridge.payload_forqueued the bare note URL while proposals carried the SOP-018 utm-taggedlink_url, so the claim digest never matched the composed payload. The claim runs first, so FB+IG 10-12 and FB 10-13 went tounknownwith no tap (nothing posted) and were never retried. The Jobs page showed them as "recovered" because the next run found nothing due. Fix: queuep['link_url']+ regression testtest_queued_url_is_the_tagged_story_link. The queued IG 10-13 row was rewritten in place to the tagged payload (backupruntime/pilot-ledger.2026-10-13-pre-url-fix.sqlite3). The threeunknownjobs still need a decision: repost late or let go. - 2026-10-13 So it cannot happen silently again. (1)
native_submission.submit_oncecompares the queued payload beforeclaim(): a mismatch now raisesQueued payload differs…and leaves the job queued (story-publisher f14ef0c). (2)Ledger.stuck()/abandon()+ CLIpython3 ledger.py stuck|abandon <job> <reason>; new stateabandoned= a person closed a job that will never publish. (3)story-publish-dueprintsSTUCKlines and exits 1 while any job is queued past its window or unknown >45 min, so the incident stays open (ops-scripts 7dc4475; job-failure hint in assistant 8d4a9c7). (4) job-fixer now gets repos named by the job's script read-only (ops-scripts 76c79b1); before that it could not see this repo and gave up. Firststuckrun found 14, not 3: 9 more from 09-23 to 10-11 had missed their window or stayed unknown with no alert. All abandoned with reasons (backupruntime/pilot-ledger.2026-10-13-pre-abandon.sqlite3). SOP-043 v1.1 step 5. - 2026-10-13 18:15 first run after the link fix passed the claim check and tapped Share on Instagram, but the editor stayed on screen (
Editor still on screen after the tap). Owner checked: no Story live; the Instagram post seen that evening was the separate Postiz feed post. Job abandoned with that reason. Root cause and fix: next line. - 2026-10-13 Instagram dropped Share tap. Same as 09-23: identical control geometry on all four Instagram runs checked (two good, two failed), editor unchanged after the tap, no Story live. Fix (story-publisher 1ddad74): watch 20 s (was 6), then one retap of the same control only if unchanged and with no modal, never a third;
retappedis recorded in the submission.run_publicationno longer says "job untouched" after a claimed tap (job-fixer spotted the contradiction). The failure screenshot had silently not been saved: capture now takes png + hierarchy with a fresh deadline and records capture errors. job-fixer (ops 07bda18) can now open a PR in a dependency repo (~/story-publisherin REPOS, kind story) when its own-repo pass finds nothing. SOP-018 v6.6. First real check: 10-14 09:05 FB, 18:05 IG. - 2026-10-13 19:19 supervised Instagram Story posted and verified (owner said "post it"; job
…:instagram_story:retest-1791932182, story 17935520874391981, link opened the note). First tap took; no retap. Getting there found two more faults: (1) Instagram 448 SIGSEGV in libstartup.so at launch, same fault address every time, Android then refused to restart it, so runs blocked at 'Profile'. Cause: a 0-byte/sdcard/Pictures/story-fixture.jpg(dated 09-22) in the gallery; removing it fixed launch. Publisher now removes an empty fixture itself (9a4c431 relaunch up to 3x, 993b972 wait for first frame, then the empty-fixture commit). (2) Host load does not shrink the emulator: it has a fixed 4 GB / 2 cores; cloud sessions run off-box. The 18:16 dropped tap is still unexplained (likely the same crashy state); the retap guard stays. - 2026-10-14: Instagram Story slot blocked at 18:15 (Profile tab not drawn in 4 quick looks), retry collided at 18:30 (monitor unit still up), hq-retry posted at 18:40. Fixed in 222cddd (timed Profile wait, stop units on a blocked untouched slot, settle on both units); job fixer's diagnosis used, its own fix had been discarded (test permission; separate task).
Open¶
- Validate sustained native social-app performance with the normal-memory Play profile. Host has one 16 GB DIMM and three empty slots (confirmed); ERP sandbox now off while idle. A 32 GB upgrade remains optional pending measurements.
- Complete the controlled native-publication adapter and viewer-click inspection under the now-approved real-note pilot; then run fault/recovery and sustained acceptance tests. See story-publisher-pilot.
- Public repository/license/release work remains deferred to phase 6.