Skip to content

test(cli): lock in #1555 destroy-side session clear so list cannot resurrect destroyed sandboxes (#1641)#1677

Open
ColinM-sys wants to merge 1 commit intoNVIDIA:mainfrom
ColinM-sys:fix/1641-list-no-resurrect-test
Open

test(cli): lock in #1555 destroy-side session clear so list cannot resurrect destroyed sandboxes (#1641)#1677
ColinM-sys wants to merge 1 commit intoNVIDIA:mainfrom
ColinM-sys:fix/1641-list-no-resurrect-test

Conversation

@ColinM-sys
Copy link
Copy Markdown
Contributor

@ColinM-sys ColinM-sys commented Apr 9, 2026

Summary

Refs #1641, #1555.

Why

#1641 reported that after `nemoclaw destroy`, `nemoclaw list` re-recovered the destroyed sandbox from the onboard session, and `nemoclaw connect` then marked it stale and removed it — looping forever between the two commands. The reporter ran on `v0.0.6-19-gea9a6f2`, which is 13 commits behind `ecc1277d` (PR #1555). #1555 added the destroy-side `session.sandboxName = null` clear that breaks the loop. So the bug is already fixed on `main`, but there is no regression test pinning the behavior, which means a future refactor of either the destroy path or the list/recovery path could silently re-introduce it.

What changed

Test plan

  • `npx vitest run src/lib/inventory-commands.test.ts` → 5/5 passing.
  • Test catches the regression by code inspection: the existing "empty-state onboarding hint" test (line 9-21) shows that swapping `sandboxName: null` for `sandboxName: "alpha"` routes to the other branch which prints `"...the last onboarded sandbox was 'alpha'"`, which my new test explicitly asserts does not appear.

Reporter follow-up

Suggesting on the issue that the reporter retest on current `main` (post-#1555). If the loop still reproduces on a current build, that's a separate bug and I'll re-investigate.

Summary by CodeRabbit

  • Tests
    • Added a regression test ensuring that when no sandboxes remain and session recovery yields nothing, the CLI displays the generic onboarding empty-state message ("No sandboxes registered. Run nemoclaw onboard to get started.") and omits any session-recovery or "last onboarded sandbox" hints, improving clarity during onboarding.

Signed-off-by: ColinM-sys cmcdonough@50words.com

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 9, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

A Vitest regression test was added to verify listSandboxesCommand shows the empty onboarding message when registry recovery returns no sandboxes and loadLastSession() returns { sandboxName: null }, ensuring no session-recovery messaging is printed.

Changes

Cohort / File(s) Summary
Regression Test
src/lib/inventory-commands.test.ts
Added a Vitest regression test for issue #1641 that invokes listSandboxesCommand with recoverRegistryEntries() returning an empty inventory and loadLastSession() returning { sandboxName: null }; asserts the generic onboarding empty-state message appears and session-recovery messages/hints do not.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Poem

🐇 I hopped into tests at dawn's first light,
Chased phantom sandboxes out of sight,
The list stayed empty, tidy, and bright,
No rescued hints to startle the night,
I thump my joy — all checks are right! 🥕

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and specifically describes the main change: adding a regression test for issue #1641 that verifies destroyed sandboxes cannot be resurrected by list command.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/lib/inventory-commands.test.ts`:
- Around line 23-58: The test currently stubs loadLastSession to { sandboxName:
null } so it never exercises the destroy codepath; instead create a shared
in-memory session/registry object and call the actual destroy flow before
invoking listSandboxesCommand so the test verifies the destroy logic clears the
session. Concretely: introduce a mutable shared object (e.g., const sharedState
= { session: { sandboxName: "X" }, registry: {...} }), wire your mocks passed to
listSandboxesCommand to read from sharedState (loadLastSession returns
sharedState.session, recoverRegistryEntries reads sharedState.registry), then
import and invoke the real destroy routine used in tests (the project’s destroy
command function) to mutate sharedState (clearing session.sandboxName) and
finally call listSandboxesCommand to assert the onboarding hint and absence of
recovery messages.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 9cd0f27d-fcfc-493f-bfc9-3f5cfba9ee32

📥 Commits

Reviewing files that changed from the base of the PR and between e8b30a2 and e0d5eae.

📒 Files selected for processing (1)
  • src/lib/inventory-commands.test.ts

Comment on lines +23 to +58
it("regression #1641: after destroy clears the session, list shows the onboard hint instead of resurrecting the sandbox", async () => {
// Reproduces the loop the reporter described in #1641: a sandbox
// is destroyed, registry is empty, the destroy code clears
// session.sandboxName to null (added in #1555), and the next
// `nemoclaw list` MUST NOT recover the destroyed sandbox from
// the session. Without the destroy-side clear, list would print
// "Recovered sandbox inventory from the last onboard session"
// and the user would loop between `list` (showing the sandbox)
// and `connect` (removing it as stale).
const lines: string[] = [];
await listSandboxesCommand({
recoverRegistryEntries: async () => ({
sandboxes: [],
defaultSandbox: null,
recoveredFromSession: false,
recoveredFromGateway: 0,
}),
getLiveInference: () => null,
// Post-destroy session: sandboxName has been cleared. The
// session object itself still exists (other fields populated)
// but loadLastSession returning a session with sandboxName=null
// must NOT trip the "last onboarded sandbox was 'X'" hint.
loadLastSession: () => ({ sandboxName: null }),
log: (message = "") => lines.push(message),
});

expect(lines).toContain(
" No sandboxes registered. Run `nemoclaw onboard` to get started.",
);
expect(
lines.some((line) =>
line.includes("Recovered sandbox inventory from the last onboard session"),
),
).toBe(false);
expect(lines.some((line) => line.includes("last onboarded sandbox was"))).toBe(false);
});
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.

⚠️ Potential issue | 🟠 Major

Regression scope is too narrow to catch destroy-path regressions.

Line 33–46 hardcodes the post-destroy state (loadLastSession already returns { sandboxName: null }), so this test only verifies list rendering. If destroy stops clearing the session again, this test will still pass because destroy is never exercised. Please add/convert this to a flow that performs destroy and then list against shared state so #1555 is actually pinned.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/lib/inventory-commands.test.ts` around lines 23 - 58, The test currently
stubs loadLastSession to { sandboxName: null } so it never exercises the destroy
codepath; instead create a shared in-memory session/registry object and call the
actual destroy flow before invoking listSandboxesCommand so the test verifies
the destroy logic clears the session. Concretely: introduce a mutable shared
object (e.g., const sharedState = { session: { sandboxName: "X" }, registry:
{...} }), wire your mocks passed to listSandboxesCommand to read from
sharedState (loadLastSession returns sharedState.session, recoverRegistryEntries
reads sharedState.registry), then import and invoke the real destroy routine
used in tests (the project’s destroy command function) to mutate sharedState
(clearing session.sandboxName) and finally call listSandboxesCommand to assert
the onboarding hint and absence of recovery messages.

@wscurran wscurran added NemoClaw CLI Use this label to identify issues with the NemoClaw command-line interface (CLI). fix labels Apr 9, 2026
@wscurran
Copy link
Copy Markdown
Contributor

wscurran commented Apr 9, 2026

✨ Thanks for submitting this PR, which proposes a way to add a regression test for the destroy-side session clear and may help prevent similar bugs in the future.


Possibly related open PRs:


Possibly related open issues:

@wscurran wscurran added the enhancement: testing Use this label to identify requests to improve NemoClaw test coverage. label Apr 9, 2026
@ColinM-sys ColinM-sys force-pushed the fix/1641-list-no-resurrect-test branch 2 times, most recently from 1493057 to 27df867 Compare April 14, 2026 01:24
@ColinM-sys ColinM-sys force-pushed the fix/1641-list-no-resurrect-test branch from 27df867 to ae710b5 Compare April 15, 2026 02:23
@wscurran wscurran added status: rebase PR needs to be rebased against main before review can continue and removed status: rebase PR needs to be rebased against main before review can continue labels Apr 15, 2026
@ColinM-sys ColinM-sys force-pushed the fix/1641-list-no-resurrect-test branch from ae710b5 to 13c625f Compare April 16, 2026 15:22
…not resurrect destroyed sandboxes

NVIDIA#1641 reported that after `nemoclaw <name> destroy`, `nemoclaw list`
would print "Recovered sandbox inventory from the last onboard
session" and re-show the destroyed sandbox, then `nemoclaw <name>
connect` would mark it stale and remove it again — looping forever
between the two commands. The reporter was on v0.0.6-19-gea9a6f2,
which is 13 commits behind ecc1277 (PR NVIDIA#1555), the commit that
added `s.sandboxName = null` to `sandboxDestroy()`. So the bug is
already fixed on main, but there is no regression test pinning the
behavior, which means a future refactor of the destroy or list path
could silently re-introduce the loop.

Add a regression test in src/lib/inventory-commands.test.ts under
"NVIDIA#1641" that exercises the post-destroy state explicitly: registry
empty, session present but with sandboxName cleared. Assert that
list prints the onboard hint and does NOT print either of the
recovery / "last onboarded sandbox was" messages that signal the
loop has come back.

Refs: NVIDIA#1641, NVIDIA#1555
Signed-off-by: ColinM-sys <cmcdonough@50words.com>
@ColinM-sys ColinM-sys force-pushed the fix/1641-list-no-resurrect-test branch from 13c625f to 781686c Compare April 27, 2026 06:40
@copy-pr-bot
Copy link
Copy Markdown

copy-pr-bot Bot commented Apr 27, 2026

This pull request requires additional validation before any workflows can run on NVIDIA's runners.

Pull request vetters can view their responsibilities here.

Contributors can view more details about this message here.

@wscurran wscurran added the status: rfr Ready for review — no conflicts, awaiting maintainer review label Apr 29, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement: testing Use this label to identify requests to improve NemoClaw test coverage. fix NemoClaw CLI Use this label to identify issues with the NemoClaw command-line interface (CLI). status: rfr Ready for review — no conflicts, awaiting maintainer review

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants