Skip to content

refactor(rebuild): remove superseded rebuild finalization - #8505

Open
harjothkhara wants to merge 4 commits into
NVIDIA:mainfrom
harjothkhara:oss-find/nemoclaw-2026-08-06e
Open

refactor(rebuild): remove superseded rebuild finalization#8505
harjothkhara wants to merge 4 commits into
NVIDIA:mainfrom
harjothkhara:oss-find/nemoclaw-2026-08-06e

Conversation

@harjothkhara

@harjothkhara harjothkhara commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

Summary

src/lib/actions/sandbox/rebuild-finalization.ts has no production caller. Its two exports were imported only by its own test, while rebuild-post-restore-phase.ts is the canonical post-restore implementation and rebuild-recreate-phase.ts:307 already clears shields state on a recovery recreate. This deletes the superseded module and moves the assertions that were genuinely unique to it onto the suites that drive the live code.

Related Issue

Refs: #8283

Changes

  • Delete src/lib/actions/sandbox/rebuild-finalization.ts and rebuild-finalization.test.ts (355 LOC). Before deleting, grep -rn "finalizeRebuildPostRestore\|resetRebuildShieldsStateAfterRecreate" across the repo returned only the module and its own test.
  • Move four assertions into rebuild-post-restore-phase.test.ts, which drives the real runRebuildPostRestorePhase: the registry → relock → forward order, that host forwarding is never attempted after a failed shields relock, the connect recovery command when forwarding is unverified, and the previously-enabled-shields warning on an unlocked recreate.
  • Move the recovery-recreate shields reset to rebuild-recreate-observability.test.ts, which drives the real runRebuildRecreatePhase. The old test asserted this against a dead helper; it now asserts it against rebuild-recreate-phase.ts:307.
  • Repoint the sandbox-rebuild retired-selector replacement from rebuild-finalization.test.ts to rebuild-post-restore-phase.test.ts in tools/e2e/retired-selector-compatibility.mts and its E2E-support test.
  • Extend the runRebuildPostRestorePhase doc comment, which named only rebuild-flow.test.ts and rebuild-config-hash.test.ts as boundary coverage. This change makes rebuild-post-restore-phase.test.ts a coverage owner too, so the comment is updated in the same PR rather than left drifting.
  • Lower the four ci/source-architecture-budget.json limits the deletion frees (branding.ts 87→86, terminal-style.ts 45→44, registry.ts 98→97, src/lib/actions/sandbox root files 184→183). npm run checks:repository fails until these are ratcheted down.

Net: 170 insertions, 372 deletions (−202). The issue estimated 330–380; the 92 lines of migrated assertions are the difference, and the mutation proof below is why they were kept rather than dropped.

Which assertions were unique

Grepping each message the deleted test asserted showed most were already covered canonically, so only these five moved:

Assertion Already covered?
State restore incomplete yes — test/helpers/rebuild-flow-recovery-cases.ts:709
Mutable config permissions / config hash yes — same file, :710, :711
Policy presets failed to reapply yes — same file, :722, :747
Recovered from a stale registry entry yes — test/rebuild-stale-recovery.test.ts:261
Failed to re-apply shields lockdown yes — rebuild-post-restore-phase.test.ts:233
Prepared backup recovery fails closed yes — rebuild-post-restore-phase.test.ts:204
Messaging webhook forward not verified no — migrated
Forwarding skipped after failed relock no — migrated
Registry → relock → forward order no — migrated
Shields were previously enabled no — migrated
clearShieldsState only on recovery recreate no — migrated
Fixed print order across all six incomplete lines no — migrated (second commit)

Review round

