ck, daemon: report env, args and protocol drift after rescan (#135)

Closed
IC
4d ago
+653-83

Linked issue

Approved issue: #135

What changes

pending_reload gains a third dimension, spec: match | mismatch | unavailable, beside path and image. Those two are unchanged.

  • The fingerprint. At spawn the daemon records a SHA-256 over the configured launch inputs: program, ordered args, the module's configured env (sorted by key) and protocol. Each field is length-prefixed, and the program path is hashed as its native bytes, so two different specs can't collide on encoding. Inherited environment and the per-spawn values the daemon injects (launch nonce, module id, connection file path) are excluded (condition 1).
  • It stays in the daemon. The fingerprint is a private newtype with a redacting Debug. Only the verdict goes on the wire (condition 2).
  • The comparison. The verdict compares the recorded fingerprint with the stored spec, which rescan overwrites. So an env-, args- or protocol-only edit reads mismatch until the restart. A module with no running process, or one spawned by a daemon that recorded no fingerprint, reads unavailable, never match (condition 3). The fingerprint is cleared with the other per-process facts.
  • Older daemons. PendingReloadVerdict.spec is #[serde(default)]. ck module list and ck module status render a missing field as "not reported" (condition 4).
  • Docs. docs/daemon-config.md says what each of the three dimensions covers.

Versions: subc-control 0.32.0 (minor, new field). subc-client-rs 0.30.0 (minor, because it re-exports subc-control types; same reasoning as on #120). subc-daemon 0.36.11, subc-core 0.20.102, subc-mcp 0.1.38, ck-bus 0.4.3. cortexkit-bus-testkit 0.1.2 and mcp-stdio-adapter 0.1.15 pinned the old subc-control/subc-client-rs, so they get bumped too.

How it was checked

At this commit, on top of current master:

  • cargo fmt --all -- --check and cargo clippy --workspace --all-targets -- -D warnings: clean.
  • cargo test --workspace --no-fail-fast: 3,244 passed, 2 failed, 38 ignored. Both failures are ck-bus tests that need a nats-server binary, which isn't installed on the test host. Each fails alone for that reason. cargo tree for subc-daemon and subc-core contains no ck-bus.
  • scripts/fleet/check-wire-crate-versions.sh origin/master: 17 crates checked, none changed without a bump.
  • Condition 5: rescan_env_args_and_protocol_only_edits_stay_pending_until_restart applies an env, an args and a protocol edit separately. Each reads mismatch after the rescan and match after the restart. distinct_connection_files_and_fresh_nonces_do_not_pending_reload is the control: a different connection file and a fresh nonce still read match.
  • Each of these changes, made on purpose, fails a named test:
    • returning match when no fingerprint was recorded;
    • joining env key and value with a delimiter instead of length-prefixing them;
    • encoding a non-UTF-8 program path lossily;
    • forcing match after an applied rescan;
    • defaulting the missing wire field to match;
    • adding the connection file path to the fingerprint;
    • not clearing the fingerprint when the process goes away.
  • An independent review from a different model family returned approve with one finding: the cleared-facts test helper didn't check the fingerprint. That is fixed in this commit.

Summary by cubic

Adds a launch-spec verdict to the daemon's pending-reload report so env, args, or protocol edits after a rescan stay pending until the module restarts.

At spawn the daemon records a private SHA-256 over the configured program, ordered args, sorted env block, and protocol; rescan overwrites the stored spec, so a process spawned from the old inputs reports mismatch until reload. Only match, mismatch, or unavailable goes over the wire — the digest stays daemon-private — and inherited or injected values (launch nonce, module id, connection file) are excluded. A stopped module or one spawned without a digest reports unavailable; daemons omitting the field render not reported. The new pending_reload.spec field is optional so old clients ignore it, and ck renders combined markers like pending (path+spec).

Dependencies

  • subc-control 0.32.0, subc-client-rs 0.30.0, plus dependent crates and test packages.