Skip to content

perf(test): reduce messaging and gateway setup overhead - #6282

Merged
cv merged 2 commits into
mainfrom
codex/perf-test-io-6245-batch-4
Jul 5, 2026
Merged

perf(test): reduce messaging and gateway setup overhead#6282
cv merged 2 commits into
mainfrom
codex/perf-test-io-6245-batch-4

Conversation

@cv

@cv cv commented Jul 5, 2026

Copy link
Copy Markdown
Collaborator

Summary

Removes repeated TypeScript process bootstrapping from the messaging build-applier tests while retaining representative executable and security boundaries. It also narrows gateway-state's known-hosts dependency to the existing leaf module so shard 3 no longer collects the full onboarding graph for that helper.

Related Issue

Related to #6245.

Changes

  • Build messaging plans in-process and exercise exported production phase/render seams directly where process behavior is not the contract.
  • Reduce the messaging-applier group from 57 top-level test-controlled subprocesses to 10: 21 legacy npx tsx builders are removed, while nine applier contracts and one generator contract remain.
  • Preserve real fake npm, openclaw, and uv command boundaries, including archive provenance/integrity, unsafe archive exit behavior, doctor rewrite/reapply, WeChat build-file routing, Hermes rendering, argv, env, and exit status.
  • Load pruneKnownHostsEntries from onboard/known-hosts instead of the 5,282-line onboarding barrel; the traced source graph falls from 495 modules to 138 modules (72.1% fewer).

Type of Change

  • Code change (feature, bug fix, or refactor)
  • Code change with doc updates
  • Doc only (prose changes, no code sample modifications)
  • Doc only (includes code sample changes)

Quality Gates

  • Tests added or updated for changed behavior
  • Existing tests cover changed behavior — justification:
  • Tests not applicable — justification:
  • Docs updated for user-facing behavior changes
  • Docs not applicable — justification: internal dependency narrowing and test execution strategy only; no command, config, default, API, output, policy, or recovery behavior changes
  • Sensitive paths changed (security, policy, credentials, preflight, onboarding, inference, runner, sandbox, or messaging)
  • Sensitive-path review completed or maintainer-approved waiver recorded — reviewer/approval link/justification: independent local review found no remaining actionable findings; archive integrity/provenance, unsafe-path failure, doctor reapply, and OpenClaw/Hermes process contracts remain real
  • Non-success, skipped, or missing CI check accepted by maintainer — check name, approval link, and follow-up issue:

Verification

  • PR description includes the DCO sign-off declaration and every commit appears as Verified in GitHub
  • Normal pre-commit, commit-msg, and pre-push hooks passed, or npm run check:diff passed when hooks were skipped or unavailable
  • Targeted behavior tests pass for the current change set, or tests are marked not applicable above — fresh npm run build:cli, then 7 focused Vitest files: 67/67 passed in 3.93s wall
  • Applicable broad gate passed — npm test for broad runtime/test-harness changes; npm run check for repo-wide validation/coverage changes — command/result: not applicable to this focused four-file batch; final-head CI remains authoritative for full coverage
  • Quality Gates section completed with required justifications or waivers
  • No secrets, API keys, or credentials committed
  • npm run docs builds without warnings (doc changes only)
  • Doc pages follow the style guide (doc changes only)
  • New doc pages include SPDX header and frontmatter (new pages only)

Performance evidence

  • Messaging-applier merged-CI baseline: 19.163s across the four files; final local test execution: 1.60s. The environments differ, so final-head CI is the authoritative comparison.
  • Gateway-state traced source graph: 495 to 138 modules; simulated cold TypeScript transpilation: 1,330ms to 476ms.
  • This is another incremental perf(test): reduce test I/O to restore 2–5 minute full-suite runs #6245 batch, not a claim that the full suite has reached the 2–5 minute target.

Signed-off-by: Carlos Villela cvillela@nvidia.com

Summary by CodeRabbit

  • Tests
    • Refactored messaging build-applier suites to invoke messaging plan reading and build phases directly (instead of relying on process execution), improving validation of safety rules and failure behavior.
    • Strengthened integrity and “fails closed” checks by asserting specific thrown error messages and verifying expected trace/artifact outcomes.
  • Chores
    • Minor internal adjustments to sandbox connection and gateway-state wiring (no end-user behavior changes).

Signed-off-by: Carlos Villela <cvillela@nvidia.com>
@coderabbitai

coderabbitai Bot commented Jul 5, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: 52182435-65cf-4cfa-8e0b-64b71dc12afe

📥 Commits

Reviewing files that changed from the base of the PR and between 65aca84 and cc9d35b.

📒 Files selected for processing (1)
  • src/lib/actions/sandbox/connect.ts

📝 Walkthrough

Walkthrough

The sandbox gateway module updates import sources for known-hosts pruning and Docker driver recovery. Messaging build applier tests now read plans from env and call build/apply/render helpers directly, replacing many spawned-process assertions with direct thrown-error and return-value checks.

Changes

Gateway State Import Re-sourcing

Layer / File(s) Summary
Re-sourced onboard imports
src/lib/actions/sandbox/gateway-state.ts
pruneKnownHostsEntries now imports from ../../onboard/known-hosts, and Docker driver recovery imports are regrouped into one block.

Messaging Build Applier Direct Invocation Test Refactor

Layer / File(s) Summary
Test helper functions and imports
test/messaging-build-applier*.test.ts
New imports and helpers (thrownMessage, buildPlanEnv, runApplierProcess, describeDryRun) support direct invocation, and withLegacyMessagingPlanEnvDirect replaces the legacy env wrapper.
Integrity test conversions to direct plan application
test/messaging-build-applier-integrity.test.ts
Integrity drift cases now read plans from env and assert thrown messages from applyMessagingBuildPhase, with one remaining process-based test also moved to the direct env helper.
Render-safety test conversions
test/messaging-build-applier-render-safety.test.ts
Path escape and multiline env injection tests now call applyMessagingAgentRenderToLocalFiles directly and assert the thrown errors.
Dry-run and plugin selection test conversions
test/messaging-build-applier.test.ts
Agent-install dry-run, channel/plugin selection, and placeholder-preservation tests use async describeDryRun() and direct plan reads instead of parseDryRun/spawnSync.
Package install and integrity enforcement test conversions
test/messaging-build-applier.test.ts
Reviewed package installs, pinned installs, Slack integrity checks, and Hermes Python package validation now use direct plan reads and applyMessagingBuildPhase with thrown-message assertions.
Post-agent-install render contract tests
test/messaging-build-applier.test.ts
Post-agent-install render, doctor rewrite, WeChat build files, and Hermes render tests now build env via withLegacyMessagingPlanEnvDirect() and run phases through runApplierProcess().

Estimated code review effort: 3 (Moderate) | ~25 minutes

Suggested labels: chore

Suggested reviewers: ericksoa, jyaunches

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main performance-focused test and gateway setup overhead reduction.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch codex/perf-test-io-6245-batch-4

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

@github-code-quality

github-code-quality Bot commented Jul 5, 2026

Copy link
Copy Markdown
Contributor

Code Coverage Overview

Languages: TypeScript

TypeScript / code-coverage/plugin

The overall coverage in the codex/perf-test-io-6... branch is 96%. Coverage data for the main branch is not yet available.

Show a code coverage summary of the most covered files.
File main codex/perf-test-io-6... cc9d35b +/-
nemoclaw/src/se...cret-scanner.ts 100%
nemoclaw/src/commands/slash.ts 100%
nemoclaw/src/li...bprocess-env.ts 100%
nemoclaw/src/bl...eprint/state.ts 98%
nemoclaw/src/onboard/config.ts 98%
nemoclaw/src/bl...int/snapshot.ts 97%
nemoclaw/src/bl...print/runner.ts 95%
nemoclaw/src/co...ration-state.ts 94%
nemoclaw/src/bl...ate-networks.ts 94%
nemoclaw/src/index.ts 94%