A private cross-review (Claude + Codex, independent then cross-examined) found three gaps in the first commit. The second commit fixes all three:

  1. A dropped assertion. The deleted test asserted a fixed relative order across all six incomplete-recovery lines simultaneously. Each line individually is covered elsewhere, so my first coverage map marked them all "already covered" — but the combined ordering was not covered anywhere, and the deleted module's own JSDoc named that fixed order as the reason the boundary exists. It is now asserted against runRebuildPostRestorePhase with every failure dimension set at once.
  2. Missing negative half. The shields-reset test proved a successful recovery recreate clears state but not that a failed one leaves it alone. Added.
  3. Compatibility backstop and fixture fidelity. rebuild-recreate-observability.test.ts is now in the sandbox-rebuild retired-selector replacement, so the moved shields-reset assertion keeps a backstop; and the new recreate suite now applies the updateSession mutator instead of discarding it, matching the sibling suite.

Both new assertions were mutation-proved the same way as the originals:

M5  print the shields warning BEFORE the policy-preset line
  print-order test    : FAIL      other #8283 tests: PASS
M6  clear shields state before the recreate-failure return
  failed-recreate test: FAIL      success-path test : PASS

npm run typecheck:cli also caught a real type error in the first draft of the ordering test (input() infers failedPresets as never[], so assigning a string[] fails); the vitest run alone did not. Fixed by building the input by spread.

Rebase note

First pushed on base 0463c5a21, then rebased onto dd62e1c32. codebase-growth-guardrails had failed on nemoclaw/src/commands/migration-state.test.ts, a file this PR does not touch: #8489 shrank it to 1301 lines and ratcheted its budget to 1301, so the old base still carried the 1562-line copy and the check compared it against the new budget. The rebase clears it. All checks and budgets below were re-run on the new base.

What was deliberately not migrated

One assertion in the deleted test was not carried over: expect(updateSandbox).toHaveBeenCalledWith("alpha", { agentVersion, policies }). That payload shape belonged to the dead helper. The live runRebuildPostRestorePhase writes { agentVersion, policies, policyTier, policyPresetsFinalized } (rebuild-post-restore-phase.ts:271-276), so copying the old two-field assertion across would have pinned a shape production does not use. The live shape is already asserted in test/helpers/rebuild-flow-recovery-cases.ts:577,716 and test/helpers/rebuild-flow-lifecycle-cases.ts:87,121, and resolveRestoredPolicyRegistryState has direct coverage at src/lib/actions/sandbox/rebuild-restore-phase.test.ts:641,654.

Proof

A deletion has no natural failing test, so each migrated assertion was checked by mutating the live production path and confirming the migrated test fails while the pre-existing suite passes. A mutation the pre-existing suite already caught would mean the assertion was redundant.

M1  drop the "Messaging webhook forward was not verified" report
  migrated assertions : FAIL   (want FAIL)
  pre-existing suite  : PASS   (want PASS)
  => M1: PROVEN UNIQUE

M2  verify host forwarding BEFORE the shields relock (order/fail-closed)
  migrated assertions : FAIL   (want FAIL)
  pre-existing suite  : PASS   (want PASS)
  => M2: PROVEN UNIQUE

M3  drop the "Shields were previously enabled" unlocked-recreate warning
  migrated assertions : FAIL   (want FAIL)
  pre-existing suite  : PASS   (want PASS)
  => M3: PROVEN UNIQUE

M4  clear shields state on EVERY recreate, not only recovery recreates
  migrated assertions : FAIL   (want FAIL)
  pre-existing suite  : PASS   (want PASS)
  => M4: PROVEN UNIQUE

M1–M3 mutate rebuild-post-restore-phase.ts; M4 mutates rebuild-recreate-phase.ts:307. The "pre-existing suite" column runs the HEAD version of the same test file against the mutated source.

Test and check runs:

npx vitest run --project cli src/lib/actions/sandbox/           230 passed, 1 failed, 1 skipped (232 files)
npx vitest run --project cli <the two changed suites>            25 passed
npx vitest run --project e2e-support                            195 passed, 2 failed, 3 skipped (200 files)
npx vitest run --project integration test/rebuild-stale-recovery.test.ts test/rebuild-shields-window.test.ts
                                                                12 passed
npm run typecheck:cli                                           clean
npm --prefix nemoclaw run typecheck                             clean
npm run test:projects:check                                     exact, 2210 files across 7 projects
npm run checks:repository                                       all passed

