Vlad Babii

Feature SmithFull stack
idea → spec → ship → review

click ↑ to go back
LinkedIn · opens in a new tab

A probe that lives inside what it observes

ArchitectureDevelopmentFundamentals

A design for debugging live browser sessions from a server: a small probe runs as part of the page's own code, reports what it is and answers questions about its own state, but only when deliberately armed. It ships three ways: built into the site itself when you own the site, as a browser extension, or as a userscript, so it can run on desktop, mobile and tablet browsers alike. It exists because the standard debugging tool changes the very thing being debugged.

An observer that changes the system isn't evidence

When the truth lives inside a running instance, everything you see from outside is inference. A probe that changes any measurable property of that instance stops being evidence and becomes an experiment, however capable it is. This is a design; nothing of it is built yet. The bug that motivated it is real.

The bug that started it

A batch of twenty requests came back with eight answers. It looked complete, and nothing anywhere reported an error. The cause was a length limit that skipped entries instead of rejecting them. Reconstructing the behaviour from outside produced explanations that were plausible and wrong; one query from inside the running session showed the pattern at once.

The lesson became a design rule: a partial answer that looks complete is worse than a failure. The tool must return the error, never the silence.

Why the standard tool is disqualified

The usual remote-debugging protocol attaches to the real browser and works. But enabling it sets a flag that the browser reports to every website, and some sites then treat the session differently: they block it, or serve different content. The debugging tool breaks the thing being debugged. It also needs a restart to enable.

A probe that is already part of the page, whether injected by an extension or by a userscript, has no such flag; it is indistinguishable from the page's own code. That is the whole argument for running inside the sandbox instead of beside it.

One probe, three ways to load it

Same probe code; the host depends on what the browser allows.

The probe itself is one piece of code: heartbeat, inventory, job runner, arming. It is loaded by whichever host the browser supports.

If you own the site, the simplest host is the site itself: the probe ships with the page code, so it runs on every browser and device the site runs on, phones included, with nothing to install. Because it then reaches every visitor, it stays dormant unless the session belongs to someone allowed to arm it, and it never collects anything outside that armed window.

For sites you don't own, an extension is the stronger host where extensions can run: a background part keeps the connection to the server, survives page reloads, sees every tab and injects the probe where it is needed. Where they can't, a userscript loaded by a script manager (such as Tampermonkey) carries the same probe on its own, one page at a time. That covers desktop browsers, Firefox on Android, and Safari on iPhone and iPad through a userscript manager app.

Each instance reports which host it runs in, so the inventory shows extension and userscript instances side by side, with the code version of each.

  • Probe coreHeartbeat, inventory, at-most-once jobs with timeouts, arming; shared by both hosts.
  • Built into the siteShips with your own site's code; every browser and device, nothing to install; dormant unless an authorised session arms it.
  • Extension hostBackground connection to the server, all tabs, survives reloads; desktop browsers and the mobile browsers that allow extensions.
  • Userscript hostSame core loaded by a script manager, per page; for browsers and devices where extensions aren't possible.

Shape

There is no way to list running instances from outside, so each one announces itself on load and on a heartbeat: identity, what it is running, which version of the code is loaded, and whether it is active. The server keeps the union and expires whatever stops reporting. The inventory honestly means "instances where the probe is loaded", not "all instances"; the version per instance is useful on its own, because a stale copy of the code was the leading suspect for most of the investigation.

Jobs carry an ID and run at most once, so a reload never re-runs something. Every job has a timeout and ends as a result, an error or "expired"; nothing stays pending.

  • Runs in the instance's own context
  • Inventory by self-report
  • Code version per instance
  • At-most-once jobs with timeouts
  • Result, error or expired, never silence
The probe inside the instance, and the phases by riskThe probe inside the instance, and the phases by risk
The probe inside the instance, and the phases by risk

Armed, not standing

This is remote code execution into a session that holds real credentials.

It is off by default: instances send heartbeats but refuse work. A person arms it for a bounded window, after which it disarms itself. It is visibly marked while armed and while running, and every job is logged and readable afterwards. If it is ever widened, it gets an allowlist, not a blocklist.

Phased by risk, not by capability

Phase 1 is inventory only: heartbeats and code versions, no execution, useful at once with none of the risk. Phase 2 adds a fixed set of named, read-only checks, so no arming is needed. Phase 3 is armed arbitrary execution, behind the toggle and the audit log. Phase 1 alone would have shortened the original investigation; phase 3 would have ended it in one round.

Where else the shape applies

  • Worker processes
  • Device firmware
  • Client extensions
  • Cache layers
  • Fleets that can only be reported, not enumerated
Stack
Built into the site (own sites) · Browser extension · Userscript (Tampermonkey and similar) · Heartbeat API · Job queue · Audit log