TypeScript / code-coverage/cli

The overall coverage in the codex/perf-test-io-6... branch is 71%. Coverage data for the main branch is not yet available.

Show a code coverage summary of the most covered files.
File main codex/perf-test-io-6... cc9d35b +/-
src/lib/shields...nsition-lock.ts 87%
src/lib/actions...all/run-plan.ts 81%
src/lib/state/o...oard-session.ts 81%
src/lib/onboard/preflight.ts 71%
src/lib/state/sandbox.ts 71%
src/lib/onboard...er-gpu-patch.ts 69%
src/lib/shields/index.ts 68%
src/lib/policy/index.ts 66%
src/lib/actions...licy-channel.ts 60%
src/lib/onboard.ts 24%

Updated July 05, 2026 02:52 UTC
Code Coverage is in Public Preview. Learn more and provide us with your feedback.

@github-actions

github-actions Bot commented Jul 5, 2026

Copy link
Copy Markdown
Contributor

E2E Advisor Recommendation

Required E2E: sandbox-operations, sandbox-rlimits-connect
Optional E2E: gateway-guard-recovery, full-e2e

Dispatch hint: sandbox-operations,sandbox-rlimits-connect

Workflow run

Full advisor summary

E2E Recommendation Advisor

Base: origin/main
Head: HEAD
Confidence: high

Required E2E

  • sandbox-operations (medium): Exercises real repo CLI, Docker/OpenShell sandbox lifecycle, list/status, registry rebuild, gateway recovery, process recovery, destroy, and multi-sandbox isolation. This is the broadest existing live coverage for gateway-state.ts and sandbox lifecycle regressions.
  • sandbox-rlimits-connect (medium): Directly exercises nemoclaw <sandbox> connect against a live onboarded sandbox. The connect.ts change is in the connect readiness/status path, so a direct connect E2E should be merge-blocking despite this job being explicit-only by default.

Optional E2E

  • gateway-guard-recovery (medium): Useful adjacent confidence because it invokes nemoclaw <sandbox> connect --probe-only, which also enters connectSandbox and ensureLiveSandboxOrExit, but its primary contract is guard-chain recovery rather than normal interactive connect readiness.
  • full-e2e (medium): Optional end-to-end user journey confidence for install/onboard/list/status/inference after gateway-state import changes, though it does not directly exercise interactive connect.

New E2E recommendations

  • gateway identity drift known_hosts cleanup (medium): gateway-state.ts changed the runtime import for pruneKnownHostsEntries used only on the identity_drift branch. Existing live tests do not appear to force an OpenShell gateway SSH identity drift and assert known_hosts pruning/retry behavior.
    • Suggested test: Add a live gateway identity-drift E2E that creates stale known_hosts entries, triggers the identity_drift path in ensureLiveSandboxOrExit, and verifies stale OpenShell host keys are pruned before retry guidance.

Dispatch hint

  • Workflow: .github/workflows/e2e.yaml
  • jobs input: sandbox-operations,sandbox-rlimits-connect

@github-actions

github-actions Bot commented Jul 5, 2026

Copy link
Copy Markdown
Contributor

E2E Target Recommendation

Required E2E targets: gateway-guard-recovery, ubuntu-repo-docker-post-reboot-recovery
Optional E2E targets: ubuntu-repo-cloud-openclaw, issue-2478-crash-loop-recovery

Dispatch required E2E targets:

  • gh workflow run e2e.yaml --ref <pr-head-ref> --field jobs=gateway-guard-recovery
  • gh workflow run e2e.yaml --ref <pr-head-ref> --field targets=ubuntu-repo-docker-post-reboot-recovery

Workflow run

Full E2E target advisor summary

E2E Target Advisor

Base: origin/main
Head: HEAD
Confidence: high

Required E2E targets

  • gateway-guard-recovery: src/lib/actions/sandbox/connect.ts changes the production sandbox connect path used by connect --probe-only recovery; the gateway-guard-recovery job directly exercises that live recovery boundary.
    • Dispatch: gh workflow run e2e.yaml --ref <pr-head-ref> --field jobs=gateway-guard-recovery
  • ubuntu-repo-docker-post-reboot-recovery: src/lib/actions/sandbox/gateway-state.ts affects sandbox status and Docker-driver recovery handling; this live-supported registry target stops the labeled sandbox container, runs nemoclaw status, and validates registry/container preservation.
    • Dispatch: gh workflow run e2e.yaml --ref <pr-head-ref> --field targets=ubuntu-repo-docker-post-reboot-recovery

Optional E2E targets

  • ubuntu-repo-cloud-openclaw: Baseline Ubuntu cloud OpenClaw target provides adjacent coverage for normal onboarding and gateway health after the sandbox connect/status import refactors.
    • Dispatch: gh workflow run e2e.yaml --ref <pr-head-ref> --field targets=ubuntu-repo-cloud-openclaw
  • issue-2478-crash-loop-recovery: Adjacent free-standing recovery job repeatedly exercises connect --probe-only across gateway crash-loop scenarios; useful if the PR owner wants broader recovery soak coverage for the connect path change.
    • Dispatch: gh workflow run e2e.yaml --ref <pr-head-ref> --field jobs=issue-2478-crash-loop-recovery

Relevant changed files

  • src/lib/actions/sandbox/connect.ts
  • src/lib/actions/sandbox/gateway-state.ts

@github-actions

github-actions Bot commented Jul 5, 2026

Copy link
Copy Markdown
Contributor

PR Review Advisor (Nemotron Ultra) — Changes requested

Merge posture: Do not merge yet
Primary next action: Resolve or justify PRA-1: Source-of-truth review needed: thrownMessage helper sync-only limitation.
Open items: 0 required · 6 warnings · 4 suggestions · 7 test follow-ups
Since last review: 0 prior items resolved · 3 still apply · 4 new items found

Action checklist

  • PRA-1 Resolve or justify: Source-of-truth review needed: thrownMessage helper sync-only limitation
  • PRA-2 Resolve or justify: Source-of-truth review needed: CLI --dry-run argument parsing coverage gap
  • PRA-3 Resolve or justify: thrownMessage helper only catches synchronous throws in test/messaging-build-applier.test.ts:181
  • PRA-4 Resolve or justify: thrownMessage helper duplicated in integrity test with same sync-only limitation in test/messaging-build-applier-integrity.test.ts:56
  • PRA-5 Resolve or justify: CLI --dry-run argument parsing and stdout formatting coverage reduced to 1 of ~9 dry-run tests in test/messaging-build-applier.test.ts:161
  • PRA-7 Resolve or justify: spawnSync still imported but only 3 call sites remain — verify CLI integration coverage in test/messaging-build-applier.test.ts:6
  • PRA-T1 Add or justify test follow-up: Mocked behavioral coverage
  • PRA-T2 Add or justify test follow-up: Mocked behavioral coverage
  • PRA-T3 Add or justify test follow-up: Mocked behavioral coverage
  • PRA-T4 Add or justify test follow-up: Unused spawnSync import after test refactoring
  • PRA-T5 Add or justify test follow-up: spawnSync still imported but only 3 call sites remain — verify CLI integration coverage
  • PRA-T6 Add or justify test follow-up: thrownMessage helper sync-only limitation
  • PRA-T7 Add or justify test follow-up: CLI --dry-run argument parsing coverage gap
  • PRA-6 In-scope improvement: Unused spawnSync import after test refactoring in test/messaging-build-applier-integrity.test.ts:1
  • PRA-8 In-scope improvement: require('../../onboard') replaced with direct imports from ../../state/gateway — verify no behavioral change in src/lib/actions/sandbox/connect.ts:829
  • PRA-9 In-scope improvement: require('../../onboard') replaced with require('../../onboard/known-hosts') for pruneKnownHostsEntries in src/lib/actions/sandbox/gateway-state.ts:7
  • PRA-10 In-scope improvement: PR fix(mcp): reconcile Hermes runtime state #6261 overlap — coordinate to avoid merge conflicts in src/lib/actions/sandbox/connect.ts:1

Findings index

ID Severity Category Location Required action
PRA-1 Resolve/justify architecture Identify the invalid state, source boundary, source-fix constraint, regression test, and removal condition before merging the localized behavior.
PRA-2 Resolve/justify architecture Identify the invalid state, source boundary, source-fix constraint, regression test, and removal condition before merging the localized behavior.
PRA-3 Resolve/justify correctness test/messaging-build-applier.test.ts:181 Add a JSDoc comment to thrownMessage noting it only handles synchronous throws, or convert to async/await pattern that catches both sync throws and promise rejections.
PRA-4 Resolve/justify correctness test/messaging-build-applier-integrity.test.ts:56 Extract to shared test helper (e.g., test/helpers/thrown-message.ts) or add JSDoc comment noting synchronous-only limitation.
PRA-5 Resolve/justify correctness test/messaging-build-applier.test.ts:161 Add a unit test for parseMessagingBuildArgs covering --agent, --phase, --dry-run combinations, or keep one dry-run test per phase using runApplierProcess(env, agent, phase, true) to preserve CLI boundary coverage.
PRA-6 Improvement tests test/messaging-build-applier-integrity.test.ts:1 Remove the unused import: `import { spawnSync } from "node:child_process";`
PRA-7 Resolve/justify tests test/messaging-build-applier.test.ts:6 Verify the 3 remaining spawnSync call sites cover critical CLI boundaries. If not, add targeted integration tests or remove unused import.
PRA-8 Improvement correctness src/lib/actions/sandbox/connect.ts:829 Confirm isSandboxReady and parseSandboxStatus have identical signatures and behavior between the old onboard barrel export and the new state/gateway module.
PRA-9 Improvement correctness src/lib/actions/sandbox/gateway-state.ts:7 Confirm pruneKnownHostsEntries has identical signature and behavior. This is a more specific import which is an improvement.
PRA-10 Improvement architecture src/lib/actions/sandbox/connect.ts:1 Coordinate with PR #6261 author to avoid merge conflicts. Review both changes together for connect.ts.
Review findings by urgency: 0 required fixes, 6 items to resolve/justify, 4 in-scope improvements

⚠️ Resolve or justify before merge

Investigate these in the current review; either fix them, explain why they are not applicable, or document the accepted risk.

PRA-1 Resolve/justify — Source-of-truth review needed: thrownMessage helper sync-only limitation

  • Location: not file-specific
  • Category: architecture
  • Problem: The advisor marked localized patch analysis as needs_followup.
  • Impact: A localized workaround can preserve or hide an invalid state when the source boundary is unclear.
  • Recommended action: Identify the invalid state, source boundary, source-fix constraint, regression test, and removal condition before merging the localized behavior.
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: Inspect the localized patch and source-of-truth review fields for a concrete invalid state, source boundary, source-fix constraint, regression test, and removal condition.
  • Missing regression test: Add test verifying thrownMessage fails when callback doesn't throw (already covered); add async rejection test if helper is converted
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: Inspect the localized patch and source-of-truth review fields for a concrete invalid state, source boundary, source-fix constraint, regression test, and removal condition.
  • Evidence: try/catch only catches synchronous throws; Promise rejections bypass catch block

PRA-2 Resolve/justify — Source-of-truth review needed: CLI --dry-run argument parsing coverage gap

  • Location: not file-specific
  • Category: architecture
  • Problem: The advisor marked localized patch analysis as needs_followup.
  • Impact: A localized workaround can preserve or hide an invalid state when the source boundary is unclear.
  • Recommended action: Identify the invalid state, source boundary, source-fix constraint, regression test, and removal condition before merging the localized behavior.
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: Inspect the localized patch and source-of-truth review fields for a concrete invalid state, source boundary, source-fix constraint, regression test, and removal condition.
  • Missing regression test: Unit test for parseMessagingBuildArgs covering all flag combinations and verifying dry-run JSON output structure
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: Inspect the localized patch and source-of-truth review fields for a concrete invalid state, source boundary, source-fix constraint, regression test, and removal condition.
  • Evidence: Only line 207 uses runApplierProcess with dryRun=true; 8 tests use describeDryRun which calls describeMessagingBuildPhase directly

PRA-3 Resolve/justify — thrownMessage helper only catches synchronous throws

  • Location: test/messaging-build-applier.test.ts:181
  • Category: correctness
  • Problem: The thrownMessage helper uses try/catch which only captures synchronous throws. If applyMessagingBuildPhase or describeMessagingBuildPhase become async in the future, tests using this helper would silently pass without catching rejections because the helper's final 'throw new Error("Expected operation to throw")' only executes when the callback returns normally.
  • Impact: Future async refactoring of tested functions could silently disable negative test assertions, reducing confidence in fail-closed behavior for integrity checks and manifest validation.
  • Recommended action: Add a JSDoc comment to thrownMessage noting it only handles synchronous throws, or convert to async/await pattern that catches both sync throws and promise rejections.
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: Check all call sites of thrownMessage (lines 898, 978 in messaging-build-applier.test.ts and lines 168, 219 in messaging-build-applier-integrity.test.ts) invoke synchronous functions (applyMessagingBuildPhase, describeMessagingBuildPhase).
  • Missing regression test: Add a test that verifies thrownMessage correctly fails when the callback doesn't throw (already covered by the helper's final throw statement).
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: Check all call sites of thrownMessage (lines 898, 978 in messaging-build-applier.test.ts and lines 168, 219 in messaging-build-applier-integrity.test.ts) invoke synchronous functions (applyMessagingBuildPhase, describeMessagingBuildPhase).
  • Evidence: function thrownMessage(run: () => void): string { try { run(); } catch (error) { return error instanceof Error ? error.message : String(error); } throw new Error("Expected operation to throw"); }

PRA-4 Resolve/justify — thrownMessage helper duplicated in integrity test with same sync-only limitation

  • Location: test/messaging-build-applier-integrity.test.ts:56
  • Category: correctness
  • Problem: The thrownMessage helper is duplicated at line 56 in messaging-build-applier-integrity.test.ts with identical sync-only try/catch behavior.
  • Impact: Same future async refactoring risk as PRA-1; duplication increases maintenance burden if helper is fixed.
  • Recommended action: Extract to shared test helper (e.g., test/helpers/thrown-message.ts) or add JSDoc comment noting synchronous-only limitation.
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: Verify thrownMessage at line 56 is identical to the one in messaging-build-applier.test.ts:181.
  • Missing regression test: Same as PRA-1 — verify helper behavior with async rejection if extracted to shared location.
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: Verify thrownMessage at line 56 is identical to the one in messaging-build-applier.test.ts:181.
  • Evidence: function thrownMessage(run: () => void): string { try { run(); } catch (error) { return error instanceof Error ? error.message : String(error); } throw new Error("Expected operation to throw"); }

PRA-5 Resolve/justify — CLI --dry-run argument parsing and stdout formatting coverage reduced to 1 of ~9 dry-run tests

  • Location: test/messaging-build-applier.test.ts:161
  • Category: correctness
  • Problem: Dry-run tests now call describeMessagingBuildPhase directly instead of using runApplierProcess with --dry-run flag. This loses coverage of parseMessagingBuildArgs (flag parsing for --agent, --phase, --dry-run) and CLI stdout JSON formatting.
  • Impact: Regression in CLI argument parsing or dry-run output formatting would not be caught by unit tests. Only line 207 uses runApplierProcess with dryRun=true.
  • Recommended action: Add a unit test for parseMessagingBuildArgs covering --agent, --phase, --dry-run combinations, or keep one dry-run test per phase using runApplierProcess(env, agent, phase, true) to preserve CLI boundary coverage.
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: Search for '--dry-run' in test/messaging-build-applier.test.ts — only line 207 uses it via runApplierProcess with dryRun=true.
  • Missing regression test: Unit test for parseMessagingBuildArgs covering all flag combinations and verifying dry-run JSON output structure matches describeMessagingBuildPhase return value.
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: Search for '--dry-run' in test/messaging-build-applier.test.ts — only line 207 uses it via runApplierProcess with dryRun=true.
  • Evidence: async function describeDryRun(envOverrides, agent) { const env = await buildPlanEnv(envOverrides, agent); return describeMessagingBuildPhase(readMessagingBuildPlanFromEnv(env, agent), "agent-install", env); }

PRA-7 Resolve/justify — spawnSync still imported but only 3 call sites remain — verify CLI integration coverage

  • Location: test/messaging-build-applier.test.ts:6
  • Category: tests
  • Problem: spawnSync is still imported but only 3 call sites remain: runApplierProcess helper (line 141), one test at line 394, and generator integration test at line 1042.
  • Impact: If these 3 call sites don't cover critical CLI boundaries (agent-install, post-agent-install, runtime-setup phases with real argument parsing), regressions in CLI entry point could go undetected.
  • Recommended action: Verify the 3 remaining spawnSync call sites cover critical CLI boundaries. If not, add targeted integration tests or remove unused import.
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: Check lines 141, 394, 1042 in messaging-build-applier.test.ts for spawnSync usage and which phases they exercise.
  • Missing regression test: Ensure at least one integration test per phase (agent-install, post-agent-install, runtime-setup) exercises the CLI entry point with real argument parsing.
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: Check lines 141, 394, 1042 in messaging-build-applier.test.ts for spawnSync usage and which phases they exercise.
  • Evidence: import { spawnSync } from "node:child_process"; // line 6; used at lines 141, 394, 1042

💡 In-scope improvements

These are lower-risk, not throwaway. Prefer fixing them in this PR when they are local to changed code; defer only with rationale or a linked follow-up.

PRA-6 Improvement — Unused spawnSync import after test refactoring

  • Location: test/messaging-build-applier-integrity.test.ts:1
  • Category: tests
  • Problem: The test file imports spawnSync from node:child_process but no longer uses it — all tests converted to direct function calls.
  • Impact: Minor code hygiene issue; unused import adds noise and may confuse readers about test execution strategy.
  • Suggested action: Remove the unused import: `import { spawnSync } from "node:child_process";`
  • Expected follow-up: Prefer a current-PR fix when local to changed code; defer only with rationale or linked follow-up.
  • Verification: grep for spawnSync in messaging-build-applier-integrity.test.ts — no matches expected after cleanup.
  • Missing regression test: N/A — code cleanup only.
  • Done when: The local improvement is applied, or the PR notes why it should be deferred.
  • Evidence: import { spawnSync } from "node:child_process"; // line 1, no usage in file

PRA-8 Improvement — require('../../onboard') replaced with direct imports from ../../state/gateway — verify no behavioral change

  • Location: src/lib/actions/sandbox/connect.ts:829
  • Category: correctness
  • Problem: The require('../../onboard') barrel import was replaced with direct imports of isSandboxReady and parseSandboxStatus from ../../state/gateway.
  • Impact: If signatures or behavior differ between the old onboard barrel export and the new state/gateway module, sandbox readiness checks could misbehave.
  • Suggested action: Confirm isSandboxReady and parseSandboxStatus have identical signatures and behavior between the old onboard barrel export and the new state/gateway module.
  • Expected follow-up: Prefer a current-PR fix when local to changed code; defer only with rationale or linked follow-up.
  • Verification: Diff the function signatures in src/lib/onboard/index.ts (or wherever they were re-exported) vs src/lib/state/gateway.ts — both export isSandboxReady(output, sandboxName) and parseSandboxStatus(output, sandboxName) with identical logic.
  • Missing regression test: Existing connect tests should cover sandbox readiness checks.
  • Done when: The local improvement is applied, or the PR notes why it should be deferred.
  • Evidence: import { isSandboxReady, parseSandboxStatus } from "../../state/gateway"; // replaces require("../../onboard")

PRA-9 Improvement — require('../../onboard') replaced with require('../../onboard/known-hosts') for pruneKnownHostsEntries

  • Location: src/lib/actions/sandbox/gateway-state.ts:7
  • Category: correctness
  • Problem: The require('../../onboard') barrel import was replaced with require('../../onboard/known-hosts') for pruneKnownHostsEntries — a more specific import which improves module boundaries.
  • Impact: Low risk — this narrows the dependency graph (495→138 modules). Verify signature matches.
  • Suggested action: Confirm pruneKnownHostsEntries has identical signature and behavior. This is a more specific import which is an improvement.
  • Expected follow-up: Prefer a current-PR fix when local to changed code; defer only with rationale or linked follow-up.
  • Verification: Check src/lib/onboard/known-hosts.ts exports pruneKnownHostsEntries with same signature (contents: string) => string.
  • Missing regression test: Existing gateway-state tests should cover known-hosts pruning.
  • Done when: The local improvement is applied, or the PR notes why it should be deferred.
  • Evidence: const { pruneKnownHostsEntries } = require("../../onboard/known-hosts") as { pruneKnownHostsEntries: (contents: string) => string };

PRA-10 Improvement — PR #6261 overlap — coordinate to avoid merge conflicts

  • Location: src/lib/actions/sandbox/connect.ts:1
  • Category: architecture
  • Problem: PR fix(mcp): reconcile Hermes runtime state #6261 (fix(mcp): reconcile Hermes runtime state) also modifies src/lib/actions/sandbox/connect.ts.
  • Impact: Merge conflicts possible; both PRs touch connect.ts imports and logic. Concurrent changes could introduce regressions if not reviewed together.
  • Suggested action: Coordinate with PR fix(mcp): reconcile Hermes runtime state #6261 author to avoid merge conflicts. Review both changes together for connect.ts.
  • Expected follow-up: Prefer a current-PR fix when local to changed code; defer only with rationale or linked follow-up.
  • Verification: Check PR fix(mcp): reconcile Hermes runtime state #6261 diff for connect.ts changes and compare with this PR's import refactoring.
  • Missing regression test: N/A — process coordination.
  • Done when: The local improvement is applied, or the PR notes why it should be deferred.
  • Evidence: Drift context shows PR fix(mcp): reconcile Hermes runtime state #6261 with sameFiles: ["src/lib/actions/sandbox/connect.ts"]
Simplification opportunities: 1 possible cut, net -1 lines possible

These are safe simplification checks only. Do not remove validation, security controls, data-loss prevention, or required tests.

  • PRA-6 delete (test/messaging-build-applier-integrity.test.ts:1): import { spawnSync } from "node:child_process";
    • Replacement: Use the simpler existing path.
    • Net: -1 lines
    • Safety boundary: No runtime behavior change; import was dead code after refactor.
Test follow-ups to resolve or justify

