Repository navigation
Emit a neutral daemon:data-plane-ready event and reload on it instead of the capability-probe event - #3417
Conversation
fcf3356 to
6f26e83
Compare
Code review: pragmatic-code-reviewer, medium depthReviewed at head Code Review SummaryThis PR is a net improvement and is scoped correctly. Core now owns a neutral readiness signal, What I checked in the code:
FindingsCritical IssuesNone. Suggested Improvements[Improvement] The new wiring test doesn't check that the emit only happens on Nitpicks
APPROVE 🤖 Generated with Claude Code |
Address-reviewFixes are in
The Mutation checks
Runs on
No re-review is needed beyond the one already done: the change is test-only, and the reviewer approved it. 🤖 Generated with Claude Code |
…f pro:tier-detected - GrpcClient::data_plane_round_trip sends one bounded GetNode for a sentinel id and reports Answered (a response or NotFound), Failed(code) or TimedOut. - probe_and_recover uses it, keeping "any completion is live, only a timeout is a wedge". - The startup task emits DATA_PLANE_READY_EVENT once, after the reachability check, when the socket is reachable and the daemon answers the round trip. - app-shell reloads schemas and collections on that event; the tautological test is replaced with source-contract tests. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ernal - lib.rs: DATA_PLANE_READY_EVENT becomes pub(crate); only the startup task and its inline tests use it. Its doc states the event is not part of the versioned extension API (ADR-082 §3.5, §8) and points extensions at onDaemonReconnect. - daemon-status.ts: the DATA_PLANE_READY_EVENT export doc carries the same note and that it is not re-exported from $lib/extension-api. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…st sources from __dirname - lib.rs run_wiring_tests: the emit test also finds the `outcome == Some(DataPlaneRoundTrip::Answered)` gate and asserts round trip < gate < emit, so emitting on any completion fails it. - props-driven-components.test.ts: the source-contract tests read files through readDesktopAppFile, resolved from __dirname instead of the runner's cwd, replacing the inaccurate "vitest config root" comment. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
6f26e83 to
b0d4b65
Compare
Part of #3412
What
The free app reloaded schemas and collections on the Pro capability probe's event, which only worked because that probe happened to be the first real gRPC round trip at startup. Core now emits its own neutral event once the daemon answers, and the shell listens to that. This covers #3412's "any reload core still needs after the probe goes is driven by a core-named event" item; the Rust probe, its emit and
ProClient::rebindstay for a later #3412 slice to delete.services/grpc_client.rs:GrpcClient::data_plane_round_trip(timeout) -> DataPlaneRoundTripsends oneGetNodefor the sentinel id__ns_channel_probe__on the shared channel, bounded by the timeout. It returns:Answeredfor a response orNotFound, which is what a healthy daemon returns for that id;Failed(code)for any other completion;TimedOutwhen nothing completes in time.It also adds
DATA_PLANE_PROBE_TIMEOUT(5 s). The enum and the constant are re-exported fromservices.commands/nodes.rsprobe_and_recover: the privateprobe(),PROBE_TIMEOUTandPROBE_IDare gone. Both probes are now!matches!(client.data_plane_round_trip(DATA_PLANE_PROBE_TIMEOUT).await, DataPlaneRoundTrip::TimedOut), so any completion still counts as live and only a timeout counts as a wedge. The rebind block and its doc paragraph are untouched.lib.rs:pub(crate) const DATA_PLANE_READY_EVENT = "daemon:data-plane-ready".socket_reachable. Itsnot_runningemit and itsnodespaced unreachable after startuplog line are byte-identical.Answered, the task broadcasts the event with anullpayload (info!on success,warn!if the emit fails). Otherwise it logs awarn!with the outcome and emits nothing.daemon-status.ts: exportsDATA_PLANE_READY_EVENT, mirroring the Rust constant. The module doc names the neutral event and no Pro event.app-shell.svelte:unlistenTieris renamedunlistenDataPlaneReady, along with its cleanup, and listens onDATA_PLANE_READY_EVENTwith the same two reload calls. TheschemasDataimport and theproSynclines are left for the [Core release blocker] Strip all Pro code, edition branching and sync/ACL state from core in one pass (ADR-081 steps 0 and 2) #3412 slice that strips the Pro frontend.props-driven-components.test.ts: the tautological test is replaced by source-contract tests (details below).The event is core-internal
daemon:data-plane-readyis not part of the versioned extension API (ADR-082 §3.5, §8):pub(crate). Only the startup task and its inline tests use it; the TS contract test reads the Rust source text, not the symbol.DATA_PLANE_READY_EVENTexport doc indaemon-status.tsboth say so, and point extensions at the host API'sonDaemonReconnect, which also fires on the session's first healthy status.src/lib/extension-api. The extension-api surface snapshot is unchanged andEXTENSION_API_VERSIONstays 1.0.Deviations from the original plan
run_wiring_testsmodule, not a newdata_plane_ready_emit_tests. That module already hasrun_source()coveringrunand the app build it drives. The new testrun_emits_data_plane_ready_after_the_reachability_check_once_the_daemon_answersslices fromnodespaced unreachable after startuptoStreamingTaskRegistry::default(). It asserts thatdata_plane_round_trip(comes beforeemit(DATA_PLANE_READY_EVENT, and thatruncontains the emit exactly once.run_spawns_daemon_ready_tasks_once_the_watcher_and_token_stream_are_wiredis unchanged and still passes: the new block sits after the reachability line, and the spawn sits before it.probe_and_recover's existing source-text test (..._between_the_rebuild_and_the_reprobe) found the re-probe byrfind("probe("). The privateprobe()is deleted, so that needle now finds the re-probe byrfind("data_plane_round_trip(").packages/desktop-app/app-liband-p nodespace-app-lib, notsrc-tauriand-p nodespace-app.Pro-boundary ratchet
bun run scripts/check-pro-boundary.tspasses, and no count is above its baseline. Delta againstorigin/main(247e0dea), by marker:proEvents81 → 77 (−4):listen('pro:tier-detected', ...);daemon-status.tsmodule doc;proWording235 → 233 (−2): app-shell's two comment lines.Every other marker is unchanged. No marker line is added. No
BASELINESchange (see above).Tests
Each new test was mutation-checked: I broke the code path it covers, confirmed the test fails, then restored the code.
a_refused_endpoint_fails_without_timing_outgrpc_client.rsNotFoundfailure reported asAnswereda_silent_endpoint_times_outgrpc_client.rsFailed(DeadlineExceeded)run_emits_data_plane_ready_after_the_reachability_check_once_the_daemon_answerslib.rsprobe_and_recover_runs_the_channel_rebuilt_hooks_between_the_rebuild_and_the_reprobe(needle updated)nodes.rsthe_data_plane_round_trip_answers_once_the_daemon_is_healthyNotFoundarm removedleft: Failed(NotFound),right: Answered)loadCollections()dropped@tauri-apps/api/eventMutation checks for this pass, on the rebased tree:
run_emits_data_plane_ready_after_the_reachability_check_once_the_daemon_answers(now also pins theAnsweredgate between the round trip and the emit)outcome.is_some() && outcome != Some(DataPlaneRoundTrip::TimedOut)), run throughbun run test:changed__dirname)__dirname)@tauri-apps/api/eventRuns on
origin/main@247e0dea, head6f26e839:cargo fmt -p nodespace-app-lib -- --checkandcargo clippy -p nodespace-app-lib --all-targets -- -D warnings: clean.--all-targetscompilestests/itagainst thepub(crate)constant.bun run quality:fix: clean, with no further changes.bun run --cwd packages/desktop-app test src/tests/extension-api: 43 passed, andextension-api-surface.jsonis unchanged.bun run test:changed: passed. Tiers: frontend Happy-DOM, 5650 tests in 311 files; scripts; browser; Rust workspace nextest, 4149 passed; app-lib units, 307 passed. Skill was out of scope.tests/itbinary (the_data_plane_round_trip_answers_once_the_daemon_is_healthy) is not intest:changed's Rust tier. The merge gate's Tauri-seam stage runs it. Its code is unchanged since the earlier run on86b7190e.Earlier runs (on
86b7190e, thena7d2f93d):cargo test --lib -p nodespace-app-lib -- data_plane run_wiring_tests probe_and_recover: 12 passed.nextest -p nodespace-app-lib --test it startup_readiness_data_plane_test:: extension_hooks_test::: 4 passed. This includesa_wedged_channel_rebuild_runs_the_hooks_before_recovery_returns, so a timeout still triggers a rebuild through the shared method.Not done
bun run dev:tauriGUI check. The machine is shared, and that check needs a full app build and a GUI window. The integration test exercises the round trip against a real spawned daemon, and the source-text test pins the emit's placement.🤖 Generated with Claude Code