A development report on SessionDock, based on the project state of September 5, 2026. SessionDock is not yet a released, end-to-end application.
Two agents are supposed to work on two projects in parallel. Each needs a browser with a prepared login. If its assigned workspace is busy, neither agent should silently switch to another profile or browser.
Separate browser profiles solve only one part of this problem: they separate browser data. We also need to know which project a workspace belongs to, who may control it at any given moment, and what should happen to a delayed action after control changes hands.
SessionDock is our attempt to answer those questions in software. We are developing a local Linux environment for prepared Chromium workspaces that a person will eventually be able to delegate to an agent for a limited time. The main state-management and scheduler components are implemented and tested. The path from the user to a real browser action is not yet complete.
A profile does not identify who owns an action
If all you need is to keep two logins apart, you do not automatically need another tool. Our starting point is also a separate Chromium user-data directory. A launch script can open two browsers with different directories and assign matching download paths.
The additional requirements appear when a workspace no longer belongs to one person alone, but is used by different actors at different times.
Consider a simple example. A person signs in to an administration interface and then delegates a limited task to an agent. During the task, the person needs to inspect something and takes control back. A browser action prepared by the agent arrives late.
The browser data may still be perfectly separate. One question remains: Is the agent still allowed to execute that action?
A directory structure cannot answer this. The system needs an authoritative record of who currently controls the workspace.
Treating the browser workspace as a managed resource
SessionDock calls a prepared browser workspace with its own assignment and local data a slot.
In the current workspace code, each slot receives a complete Chromium user-data directory, a download directory, and separate XDG and D-Bus paths. The graphical design uses a private Weston desktop. The packaged browser is Chromium, not Google Chrome.
The scheduler adds a fixed binding to this technical separation. The data model includes the project, worktree, environment, expected account, and expected tenant. An agent run receives permission for a specific binding; it should not be free to select an arbitrary environment on every request.
The word “expected” matters. A stored account name does not prove that the website is actually signed in with that account. The full login, confirmation, and delegation flow has not been integrated yet.
Likewise, a worktree assignment is currently a data-model concept in the tested core. It does not mean that SessionDock can already discover every Git worktree and open the appropriate interface automatically.
A lease controls access; an epoch fences a handover
A person and an agent should not write to the same slot at the same time. The scheduler therefore uses exclusive, time-limited access rights: leases.
A lease epoch complements that model. It is a monotonically increasing generation number for control authorization. When control changes hands, the previous generation becomes invalid.
A simplified example:
Agent A controls the slot at epoch 41.
The person takes control back.
The current epoch is now 42.
A delayed action from A arrives with epoch 41.
The authorization check rejects it as stale.
Before dispatch, the state machine checks whether the agent still has control, whether the session is ready, and whether the expected lease epoch matches the current one. This core logic is covered by unit tests.
That does not yet prove an end-to-end protected browser action. The check must sit at the correct point in the complete execution path, and that integration remains open.
Nor can such a check undo an action that has already reached the website. If a web service has accepted a change, a local handover does not reverse it. Unknown outcomes, recovery, and quarantine therefore remain part of the design.
Separate browsers can still change the same resource
The scheduler can allocate independent slots in parallel. This does not make their work independent at the application level.
Two separate browsers can use the same account to modify the same server-side resource. Two agents might, for example, edit the same product record at the same time. Separate cookies and download directories do not prevent that conflict.
The scheduler therefore also supports conflict keys. They can coordinate known shared resources, provided the conflict has been described correctly. SessionDock does not automatically understand the business logic of an arbitrary website.
This distinction matters to the data model. Local browser separation, permission to control a workspace, and conflicts over application data are three different concerns.
Running a browser and displaying it are different jobs
The graphical environment adds another requirement. A person should be able to sign in to a real Chromium workspace without giving the agent their passwords or TOTP seeds. At the same time, the browser should not constantly appear as a regular window on the person’s desktop.
The workspace prototype therefore separates browser execution from display on the host. Chromium is intended to run on a private Weston desktop. A viewer opens separately, and only after an explicit action by the person.
This is an architectural decision, not a demonstrated guarantee about focus handling or two-factor authentication. On the investigation host, the real Chromium launch failed because namespaces were blocked. The login and focus test matrix is also still open. USB security keys and smartphone passkeys are explicitly blocked in the current prototype.
SessionDock does not import existing sessions from the user’s normal desktop Chrome installation either. The intended flow is a manual login inside each slot. The persistent profile path is designed to preserve that login across restarts, but this has not yet been demonstrated with a real authentication-and-restart test.
One authority, but not yet a complete execution path
The repository contains a Go daemon with a local API, SQLite persistence, a scheduler, and a state machine. It also contains a separate workspace prototype and parts of a Chromium extension using Native Messaging.
Their responsibilities are deliberately different. The daemon is intended to remain the authoritative source for permissions and state. Browser components should not replace that authority with their own potentially stale decisions.
These parts are not yet connected into a usable product. The regular CLI does not control the daemon; in practice, only help and version output are usable there. The MCP server, agent adapters, and complete action executor are missing. The workspace prototype is not yet wired to the scheduler.
A passing scheduler test is therefore not a successfully completed agent run. Likewise, prepared slot directories do not demonstrate two browsers operating concurrently. Both provide useful evidence for individual components, but not for the complete user flow.
The security boundary this architecture does not create
Separate profiles are not a security boundary against every local process.
The slots still live on the same host and ultimately belong to the same host user. Chromium shares the host’s network access. Hard isolation between an agent and every other host file it might reach has not been implemented.
If an agent has broad file access outside SessionDock, an API permission model alone cannot stop it from taking another route. Any future security claim will have to account for that boundary.
What the current design tells us
The design therefore centers on controlled access to a prepared workspace, not on the browser window itself.
Responsibilities are divided across several components. The slot owns the local browser data, the binding describes the work context, and the lease grants current control. The epoch makes stale permissions detectable, while conflict keys coordinate known shared resources.
The core model is currently further along than the visible application. The next meaningful proof is not another architecture diagram but a complete flow: prepare a test workspace, sign in manually, delegate it for a limited time, observe a real action, and take control back.
Until that flow works and has been tested, SessionDock remains a development project. The underlying problem is already clear, though: a browser agent needs more than a browser. It needs an unambiguous workspace and a verifiable, limited right to act within it.
Addendum: What the discussion clarified (2026-09-08)
Publishing this before SessionDock is finished has been valuable. The comments brought concrete failure cases that helped expose assumptions and sharpen our design.
One important distinction is that revoking authority does not undo an action. Handover needs to fence both outgoing actions and incoming observations. If a write may have succeeded but its result is lost, OUTCOME_UNKNOWN must not become an excuse to retry. Resolving it requires trustworthy, application-specific evidence—and sometimes that evidence simply does not exist.
The discussion also highlighted that process checks alone do not establish exclusive browser control. We reproduced the reported ProcessSingleton behavior in a standalone Linux test; protection still needs verification on our packaged Chromium/Weston path.
Likewise, an expected account or tenant is not a verified remote identity. Identity evidence needs explicit provenance, freshness limits, and a recorded policy behind each write. Conflict handling must also account for human interaction, not just scheduled agent actions.
These are requirements we are incorporating into the design and tests, not claims that every protection is already implemented. We are also exploring per-slot microVM isolation, without treating it as a replacement for the other controls.
Thank you to everyone who shared practical failures and challenged the assumptions. That is exactly why we wanted to discuss the architecture while it is still taking shape.
Top comments (28)
The epoch checks host-side state. So does process/argv verification, and conflict keys sit on the same side of the line. But expected_tenant is a claim about the remote service's state, and nothing in the design ever asks that service which identity the browser is actually holding. Your own line about "expected" points at this and then stops.
Manual login is where it opens up. Nothing binds the login a person actually performed to the binding's expected account, so signing into tenant B inside a slot bound to tenant A is a normal-looking action that produces no error. Persistence makes it durable. The profile preserves the wrong login across restarts through the same mechanism that makes the slot useful in the first place. Every later agent run passes every check and writes to the wrong tenant.
The epoch cannot catch that, because the epoch catches stale authority. This authority is current. It just points somewhere else, so no generation changes and no monotonic counter fires. Cookie-jar inspection misses it too when the tenant switch happens over SSO on one domain with the same cookie names.
What would close it is an identity probe against the server at lease grant. One authenticated request through the slot's session to the application's own "who am I" endpoint, compared against the binding's expected account and tenant, with a digest of the returned identity fields stored on the lease. Dispatch then compares that digest next to the epoch. A mismatch should fail the lease rather than the single action, since an identity error was never about one click. One request per grant, and "expected" starts meaning checked.
The probe is a sample, though, so it should not be sold as an invariant. A session can be revoked server-side mid-lease. An SSO reauth can quietly drop back to a default tenant. Give the probe result its own timestamp and let dispatch call identity stale past a bound, the way it already calls control stale. That gives you a maximum age for the evidence, which is a weaker and more honest claim than continuous correctness.
Yes, I think this identifies a real missing boundary.
expected_accountandexpected_tenantare currently binding claims, not verified remote state. A perfectly current lease can therefore still point at the wrong authenticated tenant.The direction you describe makes sense: verify the identity through the slot's authenticated session when granting the lease, bind that result to the lease, and fail the lease rather than an individual action if the identity does not match.
I also agree with the distinction in your last paragraph. Such a probe is evidence with an age, not a permanent invariant. Server-side revocation, SSO reauthentication, or tenant switching can invalidate it later.
So the useful contract is probably closer to “remote identity verified no more than X ago” than “this slot is continuously guaranteed to be tenant A.”
"Verified no more than X ago" makes sense, but X is still a free parameter. Nothing in the system derives it. The quantity that grows with X is the number of writes requiring review after a mismatch, so I'd pick X from the blast radius of a wrong-tenant write. A latency budget can't justify that exposure.
Before shrinking X, though, I'd stop treating identity verification as a separate request. Many authenticated applications already echo identity in ordinary responses, perhaps a tenant id in a header or an account slug in a JSON envelope. Where that marker reliably describes the context of the operation, the dispatcher can check responses it's already receiving. That gives near-continuous sampling at zero extra requests, and the grant-time probe only has to establish which marker to inspect and its expected value. A write response still arrives after the write. Detection there doesn't undo it.
Plenty of applications expose nothing usable. For those you really are sampling, and X comes back. Even an available marker has to describe the authenticated operation's tenant rather than some unrelated page context.
Either way, attach the last good probe digest to each dispatched write as a recorded precondition, together with the verification event that produced it. The event matters because repeated successful checks return the same digest. On mismatch, the potentially damaged set is exactly the writes recorded since the last successful verification, plus the write whose response exposed it. That's an enumerable review set bounded by the evidence window, rather than auditing everything since lease start. It makes a silent error traceable. Prevention stays the stronger claim.
Would you let an identity-failed lease recover through re-probing, or make it terminal, given that writes already made stay in that review set either way?
I like the idea of deriving X from the acceptable blast radius rather than from a latency budget. That gives the evidence window an actual risk meaning.
Reusing identity markers from normal application responses is also interesting. Where the marker genuinely represents the authenticated context of that operation, it could turn the grant-time probe into the starting point and subsequent responses into continuous evidence without additional requests.
And recording the verification event, not just the digest, makes the review set much cleaner: everything since the last known-good evidence becomes enumerable.
On your last question, I am leaning toward making an identity mismatch terminal for that lease. Re-probing may establish that the identity is correct again, but it cannot restore the broken chain of evidence or remove the writes already in the review set.
So recovery would mean reconciliation/quarantine followed by a fresh lease and fresh identity evidence, rather than silently reviving the existing one.
This is exactly the kind of distinction we are still working through in the design, so this input is very useful.
Terminal fits the broken evidence chain. It also creates an incentive problem, because termination is expensive while sampling frequency stays an operator-controlled dial.
Less sampling looks healthier. If the dashboard reports terminations per day, cutting probes improves that number while increasing exposure to wrong-tenant writes, since fewer mismatches ever become visible.
A better primary signal is the distribution of identity-evidence age at write dispatch: dispatch time minus the timestamp of the newest qualifying evidence available to that write. Record it for every dispatched write. When sampling slows the distribution shifts toward older evidence, so degraded observation shows up as a degraded number. Writes with no evidence at all need their own bucket rather than dropping out of the denominator.
That only works if the evidence classes stay separate. A passive marker establishes the identity associated with that response, subject to the marker's integrity. An active probe establishes the identity returned for a request the dispatcher constructed. Folding both into one
last_verifiedfield lets ordinary traffic keep refreshing evidence that answers a different question.Two timestamps, then. Dispatch can require an active probe within a longer bound and a passive marker within a shorter one, both bounds derived from the acceptable exposure, with each write referencing the specific evidence events that satisfied the predicates.
One wrinkle on the trust boundary. A misrouted or compromised proxy can rewrite a passive marker into agreement, because the marker rides inside the channel under suspicion. An active probe through that same proxy still needs an authenticated binding to the application's own answer. Constructing the request is not sufficient on its own.
The same distinction decides quarantine scope. If passive markers stay suspect they cannot advance the last-known-good boundary, so the review set should begin at the last trusted active probe and conservatively include writes whose ordering against that probe is uncertain. Otherwise the set stays enumerable while quietly excluding writes the evidence never cleared.
That distinction between evidence age and termination count is a very useful one. A low termination rate is meaningless if we can achieve it simply by looking less often.
I also agree that active and passive evidence should not collapse into a single
last_verifiedvalue. They answer different questions and have different trust properties, so each dispatched write should reference the actual evidence events that satisfied its policy.Your proxy example is particularly important. An active probe is only stronger if we can authenticate that the identity answer really belongs to the application/session we intended to verify. Simply constructing the request ourselves is not enough.
So I think the model is moving toward separate evidence classes, separate age bounds, and a conservative last-known-good boundary for quarantine. Passive markers can improve observation frequency where they are trustworthy, but they should not silently promote themselves to the same assurance level as an authenticated active probe.
And yes, measuring evidence age at write time seems like a much healthier operational signal than counting identity failures after the fact.
If each dispatched write carries the reference to the evidence event it relied on, plus the version of the admission policy it claimed to satisfy, then the audit stops depending on what the dispatcher remembered. The policy names the required evidence class and the age bound. Given immutable evidence records and a recorded dispatch time, someone can recompute admissibility months later from the write alone. Pinning the policy version does a second job: a config change afterwards cannot quietly rewrite a historical verdict.
The clocks have to stay apart for the reason you gave. Taking min(active_age, passive_age) lets a fresh passive marker satisfy the freshness check during exactly the window where the active probe is broken, which is the window that matters. A policy requiring authenticated active evidence should stay unsatisfied for that whole window, however busy the passive stream looks.
Your point about the identity answer belonging to the session you meant to verify is where the probe design gets decided. The probe sends a fresh nonce, the application's authenticated response binds that nonce to the session under test, and each nonce is accepted once. Without that binding, a proxy can replay an older answer or substitute a different session's.
For the conservative last-known-good boundary on quarantine, do you cut it at the evidence id of the last successful authenticated probe, or at a timestamp?
I would cut the quarantine boundary at the last trusted evidence event, not at a wall-clock timestamp.
More precisely, I think we need an immutable daemon-side event sequence in addition to the evidence ID. The timestamp is useful metadata, but it should not be the authoritative ordering mechanism. Each write can then record the evidence events it relied on, its dispatch sequence, and the admission-policy version that accepted it.
That also makes your historical-audit point work nicely: admissibility can be recomputed later without depending on current configuration or dispatcher memory.
I agree on keeping the active and passive clocks independent. Fresh passive traffic must never make an expired active-evidence requirement look satisfied.
And the nonce binding is a good addition to the active-probe contract. Constructing the request ourselves is not sufficient; the authenticated response has to prove that it belongs to that probe and the session under test, with replay excluded.
So the conservative review boundary would be the last successful trusted active-evidence event, with any writes whose ordering against that event is uncertain included rather than excluded.
the delegated-action part is what cost me the most. two agents on one machine sharing a browser, and when control moved, the action that was already in flight had landed. it just never reported back.
so the retry wrote it twice. what I do now is read the field's own length before retrying anything, because the tool result is gone but the page still knows.
does a lease expiring mid-action tell you whether that action committed, or only that the lease ended? that's the gap I never closed, and I ended up giving each agent its own machine instead of solving it.
That is exactly the distinction we need to make explicit.
A lease expiring only tells us that the authority ended. It does not tell us whether an in-flight action committed.
So if the action already reached the browser but the result is lost, we have to treat it as potentially successful and move it to
OUTCOME_UNKNOWN. No automatic retry should happen until the actual application state has been reconciled.Your example is a good illustration of why “no result” must never be treated as “no effect.”
OUTCOME_UNKNOWN is the right name for it. the part I'd flag is what resolves it.
reconciling needs somewhere to look, and in the browser case the only thing that knew was the page itself. reading the field's length worked because the page was still sitting there. when the other agent had already navigated away, that evidence was gone and there was nothing left to reconcile against. the state just stayed unknown and something still had to decide.
I never got further than opening it myself and looking, which is slow and doesn't hold up past a couple of agents.
Yes, I think that exposes an important assumption in my use of “reconciliation”: there has to be an independent source of truth to reconcile against.
The DOM may provide one while the page is still there, but SessionDock cannot rely on that. After navigation, the useful evidence may simply be gone.
So I think reconciliation has to become an explicit capability of an action or application: perhaps re-read the record, query an API, find a resulting object or identifier, or use some other application-specific postcondition. The pre-action context can help with that, but it cannot prove that the write committed.
If no trustworthy reconciliation path exists,
OUTCOME_UNKNOWNhas to remain unknown and require human review rather than eventually turning into an automatic retry.That is a useful correction to the model: defining the unknown state is only half the problem; we also need to define what evidence is allowed to resolve it.
"What evidence is allowed to resolve it" is the sharper half, and I hadn't put it that way. Leaving it unknown when nothing can prove the write is the honest default, even though it's the one that costs a person.
Exactly. The human cost is uncomfortable, but I think that is preferable to inventing certainty where none exists.
If we cannot produce evidence that a write committed or did not commit, the system should preserve that uncertainty and escalate it rather than resolving it through an unsafe retry.
Your example helped sharpen that for us:
OUTCOME_UNKNOWNneeds explicit rules for what evidence may resolve it, not just a state-machine transition that eventually makes it disappear.Agreed. What bit me on the escalate path was that the queue needs its own liveness check. Mine sat with nothing reading it and nothing complained, because a job that never runs doesn't produce an error. Noticed a day later, and only by accident.
Splitting this into three concerns — local browser data, the right to control, and conflicts over application data — is what makes the epoch check readable, so I'll poke at the third one.
Conflict keys only coordinate what the scheduler dispatches. A person who takes a lease and clicks through the viewer never declares a key, so nothing stands between them and agent A editing the same product record in another slot. The scheduler cannot see a click it did not dispatch.
Having a human lease hold the conflict keys of its binding for its whole duration would close that half, at the cost of blocking agents while someone is only looking.
Yes, that is another real boundary.
Conflict keys only protect work that goes through the scheduler. A human interacting directly with the viewer is otherwise invisible at the application-conflict layer.
Holding the binding's known conflict scope for an interactive human lease is probably the conservative default. It may over-block agents while the person is only inspecting something, but that is preferable to pretending we can infer arbitrary application-level conflicts from browser isolation.
I think we may need to distinguish read-only observation from interactive takeover here. The harder limitation remains: if the binding does not describe the affected application resource, SessionDock cannot magically discover that conflict from a human click either.
The epoch fencing at the action dispatcher is the cleanest part of this design. In human-agent handoffs, delayed event dispatch is where state corruption usually happens. An agent prepares a click three seconds before the operator grabs focus, and the action fires into whatever page the human just navigated to. Checking a monotonic epoch number right before the CDP event dispatches turns that race condition into a deterministic drop.
The edge that gets messy in practice with headless slots is in-flight requests that cleared the browser before the epoch bumped. The click was authorized when sent, but the server response and subsequent redirect land after the lease expired. If the agent loop watches DOM mutations to plan its next move, canceling pending fetch channels or tearing down the network listener on lease handover saves a lot of phantom state errors.
Yes, that is exactly the gap.
The epoch already fences actions that have not been dispatched yet. Once a request has left the browser, however, revoking the lease cannot undo its server-side effect.
So the handover also needs an observation fence: delayed DOM, network, redirect, and lifecycle events from the old generation must be discarded before they influence further planning.
If the outcome of an already dispatched request is no longer reliable, we should treat it as
OUTCOME_UNKNOWNand avoid blind retries.So I think your “phantom state” point is exactly right: stale outgoing actions and stale incoming observations are really the same handover problem.
The lease and the epoch fence the dispatcher, but they only cover actions that arrive through it. If a slot's Chromium is launched with a remote debugging port, that endpoint is unauthenticated by design: I ran a plain
GET /jsonagainst a running instance on this machine just now, no header and no token, and got back the full target list including page URLs, and a WebSocket from there drives the page directly. That is the same host-user boundary you already name for file access, except it lands on the browser itself, so a stale-epoch agent with file access never has to go near the dispatcher. The check that survives it is reading the identity of the browser actually being driven off the running process, the--user-data-dirof the PID holding the control port, rather than off the slot record, since those two can diverge with nothing in the daemon noticing.That is a fair point.
SessionDock does not currently launch Chromium with
--remote-debugging-portor--remote-debugging-pipe; the intended control path is the packaged extension usingchrome.debugger.But you are right that “we did not configure it” is not a sufficient security property. We need to verify the running browser, not just trust the slot record.
That means checking the live process argv and its actual
--user-data-dir, and treating any unexpected DevTools listener or/jsonendpoint as a hard failure.So the stronger invariant is: no externally reachable CDP control path, and the browser process must be cryptographically/operationally tied back to the daemon-owned slot state.
The argv check closes the case where a stale epoch starts its own browser, but Chrome's process singleton gives that actor a path that creates no process to inspect. Measured a few minutes ago on Chrome 152 / macOS: running the browser binary a second time with the live profile's
--user-data-dirprintedOpening in existing browser session.and exited in 0.07 s real, while the target list on the existing browser's port went from 4 to 5 with the new entry being a page. So an agent that only knows the slot's profile path can get a URL opened inside the logged-in browser owned by the current epoch, and there is no new argv and no new listener for the daemon to enumerate. It needs the same host-user access to that directory that you already treat as in scope, and it hands over a command line rather than DOM control, so the property worth pinning is exclusive ownership of the profile directory, not only the process list.Exactly. We are still in the architecture and validation phase, so this kind of input is genuinely useful.
We reproduced the ProcessSingleton behavior on Linux as well, which means we now have a concrete case to test against rather than just an architectural assumption.
At the moment we are looking at two levels of isolation: closing the profile/singleton boundary properly in the current Linux design, and evaluating a per-slot MicroVM as a possible higher-assurance execution domain later on.
The VM would not replace leases, epochs, identity checks, or conflict handling, but it could give us a much cleaner local boundary if the threat model includes arbitrary code running under the same host user.
That is exactly why I wanted to write about SessionDock before calling it finished. Comments like yours expose the places where an architecture still relies on an assumption instead of evidence.
The distinction between browser isolation and application isolation is especially important here. Two agents can have completely separate profiles, sessions, and workspaces while still competing over the same server-side record. That means the real coordination boundary often has to exist above the browser itself. I like the use of conflict keys for known shared resources, but it also highlights a harder problem: agents need some awareness of the resources their actions can affect, otherwise local isolation can create a false sense of safety.
Yes, that is exactly the distinction we are trying to keep explicit.
Browser isolation can tell us that two agents are using different local state. It cannot tell us that their actions are independent at the application level.
Conflict keys only work where the affected resource is known, so they depend on some application-aware description of the action. For a product update that might be a product ID; for a broader workflow it may need a larger conflict scope.
Where SessionDock cannot determine that scope reliably, the safe answer is not to assume independence.
That is also why I see conflict handling as a separate policy layer above the browser rather than another property of the slot itself.
The late-arriving action example is the part that bites in practice. We run several agents against a shared Chrome over CDP, and the recurring failure was exactly this: a click or Runtime.evaluate prepared against a tab that another agent had just navigated elsewhere. Target IDs stay valid across navigations, so the call still succeeds and lands on the wrong page. Our workaround is re-checking the target URL right before every input dispatch, a poor man's version of your authoritative ownership record. How does SessionDock revoke in-flight actions: a lease with expiry, or does a control handover explicitly cancel anything queued?
Yes, that is exactly the race we are trying to fence.
We do not want lease expiry to be the only mechanism. A control handover explicitly revokes the lease and cancels work that is still queued in the broker.
Immediately before an effective browser dispatch, the executor is also supposed to re-check the lease/epoch, target and document generation. So a target that survived a navigation is not enough by itself to authorize the action.
The hard boundary is anything already handed to Chromium. We cannot reliably “unsend” that. If control changes after dispatch and we lose a trustworthy result, the action has to become
OUTCOME_UNKNOWNrather than being retried automatically.Your URL re-check is essentially the same class of protection; we are trying to make it part of the authoritative dispatch contract rather than an agent-side convention.
Some comments may only be visible to logged-in visitors. Sign in to view all comments.