If these cover changed behavior, prefer adding them in this PR; otherwise state why existing coverage is enough or link the follow-up.

  • PRA-T1 Mocked behavioral coverage — Unit test for parseMessagingBuildArgs covering --agent, --phase, --dry-run flag combinations. Unit tests cover all security-critical behavior (integrity, render safety, manifest gating). CLI argument parsing (parseMessagingBuildArgs) and dry-run stdout formatting lost coverage; recommend unit test for parser. Runtime validation recommended for connect.ts/gateway-state.ts import changes but they are import-only with verified signature compatibility.
  • PRA-T2 Mocked behavioral coverage — Verify thrownMessage correctly handles async function rejection if async functions are ever passed. Unit tests cover all security-critical behavior (integrity, render safety, manifest gating). CLI argument parsing (parseMessagingBuildArgs) and dry-run stdout formatting lost coverage; recommend unit test for parser. Runtime validation recommended for connect.ts/gateway-state.ts import changes but they are import-only with verified signature compatibility.
  • PRA-T3 Mocked behavioral coverage — Verify error message strings match between CLI stderr and thrown exceptions for all failure paths. Unit tests cover all security-critical behavior (integrity, render safety, manifest gating). CLI argument parsing (parseMessagingBuildArgs) and dry-run stdout formatting lost coverage; recommend unit test for parser. Runtime validation recommended for connect.ts/gateway-state.ts import changes but they are import-only with verified signature compatibility.
  • PRA-T4 Unused spawnSync import after test refactoring — Remove the unused import: `import { spawnSync } from "node:child_process";`
  • PRA-T5 spawnSync still imported but only 3 call sites remain — verify CLI integration coverage — Verify the 3 remaining spawnSync call sites cover critical CLI boundaries. If not, add targeted integration tests or remove unused import.
  • PRA-T6 thrownMessage helper sync-only limitation — Add test verifying thrownMessage fails when callback doesn't throw (already covered); add async rejection test if helper is converted. try/catch only catches synchronous throws; Promise rejections bypass catch block
  • PRA-T7 CLI --dry-run argument parsing coverage gap — Unit test for parseMessagingBuildArgs covering all flag combinations and verifying dry-run JSON output structure. Only line 207 uses runApplierProcess with dryRun=true; 8 tests use describeDryRun which calls describeMessagingBuildPhase directly
Since last review details

Current findings, using the urgency labels above:

PRA-1 Resolve/justify — Source-of-truth review needed: thrownMessage helper sync-only limitation

  • Location: not file-specific
  • Category: architecture
  • Problem: The advisor marked localized patch analysis as needs_followup.
  • Impact: A localized workaround can preserve or hide an invalid state when the source boundary is unclear.
  • Recommended action: Identify the invalid state, source boundary, source-fix constraint, regression test, and removal condition before merging the localized behavior.
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: Inspect the localized patch and source-of-truth review fields for a concrete invalid state, source boundary, source-fix constraint, regression test, and removal condition.
  • Missing regression test: Add test verifying thrownMessage fails when callback doesn't throw (already covered); add async rejection test if helper is converted
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: Inspect the localized patch and source-of-truth review fields for a concrete invalid state, source boundary, source-fix constraint, regression test, and removal condition.
  • Evidence: try/catch only catches synchronous throws; Promise rejections bypass catch block

PRA-2 Resolve/justify — Source-of-truth review needed: CLI --dry-run argument parsing coverage gap

  • Location: not file-specific
  • Category: architecture
  • Problem: The advisor marked localized patch analysis as needs_followup.
  • Impact: A localized workaround can preserve or hide an invalid state when the source boundary is unclear.
  • Recommended action: Identify the invalid state, source boundary, source-fix constraint, regression test, and removal condition before merging the localized behavior.
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: Inspect the localized patch and source-of-truth review fields for a concrete invalid state, source boundary, source-fix constraint, regression test, and removal condition.
  • Missing regression test: Unit test for parseMessagingBuildArgs covering all flag combinations and verifying dry-run JSON output structure
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: Inspect the localized patch and source-of-truth review fields for a concrete invalid state, source boundary, source-fix constraint, regression test, and removal condition.
  • Evidence: Only line 207 uses runApplierProcess with dryRun=true; 8 tests use describeDryRun which calls describeMessagingBuildPhase directly

PRA-3 Resolve/justify — thrownMessage helper only catches synchronous throws

  • Location: test/messaging-build-applier.test.ts:181
  • Category: correctness
  • Problem: The thrownMessage helper uses try/catch which only captures synchronous throws. If applyMessagingBuildPhase or describeMessagingBuildPhase become async in the future, tests using this helper would silently pass without catching rejections because the helper's final 'throw new Error("Expected operation to throw")' only executes when the callback returns normally.
  • Impact: Future async refactoring of tested functions could silently disable negative test assertions, reducing confidence in fail-closed behavior for integrity checks and manifest validation.
  • Recommended action: Add a JSDoc comment to thrownMessage noting it only handles synchronous throws, or convert to async/await pattern that catches both sync throws and promise rejections.
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: Check all call sites of thrownMessage (lines 898, 978 in messaging-build-applier.test.ts and lines 168, 219 in messaging-build-applier-integrity.test.ts) invoke synchronous functions (applyMessagingBuildPhase, describeMessagingBuildPhase).
  • Missing regression test: Add a test that verifies thrownMessage correctly fails when the callback doesn't throw (already covered by the helper's final throw statement).
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: Check all call sites of thrownMessage (lines 898, 978 in messaging-build-applier.test.ts and lines 168, 219 in messaging-build-applier-integrity.test.ts) invoke synchronous functions (applyMessagingBuildPhase, describeMessagingBuildPhase).
  • Evidence: function thrownMessage(run: () => void): string { try { run(); } catch (error) { return error instanceof Error ? error.message : String(error); } throw new Error("Expected operation to throw"); }

PRA-4 Resolve/justify — thrownMessage helper duplicated in integrity test with same sync-only limitation

  • Location: test/messaging-build-applier-integrity.test.ts:56
  • Category: correctness
  • Problem: The thrownMessage helper is duplicated at line 56 in messaging-build-applier-integrity.test.ts with identical sync-only try/catch behavior.
  • Impact: Same future async refactoring risk as PRA-1; duplication increases maintenance burden if helper is fixed.
  • Recommended action: Extract to shared test helper (e.g., test/helpers/thrown-message.ts) or add JSDoc comment noting synchronous-only limitation.
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: Verify thrownMessage at line 56 is identical to the one in messaging-build-applier.test.ts:181.
  • Missing regression test: Same as PRA-1 — verify helper behavior with async rejection if extracted to shared location.
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: Verify thrownMessage at line 56 is identical to the one in messaging-build-applier.test.ts:181.
  • Evidence: function thrownMessage(run: () => void): string { try { run(); } catch (error) { return error instanceof Error ? error.message : String(error); } throw new Error("Expected operation to throw"); }

PRA-5 Resolve/justify — CLI --dry-run argument parsing and stdout formatting coverage reduced to 1 of ~9 dry-run tests

  • Location: test/messaging-build-applier.test.ts:161
  • Category: correctness
  • Problem: Dry-run tests now call describeMessagingBuildPhase directly instead of using runApplierProcess with --dry-run flag. This loses coverage of parseMessagingBuildArgs (flag parsing for --agent, --phase, --dry-run) and CLI stdout JSON formatting.
  • Impact: Regression in CLI argument parsing or dry-run output formatting would not be caught by unit tests. Only line 207 uses runApplierProcess with dryRun=true.
  • Recommended action: Add a unit test for parseMessagingBuildArgs covering --agent, --phase, --dry-run combinations, or keep one dry-run test per phase using runApplierProcess(env, agent, phase, true) to preserve CLI boundary coverage.
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: Search for '--dry-run' in test/messaging-build-applier.test.ts — only line 207 uses it via runApplierProcess with dryRun=true.
  • Missing regression test: Unit test for parseMessagingBuildArgs covering all flag combinations and verifying dry-run JSON output structure matches describeMessagingBuildPhase return value.
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: Search for '--dry-run' in test/messaging-build-applier.test.ts — only line 207 uses it via runApplierProcess with dryRun=true.
  • Evidence: async function describeDryRun(envOverrides, agent) { const env = await buildPlanEnv(envOverrides, agent); return describeMessagingBuildPhase(readMessagingBuildPlanFromEnv(env, agent), "agent-install", env); }

PRA-6 Improvement — Unused spawnSync import after test refactoring

  • Location: test/messaging-build-applier-integrity.test.ts:1
  • Category: tests
  • Problem: The test file imports spawnSync from node:child_process but no longer uses it — all tests converted to direct function calls.
  • Impact: Minor code hygiene issue; unused import adds noise and may confuse readers about test execution strategy.
  • Suggested action: Remove the unused import: `import { spawnSync } from "node:child_process";`
  • Expected follow-up: Prefer a current-PR fix when local to changed code; defer only with rationale or linked follow-up.
  • Verification: grep for spawnSync in messaging-build-applier-integrity.test.ts — no matches expected after cleanup.
  • Missing regression test: N/A — code cleanup only.
  • Done when: The local improvement is applied, or the PR notes why it should be deferred.
  • Evidence: import { spawnSync } from "node:child_process"; // line 1, no usage in file

PRA-7 Resolve/justify — spawnSync still imported but only 3 call sites remain — verify CLI integration coverage

  • Location: test/messaging-build-applier.test.ts:6
  • Category: tests
  • Problem: spawnSync is still imported but only 3 call sites remain: runApplierProcess helper (line 141), one test at line 394, and generator integration test at line 1042.
  • Impact: If these 3 call sites don't cover critical CLI boundaries (agent-install, post-agent-install, runtime-setup phases with real argument parsing), regressions in CLI entry point could go undetected.
  • Recommended action: Verify the 3 remaining spawnSync call sites cover critical CLI boundaries. If not, add targeted integration tests or remove unused import.
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: Check lines 141, 394, 1042 in messaging-build-applier.test.ts for spawnSync usage and which phases they exercise.
  • Missing regression test: Ensure at least one integration test per phase (agent-install, post-agent-install, runtime-setup) exercises the CLI entry point with real argument parsing.
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: Check lines 141, 394, 1042 in messaging-build-applier.test.ts for spawnSync usage and which phases they exercise.
  • Evidence: import { spawnSync } from "node:child_process"; // line 6; used at lines 141, 394, 1042

PRA-8 Improvement — require('../../onboard') replaced with direct imports from ../../state/gateway — verify no behavioral change

  • Location: src/lib/actions/sandbox/connect.ts:829
  • Category: correctness
  • Problem: The require('../../onboard') barrel import was replaced with direct imports of isSandboxReady and parseSandboxStatus from ../../state/gateway.
  • Impact: If signatures or behavior differ between the old onboard barrel export and the new state/gateway module, sandbox readiness checks could misbehave.
  • Suggested action: Confirm isSandboxReady and parseSandboxStatus have identical signatures and behavior between the old onboard barrel export and the new state/gateway module.
  • Expected follow-up: Prefer a current-PR fix when local to changed code; defer only with rationale or linked follow-up.
  • Verification: Diff the function signatures in src/lib/onboard/index.ts (or wherever they were re-exported) vs src/lib/state/gateway.ts — both export isSandboxReady(output, sandboxName) and parseSandboxStatus(output, sandboxName) with identical logic.
  • Missing regression test: Existing connect tests should cover sandbox readiness checks.
  • Done when: The local improvement is applied, or the PR notes why it should be deferred.
  • Evidence: import { isSandboxReady, parseSandboxStatus } from "../../state/gateway"; // replaces require("../../onboard")

PRA-9 Improvement — require('../../onboard') replaced with require('../../onboard/known-hosts') for pruneKnownHostsEntries

  • Location: src/lib/actions/sandbox/gateway-state.ts:7
  • Category: correctness
  • Problem: The require('../../onboard') barrel import was replaced with require('../../onboard/known-hosts') for pruneKnownHostsEntries — a more specific import which improves module boundaries.
  • Impact: Low risk — this narrows the dependency graph (495→138 modules). Verify signature matches.
  • Suggested action: Confirm pruneKnownHostsEntries has identical signature and behavior. This is a more specific import which is an improvement.
  • Expected follow-up: Prefer a current-PR fix when local to changed code; defer only with rationale or linked follow-up.
  • Verification: Check src/lib/onboard/known-hosts.ts exports pruneKnownHostsEntries with same signature (contents: string) => string.
  • Missing regression test: Existing gateway-state tests should cover known-hosts pruning.
  • Done when: The local improvement is applied, or the PR notes why it should be deferred.
  • Evidence: const { pruneKnownHostsEntries } = require("../../onboard/known-hosts") as { pruneKnownHostsEntries: (contents: string) => string };

PRA-10 Improvement — PR #6261 overlap — coordinate to avoid merge conflicts

  • Location: src/lib/actions/sandbox/connect.ts:1
  • Category: architecture
  • Problem: PR fix(mcp): reconcile Hermes runtime state #6261 (fix(mcp): reconcile Hermes runtime state) also modifies src/lib/actions/sandbox/connect.ts.
  • Impact: Merge conflicts possible; both PRs touch connect.ts imports and logic. Concurrent changes could introduce regressions if not reviewed together.
  • Suggested action: Coordinate with PR fix(mcp): reconcile Hermes runtime state #6261 author to avoid merge conflicts. Review both changes together for connect.ts.
  • Expected follow-up: Prefer a current-PR fix when local to changed code; defer only with rationale or linked follow-up.
  • Verification: Check PR fix(mcp): reconcile Hermes runtime state #6261 diff for connect.ts changes and compare with this PR's import refactoring.
  • Missing regression test: N/A — process coordination.
  • Done when: The local improvement is applied, or the PR notes why it should be deferred.
  • Evidence: Drift context shows PR fix(mcp): reconcile Hermes runtime state #6261 with sameFiles: ["src/lib/actions/sandbox/connect.ts"]

Workflow run details

This is an automated, non-binding review; it still expects maintainers and agents to respond to each required or warning item. Treat suggestions as current-PR improvements when they touch changed code; defer only with maintainer rationale or a linked follow-up. A human maintainer must make the final merge decision.

@github-actions

github-actions Bot commented Jul 5, 2026

Copy link
Copy Markdown
Contributor

PR Review Advisor — Changes requested

Merge posture: Do not merge yet
Primary next action: Resolve or justify PRA-1: Restore executable-boundary coverage for security fail-closed paths.
Open items: 0 required · 1 warning · 0 suggestions · 3 test follow-ups
Since last review: 0 prior items resolved · 1 still applies · 0 new items found

Action checklist

  • PRA-1 Resolve or justify: Restore executable-boundary coverage for security fail-closed paths in test/messaging-build-applier-render-safety.test.ts:43
  • PRA-T1 Add or justify test follow-up: Runtime validation
  • PRA-T2 Add or justify test follow-up: Runtime validation
  • PRA-T3 Add or justify test follow-up: Runtime validation

Findings index

ID Severity Category Location Required action
PRA-1 Resolve/justify security test/messaging-build-applier-render-safety.test.ts:43 Keep the fast direct tests, but retain one or two small subprocess tests for representative security failures. At minimum, cover one `post-agent-install` render-safety failure and one `agent-install` installer-trust failure through `node --experimental-strip-types .../messaging-build-applier.mts`, asserting exit 2 or another nonzero status, expected stderr, and no unsafe file/install side effects.
Review findings by urgency: 0 required fixes, 1 item to resolve/justify, 0 in-scope improvements

⚠️ Resolve or justify before merge

Investigate these in the current review; either fix them, explain why they are not applicable, or document the accepted risk.

