Skip to content

Commit 333a99e

Browse files
Ryanmello07claude
andcommitted
p2: the developer/reliability screen, the session notice, and the null-list crash
Three things, in the order they had to happen. 1. The app survives a live session. `detail::parseJson<T>` in the generated C-ABI wrapper guards a NULL char* but not the four-byte document "null" — which is exactly what Go marshals for a non-nil list whose backing slice is nil. `json::parse("null").get<vector<T>>()` throws type_error.302 out of an ordinary getter, and the ReadStats path is reached from a DISPATCHED window Activated, so it is outside ShowWindow's try/catch: unhandled, the process dies the moment a device_ exists. P2 is the first phase that reliably produces one. app/third_party is a build artifact with exactly one tracked file (a README) and Go is not installed here, so the generator cannot be fixed from this repo. Guarded instead at every list-shaped getter through one helper, ReadList, whose `logged` argument is a per-call-site latch — each of these sites is a listener callback or a poll, and an unlatched log would fill the file at the listener's rate. Nine sites; the two that already had try/catch + LogWarn were left alone and the helper matches them. The one-line upstream fix (cgo/gen/hpp.go:260-267, make a null document yield an empty container — struct from_json is already null-tolerant, only the top-level vector unwrap is not) is written up in docs/superpowers/reports/2026-08-07-sdk-null-list-unwrap.md, along with why this is the FOURTH defect Windows has found in that wrapper: it is the only compiling consumer of the header, so nothing else in the fleet can find them. 2. The session notice has a consumer. P1 shipped SetModeNoticeHandler with nothing bound to it, so an rpc-only session showed no banner and a failed resume was log-only — the app could fail to reach the service and say nothing on screen. DeveloperPage binds it and drives ModeNoticeBar, a window-level InfoBar (row 2 of the root grid, appended so no existing element's Grid.Row moves) that is visible from every destination, renders `message` verbatim with no title, and has no dismiss control. The handler does one thing — TryEnqueue and return — because it is invoked with SdkHost's mutex_ held. 3. The screen itself. iOS DeveloperView + ReliabilityStore parity: measurements, all 34 ReliabilitySettings across Detection / Placement / Recovery / Probing / Observability, and the actions. Desktop goes past the phones with real tables for the exits and, new here, the destination exits — the readout that shows a site split across exits, which iOS never renders. The traps, kept: - an edit is a read-modify-write of the WHOLE struct from a FRESH read, inside SdkHost under its lock so two edits cannot revert each other; - a NIL settings read is "nothing in force", NOT "everything off" — the write is a no-op and says so, because a zeroed struct disables the whole reliability stack and sync() latches it; - the 5s poll runs only while the destination is selected AND the window is presenting, always on a worker: every getter is a synchronous rpc; - MigrateExit/ProbeAllExits drop their int32 counts over the C ABI, so the feedback is "Requested:" and no count is invented. dropExit, stallExit, shuffleExits and the probe-suite getters are DeviceLocal- only with no DeviceRemote equivalent and are deliberately absent. MainWindow's share of this is a nav item, a host ScrollViewer, the notice bar, and one line in the navigation relay — the whole ~50-control surface is built in code, because four phases share that file. Strings: the localization store has NO key for this surface (`reliability` is the earnings word, `reliability_settings` is "Contribute bandwidth"), and iOS is in the same position — its DeveloperView passes bare LocalizedStringKey literals with no catalog entries. So each of the 84 strings carries the `dev_*` key id it should have plus the iOS literal, and Dev() prefers the store the moment the key lands, using the same missing-key test Plural() already uses. Adding the keys to urnetwork/localizations is separate work and this screen needs no code change when they arrive. Verified by running, not reading: --preview-ui=developer now renders both the empty state and (via a synthetic snapshot, the same pattern as the two preview snackbars) the populated one, and the log shows the poll starting and stopping with window activation. What could NOT be verified is stated in the phase report: no account is signed in on this machine, so no live DeviceRemote was ever created and neither the null-list guard firing nor a real RpcOnly/SessionFailed notice has been observed. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PT7KcWCPKfFwQUc7SM3oZY
1 parent 2bb3918 commit 333a99e

11 files changed

Lines changed: 1772 additions & 10 deletions

File tree

app/src/App/App.vcxproj

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -228,6 +228,7 @@
228228
<!-- per-destination units split out of MainWindow.xaml.cpp -->
229229
<ClCompile Include="AccountPage.cpp" />
230230
<ClCompile Include="ConnectPage.cpp" />
231+
<ClCompile Include="DeveloperPage.cpp" />
231232
<ClCompile Include="LoginPage.cpp" />
232233
<ClCompile Include="PageContext.cpp" />
233234
<ClCompile Include="SettingsPage.cpp" />
@@ -256,6 +257,7 @@
256257
<ClInclude Include="MainWindow.xaml.h"><DependentUpon>MainWindow.xaml</DependentUpon></ClInclude>
257258
<ClInclude Include="AccountPage.h" />
258259
<ClInclude Include="ConnectPage.h" />
260+
<ClInclude Include="DeveloperPage.h" />
259261
<ClInclude Include="LoginPage.h" />
260262
<ClInclude Include="PageContext.h" />
261263
<ClInclude Include="SettingsPage.h" />

0 commit comments

Comments
 (0)