The 5 failures are pre-existing on this host and reproduce identically with the branch stashed: gateway-restart-hermes-drift.test.ts fails on zip() takes no keyword arguments (host Python predates zip(strict=)), and 4 e2e-support failures come from ${TRIGGERING_ACTOR,,} needing bash 4 on a macOS bash 3.2 host. Neither touches any file in this change.

Coverage note

Deleting 168 lines of fully covered source lowers the CLI coverage ratio slightly, so it is worth bounding. scripts/check-coverage-ratchet.mts:21 allows a TOLERANCE of 0.1 percentage point below each threshold. The coverage include set (src/**/*.ts minus tests, plus bin/**/*.js) is about 306,900 lines. Treating all 168 deleted lines as covered lines removed — the worst case — moves lines from 73.900% to 73.886%, a shift of 0.014 ppt, roughly 7x inside the tolerance. The other three metrics scale the same way.

I could not confirm this empirically: the repo's test and coverage workflows are pull_request_target-gated and are not among the 9 checks running on this unvetted fork PR, and the local run is the one described above. The bound is arithmetic, not a measurement, and a maintainer's vetted CI run supersedes it.

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: no user-visible surface changes. The deleted module had no production caller, so no CLI, config, output, or documented behavior moves.
  • 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: requesting maintainer review. The change is test-and-registry only; no src/ production file is modified, and the shields and messaging-forward assertions gain coverage rather than lose it.
  • Non-success, skipped, or missing CI check accepted by maintainer — check name, approval link, and follow-up issue:

Documentation Writer Review

  • Documentation writer subagent reviewed the completed changes
  • Result: no-docs-needed
  • Evidence: no documentation paths changed. The deletion removes a module with no production caller and no user-visible surface; the remaining edits are test files, the retired-selector replacement registry, and a CI budget file.
  • Agent: Codex Desktop

Verification

  • PR description includes a Signed-off-by: line and every commit appears as Verified in GitHub
  • Normal pre-commit, commit-msg, and pre-push hooks passed, or npm run validate:pr passed after refreshing origin/main when hooks were skipped or unavailable
  • Targeted behavior tests pass for the current change set, or tests are marked not applicable above — command/result: see Proof above
  • Applicable broad gate passed — npm test for broad runtime/test-harness changes; npm run check for repo-wide validation/coverage changes — command/result: not run to completion locally. npm run test:coverage:cli was started but the branch was rebased and amended under it, so its number would not describe this tree, and it was stopped. See the coverage note below for why the ratchet is not at risk. Please treat the vetted CI run as the gate.
  • 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)

Signed-off-by: harjoth harjoth.khara@gmail.com

Summary by CodeRabbit

  • Bug Fixes

    • Improved sandbox rebuild recovery, including shield-state preservation, relocking, host-forwarding order, and failure reporting.
    • Added clearer handling for incomplete or failed recovery scenarios.
  • Tests

    • Expanded coverage for sandbox recreation observability and post-restore recovery behavior.
    • Added checks for recovery warnings, forwarding failures, and deterministic status reporting.
    • Updated end-to-end compatibility checks to reflect the revised rebuild test coverage.

@copy-pr-bot

copy-pr-bot Bot commented Aug 7, 2026

Copy link
Copy Markdown

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.

@coderabbitai

coderabbitai Bot commented Aug 7, 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: be20f191-92ac-478b-919b-adc281c18264

📥 Commits

Reviewing files that changed from the base of the PR and between c605611 and 46724ac.

📒 Files selected for processing (1)
  • ci/source-architecture-budget.json
🚧 Files skipped from review as they are similar to previous changes (1)
  • ci/source-architecture-budget.json

📝 Walkthrough

Walkthrough

The rebuild finalization module and its test file were removed. Coverage moved to post-restore and recreate observability tests. Retired-selector inventories were updated, and architecture budget thresholds were reduced.

Changes

Sandbox rebuild recovery