PRA-1 Resolve/justify — Restore executable-boundary coverage for security fail-closed paths

  • Location: test/messaging-build-applier-render-safety.test.ts:43
  • Category: security
  • Problem: Several negative security tests now call exported internals directly instead of invoking `messaging-build-applier.mts` as the executable. The core render-safety and installer-trust checks are still exercised, but the tests no longer prove that production invocation maps representative failures through `main()`, argv/env parsing, stderr, and exit code handling before side effects.
  • Impact: A future regression in the executable entrypoint, argument handling, environment decoding, or catch block could break the fail-closed CLI contract while these direct unit tests still pass. That matters for security boundaries such as render path escape rejection, multiline env injection rejection, and OpenClaw plugin provenance/integrity rejection.
  • Recommended action: Keep the fast direct tests, but retain one or two small subprocess tests for representative security failures. At minimum, cover one `post-agent-install` render-safety failure and one `agent-install` installer-trust failure through `node --experimental-strip-types .../messaging-build-applier.mts`, asserting exit 2 or another nonzero status, expected stderr, and no unsafe file/install side effects.
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: Read the changed tests and compare process-boundary assertions: `test/messaging-build-applier-render-safety.test.ts` now uses `applyMessagingAgentRenderToLocalFiles(...).toThrow`; `test/messaging-build-applier-integrity.test.ts` now uses `applyMessagingBuildPhase` for tarball URL and packed-integrity drift; `test/messaging-build-applier.test.ts` now uses direct `toThrow`/`thrownMessage` checks for several installer-trust failures.
  • Missing regression test: Add tests named like `executable exits 2 and writes stderr when post-agent-install render target escapes agent root` and `executable exits before openclaw install when registry integrity drifts`, using fake local commands and asserting no escaped file or install trace is produced.
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: Read the changed tests and compare process-boundary assertions: `test/messaging-build-applier-render-safety.test.ts` now uses `applyMessagingAgentRenderToLocalFiles(...).toThrow`; `test/messaging-build-applier-integrity.test.ts` now uses `applyMessagingBuildPhase` for tarball URL and packed-integrity drift; `test/messaging-build-applier.test.ts` now uses direct `toThrow`/`thrownMessage` checks for several installer-trust failures.
  • Evidence: The diff removes `spawnSync("node", ["--experimental-strip-types", SCRIPT_PATH, ...])` from the render-safety negative tests and converts multiple installer-trust negative tests from `result.status`/`result.stderr` assertions to direct thrown-message assertions.

💡 In-scope improvements

These are lower-risk, not throwaway. Prefer fixing them in this PR when they are local to changed code; defer only with rationale or a linked follow-up.

  • None.
Test follow-ups to resolve or justify

If these cover changed behavior, prefer adding them in this PR; otherwise state why existing coverage is enough or link the follow-up.

  • PRA-T1 Runtime validation — executable exits 2 and writes stderr when post-agent-install render target escapes agent root. Unit-level direct tests cover the core logic, and several subprocess tests remain, but the changed security-sensitive messaging tests should retain representative executable/runtime validation for fail-closed CLI behavior. The production import-narrowing changes are behavior-equivalent but would also benefit from a small module-load/import-boundary check.
  • PRA-T2 Runtime validation — executable exits before openclaw install when registry integrity drifts. Unit-level direct tests cover the core logic, and several subprocess tests remain, but the changed security-sensitive messaging tests should retain representative executable/runtime validation for fail-closed CLI behavior. The production import-narrowing changes are behavior-equivalent but would also benefit from a small module-load/import-boundary check.
  • PRA-T3 Runtime validation — gateway-state loads pruneKnownHostsEntries from onboard/known-hosts without loading the onboarding barrel. Unit-level direct tests cover the core logic, and several subprocess tests remain, but the changed security-sensitive messaging tests should retain representative executable/runtime validation for fail-closed CLI behavior. The production import-narrowing changes are behavior-equivalent but would also benefit from a small module-load/import-boundary check.
Since last review details

Current findings, using the urgency labels above:

PRA-1 Resolve/justify — Restore executable-boundary coverage for security fail-closed paths

  • Location: test/messaging-build-applier-render-safety.test.ts:43
  • Category: security
  • Problem: Several negative security tests now call exported internals directly instead of invoking `messaging-build-applier.mts` as the executable. The core render-safety and installer-trust checks are still exercised, but the tests no longer prove that production invocation maps representative failures through `main()`, argv/env parsing, stderr, and exit code handling before side effects.
  • Impact: A future regression in the executable entrypoint, argument handling, environment decoding, or catch block could break the fail-closed CLI contract while these direct unit tests still pass. That matters for security boundaries such as render path escape rejection, multiline env injection rejection, and OpenClaw plugin provenance/integrity rejection.
  • Recommended action: Keep the fast direct tests, but retain one or two small subprocess tests for representative security failures. At minimum, cover one `post-agent-install` render-safety failure and one `agent-install` installer-trust failure through `node --experimental-strip-types .../messaging-build-applier.mts`, asserting exit 2 or another nonzero status, expected stderr, and no unsafe file/install side effects.
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: Read the changed tests and compare process-boundary assertions: `test/messaging-build-applier-render-safety.test.ts` now uses `applyMessagingAgentRenderToLocalFiles(...).toThrow`; `test/messaging-build-applier-integrity.test.ts` now uses `applyMessagingBuildPhase` for tarball URL and packed-integrity drift; `test/messaging-build-applier.test.ts` now uses direct `toThrow`/`thrownMessage` checks for several installer-trust failures.
  • Missing regression test: Add tests named like `executable exits 2 and writes stderr when post-agent-install render target escapes agent root` and `executable exits before openclaw install when registry integrity drifts`, using fake local commands and asserting no escaped file or install trace is produced.
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: Read the changed tests and compare process-boundary assertions: `test/messaging-build-applier-render-safety.test.ts` now uses `applyMessagingAgentRenderToLocalFiles(...).toThrow`; `test/messaging-build-applier-integrity.test.ts` now uses `applyMessagingBuildPhase` for tarball URL and packed-integrity drift; `test/messaging-build-applier.test.ts` now uses direct `toThrow`/`thrownMessage` checks for several installer-trust failures.
  • Evidence: The diff removes `spawnSync("node", ["--experimental-strip-types", SCRIPT_PATH, ...])` from the render-safety negative tests and converts multiple installer-trust negative tests from `result.status`/`result.stderr` assertions to direct thrown-message assertions.

Workflow run details

This is an automated, non-binding review; it still expects maintainers and agents to respond to each required or warning item. Treat suggestions as current-PR improvements when they touch changed code; defer only with maintainer rationale or a linked follow-up. A human maintainer must make the final merge decision.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick comments (2)
test/messaging-build-applier-integrity.test.ts (1)

56-63: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Extract thrownMessage to the shared test helper module.

This helper is duplicated verbatim in test/messaging-build-applier.test.ts (lines 181-188) and is also referenced from a third call site there. Consider moving it into test/messaging-plan-test-helper.ts alongside withLegacyMessagingPlanEnvDirect so all three messaging-applier test files import one implementation.

♻️ Proposed consolidation
-function thrownMessage(run: () => void): string {
-  try {
-    run();
-  } catch (error) {
-    return error instanceof Error ? error.message : String(error);
-  }
-  throw new Error("Expected operation to throw");
-}
+import { thrownMessage } from "./messaging-plan-test-helper";
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@test/messaging-build-applier-integrity.test.ts` around lines 56 - 63, The
thrownMessage helper is duplicated across messaging-applier tests and should be
centralized in the shared test helper module. Move thrownMessage into
test/messaging-plan-test-helper.ts alongside withLegacyMessagingPlanEnvDirect,
then update messaging-build-applier-integrity.test.ts and the existing call
sites in messaging-build-applier.test.ts to import and use the shared
implementation. Keep the behavior identical so all messaging-applier tests rely
on one helper definition.
src/lib/actions/sandbox/gateway-state.ts (1)

16-17: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Use a static import here instead of require(). src/lib/onboard/known-hosts.ts is a leaf module, so the deferred load is unnecessary; switching to import { pruneKnownHostsEntries } from "../../onboard/known-hosts"; keeps this file consistent with the rest of the imports and simplifies type-checking.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/lib/actions/sandbox/gateway-state.ts` around lines 16 - 17, Replace the
deferred require in gateway-state.ts with a static import for
pruneKnownHostsEntries from the known-hosts module. Update the top-level import
section to use import { pruneKnownHostsEntries } from
"../../onboard/known-hosts"; and remove the inline type assertion, keeping the
rest of the gateway-state logic unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@src/lib/actions/sandbox/gateway-state.ts`:
- Around line 16-17: Replace the deferred require in gateway-state.ts with a
static import for pruneKnownHostsEntries from the known-hosts module. Update the
top-level import section to use import { pruneKnownHostsEntries } from
"../../onboard/known-hosts"; and remove the inline type assertion, keeping the
rest of the gateway-state logic unchanged.

In `@test/messaging-build-applier-integrity.test.ts`:
- Around line 56-63: The thrownMessage helper is duplicated across
messaging-applier tests and should be centralized in the shared test helper
module. Move thrownMessage into test/messaging-plan-test-helper.ts alongside
withLegacyMessagingPlanEnvDirect, then update
messaging-build-applier-integrity.test.ts and the existing call sites in
messaging-build-applier.test.ts to import and use the shared implementation.
Keep the behavior identical so all messaging-applier tests rely on one helper
definition.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: dda3f324-c029-45e9-9dfd-471a2b0fb140

📥 Commits

Reviewing files that changed from the base of the PR and between 34ac134 and 65aca84.

📒 Files selected for processing (4)
  • src/lib/actions/sandbox/gateway-state.ts
  • test/messaging-build-applier-integrity.test.ts
  • test/messaging-build-applier-render-safety.test.ts
  • test/messaging-build-applier.test.ts

Signed-off-by: Carlos Villela <cvillela@nvidia.com>
@cv

cv commented Jul 5, 2026

Copy link
Copy Markdown
Collaborator Author

Final-head evidence for cc9d35b0d:

  • All CI, coverage shards, CodeQL, automated review, and self-hosted E2E checks are green: final run.
  • Messaging-applier execution fell from 19.165s to 1.610s across the three changed suites (-91.6%), while preserving nine applier process contracts, one generator contract, and real fake npm/openclaw/uv boundaries.
  • gateway-state-drift collection fell from 10.133s to 0.189s (-98.1%); whole-file setup/collection/test time fell from 10.695s to 0.746s (-93.0%).
  • The CI-discovered cold-load regression is resolved without raising timeouts: the former timeout cases passed under coverage in 14.795ms (connect-flow) and 15.315ms (connect-route-lifecycle), with both full files green and zero unhandled errors.
  • Shard 5 improved 7:11 to 6:58 and shard 4 improved 5:41 to 5:33. Critical shard 3 improved only 8:38 to 8:33. Aggregate blob time increased 1.75% because shard 1 varied by +68.6s, so this PR does not claim a repo-wide wall-time win.

Automated-review disposition:

  • CodeRabbit completed with no actionable comments.
  • GPT-5.5's executable-boundary warning is covered compositionally: a real agent-install unsafe-archive failure asserts nonzero/stderr/no install, real post-agent-install processes exercise phase/argv/env dispatch, and direct render-safety tests assert the core rejection and absence of unsafe file side effects. The executable catch path is phase-independent, so duplicating the same failure adapter for each phase would not cover a distinct branch.
  • Nemotron's sync-helper concern is not a silent-pass risk: both call sites are synchronous, and an async callback would return normally and trigger the helper's Expected operation to throw sentinel, failing the test. Its dry-run and unused-import claims are factually satisfied by the retained runApplierProcess(..., true) contract and the retained integrity spawnSync unsafe-archive contract.
  • The leaf imports use the exact functions re-exported by the onboarding barrel; independent review found no cycle, initialization, or behavior difference.

Docs review found no user-facing change, so no docs update/build was needed.

@cv
cv merged commit f1135d3 into main Jul 5, 2026
46 checks passed
@cv
cv deleted the codex/perf-test-io-6245-batch-4 branch July 5, 2026 17:23
Hadar301 pushed a commit to Hadar301/NemoClaw-OpenShift that referenced this pull request Jul 12, 2026
## Summary

Removes repeated TypeScript process bootstrapping from the messaging
build-applier tests while retaining representative executable and
security boundaries. It also narrows `gateway-state`'s known-hosts
dependency to the existing leaf module so shard 3 no longer collects the
full onboarding graph for that helper.

## Related Issue

Related to NVIDIA#6245.

## Changes

- Build messaging plans in-process and exercise exported production
phase/render seams directly where process behavior is not the contract.
- Reduce the messaging-applier group from 57 top-level test-controlled
subprocesses to 10: 21 legacy `npx tsx` builders are removed, while nine
applier contracts and one generator contract remain.
- Preserve real fake `npm`, `openclaw`, and `uv` command boundaries,
including archive provenance/integrity, unsafe archive exit behavior,
doctor rewrite/reapply, WeChat build-file routing, Hermes rendering,
argv, env, and exit status.
- Load `pruneKnownHostsEntries` from `onboard/known-hosts` instead of
the 5,282-line onboarding barrel; the traced source graph falls from 495
modules to 138 modules (72.1% fewer).

## Type of Change

- [x] Code change (feature, bug fix, or refactor)
- [ ] Code change with doc updates
- [ ] Doc only (prose changes, no code sample modifications)
- [ ] Doc only (includes code sample changes)

## Quality Gates

- [x] Tests added or updated for changed behavior
- [ ] Existing tests cover changed behavior — justification:
- [ ] Tests not applicable — justification:
- [ ] Docs updated for user-facing behavior changes
- [x] Docs not applicable — justification: internal dependency narrowing
and test execution strategy only; no command, config, default, API,
output, policy, or recovery behavior changes
- [x] Sensitive paths changed (security, policy, credentials, preflight,
onboarding, inference, runner, sandbox, or messaging)
- [x] Sensitive-path review completed or maintainer-approved waiver
recorded — reviewer/approval link/justification: independent local
review found no remaining actionable findings; archive
integrity/provenance, unsafe-path failure, doctor reapply, and
OpenClaw/Hermes process contracts remain real
- [ ] Non-success, skipped, or missing CI check accepted by maintainer —
check name, approval link, and follow-up issue:

## Verification

- [x] PR description includes the DCO sign-off declaration and every
commit appears as `Verified` in GitHub
- [x] Normal `pre-commit`, `commit-msg`, and `pre-push` hooks passed, or
`npm run check:diff` passed when hooks were skipped or unavailable
- [x] Targeted behavior tests pass for the current change set, or tests
are marked not applicable above — fresh `npm run build:cli`, then 7
focused Vitest files: 67/67 passed in 3.93s wall
- [ ] Applicable broad gate passed — `npm test` for broad
runtime/test-harness changes; `npm run check` for repo-wide
validation/coverage changes — command/result: not applicable to this
focused four-file batch; final-head CI remains authoritative for full
coverage
- [x] Quality Gates section completed with required justifications or
waivers
- [x] No secrets, API keys, or credentials committed
- [ ] `npm run docs` builds without warnings (doc changes only)
- [ ] Doc pages follow the [style
guide](https://github.com/NVIDIA/NemoClaw/blob/main/docs/CONTRIBUTING.md)
(doc changes only)
- [ ] New doc pages include SPDX header and frontmatter (new pages only)

## Performance evidence

- Messaging-applier merged-CI baseline: 19.163s across the four files;
final local test execution: 1.60s. The environments differ, so
final-head CI is the authoritative comparison.
- Gateway-state traced source graph: 495 to 138 modules; simulated cold
TypeScript transpilation: 1,330ms to 476ms.
- This is another incremental NVIDIA#6245 batch, not a claim that the full
suite has reached the 2–5 minute target.

---
Signed-off-by: Carlos Villela <cvillela@nvidia.com>


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **Tests**
* Refactored messaging build-applier suites to invoke messaging plan
reading and build phases directly (instead of relying on process
execution), improving validation of safety rules and failure behavior.
* Strengthened integrity and “fails closed” checks by asserting specific
thrown error messages and verifying expected trace/artifact outcomes.
* **Chores**
* Minor internal adjustments to sandbox connection and gateway-state
wiring (no end-user behavior changes).
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Signed-off-by: Carlos Villela <cvillela@nvidia.com>
@wscurran wscurran added area: ci CI workflows, checks, release automation, or GitHub Actions area: messaging Messaging channels, bridges, manifests, or channel lifecycle chore Build, CI, dependency, or tooling maintenance labels Aug 1, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area: ci CI workflows, checks, release automation, or GitHub Actions area: messaging Messaging channels, bridges, manifests, or channel lifecycle chore Build, CI, dependency, or tooling maintenance

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants