Skip to content

fix(mc-host): harden cross-harness lifecycle integration - #46

Draft
ahrav wants to merge 1 commit into
stack/mc-host-09-release-verificationfrom
feat/mc-host-daemon-lifecycle
Draft

fix(mc-host): harden cross-harness lifecycle integration#46
ahrav wants to merge 1 commit into
stack/mc-host-09-release-verificationfrom
feat/mc-host-daemon-lifecycle

Conversation

@ahrav

@ahrav ahrav commented Aug 26, 2026

Copy link
Copy Markdown
Owner

Summary

  • keep start non-preemptive while explicit restart merges qualified harness selection
  • bind persisted credential identities to the active connection key without storing values
  • quarantine unknown selector schemas and preserve exact restart effects
  • move local qualification/install evidence to ignored tmp/ paths
  • add two-owner cross-harness smoke and aggregate release gates

Stack

PR 10 of 17. Base: stack/mc-host-09-release-verification (#52).

Focused review follow-ups:

Validation

  • cargo test -p mc-host
  • cargo test -p mc-module
  • cargo clippy --workspace --all-targets -- -D warnings
  • shared lifecycle policy/client tests
  • plugin demand-path and CLI contract suites
  • bun run typecheck, bun run build, bun run lint
  • parallel invariant, TypeScript, complexity, and final structured reviews

Known Residuals

  • Exact Linux kernel 4.18 and macOS target qualification require external runners.
  • Environment-gated retained-fd and cross-harness installed smokes require qualified MC_HOST_CANARY_* inputs.
  • Payload-name reservation, protected qualification workflow, registry canaries, and npm publication remain external; publication is intentionally out of scope.

@coderabbitai

coderabbitai Bot commented Aug 26, 2026

Copy link
Copy Markdown

Important

Draft PR not reviewed

Draft PRs are not automatically reviewed by default.

  • Trigger a manual review

To automatically review draft PRs, update your CodeRabbit configuration:

reviews:
  auto_review:
    drafts: true

Comment @coderabbitai help to get the list of available commands.

@ahrav
ahrav force-pushed the feat/mc-host-daemon-lifecycle branch from 6f7136d to 1d171f8 Compare August 26, 2026 17:01
@ahrav ahrav changed the title feat(mc-host): add managed daemon lifecycle and release gates fix(mc-host): harden cross-harness lifecycle integration Aug 26, 2026
@ahrav
ahrav changed the base branch from main to stack/mc-host-09-release-verification August 26, 2026 17:01
Comment on lines 1174 to +1183
match observed.state {
// No lock-held incarnation: nothing to signal, unlink, or clean.
LifecycleState::Stopped => DaemonResult::new(command, true, "stopped", "already_stopped"),
// No lock-held incarnation exists. Selector cleanup is best-effort
// stale-state removal under the transaction ownership boundary.
LifecycleState::Stopped => match serve::clear_active_selection() {
Ok(()) => DaemonResult::new(command, true, "stopped", "already_stopped"),
Err("unsupported active harness selection schema") => {
DaemonResult::new(command, false, "wedged", "unsupported_state_schema")
}
Err(_) => DaemonResult::new(command, false, "wedged", "internal_error"),
},

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comment says selector cleanup here is "best-effort," but the implementation does the opposite: any clear_active_selection() error — including a plain, transient I/O failure on active-selection.json (permission hiccup, disk error, etc.), not just the deliberate unsupported_state_schema quarantine case — turns a stop on an already-Stopped daemon into a hard failure (wedged/internal_error). The same pattern repeats for the Running branch below (lines 1199-1205): a stop that already succeeded at stop_phase can still be reported as wedged solely because of a bookkeeping-file read/write error, even though the daemon itself is confirmed stopped.

Previously Stopped => already_stopped was a trivially-successful, idempotent no-op. Now callers that rely on stop being safe to call defensively (cleanup scripts, uninstallers, retry loops) can get a wedged result — which per the release contract implies "inspect the daemon process" — even though there's no daemon at all.

If the intent is genuinely best-effort (as the comment claims), consider only hard-failing on the deliberate unsupported_state_schema quarantine case and swallowing/logging other I/O errors instead of surfacing them as wedged. If the strict fail-closed behavior for any selection-file error is intentional, the comment should be updated to say so rather than "best-effort," since the two read very differently to a future maintainer.

@claude

claude Bot commented Aug 26, 2026

Copy link
Copy Markdown

Review summary

Focused review of the lifecycle/credential-selection hardening in ck-mc-host.rs / serve.rs, the TS lifecycle-policy wiring, and the release-evidence path relocation.

Overall: the core state machine is careful and well-tested. I traced through the PreparedLauncherEnvelope/merge_selection/credential_identities flow in detail:

  • start correctly stays non-preemptive (any diff from the active selection, including additive credential merges, is rejected with harness_unavailable), while restart on a Running daemon requires exact preservation of previously-bound credential identities (require_previous_credentials: true) before it will merge in a new harness selection — matches the stated goal of "keep start non-preemptive while explicit restart merges qualified harness selection," and the new credentialed_restart_is_explicit_exact_and_clears_stale_selection test exercises the tricky cases (conflicting value, invalid descriptor, additive merge via start vs restart, forced commit failure, unknown schema quarantine) well.
  • active-selection.json handling (read_selection/write_selection) is solid: O_NOFOLLOW, uid/mode/nlink checks, size bound, atomic temp-file + rename + directory fsync, deny_unknown_fields, and an explicit schema gate that quarantines unknown future schemas instead of guessing. Good defensive filesystem code.
  • Binding credential identities (not values) to the live connection key via a domain-separated HMAC (ACTIVE_SELECTION_CREDENTIAL_DOMAIN) is a reasonable way to detect "same secret, different owner" without ever persisting the secret — the domain separation means this isn't a harmful key-reuse pattern.
  • The client.ts change (this.liveRoutesactive?.liveRoutes) looks like a genuine pre-existing bug fix — liveRoutes lives on the per-connection object, not on McHostClient itself, and the surrounding code already scopes to this.active.

One finding posted inline: the cmd_stop selector-cleanup comment claims "best-effort" but the code fail-closes on any clear_active_selection() error (not just the deliberate unsupported-schema quarantine), so a previously always-succeeding, idempotent stop on a stopped/already-stopped daemon can now return wedged purely from a bookkeeping-file I/O hiccup. Worth confirming this is the intended tradeoff (and fixing the comment either way).

No other correctness, security, or performance issues found in the build-mc-host-payload.ts / qualify-mc-host-production-inputs.ts evidence-path relocation (docs/evidence/tmp/) — the fail-closed synthesis path (missing local evidence is only permitted when the committed lock itself is unqualified) is consistent between the two scripts and covered by the new tests.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant