Skip to content

fix(mc-host): bind runtime execution to verified identity - #59

Merged
ahrav merged 8 commits into
feat/mc-host-daemon-lifecyclefrom
stack/mc-host-12-runtime-identity
Aug 29, 2026
Merged

fix(mc-host): bind runtime execution to verified identity#59
ahrav merged 8 commits into
feat/mc-host-daemon-lifecyclefrom
stack/mc-host-12-runtime-identity

Conversation

@ahrav

@ahrav ahrav commented Aug 26, 2026

Copy link
Copy Markdown
Owner

Summary

Native lifecycle execution now stays bound to verified generation and closure objects through spawn. The layer also closes restart snapshot drift, prevents dispatch after terminal closure, makes self-exec explicitly debug-test-only, and preserves cleanup ownership across failure paths.

Verification

  • cargo clippy --workspace --all-targets -- -D warnings
  • cargo test -p mc-host
  • cargo test -p mc-module
  • Focused lifecycle, closure, and Broca subprocess suites

Stack

  1. fix(mc-host): authenticate daemon version transcripts #58 authentication transcript
  2. fix(mc-host): bind runtime execution to verified identity #59 native runtime identity
  3. fix(plugin): fence lifecycle compatibility by daemon #60 client compatibility
  4. test(release): bind lifecycle evidence to attested runs #61 release evidence
  5. fix(ci): restore portable lifecycle source checks #62 CI portability

@coderabbitai

coderabbitai Bot commented Aug 26, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 22612693-0662-4462-b878-fc48c381bc96

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

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

@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for security reviews. Please try again later.

Base automatically changed from stack/mc-host-11-auth-transcript to feat/mc-host-daemon-lifecycle August 28, 2026 19:03
@ahrav
ahrav force-pushed the stack/mc-host-12-runtime-identity branch from 4a2d65c to 07af908 Compare August 28, 2026 19:03
@kilo-code-bot

kilo-code-bot Bot commented Aug 28, 2026

Copy link
Copy Markdown

Code Review Summary

Status: No Issues Found | Recommendation: Merge

Files Reviewed (1 file)
  • docs/evidence/claims-backfill/v84-process-crash.json
Previous Review Summaries (5 snapshots, latest commit f160a91)

Current summary above is authoritative. Previous snapshots are kept for context only.

Previous review (commit f160a91)

Status: No Issues Found | Recommendation: Merge

Files Reviewed (2 files)
  • packages/e2e-tests/src/incident-pool/evidence.test.ts
  • packages/e2e-tests/src/incident-pool/evidence.ts

Previous review (commit b998c56)

Status: No Issues Found | Recommendation: Merge

Files Reviewed (6 files)
  • crates/mc-host/examples/synapse_perf.rs
  • crates/mc-host/src/lifecycle.rs
  • packages/e2e-tests/incidents/source-inventory.json
  • packages/e2e-tests/src/incident-pool/evidence.ts
  • packages/e2e-tests/tests/cache-invariants.test.ts
  • packages/e2e-tests/tests/pi-cache-invariants.test.ts

Previous review (commit 8b499a8)

Status: No Issues Found | Recommendation: Merge

Files Reviewed (1 file)
  • .github/workflows/ci.yml

Previous review (commit c438f4a)

Status: No Issues Found | Recommendation: Merge

Files Reviewed (20 files)
  • crates/mc-host/Cargo.toml
  • crates/mc-host/src/broca/backend.rs
  • crates/mc-host/src/broca/config.rs
  • crates/mc-host/src/broca/opencode.rs
  • crates/mc-host/src/broca/pi.rs
  • crates/mc-host/src/broca/protocol.rs
  • crates/mc-host/src/broca/subprocess.rs
  • crates/mc-host/src/broca/supervisor.rs
  • crates/mc-host/src/control.rs
  • crates/mc-host/src/generation.rs
  • crates/mc-host/src/harness_closure.rs
  • crates/mc-host/tests/broca_protocol.rs
  • crates/mc-host/tests/broca_subprocess.rs
  • crates/mc-host/tests/harness_closure.rs
  • crates/mc-module/src/bin/ck-mc-host.rs
  • crates/mc-module/src/bin/ck_mc_host/serve.rs
  • crates/mc-module/src/bin/ck_mc_host/spawn.rs
  • crates/mc-module/src/lib.rs
  • crates/mc-module/tests/host_adapter.rs
  • crates/mc-module/tests/lifecycle_cli.rs

Previous review (commit 07af908)

Status: No Issues Found | Recommendation: Merge

Files Reviewed (19 files)
  • crates/mc-host/Cargo.toml
  • crates/mc-host/src/broca/backend.rs
  • crates/mc-host/src/broca/opencode.rs
  • crates/mc-host/src/broca/pi.rs
  • crates/mc-host/src/broca/protocol.rs
  • crates/mc-host/src/broca/subprocess.rs
  • crates/mc-host/src/broca/supervisor.rs
  • crates/mc-host/src/control.rs
  • crates/mc-host/src/generation.rs
  • crates/mc-host/src/harness_closure.rs
  • crates/mc-host/tests/broca_protocol.rs
  • crates/mc-host/tests/broca_subprocess.rs
  • crates/mc-host/tests/harness_closure.rs
  • crates/mc-module/src/bin/ck-mc-host.rs
  • crates/mc-module/src/bin/ck_mc_host/serve.rs
  • crates/mc-module/src/bin/ck_mc_host/spawn.rs
  • crates/mc-module/src/lib.rs
  • crates/mc-module/tests/host_adapter.rs
  • crates/mc-module/tests/lifecycle_cli.rs

Reviewed by gemini-3.7-flash · Input: 65.6K · Output: 4.8K · Cached: 126.4K

Descriptor-rooted paths assumed Linux `/proc/self/fd` magic-symlink
semantics. On darwin, a shipped supported target, `open("/dev/fd/N")` is
equivalent to `fcntl(N, F_DUPFD, 0)` and the entry is not a symlink, so
verification left the handed-out descriptor at EOF and interpreted module
arguments lost the closure tree their sibling imports resolve against.

- Rewind a resolved node descriptor after verification hashes it to EOF.
- Give interpreted module arguments a path the loader can walk back to the
  closure, and inherit a module descriptor only where that path is
  descriptor-rooted.
- Append `harness_dispatch` from the reserved terminal headroom like
  `run_started`, so aggregate pressure can no longer fail a run the
  supervisor already admitted before it spawns, and the per-run
  assistant-text budget stays whole.
- Inherit only the descriptors a child's own arguments name, dropping the
  closure directory descriptor from both harness adapters.
- Collapse the duplicated descriptor-root selection into one helper and
  drop the now-unused `resolve_node` and `ValidatedGeneration::path`.
- Drop an unreachable disjunct in `merge_selection`.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: c438f4a22c

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment on lines +982 to +983
BackendEvent::HarnessDispatch { harness } => {
return append_reserved(run, protocol::harness_dispatch_unit(&run.run_id, harness));

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Bound repeated harness dispatch events

A custom LlmExecutionBackend can emit HarnessDispatch repeatedly, and every occurrence is appended without charging retained bytes, incrementing replay_bytes, or recording that the one reserved dispatch slot was already used. Because the public backend contract permits emitting events synchronously, an erroneous backend can loop on this variant and grow a run's replay without either configured memory cap until the host exhausts memory; reject duplicate dispatches or track and enforce a single reserved dispatch per run.

Useful? React with 👍 / 👎.

ahrav added 3 commits August 28, 2026 23:18
Two public-CI jobs assumed the private ../commons cortexkit crates were
available. They are not: provision-rust-ci-stubs.sh creates metadata-only
stubs with an empty lib.rs, which satisfies the manifest graph but resolves
no types.

The shared-memory source build compiled mc-module, whose mc-core and
mc-store dependencies import real cortexkit items, so the stub lib.rs
produced unresolved imports and 35 cascading errors in mc-store. Drop the
ck-mc-host binary build and the lifecycle_cli contract from the public
matrix; the local release gate runs the whole workspace against the real
sibling sources, and mc-host itself does not depend on mc-store, so the
transport, host, and addon coverage this job exists for is unchanged.

Check (plugin) had the opposite gap. Its `bun run test` ends in
test:release, whose dependency-boundary check shells out to
`cargo tree -p mc-host`, and cargo refuses to load the workspace until
every path-dep manifest exists. That job never provisioned the stubs, so
the check failed on a missing cortexkit-cache-core manifest rather than on
the dependency edge it asserts. Provision the stubs there too; nothing in
the job compiles them.
Two build breaks that public CI could not see. The shared-memory matrix
stopped at an earlier failure before reaching the macOS test step, and no
job compiles examples at all.

`hostile_shapes_at_the_lock_names_fail_closed` planted its FIFO with
`rustix::fs::mkfifoat`, which rustix gates away from Apple targets, so the
test compiled only on Linux even though it carries no cfg gate. Plant the
FIFO with the POSIX `mkfifo` utility instead, matching the same decision
already recorded in `connection_file.rs`: a lock name must classify as a
hostile shape on every platform, so the test stays compiled everywhere
rather than being cfg'd out on the platform whose absence let the break
through. `mkfifo` honours the umask, so the mode is set explicitly after.

The `synapse_perf` example still built `LaneInfo` without the
`execution_provider` field added when lanes began publishing their
provider. Its inline engine computes on the CPU, so it advertises the same
value a bundle-backed CPU lane does. This break also fails
`cargo nextest run --workspace`, which is the local release gate.
The seven `shm-hardening-*` drills landed in shapes the evidence loader
could not read, so `validate:incident-verifiers:ci` failed on the first one
it reached. The job had been skipped behind a failing upstream check, so
this never surfaced.

The verifier resolver understood only `mc-module` and paths rooted at the
e2e package. Resolve Rust verifiers through cargo's target layout instead:
`--test <target>` names an integration target under `tests/`, and a
`::`-qualified `--lib` filter names an inline `#[cfg(test)]` module, so the
verifier is the module's own source file. A `src/`-rooted TS path is
recorded relative to a package root the command never names, so it resolves
against every package and requires exactly one hit rather than attributing
the mutation to whichever package sorts first. Every resolved path is
already required to exist, so an unhandled layout fails loudly instead of
pointing at a plausible wrong file.

A deferred record states that no mutation was applied and names the reason.
It binds no verifier and carries no replay, so it is not evidence and does
not become an evidence record; the hardening-matrix gate is what keeps the
unproven claim blocked. An artifact whose records are all deferred
therefore has no run command to require, and the empty-artifact guard now
counts what the artifact declared rather than what survived, so it still
rejects an artifact that declares nothing.

The accepted snapshot moves to 20 artifacts and 27 records.

The three inventory-completeness assertions still fail: `source-inventory`
carries no items for these drills, and each entry needs a disposition and
rationale per claim that only their author can decide.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 20312f1368

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

} else {
"/proc/self/fd/"
};
assert!(args[0].starts_with(descriptor_root));

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Use closure-path expectations for Pi modules on macOS

On macOS, ResolvedHarnessNode::module_path() deliberately returns closure_path because DESCRIPTOR_PATHS_ARE_FILE_LIKE is false, so the Pi entrypoint and provider-extension arguments will not start with /dev/fd/. Consequently, cargo test -p mc-host --test broca_subprocess always fails pi_argv_privacy_contract on the supported macOS targets after the fixture successfully runs; make these assertions follow the same platform-specific path semantics as module_path().

Useful? React with 👍 / 👎.

…tract

The B-class m[0]/m[1] taxonomy tests failed for two different reasons.

B10 and B12 hit the epoch-settling bug 2a66471 already fixed on the Pi
side: seeding a memory promotes it to verified, which queues a verification
event whose ONE epoch bump lands during the next turn's injection, after
`setProjectEpoch` has pinned. m[0] then HARD-refolds on
project_memory_change and the write lands in m[0] instead of the m[1] delta
the test looks in, so the surfacing request is never found. Port the same
`verifyAndSettle` drain into the OpenCode suite's `seedMemory`, which is why
the Pi mirrors of both already pass.

B11 asserted an invariant the design makes unreachable.
`sessionMemoryBlockStillEligible` compares every rendered id's render-time
content digest against the row's current digest, so an in-place rewrite of a
memory that m[0] already rendered makes the cached block ineligible and m[0]
MUST re-materialize; no epoch pin can hold it byte-frozen. Both renderers
share that gate, so both mirrors asserted a stale-but-frozen m[0] that
cannot happen. Hold the test to the contract the gate actually provides
instead: the rewrite HARD-refolds m[0] onto the revised bytes, the frozen
baseline is gone, and the refold advances the mutation cursor so no
<memory-updates> delta remains. Pinning the epoch back stays in the setup
because it is what proves the refold comes from the digest gate rather than
from a project_memory_change bump. The <memory-updates> lane keeps its
coverage in the renderer unit suites, which exercise it directly.

