dashboard.html — Feed and Timeline swap places; Feed is every platform's
capture now, not Twitter intel, so rows carry their own platform glyph and an
unknown platform renders neutral rather than being dropped. A row whose ts is
really first_seen reads "seen X ago": saying "just now" for a post of unknown
age is a lie that sorts it to the top.
dashboard.json — regenerated by the refresher; _yt_caveat dropped, the
activate fix made it stale.
deploy/home — dash, openbridge, refresh service and timer for this desktop.
Refresh every 30min with --skip-foreground, not kdmirah's 10min full pass:
there is a human at this box and the metrics table only needs enough
resolution to watch engagement move. No Restart= on the oneshot — a down
browser is a waiting state the refresher records and exits 0 for.
NAPKIN.md — the whiteboard: measured delay budget, the background-render
table, the three landmines earned (a DOM signal is a rendering question, %z
cannot come back out of struct_time, a pure time sort is not a feed), and the
open calls.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
capture.py — read the platform's own JSON instead of the pixels it painted.
Network capture on X (/i/api/graphql HomeLatestTimeline) and Threads
(/graphql/query feedData); in-document read on Instagram, whose feed is
prefetched into a RelayPrefetchedStreamCache script and never crosses the
wire. 190 X rows in 0.9s against the DOM lane's 10 in 11.1s, with exact
integer counts and view numbers the DOM never exposes. Waits for
Network.loadingFinished, not responseReceived — the body is not there yet at
responseReceived. Nothing captured raises; an empty list would say the
platform posted nothing when the truth is our listener missed it.
store.py — SQLite, stdlib only. platform_checks / items / metrics.
id = sha1(platform|kind|url or text), first_seen written once and ts under
COALESCE so a derived Threads marker cannot decay across passes.
FEED_PER_PLATFORM = 10 caps any one platform before the merge, or X's ~185
rows a pass sort Instagram's 3 off the page entirely. dashboard.json is now a
derived view of the database; dashboard.html did not have to change for it.
refresher.py — check_all runs the background-safe platforms in parallel
(19.0s sequential to 6.1s), tiktok still sequential and foreground.
--skip-foreground leaves it out of a timed pass and store.latest_checks keeps
returning its last real result with its own older checkedAt; stale is honest,
a fabricated row is not. Browser down stays the third state and exits 0.
.gitignore: socialmag.db (regenerable), deploy/kdmirah/ (carries the box's
VNC password and addresses — stays in the lab, out of git).
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
get_or_open_tab(activate=True) — added, not replaced. Read paths pass
activate=False; post flows keep the foreground for dialogs and file inputs.
check_login moved off DOM signals onto session state: fb c_user, ig/threads
ds_user_id, twitter twid, yt ytcfg.LOGGED_IN. Three platforms were reporting
OUT on a signed-in account because their composer never mounts in a hidden
tab. The fixed sleep(4)/sleep(5) before each check goes with them — every
signal reads present the moment navigate() returns.
Unreadable cookies raise instead of returning False: "cannot tell" is not
"signed out". tiktok untouched and still activated — it reported
visibilityState "visible" from a sibling-activated tab, so it has never been
read from a genuine background.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
- dashboard.html: local dashboard.json mode (10s poll) alongside artifact db mode;
clickable cards behind an http(s)-only safeUrl filter; meta charset; mode-aware
freshness line
- openbridge.py: localhost shim exposing open_link so dashboard clicks reuse the
platform's warm tab instead of spawning one per click
- cdp.py: Tab.activate(); get_or_open_tab activates reused tabs — a backgrounded
tab never finishes rendering, which made YouTube's login check read a signed-in
account as signed out
- README/MANIFEST: corrected CDP port (9336, was documented as 9222), removed the
false claim that the server writes dashboard.json, documented the reboot/VPS
requirements
- .gitignore: __pycache__/, *.pyc, state.json, Archived/; removed stale tracked
pycache and state.json from index