Layer / File(s) Summary
Post-restore recovery validation
src/lib/actions/sandbox/rebuild-post-restore-phase.ts, src/lib/actions/sandbox/rebuild-post-restore-phase.test.ts, src/lib/actions/sandbox/rebuild-finalization.ts, src/lib/actions/sandbox/rebuild-finalization.test.ts
Post-restore tests cover registry updates, shield relocking, host-forwarding behavior, recreated-sandbox warnings, and ordered recovery reports. The former finalization module and test file were removed.
Recovery recreate shield handling
src/lib/actions/sandbox/rebuild-recreate-observability.test.ts
Tests verify that shield state is cleared only after a successful recovery recreate.
Replacement test inventory
test/e2e/support/retired-selector-compatibility.test.ts, tools/e2e/retired-selector-compatibility.mts
Retired-selector checks now reference the post-restore and recreate observability tests.

Architecture budget updates

Layer / File(s) Summary
Budget threshold adjustments
ci/source-architecture-budget.json
Fan-in budgets and the src/lib/actions/sandbox maxRootFiles budget were reduced.

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

Possibly related PRs

Suggested labels: refactor

Suggested reviewers: apurvvkumaria

🚥 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 clearly and concisely describes the primary change: removing the superseded rebuild finalization module and test.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
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 unit tests (beta)
  • Create PR with unit tests

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

@harjothkhara
harjothkhara force-pushed the oss-find/nemoclaw-2026-08-06e branch from e393e16 to 04006e5 Compare August 7, 2026 00:39
rebuild-finalization.ts had no production caller. Its two exports,
finalizeRebuildPostRestore and resetRebuildShieldsStateAfterRecreate,
were imported only by its own test.

rebuild-post-restore-phase.ts is the canonical post-restore
implementation, and rebuild-recreate-phase.ts:307 already clears
shields state on a recovery recreate.

Four assertions in the deleted test covered behavior no other test
checked, so they move to the suites that drive the live code:
the relock-then-forward order, the forwarding skip after a failed
relock, the unverified-forwarding recovery command, and the
previously-enabled-shields warning on an unlocked recreate. The
recovery-recreate shields reset moves to the recreate-phase suite.

Repoint the sandbox-rebuild retired-selector replacement at
rebuild-post-restore-phase.test.ts, and lower the source-architecture
budgets the deletion frees.

Refs: NVIDIA#8283
Signed-off-by: harjoth <harjoth.khara@gmail.com>
@harjothkhara
harjothkhara force-pushed the oss-find/nemoclaw-2026-08-06e branch from 04006e5 to e925815 Compare August 7, 2026 00:41
Cross-review found three gaps in the migration.

The deleted test asserted a fixed print order across all six
incomplete-recovery lines at once. Each line was individually covered
elsewhere, but the order was not, so a reordering of that print block
would have gone unnoticed. Assert it against runRebuildPostRestorePhase
with every failure dimension set together.

Prove the negative half of the recovery-recreate shields reset: a
failed recreate must leave prior shields state alone. The success path
alone did not pin that.

Add rebuild-recreate-observability.test.ts to the sandbox-rebuild
retired-selector replacement so the moved shields-reset assertion keeps
a compatibility backstop, and make the new recreate suite apply the
updateSession mutator instead of discarding it.

Refs: NVIDIA#8283
Signed-off-by: harjoth <harjoth.khara@gmail.com>
@github-actions

github-actions Bot commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

PR Review Advisor — No blocking findings reported

Advisor assessment: No blocking advisor findings reported
Next action: No advisor follow-up needed.
Findings: 0 blockers · 0 warnings · 0 suggestions

Model lanes

  • GPT-5.6 Terra (primary): Completed · high confidence · 0 blockers · 0 warnings · 0 suggestions
  • Nemotron 3 Ultra (second opinion): Completed · high confidence · 0 blockers · 0 warnings · 0 suggestions
  • Model comparison: normalized findings match; normalized terminology decisions differ; normalized E2E selections differ; severity counts match.
1 terminology difference from the second opinion

Advisory only. These are normalized differences from the primary terminology receipt.

  • relock-then-forward at src/lib/actions/sandbox/rebuild-post-restore-phase.ts:144: selected only by the second-opinion lane as justified.