Also register the seven shm-hardening drills in the source inventory. Each
non-deferred drill applied a crafted invalid state, observed it red, and
observed its reverted rerun green against a bound verifier, which is exactly
the mechanical `verifier_evidence` disposition every other mutation claim
carries. The deferred drill records only why no mutation was applied, so it
contributes an item with no claims.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: b998c561de

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment on lines +1156 to +1157
let descriptor_path = validated.descriptor_root_path().join("bin/ck-mc-host");
let expected = std::fs::read(&descriptor_path).expect("descriptor bytes");

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Gate descriptor-root traversal test to Linux

On macOS, descriptor_root_path() returns /dev/fd/<dir-fd>, but /dev/fd entries cannot be traversed as directories (as the new descriptor_path documentation itself notes). Consequently, this initial read of /dev/fd/<n>/bin/ck-mc-host fails before the replacement assertion, so a full cargo test -p mc-host fails on the supported macOS targets; restrict this test to platforms with file-like descriptor paths or use a macOS-compatible assertion.

Useful? React with 👍 / 👎.

ahrav added 2 commits August 29, 2026 00:09
…r justifies

Review of the previous commit found the deferred-record path had turned a
fail-closed error into a silent pass. Before that change the loader rejected
`shm-hardening-u6.json` outright (no top-level `command`), so the gate held
by accident. Skipping deferred records removed the rejection and rested the
guarantee on the failure-hardening matrix gate instead, which does not
provide it: `validate-shm-hardening-matrix.ts` never reads mutation
artifacts, and CI runs it with `--allow-unresolved`, which exits 0. Marking
a record `deferred` was therefore enough to carry an untested hardening
claim through the merge gate that exists to stop exactly that.

Bind the deferral to the machine-checked condition it already cites. Every
deferral's stated reason is that the failure_hardening matrix is unresolved,
and that is also the state in which tuple-specific execution is blocked, so
a deferral is only defensible while `validateCommittedMatrix()` reports
`unresolved`. Freezing the matrix unblocks that execution, so a surviving
deferral then fails closed and must be replaced by a real mutation record.
An `invalid` matrix is not a licence either: failing its own validation says
nothing about whether the drill is inapplicable.

Verified by flipping the committed manifest's status to FROZEN, observing
`loadMutationEvidence` throw, and restoring the manifest byte-identically.
The exported predicate carries that policy in a regression test so the
gate cannot quietly reopen.
… bytes

`dirtyDiffDigest` hashes the bytes of every path in the campaign's
IMPLEMENTATION_FILES manifest, and that manifest covers
packages/e2e-tests/tests/cache-invariants.test.ts and
tests/pi-cache-invariants.test.ts. Retargeting the B-class tests changed
those bytes, so the committed digest no longer described the implementation
the campaign had been observed against.

Regenerated through the test's own UPDATE_CLAIMS_CRASH_EVIDENCE path rather
than by hand-editing the digest: the campaign re-ran the full matrix and
recovered every cut, so the artifact records a real observation of the
current bytes instead of asserting that an older run covered them. The
matrix, summary, limits, and implementationFiles are byte-identical, which
is the evidence that only the covered bytes moved and no recorded outcome
changed.

`limits` scopes this to a single host, so the re-observation also replaces
the recorded environment and runtimes with the ones that actually produced
it: linux/x64 on bun 1.3.14 and node v24.18.0, where the previous record was
linux/arm64 on bun 1.4.0 and node v24.15.0. CI checks those fields for shape
only. Re-run the campaign on an arm64 host if that environment is the one
worth carrying in the record.
@ahrav
ahrav merged commit 3c02fcf into feat/mc-host-daemon-lifecycle Aug 29, 2026
16 of 19 checks passed
@ahrav
ahrav deleted the stack/mc-host-12-runtime-identity branch August 29, 2026 00:28
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