Repository navigation
Conversation
- Drop userinfo from the opened dashboard URL - Stop appending the shared token inside an existing fragment - Keep the route off the query string Signed-off-by: Sebastien Tardif <SebTardif@ncf.ca>
|
🦞👀 Pull request received. I will update this pull request when review starts. ClawSweeper review completeClawSweeper finished reviewing this revision. The review result is being finalized. |
Signed-off-by: Sebastien Tardif <SebTardif@ncf.ca>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: c998b504-ca22-49c5-8712-15da55226686
|
Codex review: needs real behavior proof before merge. Reviewed October 1, 2026, 3:12 PM ET / 19:12 UTC (Revision 16). ClawSweeper reviewWhat this changesThe PR composes dashboard routes, queries, and fragments separately, removes misplaced credentials, preserves supported session selection, and handles unsupported saved addresses recoverably. Merge readiness⛔ Blocked before merge - 2 items remain Keep open: current main still lacks the complete repair, and no blocking source defect remains in the published head. Updated authenticated Gateway evidence resolves much of the previous proof gap; the latest maintainer disposition still requires native launch and request-level session evidence. Priority: P2 Review scores
Verification
How this fits togetherWindows Companion turns saved Gateway addresses and selected credentials into dashboard links for native browser actions and MCP callers. The Gateway web app then consumes fragment authentication and selects the requested session. flowchart LR
A[Saved Gateway address] --> C[Dashboard URL composition]
B[Authorized shared credential] --> C
D[Requested route and session] --> C
C --> E[Native browser or MCP result]
E --> F[Gateway web app]
F --> G[Authentication and session selection]
Before merge
Agent review detailsSecurityNone. Review metrics
Technical reviewBest possible solution: Keep one dashboard URL composer behind the existing authorized credential and launch owners, with verified native handoff and intended session routing. Do we have a high-confidence way to reproduce the issue? Yes, from source: saved token queries remain in current-main dashboard links, and supplying a route discards the saved query. This read-only review did not execute a failing runtime reproduction. Is this the best way to solve the issue? Yes. Repairing the existing composer and preserving its callers' authorization owners is a focused solution; the earlier session and rejection defects are now addressed. AGENTS.md: found and applied where relevant. Codex review notes: model internal, reasoning medium; reviewed against 28df9c599b88. LabelsLabel changes: No label changes. Label justifications:
EvidenceWhat I checked:
Likely related people:
Rank-up movesOptional improvements that raise the rating; they are not merge blockers.
Rating scale
Overall follows the weaker of proof and patch quality. Workflow
HistoryReview history (15 earlier review cycles; latest 8 shown)
|
|
Global triage: TAKE_AFTER_CHECKS. Take confidence 85%; recommendation confidence 90%; effort extra-small; risk low. Reviewed exact head Owner: maintainer. Complete the declared browser-launch |
A scheme-less value such as localhost:18789 parses as an absolute URI with scheme localhost, and the dashboard builder then opened the wrong host. Accept only http, https, ws, and wss. Test: GatewayDashboardUrlBuilderTests 8 passed. Signed-off-by: Sebastien Tardif <SebTardif@ncf.ca>
|
The scheme-less edge is closed on Browser launch on that head: dev-identity Debug tray, disposable profile, dummy shared token, then The protocol delivered the path The three red setup E2E jobs on |
Preserve SebTardif's dashboard commits while integrating the latest setup and migration fixes from main. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: c998b504-ca22-49c5-8712-15da55226686
A nonempty unsupported address still passes credential resolution, then the dashboard builder throws. Open Dashboard, the saved-row dashboard action, and the app-capability handler now catch that rejection. The tray opens Connection settings or shows the error. The capability caller returns the error instead of throwing. ./build.ps1 exit 0. Shared tests: 4107 passed, 32 skipped. Tray tests: 3121 passed, 0 failed. GatewayDashboardUrlBuilderTests: 9 passed. Signed-off-by: Sebastien Tardif <SebTardif@ncf.ca>
|
@clawsweeper re-review |
|
🦞👀 Re-review progress:
|
|
@SebTardif: the current-main review found one bounded compatibility regression in the original patch. Per maintainer direction, I prepared the small repair below locally only, on unpublished normal integration The repair only allowlists the existing fragment session selector. It preserves first-query precedence, including empty/bare values, then first route-fragment selection ahead of the saved URL's selector. Encoded values remain encoded. Old authentication, password, endpoint overrides and unknown fragment content stay removed. Query behavior and credential/authorization owners are unchanged. Please apply the bounded repair/tests in your author-owned update. The original builder and test file are identical between your remote head and the local integration; the documentation addition targets the current connection architecture. Patch SHA256: Patched local validation: full build passed; Shared 4,169 passed/33 skipped; Tray 3,388 passed; full Connection 1,419 passed/1 skipped; full WinNode CLI 129 passed; focused URL tests 28 passed; combined caller/owner characterization 183 passed. The production builder plus exact pinned SPA startup/normalization passed 32 controls, retaining the requested session and ingesting/scrubbing only the dummy token. Review: actual runtime models Not merge-ready: local source-chain proof is not a native Open Dashboard click or successful real Gateway/browser authentication. Supported native launch lacks the isolation environment; no workaround or user Gateway was used. Your required hosted Setup/connect, Revocation and CI Gate remain red. Current-main E2E is green but its different Shared MXC cleanup-deadline failure is not a waiver. The PR body now retains the full template, historical author proof, exact revision provenance and current blockers. A new author head needs fresh required CI and behavior proof. Applyable working-tree repair, three files (+104/-2)diff --git a/docs/CONNECTION_ARCHITECTURE.md b/docs/CONNECTION_ARCHITECTURE.md
index 2d94f6aa..6dffaa93 100644
--- a/docs/CONNECTION_ARCHITECTURE.md
+++ b/docs/CONNECTION_ARCHITECTURE.md
@@ -211,6 +211,12 @@ Node credential precedence follows the same invariant with a distinct stored tok
**`InteractiveGatewayCredentialResolver`** resolves credentials for HTTP surfaces (chat URL `?token=` auth). It **prefers SharedGatewayToken** over DeviceToken because HTTP endpoints expect the shared token, not the per-device WebSocket token. Browser proxy diagnostics should treat the missing shared token as a browser-control caveat, not as proof that the operator or node gateway connection is disconnected.
+Dashboard links put only the selected shared token in `#token` and preserve the
+SPA's supported `session` selector. The first query selector takes precedence,
+including an empty value; otherwise the first route-fragment selector wins over
+the saved URL's selector. Other fragment parameters, including old authentication
+and endpoint overrides, are discarded.
+
The legacy web-chat readiness probe bypasses the process proxy only for loopback
URLs; remote HTTPS gateways retain proxy support. It accepts the original
200-399 response without following redirects, so a readiness check never
diff --git a/src/OpenClaw.Tray.WinUI/Helpers/GatewayDashboardUrlBuilder.cs b/src/OpenClaw.Tray.WinUI/Helpers/GatewayDashboardUrlBuilder.cs
index d782dfef..5672e458 100644
--- a/src/OpenClaw.Tray.WinUI/Helpers/GatewayDashboardUrlBuilder.cs
+++ b/src/OpenClaw.Tray.WinUI/Helpers/GatewayDashboardUrlBuilder.cs
@@ -18,6 +18,7 @@ public static class GatewayDashboardUrlBuilder
var route = path?.Trim() ?? string.Empty;
var fragmentStart = route.IndexOf('#');
+ var routeFragment = fragmentStart >= 0 ? route[fragmentStart..] : string.Empty;
if (fragmentStart >= 0)
route = route[..fragmentStart];
@@ -32,10 +33,17 @@ public static class GatewayDashboardUrlBuilder
var scheme = ToHttpScheme(uri.Scheme);
var url = $"{scheme}://{FormatHost(uri)}{FormatPort(scheme, uri.Port)}{JoinPath(uri.AbsolutePath, routePath)}{query}";
+ // The SPA prefers the first query session, even when empty, over a fragment session.
+ var session = FindSessionParameter(query) is null
+ ? FindSessionParameter(routeFragment) ?? FindSessionParameter(uri.Fragment)
+ : null;
+ var fragment = new List<string>();
+ if (session is not null)
+ fragment.Add(session);
if (appendSharedGatewayToken && !string.IsNullOrEmpty(sharedGatewayToken))
- url += $"#token={Uri.EscapeDataString(sharedGatewayToken)}";
+ fragment.Add($"token={Uri.EscapeDataString(sharedGatewayToken)}");
- return url;
+ return fragment.Count == 0 ? url : $"{url}#{string.Join('&', fragment)}";
}
public static bool TryBuild(
@@ -66,6 +74,23 @@ public static class GatewayDashboardUrlBuilder
scheme.Equals("ws", StringComparison.OrdinalIgnoreCase) ||
scheme.Equals("wss", StringComparison.OrdinalIgnoreCase);
+ private static string? FindSessionParameter(string parameters)
+ {
+ if (string.IsNullOrEmpty(parameters))
+ return null;
+
+ var body = parameters[0] is '?' or '#' ? parameters[1..] : parameters;
+ foreach (var part in body.Split('&', StringSplitOptions.RemoveEmptyEntries))
+ {
+ var nameEnd = part.IndexOf('=');
+ var name = nameEnd >= 0 ? part[..nameEnd] : part;
+ if (Uri.UnescapeDataString(name).Equals("session", StringComparison.Ordinal))
+ return nameEnd >= 0 ? $"session{part[nameEnd..]}" : "session=";
+ }
+
+ return null;
+ }
+
private static string ToHttpScheme(string scheme)
{
if (scheme.Equals("wss", StringComparison.OrdinalIgnoreCase) ||
diff --git a/tests/OpenClaw.Tray.Tests/GatewayDashboardUrlBuilderTests.cs b/tests/OpenClaw.Tray.Tests/GatewayDashboardUrlBuilderTests.cs
index d68109eb..25c3d412 100644
--- a/tests/OpenClaw.Tray.Tests/GatewayDashboardUrlBuilderTests.cs
+++ b/tests/OpenClaw.Tray.Tests/GatewayDashboardUrlBuilderTests.cs
@@ -107,4 +107,75 @@ public sealed class GatewayDashboardUrlBuilderTests
Assert.Equal("http://localhost:4317/ui/config?tab=one&x=1", url);
}
+
+ [Theory]
+ [InlineData("ws://gateway.example", "chat#session=agent%3Amain%3Areview", "http://gateway.example/chat#session=agent%3Amain%3Areview")]
+ [InlineData("ws://gateway.example#session=agent%3Amain%3Areview", null, "http://gateway.example#session=agent%3Amain%3Areview")]
+ [InlineData("ws://gateway.example#session=base", "chat#ses%73ion=route%26one%2Btwo+three", "http://gateway.example/chat#session=route%26one%2Btwo+three")]
+ [InlineData("ws://gateway.example#session=base", "chat#session=first&session=second", "http://gateway.example/chat#session=first")]
+ [InlineData("ws://gateway.example#session=base", "chat#session=&session=second", "http://gateway.example/chat#session=")]
+ [InlineData("ws://gateway.example#session=base", "chat#session", "http://gateway.example/chat#session=")]
+ public void Build_PreservesOnlyTheFirstFragmentSession(
+ string gatewayUrl, string? path, string expected)
+ {
+ Assert.Equal(expected, GatewayDashboardUrlBuilder.Build(
+ gatewayUrl, path, "test-auth-token", appendSharedGatewayToken: false));
+ Assert.Equal(expected + "&token=test-auth-token", GatewayDashboardUrlBuilder.Build(
+ gatewayUrl, path, "test-auth-token", appendSharedGatewayToken: true));
+ }
+
+ [Theory]
+ [InlineData("ws://gateway.example", "chat?session=query#session=fragment", "http://gateway.example/chat?session=query")]
+ [InlineData("ws://gateway.example?session=base-query", "chat#session=fragment", "http://gateway.example/chat?session=base-query")]
+ [InlineData("ws://gateway.example?session=base-query", "chat?session=route-query#session=fragment", "http://gateway.example/chat?session=route-query&session=base-query")]
+ [InlineData("ws://gateway.example", "chat?ses%73ion=encoded%3Aquery#session=fragment", "http://gateway.example/chat?ses%73ion=encoded%3Aquery")]
+ [InlineData("ws://gateway.example", "chat?session=&session=second#session=fragment", "http://gateway.example/chat?session=&session=second")]
+ [InlineData("ws://gateway.example", "chat?session#session=fragment", "http://gateway.example/chat?session")]
+ public void Build_PreservesQuerySessionPrecedenceIncludingEmptySelection(
+ string gatewayUrl, string path, string expected)
+ {
+ Assert.Equal(expected, GatewayDashboardUrlBuilder.Build(
+ gatewayUrl, path, "test-auth-token", appendSharedGatewayToken: false));
+ Assert.Equal(expected + "#token=test-auth-token", GatewayDashboardUrlBuilder.Build(
+ gatewayUrl, path, "test-auth-token", appendSharedGatewayToken: true));
+ }
+
+ [Theory]
+ [InlineData(false)]
+ [InlineData(true)]
+ public void Build_SessionAllowlistDoesNotRestoreFragmentAuthOrEndpointOverrides(bool appendToken)
+ {
+ var url = GatewayDashboardUrlBuilder.Build(
+ "ws://gateway.example?token=old&x=1#gatewayUrl=wss%3A%2F%2Fother.example&password=old&token=old&session=base",
+ "chat?to%6ben=old-route#token=old-route&session=agent%3Amain%3Areview&token=duplicate&gatewayUrl=wss%3A%2F%2Fother.example&password=old-route",
+ "test-auth-token",
+ appendToken);
+
+ Assert.Equal(
+ "http://gateway.example/chat?x=1#session=agent%3Amain%3Areview" +
+ (appendToken ? "&token=test-auth-token" : string.Empty),
+ url);
+ }
+
+ [Theory]
+ [InlineData(null)]
+ [InlineData("")]
+ public void Build_PreservesSessionWithoutAnAvailableSharedToken(string? sharedToken)
+ {
+ Assert.Equal("http://gateway.example/chat#session=agent%3Amain%3Areview",
+ GatewayDashboardUrlBuilder.Build(
+ "ws://gateway.example", "chat#session=agent%3Amain%3Areview",
+ sharedToken, appendSharedGatewayToken: true));
+ }
+
+ [Theory]
+ [InlineData("chat#old")]
+ [InlineData("chat#SESSION=ignored")]
+ [InlineData("chat#token=old&password=old&gatewayUrl=wss%3A%2F%2Fother.example")]
+ public void Build_DoesNotInventMissingSessionSelection(string path)
+ {
+ Assert.Equal("http://gateway.example/chat#token=test-auth-token",
+ GatewayDashboardUrlBuilder.Build(
+ "ws://gateway.example", path, "test-auth-token", appendSharedGatewayToken: true));
+ }
} |
A route or saved fragment session such as agent:main:review was dropped when the shared token was written into the hash. Keep the first query session, including an empty value, otherwise the first route-fragment session, ahead of the saved URL. Other fragment parameters stay removed. Signed-off-by: Sebastien Tardif <SebTardif@ncf.ca>
Keep the session-selector builder. Open Dashboard uses main's GatewayDashboardLauncher, which calls that builder. Signed-off-by: Sebastien Tardif <SebTardif@ncf.ca>
Session selection stays the supported selector. A non-secret view parameter stays in the fragment, and an existing fragment token stays when no replacement token is supplied. Password, gatewayUrl, and other fragment content stay out. Signed-off-by: Sebastien Tardif <SebTardif@ncf.ca>
|
@SebTardif: the published session repair at The one owned runtime attempt demonstrated wrong-token refusal, correct-token Remaining proof is specific: a current-head native Open Dashboard click from an isolated Companion profile, and metadata showing the actual Disposition remains NEEDS_HUMAN_TEST, not a stale source/CI blocker. No merge, agent source push or superseding PR. The retained dirty maintainer repair is still intact. |
|
Native Open Dashboard click on Launch was The click was the Connection page Dashboard button. The address bar first showed
|
What Problem This Solves
Fixes dashboard routes and credentials landing in the wrong URL component when a saved Gateway address contains a query or fragment.
User Impact
Dashboard links keep routes on the path, remove userinfo and old token query parameters, preserve supported session selection, and place the selected shared token in the fragment. Unsupported saved schemes fail recoverably.
October 1 disposition: NEEDS_HUMAN_TEST, not merged. The author published the session repair at
17def2bb8987cdc7fda5a5db4db6926ecc98f5be, and the required hosted CI Gate is now passing. Real current-head enabled-auth SPA proof established wrong-token refusal, correct-tokenhello-ok, successful read-only RPCs, token scrubbing and selector retention in the cleaned browser URL. Current native Open Dashboard click proof remains blocked by the supported isolated-launch limitation. The exact selected-session RPC parameter was not captured; it is not inferred from the URL or source tests.Why This Change Was Made
One existing builder composes components rather than appending routes after queries/fragments. It keeps the first query session, including empty/bare values, ahead of fragment selection; otherwise the first route-fragment selector precedes the saved URL selector. Fragment password, gateway endpoint overrides and unknown fields stay excluded. Current-main
viewcompatibility is retained. A supplied shared token replaces old fragment auth; the existing fragment token is retained only in the compatibility modeappendSharedGatewayToken=truewith a null/empty replacement. Current production callers require a nonempty shared token before enabling export.Current
GatewayDashboardLauncherowns native launch and expected error handling; App is its composition root. The modified MCP and saved-row callers useTryBuild. Shared-token-first interactive resolution, device-first operator/node WebSockets, managed/native endpoint authorization, selected endpoint and existing connection owners are unchanged. No legacy credential writes, parallel clients or new auth protocol.Evidence
Exact revisions and preserved work:
17def2bb8987cdc7fda5a5db4db6926ecc98f5be, treefcac637670f8c2ef3a0d77c34785062e06bf728c.e684d78drestores the supported session selector and characterization tests;55c11847merges main;17def2bbretains current-main view/token compatibility.f4122a8927e7cd452d166a23c0d5e30299f94368.28df9c599b88889f70dee6640885e47cdaeafee8. A read-only, conflict-free merge-tree isa90afd41dd8ed1a5ee2abba9e65704e90628b969. Its delta from the tested author head is only seven Local AI artifact-cache/setup files. Dashboard, credential, endpoint authorizer, Connection/Shared and all five exercised Gateway provisioning/cleanup owners are unchanged. No extra integration commit/checkout, blind full rerun or runtime restart was made. This is source applicability, not a claim that the combined tree was built or exercised.95a1bfe924e4e89996d1a72938d17262e2ca2c8d, September 28 unpublished integration5284dc0439d393f493878b89c5c940a69434ed0cand September 30 unpublished integrationf2f9fefc8440dbb0f8c806287d093a319bb0d7c4are preserved. The original dirty three-file repair and exact patch SHA25651C2B1978BFC0D5CBA10097BC0C70A7F44E92640E433B812F711A12885B9DFE7remain unchanged. Its builder/test blobs exactly match the author'se684d78dcommit. Its uncommitted documentation addition remains retained, not silently discarded.Current independent source review: one identical-prompt direct pair, actual runtime metadata
claude-opus-5.5andgpt-6-astra, no nested reviewers, fallback models or duplicate panel. Both found no blocking code defect. Opus alone noted two LOW nonblocking hardening cases: empty-token route fallback (unreachable in current production callers), and unusual saved query passwords also being forwarded to route URLs (root forwarding existed already). Neither led to unrelated parser/auth redesign.Pinned dependency: the body and author source retain
openclaw/openclaw@2d2ddc43d0dcf71f31283d780f9fe9ff4cc04fe4,v2026.7.1. SPA startup consumes/scrubs the fragment token and applies query-first session precedence. Browser connect carries auth in the WebSocket envelope. Chat startup selectschat.startupwhen advertised, withchat.historyas fallback. The proof driver's unconditionalchat.historyassertion was too narrow and is recorded below, not rewritten into a pass.Preserved historical author/maintainer evidence (not current-head proof)
At original remote
95a1bfe..., September 28 reported build passed, Shared 4,115 passed/32 skipped, Tray 3,160 passed, focused builder 9 passed, and diff check passed. Initial missing test assets were restored before nonzero-count--no-restorereruns.Historical isolated MCP-only app discovery exposed
app.dashboard.url. Saved addressws://127.0.0.1:43179/ui?x=1&to%6ben=old#old-base, routeconfig?tab=one&token=old-route#old-route, returnedhttp://127.0.0.1:43179/ui/config?tab=one&x=1#token=[REDACTED], shared-token source,usesSharedGatewayToken=true,hasTokenQuery=false. Computer Use selected Open Dashboard; Edge's structured URL washttp://127.0.0.1:43179/ui?x=1#token=[REDACTED]. The deterministic target returned 404. This established historical native launch and composition, not authentication.Seb's September 24
c869ed59comment also recorded eight builder tests and a dev/disposable-profile protocol launch opening/ui/config?x=1#token=[REDACTED]. The protocol omitted the route query; query composition had separate unit/MCP coverage. No usable screenshot was attached.September 30 local repair validation: build passed; Shared 4,169/33 skipped, Tray 3,388, Connection 1,419/1 skipped, WinNode 129, focused URL 28, combined owner checks 183. Thirty-two exact production-startup controls verified original
chat#session=...loss/reset tomainand its local correction. The author handoff preserves the full patch.Historical red run
36448923464was on95a1bfe...: post-wizard state-lifecycle restart contention prevented dashboard assertion execution. Historical main04a880fe...had a different MXC 3232ms cleanup-deadline failure. These are not current blockers: author run36890718374now passes its required Gate and executes the dashboard assertion.Change Type
Scope
winnodeRequired proof pools
windows-winui-interactive: current native Open Dashboard click/error UX and browser handoff still need visible isolated proof. Historical native evidence is retained, not promoted to the new head.windows-wsl-gateway-e2e: real local ownership/credential handoff and enabled-auth packaged SPA path. One scoped headless scenario collected current auth/read evidence and cleaned its owned resources; it is not a native UI proof.Validation
All October 1 local results are exact author
17def2bb.../ treefcac637..., not the old dirty repair or generated current-main merge tree.OPENCLAW_REPO_ROOTpointed at the detached validation checkout. Task-only tray data and C: NTFSTEMP/TMPwere process-local; both competing local-data/root overrides and real E2E enable flags were unset. No user settings, global environment/ACL/default-distro change or shared process kill.Fresh Shared, Tray, Connection and WinNode test projects each ran
dotnet build .\tests\<Project>\<Project>.csproj --source https://packagefeedproxy.microsoft.io/nuget/v3/index.json --verbosity quiet: passed, zero warnings/errors. Tests ran with nonzero counts. Each command below also used a named TRX logger, task-owned<session-files>\validation-oct1results directory and--verbosity quiet.$env:OPENCLAW_REPO_ROOT=(Get-Location).Path; .\build.ps1dotnet test .\tests\OpenClaw.Shared.Tests\OpenClaw.Shared.Tests.csproj --no-restore -- xUnit.MaxParallelThreads=1 xUnit.ParallelizeTestCollections=falseshared-serialized-diagnostic-17def2bb.trxdotnet test .\tests\OpenClaw.Tray.Tests\OpenClaw.Tray.Tests.csproj --no-restoretray-serialized-closeout-17def2bb.trxdotnet test .\tests\OpenClaw.Connection.Tests\OpenClaw.Connection.Tests.csproj --no-restoreconnection-rerun-17def2bb.trxdotnet test .\tests\OpenClaw.WinNode.Cli.Tests\OpenClaw.WinNode.Cli.Tests.csproj --no-restoredotnet test .\tests\OpenClaw.Tray.Tests\OpenClaw.Tray.Tests.csproj --no-restore --no-build --filter 'FullyQualifiedName~GatewayDashboardUrlBuilderTests|FullyQualifiedName~SetupDashboardHandoffTests|FullyQualifiedName~GatewayDirectConnectServiceTests|FullyQualifiedName~ActivationRouterTests|FullyQualifiedName~AppRefactorContractTests'& '<session-files>\reproduce-dashboard-session.ps1' -Repository '<exact-author-validation-checkout>' -ExpectPatchedgit diff --check/ exact candidate diff checkdotnet run --no-build --project '<session-files>\wsl-browser-proof-1505\Proof.csproj' --verbosity quietchat.historyassertion failed. Immediate cleanup bind check also failed; later IPv4/IPv6 checks both free, resources fully removed. No second scenarioLocal failures retained and diagnosed, not hidden:
NativeRestartAdmissionTests.BoundedFailureRetainsProtectedHandleForExplicitReopenfailed its protected-file-ACL assertion. Exact case passed with task-owned C: NTFS temp; the entire required subset was rerun, not just the case.McpHttpServerTests.Dispose_DuringInFlightHandler_DoesNotSurfaceObjectDisposedExceptioncaptures of closedFileStream/SafeFileHandle+StreamReader.ReadToEndAsyncInternaltasks. The MCP test has no nonparallel collection annotation and observes global unobserved exceptions during forced GC. Exact focused cases passed, but were not substituted for a full pass. Producer attribution is not established from the stacks. Two direct owned-process BoundedProcessWait diagnostics produced zero unobserved faults, so no speculative attribution to that owner or another OS session. The one final bounded correction used the repository's existing xUnit runner's documented collection setting, then reran full build/Shared/Tray successfully. Default-parallel instability remains recorded; serialized success is labelled explicitly.LocalAiApiCredentialStoreTests.ConcurrentCreationConvergesOnOneCredentialhit a sharingIOExceptionreading its task-local DPAPI credential. That owner has no PR delta. Focused case passed and the complete Connection rerun passed; required build/Shared/Tray closeout followed. No Local AI/MCP source repair or assertion weakening.HEAD^{tree}. Corrected read-only command confirmed the tree; no checkout/ref mutation.Current hosted CI:
36890718374, exact17def2bb..., success. Required CI Gate passes; Setup/connect, Revocation, Network, Tray/setup/integration and UI tests pass. Core/CLI is classifier-skipped, not credited as a hosted pass. The dashboard assertion did run:source=record.SharedGatewayToken; tokenQuery=False; length=93, static HTTP 200, assertion passed in 387ms. This is current runtime MCP/URL evidence, not SPA browser authentication by itself. No required Gate was bypassed or waived.Real Behavior Proof
OpenClawE2E-1505, port 31355, pinned CLI2026.7.1, token auth enabled with allowlisted dummy token, no providers/models. Real packaged SPA in two fresh ephemeral Playwright Chromium contexts (wrong-token control, then correct-token control), never a user's browser profile.17def2bb8987cdc7fda5a5db4db6926ecc98f5be, treefcac637670f8c2ef3a0d77c34785062e06bf728c.{"phase":"real-spa-negative","facts":{"hello":false,"authRefused":true,"connectIdentityPresent":true,"httpTokenRequests":0,"tokenScrubbed":true,"requestedSessionPreserved":true,"successfulReadOperations":[],"actualNativeOpenDashboardClick":false}} {"phase":"real-spa-positive","facts":{"hello":true,"authRefused":false,"connectTokenMatches":true,"connectIdentityPresent":true,"httpTokenRequests":0,"tokenScrubbed":true,"requestedSessionPreserved":true,"successfulReadOperations":["sessions.subscribe","sessions.messages.subscribe","agent.identity.get","models.authStatus","config.get","sessions.list","chat.startup","chat.metadata"],"actualNativeOpenDashboardClick":false}} {"phase":"browser-blocked","facts":{"type":"AssertionError","assertionFailed":true}}hello-okwith browser device identity and successful read-onlysessions.list/config.get/startup RPCs. HTTP credential queries stayed absent; the SPA scrubbed the token and retained the requested selector in its cleaned URL. These auth/read controls count independently of the driver's failed assertion. The pinned SPA actually prefers advertisedchat.startup, so requiringchat.historywas not the product requirement. The original run remains ASSERTFAILED and exit 4; it is not relabelled a wholly passing scenario. Exact selected-session RPC parameters were not retained, so request-level selected-session routing is still unverified. No reprovisioning or scenario rerun.Yes/No/N/A): N/A. No new native screenshot/public binary artifact. Sanitized original transcript, immutable source harness, TRX and pinned source controls are retained in session artifacts; the hosted run link above resolves.Resource cleanup: product cleanup ran with
ConfirmDestructive=false, requiring its durable marker and live canonical registry BasePath checks. It succeeded; task registration and VHD/install path are absent, local marker/temp directories empty, baseline default unchanged. The immediate port bind check failed; later scoped checks found no listener and both IPv4/IPv6 binds succeeded. No PID or shared WSL relay/broker was killed. The inspected exact task root, task NTFS temp and clean detached validation worktree were then removed. The local-wsl-gateway lease is released; no live fixture is inherited.Security Impact
Yes/No): No.Yes/No): Yes.Yes/No): No new auth protocol or production call.Yes/No): No new command; existing dashboard URL composition/error behavior changes.Yes/No): No.Yes, explain the risk and mitigation: userinfo and token queries are excluded; only the selected shared token replaces fragment auth. Supported session/view fields are retained without arbitrary password/gateway overrides. Export-disabled mode excludes supplied/existing token fragments. Dummy-only proof, no real credential/storage/config content published. Current endpoint authorization and device/bootstrap exclusion are unchanged.Compatibility and Migration
Yes/No): Yes for tested root/path/query/session selectors and current-main custodian/view compatibility. Original session loss is repaired in the published head.Yes/No): No persistent user/global changes. Proof fixture was disposable and removed.Yes/No): No.Review Conversations
No submitted reviews or inline threads exist. Current ClawSweeper's missing-proof observation is advisory but the remaining native/current-session-request evidence gaps are genuine. Source repair and old CI blockers are closed; no stale red-CI rationale remains. Current blocker: safely isolated current-head native proof, plus narrowly uncaptured session-RPC parameter evidence. Do not merge until the applicable proof gates are resolved.