5 additional E2E selections from the second opinion

Advisory only. The primary lane did not select these E2E jobs or targets.

  • rebuild-hermes: The completed second-opinion lane identified E2E coverage that the primary lane omitted.
  • rebuild-hermes-stale-base: The completed second-opinion lane identified E2E coverage that the primary lane omitted.
  • snapshot-commands: The completed second-opinion lane identified E2E coverage that the primary lane omitted.
  • network-policy: The completed second-opinion lane identified E2E coverage that the primary lane omitted.
  • shields-config: The completed second-opinion lane identified E2E coverage that the primary lane omitted.

Second-opinion terminology and E2E selections are advisory. Live E2E does not run automatically for pull requests.

3 semantic terminology decisions

Terminology decisions are advisory. They affect the assessment only when a separate finding identifies concrete semantic impact.

  • justified — recovery recreate at src/lib/actions/sandbox/rebuild-recreate-observability.test.ts:449: Keep `recovery recreate` where the recovery-path distinction controls shields-state behavior.
  • justified — host forwarding at src/lib/actions/sandbox/rebuild-post-restore-phase.test.ts:236: Keep `host forwarding` to distinguish the host-side messaging resources under verification.
  • justified — post-restore at src/lib/actions/sandbox/rebuild-post-restore-phase.ts:143: Keep `post-restore` for the existing rebuild lifecycle phase and its boundary coverage.

E2E guidance

Advisory only. A maintainer can dispatch the default E2E suite against this exact revision.

Recommended E2E: cloud-inference, cloud-onboard, managed-image-multiarch-startup, managed-image-protected-runtime, security-posture, onboard-repair, onboard-resume, rebuild-openclaw, state-backup-restore

Workflow run details

This automated review informs maintainers. Warnings and suggestions do not require a response. A maintainer decides whether to merge.

The fixed-order test claimed every incomplete recovery dimension but
asserted six of them. The post-restore path also reports an unrefreshed
MCP bridge and an incomplete live-policy reconciliation, so a reordering
of either would have gone unnoticed (PRA-1).

Assert both, and name the test for the OpenClaw path it actually drives.
The Hermes gateway report stays out because
ensureHermesGatewayAfterStateRestore returns "not-applicable" for
OpenClaw, and baseline exclusions already have the NVIDIA#7194 test.

Refs: NVIDIA#8283
Signed-off-by: harjoth <harjoth.khara@gmail.com>
@harjothkhara
harjothkhara marked this pull request as ready for review August 7, 2026 01:05

@cv cv left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Please resolve the reported merge conflicts against the current main commit and run the required PR workflows. GitHub reports CONFLICTING, and checks, check-hash, changes, commit-lint, and dco-check are missing for this revision. The dead-module removal and transferred invariant coverage are aligned with the stated refactor; approval remains blocked by the branch and CI state.

Signed-off-by: Apurv Kumaria <akumaria@nvidia.com>
@apurvvkumaria

Copy link
Copy Markdown
Collaborator

Resolved cv's current-main and CI request in revision 46724ac.

  • Preserved all three contributor commits and merged current main normally; the sole conflict was ci/source-architecture-budget.json. The merged tree keeps both valid ratchet reductions, and repository checks pass.
  • Issue Remove superseded rebuild finalization #8283's runtime contract is unchanged: the deleted helper has no callers, while the unique policy, Shields, forwarding, recovery-order, and fail-closed assertions now run against the canonical phases. No review threads remain.
  • Validation: 25/25 focused recovery tests, 5/5 retired-selector tests, CLI build and typecheck, source architecture, project membership, and title gates pass. The broad changed-test run had six local concurrency timeouts or a cascading mock assertion outside the PR files; every affected file passed in isolation (98 tests).
  • Documentation writer: no docs needed; the PR receipt is refreshed.
  • Security review: PASS. Authentication, secrets, command execution, network, filesystem, dependency, and runtime trust boundaries are unchanged; no findings.

Fresh required workflows are running. The branch is ready for re-review once they complete.

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

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants