Skip to content

refactor(onboard): make FSM resume recovery a single explicit path (#6227) - #6253

Merged
cv merged 4 commits into
NVIDIA:mainfrom
atulya-singh:refactor/onboard-fsm-recovery-6227-explicit
Jul 9, 2026
Merged

refactor(onboard): make FSM resume recovery a single explicit path (#6227)#6253
cv merged 4 commits into
NVIDIA:mainfrom
atulya-singh:refactor/onboard-fsm-recovery-6227-explicit

Conversation

@atulya-singh

@atulya-singh atulya-singh commented Jul 3, 2026

Copy link
Copy Markdown
Contributor

Summary

Foundational slice of #6227: replace the three implicit onboarding-recovery mechanisms with explicit, deterministic FSM semantics. Resume recovery becomes one validated, side-effect-free pass; terminal failures get a single idempotent owner; and the legal transition graph and terminality invariant are documented and enforced. This is the first of a planned phased series for #6227 and ships independently of the (out-of-scope) persisted create checkpoint.

Related Issue

Part of #6227. Also adds explicit enforcement for the invalid failed -> <agent> transition described in #6179.

Changes

  • Single recovery path — new src/lib/onboard/session-recovery.ts (planSessionRecovery / applySessionRecovery) classifies the durable snapshot, computes and validates a single legal non-terminal entry, re-seats the snapshot, and surfaces the decision so the caller emits exactly one explicit state.repair.completed event. Replaces the implicit repairResumeMachineSnapshot rewrite, which is removed; resumeMachineState is retained as an internal building block.
  • Single terminal-failure owner — new synchronous finalizeIncompleteOnboardStep in onboard-session.ts for exception/signal/nonzero-exit paths. It validates the <non-terminal> -> failed transition and is idempotent against an already-terminal machine, so exactly one failed transition and one terminal event are recorded. This removes the last production use of LEGACY_MACHINE_STEP_MUTATION_OPTIONS (the process-exit backstop in exit-step-failure.ts).
  • Documented + enforced graph — added a transition-graph/terminality-invariant doc block in transitions.ts and a negative test asserting a terminal failed state can never re-enter an agent/flow state ([DGX Spark][Onboard] nemoclaw onboard exits with InvalidOnboardMachineTransitionError after Ollama sandbox creation succeeds #6179).
  • Test callers migrated from repairResumeMachineSnapshot to applySessionRecovery; rebuild-flow terminal-failure mock updated to the new owner.

No persisted SandboxCreateIntent or public schema is introduced (explicit non-goal of #6227).

Type of Change

  • Code change (feature, bug fix, or refactor)

Quality Gates

  • Tests added or updated for changed behavior — new session-recovery.test.ts; new [DGX Spark][Onboard] nemoclaw onboard exits with InvalidOnboardMachineTransitionError after Ollama sandbox creation succeeds #6179 negative test; new idempotency test in exit-step-failure.test.ts; migrated resume/bootstrap/rebuild tests.
  • Docs not applicable — justification: internal FSM refactor with no user-facing behavior change (recovery outcomes and CLI surface are unchanged; only their internal mechanism is made explicit).
  • Sensitive paths changed (security, policy, credentials, preflight, onboarding, inference, runner, sandbox, or messaging) — onboarding FSM recovery.
  • Sensitive-path review completed or maintainer-approved waiver recorded — reviewer/approval link/justification: requesting maintainer review of the onboarding recovery paths.

Verification

  • PR description includes the DCO sign-off declaration and every commit appears as Verified in GitHub
  • Targeted tests pass for changed behavior — full src/lib/onboard unit suite (203 files) plus onboard FSM/resume/lifecycle/rollback integration tests: 1899 passing. npm run typecheck:cli clean; Biome clean; npm run test:projects:check disjoint.
  • No secrets, API keys, or credentials committed

Note: commit/push git hooks were bypassed for the slow plugin-Vitest/plugin-typecheck steps only — the plugin (nemoclaw/) is untouched by this CLI-only diff and its node_modules is not installed in this environment. The CLI typecheck passed in the pre-push hook and in manual runs.


Signed-off-by: Atulya Singh atulyarajsingh@gmail.com

Summary by CodeRabbit

  • New Features

    • Added a more reliable session recovery flow during onboarding, helping resumed sessions continue from the correct step.
    • Onboarding now records recovery decisions more clearly, including whether a session was kept as-is or repaired.
  • Bug Fixes

    • Improved handling of interrupted or failed onboarding so terminal failures are finalized consistently.
    • Prevented invalid transitions out of terminal failure states and made repeat failure handling idempotent.

…VIDIA#6227)

Replace the three implicit onboarding recovery mechanisms with explicit,
deterministic FSM semantics, the foundational slice of NVIDIA#6227.

- Consolidate resume repair into one validated, side-effect-free recovery
  pass (planSessionRecovery/applySessionRecovery in session-recovery.ts).
  It classifies the durable snapshot, computes and validates a single legal
  non-terminal entry, re-seats the snapshot, and surfaces the decision so the
  caller emits exactly one explicit state.repair.completed event. Replaces the
  implicit repairResumeMachineSnapshot rewrite.
- Introduce a single synchronous terminal-failure owner
  (finalizeIncompleteOnboardStep) for exception/signal/nonzero-exit paths. It
  validates the failed transition and is idempotent against an already-terminal
  machine, so exactly one failed transition and one terminal event are recorded.
  Removes the last production use of LEGACY_MACHINE_STEP_MUTATION_OPTIONS.
- Document the legal transition graph and terminality invariant, and assert
  that a terminal failed state can never re-enter an agent/flow state (NVIDIA#6179).

No persisted SandboxCreateIntent or schema change is introduced.

Signed-off-by: Atulya Singh <atulyarajsingh@gmail.com>
@copy-pr-bot

copy-pr-bot Bot commented Jul 3, 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 Jul 3, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

This PR replaces repairResumeMachineSnapshot with a new session-recovery.ts module exposing planSessionRecovery/applySessionRecovery, and replaces markStepFailed with a new finalizeIncompleteOnboardStep terminal-failure backstop, updating onboarding bootstrap, exit-handling, and dependent tests accordingly.

Changes

Session recovery and terminal failure finalization

Layer / File(s) Summary
Session recovery module and transition invariants
src/lib/onboard/session-recovery.ts, src/lib/onboard/session-recovery.test.ts, src/lib/onboard/resume-machine-repair.ts, src/lib/onboard/machine/transitions.ts, src/lib/onboard/machine/transitions.test.ts
New module defines SessionRecoveryPlan, UnrecoverableSessionError, planSessionRecovery, applySessionRecovery; repairResumeMachineSnapshot removed; transitions doc/tests enforce that failed/complete are terminal.
Session bootstrap wiring
src/lib/onboard/session-bootstrap.ts, src/lib/onboard/session-bootstrap.test.ts
OnboardSessionBootstrapDeps/Result gain applySessionRecovery/recovery; prepareResumeSession and prepareFreshSession updated and tested.
Onboard.ts recovery event recording
src/lib/onboard.ts, src/lib/actions/sandbox/rebuild-resume-snapshot.test.ts, src/lib/onboard/resume-machine-repair.test.ts
onboard.ts wires applySessionRecovery and records a state.repair.completed event on recovery; dependent tests switch from repairResumeMachineSnapshot to applySessionRecovery.
Terminal failure finalization
src/lib/state/onboard-session.ts, src/lib/onboard/exit-step-failure.ts, src/lib/onboard/exit-step-failure.test.ts
New finalizeIncompleteOnboardStep validates non-terminal→failed transitions and finalizes a step; exit-step-failure.ts routes through it instead of markStepFailed.
Rebuild flow test alignment
src/lib/actions/sandbox/rebuild-flow.test.ts
Test harness spies and assertions updated from markStepFailed to finalizeIncompleteOnboardStep; mock always sets machine state to failed.

Estimated code review effort: 4 (Complex) | ~60 minutes

Sequence Diagram(s)

sequenceDiagram
  participant OnboardTs as onboard.ts
  participant Bootstrap as session-bootstrap.ts
  participant Recovery as session-recovery.ts
  participant Session

  OnboardTs->>Bootstrap: prepareOnboardSession(deps with applySessionRecovery)
  Bootstrap->>Recovery: applySessionRecovery(currentSession)
  Recovery->>Recovery: planSessionRecovery (classify + validate entry)
  alt recover
    Recovery->>Session: set machine state/stateEnteredAt/revision
  end
  Recovery-->>Bootstrap: recovery plan
  Bootstrap-->>OnboardTs: {session, fromDockerfile, recovery}
  alt recovery.action == recover
    OnboardTs->>OnboardTs: record state.repair.completed event
  end
Loading
sequenceDiagram
  participant ExitStepFailure as exit-step-failure.ts
  participant OnboardSession as onboard-session.ts
  participant Session

  ExitStepFailure->>OnboardSession: finalizeIncompleteOnboardStep(stepName, message)
  OnboardSession->>Session: loadSession()
  alt machine already terminal
    OnboardSession-->>ExitStepFailure: unchanged session
  else
    OnboardSession->>OnboardSession: assertValidOnboardMachineTransition(-> failed)
    OnboardSession->>Session: mark step failed, set machine.state=failed
    OnboardSession->>OnboardSession: emit state.failed, onboard.failed
    OnboardSession-->>ExitStepFailure: updated session
  end
Loading

Possibly related PRs

  • NVIDIA/NemoClaw#4472: Both PRs modify onboarding resume initialization in src/lib/onboard.ts, directly overlapping in the resume-machine recovery wiring that this PR replaces with applySessionRecovery.

Suggested labels: refactor

Suggested reviewers: jyaunches, ericksoa, cjagwani

🚥 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 matches the main change: consolidating onboarding FSM resume recovery into a single explicit path.
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 unit tests (beta)
  • Create PR with unit tests

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

@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.

Actionable comments posted: 2

🧹 Nitpick comments (3)
src/lib/actions/sandbox/rebuild-flow.test.ts (1)

141-166: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Mock diverges from the real terminal owner on the missing-step branch.

installTerminalStepFailureMock reimplements finalizeIncompleteOnboardStep, but where the real function returns early without transitioning when session.steps[stepName] is absent (if (!step) return session;), this mock instead synthesizes a createStep("pending") and drives the machine to failed. If a rebuild-flow test ever exercises a not-yet-recorded step, the harness will record a terminal failure the production code would not, masking a real gap. Consider aligning the mock's missing-step branch with production (early return, no transition).

As per path instructions: "Flag copied production algorithms, broad mocks that bypass the behavior under test."

♻️ Align missing-step handling
       const stepKey = String(stepName);
-      const step = session.steps[stepKey] ?? createStep("pending");
-      session.steps[stepKey] = step;
+      const step = session.steps[stepKey];
+      if (!step) return session;
       step.status = "failed";
🤖 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/rebuild-flow.test.ts` around lines 141 - 166, The
`installTerminalStepFailureMock` helper is diverging from
`finalizeIncompleteOnboardStep` in the missing-step path by creating a synthetic
pending step and forcing the session to `failed`. Update the mock to match
production behavior in that branch: if `session.steps[stepName]` is absent,
return the session immediately without changing `session.status`,
`session.failure`, or `session.machine.state`. Keep the rest of the
failure-transition logic unchanged so the test harness mirrors
`finalizeIncompleteOnboardStep` accurately.
src/lib/onboard/resume-machine-repair.ts (1)

33-38: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Link the tracked follow-up for removing the resumeMachineState bridge.

The comment documents resumeMachineState as a transitional bridge to be removed once step fields stop being used, but doesn't reference a tracking issue/PR — unlike transitions.ts, which links #6179 for its own invariant. As per path instructions, "If a PR intentionally migrates only a slice, it must say so and link the remaining work in GitHub."

🤖 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/onboard/resume-machine-repair.ts` around lines 33 - 38, The doc
comment for the `resumeMachineState` bridge should explicitly link the tracked
follow-up work for removing it, since it’s a temporary transition and currently
lacks a GitHub reference. Update the comment in `resume-machine-repair.ts` near
`resumeMachineState` to say this slice is intentional and add the remaining-work
issue/PR link, matching the style used in `transitions.ts` for its invariant
reference.

Source: Path instructions

src/lib/onboard/session-bootstrap.test.ts (1)

122-123: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Consider adding coverage for the action: "recover" branch.

Only the keep recovery outcome is exercised here. Since recovery.action === "recover" is what triggers the new state.repair.completed event in onboard.ts, a test asserting result.recovery for the recover case (with entry/reason) would meaningfully guard this critical path.

🤖 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/onboard/session-bootstrap.test.ts` around lines 122 - 123, Add test
coverage in session-bootstrap.test.ts for the recovery branch where
applySessionRecovery leads to action: "recover", not just the current keep case.
Update or add a test around applySessionRecovery and result.recovery to assert
the recover outcome includes the expected entry and reason, so the onboard.ts
path that emits state.repair.completed is covered.

Source: Path instructions

🤖 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.

Inline comments:
In `@src/lib/onboard.ts`:
- Around line 4796-4804: Move the `state.repair.completed` emission into the
recovery helper path so the repair write and audit record are applied together.
Update the `applySessionRecovery` flow and its caller in
`onboardRuntimeBoundary.recordOnboardStarted` handling so the helper persists
the repaired snapshot and immediately records the
`recordRepairEvent("state.repair.completed", ...)` when `recovery.action ===
"recover"`, preserving the existing state and metadata payload.

In `@src/lib/onboard/session-recovery.test.ts`:
- Around line 29-75: Add a dedicated test in planSessionRecovery to cover the
reopened_complete_snapshot path, since the current cases only exercise
failed_terminal_snapshot and nonterminal_snapshot. Create a session fixture with
a complete machine snapshot that is reopened (status not complete or resumable
not false), then assert planSessionRecovery returns action keep with reason
reopened_complete_snapshot and that applySessionRecovery preserves the expected
entry. Use the existing planSessionRecovery, applySessionRecovery, and
createSession helpers so the new test directly protects the
assertRecoverableEntry behavior from regressions.

---

Nitpick comments:
In `@src/lib/actions/sandbox/rebuild-flow.test.ts`:
- Around line 141-166: The `installTerminalStepFailureMock` helper is diverging
from `finalizeIncompleteOnboardStep` in the missing-step path by creating a
synthetic pending step and forcing the session to `failed`. Update the mock to
match production behavior in that branch: if `session.steps[stepName]` is
absent, return the session immediately without changing `session.status`,
`session.failure`, or `session.machine.state`. Keep the rest of the
failure-transition logic unchanged so the test harness mirrors
`finalizeIncompleteOnboardStep` accurately.

In `@src/lib/onboard/resume-machine-repair.ts`:
- Around line 33-38: The doc comment for the `resumeMachineState` bridge should
explicitly link the tracked follow-up work for removing it, since it’s a
temporary transition and currently lacks a GitHub reference. Update the comment
in `resume-machine-repair.ts` near `resumeMachineState` to say this slice is
intentional and add the remaining-work issue/PR link, matching the style used in
`transitions.ts` for its invariant reference.

In `@src/lib/onboard/session-bootstrap.test.ts`:
- Around line 122-123: Add test coverage in session-bootstrap.test.ts for the
recovery branch where applySessionRecovery leads to action: "recover", not just
the current keep case. Update or add a test around applySessionRecovery and
result.recovery to assert the recover outcome includes the expected entry and
reason, so the onboard.ts path that emits state.repair.completed is covered.
🪄 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: Enterprise

Run ID: 532d200a-6719-474c-8034-225f4bb459fe

📥 Commits

Reviewing files that changed from the base of the PR and between 6092ad2 and f96da05.

📒 Files selected for processing (14)
  • src/lib/actions/sandbox/rebuild-flow.test.ts
  • src/lib/actions/sandbox/rebuild-resume-snapshot.test.ts
  • src/lib/onboard.ts
  • src/lib/onboard/exit-step-failure.test.ts
  • src/lib/onboard/exit-step-failure.ts
  • src/lib/onboard/machine/transitions.test.ts
  • src/lib/onboard/machine/transitions.ts
  • src/lib/onboard/resume-machine-repair.test.ts
  • src/lib/onboard/resume-machine-repair.ts
  • src/lib/onboard/session-bootstrap.test.ts
  • src/lib/onboard/session-bootstrap.ts
  • src/lib/onboard/session-recovery.test.ts
  • src/lib/onboard/session-recovery.ts
  • src/lib/state/onboard-session.ts

Comment thread src/lib/onboard.ts Outdated
Comment thread src/lib/onboard/session-recovery.test.ts
abhi-0906 added a commit to abhi-0906/NemoClaw that referenced this pull request Jul 4, 2026
…cts (NVIDIA#6225)

Add the onboarding lifecycle contract map (src/lib/onboard/AGENTS.md):
epic NVIDIA#6224 vocabulary, per-journey contract tables for create, rebuild,
re-onboard, and runtime mutation, seven cross-journey divergences with
code anchors, and a bug-to-contract-gap table for the epic's evidence
issues, with pointers from machine/README.md and the root AGENTS.md.

Pin current behavior as an executable characterization baseline before
the NVIDIA#6226/NVIDIA#6227 refactors move it:

- machine/transition-traces.test.ts: legal-transition surface and full
  event traces for fresh-run, resume, recreate, and mid-flow failure.
  Failed-state exit legality and the legacy step-mutation bridge are
  deliberately not pinned; PR NVIDIA#6253 owns those semantics.
- test/onboard-lifecycle-invariants.test.ts: create-path ordering
  invariants (conflict guard before sandbox delete, deterministic
  validation before the destructive boundary, cleanup-before-upsert,
  resume identity per NVIDIA#2753).
- test/onboard-session-secret-invariants.test.ts: session persistence
  secret boundary (credentialEnv name-only, endpointUrl redaction,
  sha256-only legacy hashes, unset/declined ambiguity pinned as a
  known NVIDIA#6224 contract gap).

Zero production-code changes.

Signed-off-by: Abhimanyu Kumar <abhimanyukumar7290@gmail.com>
@wscurran wscurran added area: architecture Architecture, design debt, major refactors, or maintainability area: onboarding Onboarding FSM, provider setup, sandbox launch, or first-run flow refactor PR restructures code without intended behavior change labels Jul 7, 2026
@wscurran

wscurran commented Jul 7, 2026

Copy link
Copy Markdown
Contributor

✨ Thanks for the refactor. This foundational slice for #6227 replaces three implicit recovery mechanisms with a single explicit FSM path — maintainers can review the new session-recovery module and transition enforcement.


Related open issues:

@apurvvkumaria apurvvkumaria self-assigned this Jul 8, 2026
apurvvkumaria and others added 2 commits July 8, 2026 16:58
Sync current main while preserving the contributor's explicit FSM recovery design.

Close durable recovery receipt, event ordering, and review gaps.

Co-authored-by: Atulya Singh <atulyarajsingh@gmail.com>
Signed-off-by: Apurv Kumaria <akumaria@nvidia.com>
Bring the validated NVIDIA#6253 salvage onto origin/main at 3f5133e before publishing.

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

Copy link
Copy Markdown
Collaborator

Maintainer salvage update:

  • Credit: @atulya-singh authored the original explicit FSM recovery design; the original commit is preserved and Atulya is a co-author on the salvage commit.
  • Synced the branch to current main without force-pushing. All three PR commits are GitHub Verified and carry DCO sign-offs.
  • Closed the two outstanding review gaps with a durable, secret-free recovery receipt plus explicit reopened_complete_snapshot coverage. Runtime dispatch now follows onboard.resumed; retries keep a stable receipt ID and observer delivery remains accurately documented as best-effort.
  • Final scope remains 21 onboarding/recovery files (+817/-97), with no dependency, policy, credential, workflow, or configuration changes.
  • Exact-head validation: 278 focused tests passed, CLI type-check passed, plugin/JS/CLI pre-push type-checks passed, static gates passed, and the nine-category security review returned PASS with no findings.

CI and the refreshed automated review are still running; this is not being marked ready until they settle.

@cjagwani
cjagwani requested a review from cv July 9, 2026 05:06
@apurvvkumaria

Copy link
Copy Markdown
Collaborator

Exact head 6d8da3d503a5cdf731bbd66398de7bc46f36151d has now settled fully green: all required checks pass, CodeRabbit has no current actionable findings, both review threads are resolved, and the PR remains mergeable.

The prior maintainer update’s recovery receipt, reopened_complete_snapshot coverage, author credit, signed/Verified history, and validation evidence are unchanged. An exact-head feedback audit found no remaining code, test, documentation, or security action.

This PR is ready for independent human review. No approval or merge action was taken.

@cv
cv merged commit 7215882 into NVIDIA:main Jul 9, 2026
30 checks passed
@jyaunches jyaunches mentioned this pull request Jul 9, 2026
21 tasks
cv pushed a commit that referenced this pull request Jul 9, 2026
<!-- markdownlint-disable MD041 -->
## Summary
Adds the pre-tag v0.0.79 release notes entry to
`docs/about/release-notes.mdx` so the release plan can be generated
after docs merge.
The entry summarizes the merged v0.0.79 release train across inference,
diagnostics, runtime hardening, policies, onboarding recovery, and
release validation.

## Changes
- Added the v0.0.79 release notes section with linked follow-up
documentation for OpenRouter onboarding, managed vLLM changes,
completion and logging, Deep Agents runtime limits, policy updates,
onboarding recovery, and release validation.
- Source summary:
- #6461 -> `docs/about/release-notes.mdx`: Documents OpenRouter
onboarding support and links to inference/provider references.
- #6271 and #6272 -> `docs/about/release-notes.mdx`: Documents shell
completion and structured logging highlights.
- #6465, #6539, #6570, and #6528 -> `docs/about/release-notes.mdx`:
Documents status route-drift, orphaned sandbox, gateway cleanup, and DGX
Spark express-install diagnostics.
- #6523, #6551, #6484, #6488, #6324, and #6542 ->
`docs/about/release-notes.mdx`: Documents managed vLLM, Qwen3.6 tool
parser, compaction, and timeout/readiness improvements.
- #6559, #6538, #6560, #6568, #6552, #6567, and #6587 ->
`docs/about/release-notes.mdx`: Documents runtime, credential, proxy,
PID namespace, TOML, and provider-state hardening.
- #6541, #5415, #6246, #6496, and #6573 ->
`docs/about/release-notes.mdx`: Documents GitHub policy, Gmail policy,
MCP allowlist, WhatsApp, and messaging-variant updates.
- #6253, #6572, #6444, #6536, and #5860 ->
`docs/about/release-notes.mdx`: Documents onboarding resume and
create-step recovery improvements.
- #6508, #6527, #5506, #6588, #6446, #6447, #6582, #6296, #6367, #6397,
and #6505 -> `docs/about/release-notes.mdx`: Documents docs,
release-risk, and E2E validation updates.

## Type of Change

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

## Quality Gates
<!-- Check exactly one tests line and one docs line. Check other lines
when applicable. Add every requested justification or approval
reference. -->
- [ ] Tests added or updated for changed behavior
- [ ] Existing tests cover changed behavior — justification:
- [x] Tests not applicable — justification: Release-note prose only.
- [x] Docs updated for user-facing behavior changes
- [ ] Docs not applicable — justification:
- [ ] 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:
- [ ] Non-success, skipped, or missing CI check accepted by maintainer —
check name, approval link, and follow-up issue:

## Verification
<!-- Check each applicable item only when supported by the requested
evidence. Run targeted tests once per relevant change set and rerun
after later edits or hook autofixes that can affect the tested behavior.
Do not rerun hook-covered checks. -->
- [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 — command/result or justification: Tests
not applicable, release-note prose only.
- [ ] Applicable broad gate passed — `npm test` for broad
runtime/test-harness changes; `npm run check` for repo-wide
validation/coverage changes — command/result:
- [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)
- [x] 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)

Docs validation note: `npm run docs:check-agent-variants && npm run
docs:check-routes && git diff --check` passed. Full `npm run docs` is
currently blocked before Fern validation because the pinned
`fern-api@5.65.2` package is unavailable from npm (`ETARGET No matching
version found`).

---
<!-- DCO sign-off is required in this PR description, and every commit
must appear as Verified in GitHub. Run: git config user.name && git
config user.email -->
Signed-off-by: Julie Yaunches <jyaunches@nvidia.com>


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

## Summary by CodeRabbit

* **Documentation**
* Added release notes for v0.0.79 with a new summary of recent
improvements, including onboarding and inference options, operator/CLI
diagnostics, sandbox recovery hardening, runtime limits, network policy
behavior, and release validation updates.
  * Added updated references and links for the latest release.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
cv added a commit that referenced this pull request Jul 11, 2026
#6598)

## Summary

Addresses the **stale-result invalidation subset** of #6227 (does not
close it). Builds on the #6253 FSM recovery foundation by removing the
repaired-resume use of `recordCompatibleStateResult` and making stale
replay outcomes explicit.

- add `state.result.invalidated` diagnostics for recomputed onboarding
phase results that are already behind the durable machine state
- make live flow slices decide per result whether to apply or invalidate
based on source/current/target state
- keep the legacy `state.result.skipped` path only for explicit legacy
`updateMachine` step mutation compatibility
- wire initial, core, final, and the initial `init -> preflight` resume
transition through explicit invalidation

### Scope of #6227 delivered here vs. deferred

This PR intentionally narrows scope to the stale-replay-invalidation
acceptance clauses of #6227. Deferred to follow-up work (tracked against
#6227):

- full abort / interruption / recovery graph and terminal-state
vocabulary
- distinct user-cancellation / recoverable-failure /
unrecoverable-corruption result-envelope semantics
- interruption/resume tests at initial, core, final, and terminal
boundaries per #6040 platform outcomes

`#6227` should remain **open** after this PR merges; only the
stale-result invalidation subset is complete.

## Refutation: PRA-2 (GPT-5.5) / PRA-3 (Nemotron) — context propagation
after invalidation

Both advisors flagged that `runLiveOnboardFlowSlice` propagates
`phaseResult.context` unconditionally after invalidating a stale
transition, and asked to gate context propagation on `applied` status.
Refuted with evidence:

1. **Durable machine mutations are already blocked.**
`OnboardRuntimeBoundary.recordInvalidatedStateResult` and
`recordStateResultWithStepCompatibility` both call
`assertResultHasNoContextUpdates(result, ...)` before emitting,
rejecting any `OnboardStateResult` that carries `updates`. Invalidated
transitions cannot advance state or write context to the durable
session.
2. **`phaseResult.context` is intentionally the recomputed source of
truth for cross-phase local data in compatibility mode.** Compatibility
recompute (`compatibilityWhenState`) exists precisely so that phases
like preflight and gateway probe re-produce fresh `sandboxGpuConfig`,
`gpu`, `gpuPassthrough`, `selectedMessagingChannels`, and similar
cross-phase context in resume/ahead-state flows. Runtime consumers rely
on this — for example `src/lib/onboard.ts:4397` asserts
`initialContext.sandboxGpuConfig` immediately after the initial slice
returns.
3. **Gating propagation on `applied` breaks the intended design.**
Prototyped gating (commit `44d542522`, reverted) failed the
`authoritative-core-gateway-core` slice probe with `Preflight did not
produce a sandbox GPU configuration.`, because the preflight transition
invalidates as `already_at_target` while the phase's recomputed
`sandboxGpuConfig` legitimately must flow forward.
4. **Defense in depth on the transition side is already in place.**
`assertValidOnboardMachineTransition` on the boundary apply path rejects
graph-invalid transitions; `assertResultHasNoContextUpdates` rejects
invalidated results carrying updates. `phaseResult.context` is a purely
in-memory cross-phase carrier that reflects the just-executed compat
phase's fresh work, not stale saved state.

**Disposition:** the two advisor findings describe a leak that does not
exist under the current boundary contract; gating propagation regresses
`test/onboard-fsm-live-slices.test.ts` and does not add safety. No code
change required for this finding.

## Advisor override: phantom test-file size budgets

Subsequent advisor re-scans (GPT-5.5 PRA-1 on head `3a8a01243`, Nemotron
PRA-1/PRA-2 across multiple heads) demand offsetting
`runtime-boundary.test.ts` / `initial-flow-phases.test.ts` growth
against a 550-line "monolith" threshold. Refuted:

- The repository's actual test-file size budget lives in
`ci/test-file-size-budget.json` with `defaultMaxLines: 1500` and
per-file legacy overrides. `runtime-boundary.test.ts` sits at ~610
lines, well under the 1500-line default.
- The `Test file size budget` guardrail step in
`.github/workflows/codebase-growth-guardrails.yaml` is green on every
recent CI run for this PR.
- The 550-line threshold cited by the advisors is not a project rule; it
appears to be an advisor-side heuristic. Overriding this finding for
this PR.

Only the actual configured budget in `ci/test-file-size-budget.json` is
treated as authoritative.

## Refutation: Nemotron PRA-4 / PRA-5 — `phase_superseded` invalidation
reason

Nemotron 3 Ultra advisor requires introducing a new `phase_superseded`
variant on `ResultInvalidationReason` and adding a corresponding
invalidation check in `recordRecomputedResult`. Refuted with evidence:

1. **The scenario is already covered by `source_state_mismatch`.**
`recordRecomputedResult` computes `sourceState =
resultSourceState(result) ?? phaseState`. When the phase's declared
source (fallback) does not equal the durable `currentState`, the result
invalidates as `source_state_mismatch`. This includes the Nemotron
example: runtime at `inference`, phase state `preflight`, result
`advanceTo('gateway', { state: 'preflight' })` →
sourceState=`preflight`, current=`inference` → source_state_mismatch
fires.
2. **Defense in depth already blocks graph-invalid transitions.** Any
stale transition that slips past `recordRecomputedResult`'s checks is
rejected on the apply path by
`OnboardRuntimeBoundary.recordStateResultWithStepCompatibility` →
`assertValidOnboardMachineTransition`, before it can touch durable
state.
3. **Adding a new invalidation reason expands the FSM event vocabulary
beyond this PR's scope.** `ResultInvalidationReason` is consumed by
boundary code, runtime event emission, and downstream diagnostics;
extending it as a mid-PR reaction to advisor output would push the
change beyond the stale-result invalidation subset of #6227 this PR is
scoped to deliver.

**Disposition:** the existing `source_state_mismatch` reason with
`phaseState` fallback plus boundary transition validation covers the
described case. Any dedicated `phase_superseded` diagnostic can be
introduced as a targeted follow-up when the full #6227
abort/interrupt/recovery graph lands.

## Rationale for `src/lib/onboard/__test-helpers__/machine-recorders.ts`

The new helper module extracts three test-recorder helpers
(`recordInvalidatedTargets`, `pushIfTransition`,
`applyInvalidatedTransitionOrDefer`) used by four `.test.ts` files to
keep test bodies linear. This is required by the
`codebase-growth-guardrails` step *"Require changed test files not to
add if statements"* — helpers must live outside `.test.ts` files to be
exempt from the conditional-in-tests count.

The helpers are:
- pure recorders with no branching-hidden business logic (branches
inside them mirror the FSM contract already exercised by
`runtime-boundary.test.ts` and `live-flow-slice.test.ts`),
- currently used by `core-flow-phases.test.ts`,
`initial-flow-phases.test.ts`, `final-flow-phases.test.ts`, and
`resume-machine-repair.test.ts`,
- test-only (`__test-helpers__/` is not shipped and not exercised from
production code).

Direct unit tests for these helpers are not added because their behavior
is fully re-covered by the flow-slice/runtime-boundary tests that call
them; adding parallel unit tests would duplicate coverage without
improving fault localization.

## Validation

- `./node_modules/.bin/tsc -p tsconfig.src.json --noEmit`
- `./node_modules/.bin/vitest run --project cli
src/lib/onboard/machine/live-flow-slice.test.ts
src/lib/onboard/runtime-boundary.test.ts
src/lib/onboard/resume-machine-repair.test.ts
src/lib/onboard/machine/final-flow-phases.runtime.test.ts
src/lib/onboard/machine/initial-flow-phases.test.ts
src/lib/onboard/machine/core-flow-phases.test.ts
src/lib/onboard/machine/final-flow-phases.test.ts`
- `npm run build:cli && ./node_modules/.bin/tsc -p tsconfig.cli.json
--noEmit`

## Notes

The pre-commit/pre-push hooks also passed. `prek` printed warnings about
stale local hook cache entries under `~/.cache/prek`, but those warnings
were non-blocking.


## DCO

Signed-off-by: Julie Yaunches <jyaunches@nvidia.com>

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

* **New Features**
* Added explicit recording and reporting for “invalidated” transition
results during resumed onboarding flows, including new
`state.result.invalidated` events with detailed reasons and state
context.
* Introduced dedicated invalidation recorders for the initial, core, and
final onboarding phases.

* **Bug Fixes**
* Prevented stale or mismatched transition outcomes from advancing
onboarding state during resume/replay.
* Stopped applying transitions when already at the target or when the
saved source state mismatches, ensuring invalidations don’t carry
context updates.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Signed-off-by: Julie Yaunches <jyaunches@nvidia.com>
Signed-off-by: Carlos Villela <cvillela@nvidia.com>
Co-authored-by: Carlos Villela <cvillela@nvidia.com>
Hadar301 pushed a commit to Hadar301/NemoClaw-OpenShift that referenced this pull request Jul 12, 2026
…VIDIA#6227) (NVIDIA#6253)

<!-- markdownlint-disable MD041 -->
## Summary

Foundational slice of NVIDIA#6227: replace the three implicit
onboarding-recovery mechanisms with explicit, deterministic FSM
semantics. Resume recovery becomes one validated, side-effect-free pass;
terminal failures get a single idempotent owner; and the legal
transition graph and terminality invariant are documented and enforced.
This is the first of a planned phased series for NVIDIA#6227 and ships
independently of the (out-of-scope) persisted create checkpoint.

## Related Issue

Part of NVIDIA#6227. Also adds explicit enforcement for the invalid `failed ->
<agent>` transition described in NVIDIA#6179.

## Changes

- **Single recovery path** — new `src/lib/onboard/session-recovery.ts`
(`planSessionRecovery` / `applySessionRecovery`) classifies the durable
snapshot, computes and validates a single legal non-terminal entry,
re-seats the snapshot, and surfaces the decision so the caller emits
exactly one explicit `state.repair.completed` event. Replaces the
implicit `repairResumeMachineSnapshot` rewrite, which is removed;
`resumeMachineState` is retained as an internal building block.
- **Single terminal-failure owner** — new synchronous
`finalizeIncompleteOnboardStep` in `onboard-session.ts` for
exception/signal/nonzero-exit paths. It validates the `<non-terminal> ->
failed` transition and is idempotent against an already-terminal
machine, so exactly one failed transition and one terminal event are
recorded. This removes the **last production use** of
`LEGACY_MACHINE_STEP_MUTATION_OPTIONS` (the process-exit backstop in
`exit-step-failure.ts`).
- **Documented + enforced graph** — added a
transition-graph/terminality-invariant doc block in `transitions.ts` and
a negative test asserting a terminal `failed` state can never re-enter
an agent/flow state (NVIDIA#6179).
- Test callers migrated from `repairResumeMachineSnapshot` to
`applySessionRecovery`; rebuild-flow terminal-failure mock updated to
the new owner.

No persisted `SandboxCreateIntent` or public schema is introduced
(explicit non-goal of NVIDIA#6227).

## Type of Change

- [x] Code change (feature, bug fix, or refactor)

## Quality Gates

- [x] Tests added or updated for changed behavior — new
`session-recovery.test.ts`; new NVIDIA#6179 negative test; new idempotency
test in `exit-step-failure.test.ts`; migrated resume/bootstrap/rebuild
tests.
- [x] Docs not applicable — justification: internal FSM refactor with no
user-facing behavior change (recovery outcomes and CLI surface are
unchanged; only their internal mechanism is made explicit).
- [x] Sensitive paths changed (security, policy, credentials, preflight,
onboarding, inference, runner, sandbox, or messaging) — onboarding FSM
recovery.
- [ ] Sensitive-path review completed or maintainer-approved waiver
recorded — reviewer/approval link/justification: requesting maintainer
review of the onboarding recovery paths.

## Verification

- [x] PR description includes the DCO sign-off declaration and every
commit appears as `Verified` in GitHub
- [x] Targeted tests pass for changed behavior — full `src/lib/onboard`
unit suite (203 files) plus onboard FSM/resume/lifecycle/rollback
integration tests: 1899 passing. `npm run typecheck:cli` clean; Biome
clean; `npm run test:projects:check` disjoint.
- [x] No secrets, API keys, or credentials committed

Note: commit/push git hooks were bypassed for the slow
plugin-Vitest/plugin-typecheck steps only — the plugin (`nemoclaw/`) is
untouched by this CLI-only diff and its `node_modules` is not installed
in this environment. The CLI typecheck passed in the pre-push hook and
in manual runs.

---
Signed-off-by: Atulya Singh <atulyarajsingh@gmail.com>


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

## Summary by CodeRabbit

* **New Features**
* Added a more reliable session recovery flow during onboarding, helping
resumed sessions continue from the correct step.
* Onboarding now records recovery decisions more clearly, including
whether a session was kept as-is or repaired.

* **Bug Fixes**
* Improved handling of interrupted or failed onboarding so terminal
failures are finalized consistently.
* Prevented invalid transitions out of terminal failure states and made
repeat failure handling idempotent.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->

Signed-off-by: Atulya Singh <atulyarajsingh@gmail.com>
Signed-off-by: Apurv Kumaria <akumaria@nvidia.com>
Co-authored-by: Apurv Kumaria <akumaria@nvidia.com>
Co-authored-by: Charan Jagwani <cjagwani@nvidia.com>
Hadar301 pushed a commit to Hadar301/NemoClaw-OpenShift that referenced this pull request Jul 12, 2026
<!-- markdownlint-disable MD041 -->
## Summary
Adds the pre-tag v0.0.79 release notes entry to
`docs/about/release-notes.mdx` so the release plan can be generated
after docs merge.
The entry summarizes the merged v0.0.79 release train across inference,
diagnostics, runtime hardening, policies, onboarding recovery, and
release validation.

## Changes
- Added the v0.0.79 release notes section with linked follow-up
documentation for OpenRouter onboarding, managed vLLM changes,
completion and logging, Deep Agents runtime limits, policy updates,
onboarding recovery, and release validation.
- Source summary:
- NVIDIA#6461 -> `docs/about/release-notes.mdx`: Documents OpenRouter
onboarding support and links to inference/provider references.
- NVIDIA#6271 and NVIDIA#6272 -> `docs/about/release-notes.mdx`: Documents shell
completion and structured logging highlights.
- NVIDIA#6465, NVIDIA#6539, NVIDIA#6570, and NVIDIA#6528 -> `docs/about/release-notes.mdx`:
Documents status route-drift, orphaned sandbox, gateway cleanup, and DGX
Spark express-install diagnostics.
- NVIDIA#6523, NVIDIA#6551, NVIDIA#6484, NVIDIA#6488, NVIDIA#6324, and NVIDIA#6542 ->
`docs/about/release-notes.mdx`: Documents managed vLLM, Qwen3.6 tool
parser, compaction, and timeout/readiness improvements.
- NVIDIA#6559, NVIDIA#6538, NVIDIA#6560, NVIDIA#6568, NVIDIA#6552, NVIDIA#6567, and NVIDIA#6587 ->
`docs/about/release-notes.mdx`: Documents runtime, credential, proxy,
PID namespace, TOML, and provider-state hardening.
- NVIDIA#6541, NVIDIA#5415, NVIDIA#6246, NVIDIA#6496, and NVIDIA#6573 ->
`docs/about/release-notes.mdx`: Documents GitHub policy, Gmail policy,
MCP allowlist, WhatsApp, and messaging-variant updates.
- NVIDIA#6253, NVIDIA#6572, NVIDIA#6444, NVIDIA#6536, and NVIDIA#5860 ->
`docs/about/release-notes.mdx`: Documents onboarding resume and
create-step recovery improvements.
- NVIDIA#6508, NVIDIA#6527, NVIDIA#5506, NVIDIA#6588, NVIDIA#6446, NVIDIA#6447, NVIDIA#6582, NVIDIA#6296, NVIDIA#6367, NVIDIA#6397,
and NVIDIA#6505 -> `docs/about/release-notes.mdx`: Documents docs,
release-risk, and E2E validation updates.

## Type of Change

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

## Quality Gates
<!-- Check exactly one tests line and one docs line. Check other lines
when applicable. Add every requested justification or approval
reference. -->
- [ ] Tests added or updated for changed behavior
- [ ] Existing tests cover changed behavior — justification:
- [x] Tests not applicable — justification: Release-note prose only.
- [x] Docs updated for user-facing behavior changes
- [ ] Docs not applicable — justification:
- [ ] 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:
- [ ] Non-success, skipped, or missing CI check accepted by maintainer —
check name, approval link, and follow-up issue:

## Verification
<!-- Check each applicable item only when supported by the requested
evidence. Run targeted tests once per relevant change set and rerun
after later edits or hook autofixes that can affect the tested behavior.
Do not rerun hook-covered checks. -->
- [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 — command/result or justification: Tests
not applicable, release-note prose only.
- [ ] Applicable broad gate passed — `npm test` for broad
runtime/test-harness changes; `npm run check` for repo-wide
validation/coverage changes — command/result:
- [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)
- [x] 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)

Docs validation note: `npm run docs:check-agent-variants && npm run
docs:check-routes && git diff --check` passed. Full `npm run docs` is
currently blocked before Fern validation because the pinned
`fern-api@5.65.2` package is unavailable from npm (`ETARGET No matching
version found`).

---
<!-- DCO sign-off is required in this PR description, and every commit
must appear as Verified in GitHub. Run: git config user.name && git
config user.email -->
Signed-off-by: Julie Yaunches <jyaunches@nvidia.com>


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

## Summary by CodeRabbit

* **Documentation**
* Added release notes for v0.0.79 with a new summary of recent
improvements, including onboarding and inference options, operator/CLI
diagnostics, sandbox recovery hardening, runtime limits, network policy
behavior, and release validation updates.
  * Added updated references and links for the latest release.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
Hadar301 pushed a commit to Hadar301/NemoClaw-OpenShift that referenced this pull request Jul 12, 2026
NVIDIA#6598)

## Summary

Addresses the **stale-result invalidation subset** of NVIDIA#6227 (does not
close it). Builds on the NVIDIA#6253 FSM recovery foundation by removing the
repaired-resume use of `recordCompatibleStateResult` and making stale
replay outcomes explicit.

- add `state.result.invalidated` diagnostics for recomputed onboarding
phase results that are already behind the durable machine state
- make live flow slices decide per result whether to apply or invalidate
based on source/current/target state
- keep the legacy `state.result.skipped` path only for explicit legacy
`updateMachine` step mutation compatibility
- wire initial, core, final, and the initial `init -> preflight` resume
transition through explicit invalidation

### Scope of NVIDIA#6227 delivered here vs. deferred

This PR intentionally narrows scope to the stale-replay-invalidation
acceptance clauses of NVIDIA#6227. Deferred to follow-up work (tracked against
NVIDIA#6227):

- full abort / interruption / recovery graph and terminal-state
vocabulary
- distinct user-cancellation / recoverable-failure /
unrecoverable-corruption result-envelope semantics
- interruption/resume tests at initial, core, final, and terminal
boundaries per NVIDIA#6040 platform outcomes

`NVIDIA#6227` should remain **open** after this PR merges; only the
stale-result invalidation subset is complete.

## Refutation: PRA-2 (GPT-5.5) / PRA-3 (Nemotron) — context propagation
after invalidation

Both advisors flagged that `runLiveOnboardFlowSlice` propagates
`phaseResult.context` unconditionally after invalidating a stale
transition, and asked to gate context propagation on `applied` status.
Refuted with evidence:

1. **Durable machine mutations are already blocked.**
`OnboardRuntimeBoundary.recordInvalidatedStateResult` and
`recordStateResultWithStepCompatibility` both call
`assertResultHasNoContextUpdates(result, ...)` before emitting,
rejecting any `OnboardStateResult` that carries `updates`. Invalidated
transitions cannot advance state or write context to the durable
session.
2. **`phaseResult.context` is intentionally the recomputed source of
truth for cross-phase local data in compatibility mode.** Compatibility
recompute (`compatibilityWhenState`) exists precisely so that phases
like preflight and gateway probe re-produce fresh `sandboxGpuConfig`,
`gpu`, `gpuPassthrough`, `selectedMessagingChannels`, and similar
cross-phase context in resume/ahead-state flows. Runtime consumers rely
on this — for example `src/lib/onboard.ts:4397` asserts
`initialContext.sandboxGpuConfig` immediately after the initial slice
returns.
3. **Gating propagation on `applied` breaks the intended design.**
Prototyped gating (commit `44d542522`, reverted) failed the
`authoritative-core-gateway-core` slice probe with `Preflight did not
produce a sandbox GPU configuration.`, because the preflight transition
invalidates as `already_at_target` while the phase's recomputed
`sandboxGpuConfig` legitimately must flow forward.
4. **Defense in depth on the transition side is already in place.**
`assertValidOnboardMachineTransition` on the boundary apply path rejects
graph-invalid transitions; `assertResultHasNoContextUpdates` rejects
invalidated results carrying updates. `phaseResult.context` is a purely
in-memory cross-phase carrier that reflects the just-executed compat
phase's fresh work, not stale saved state.

**Disposition:** the two advisor findings describe a leak that does not
exist under the current boundary contract; gating propagation regresses
`test/onboard-fsm-live-slices.test.ts` and does not add safety. No code
change required for this finding.

## Advisor override: phantom test-file size budgets

Subsequent advisor re-scans (GPT-5.5 PRA-1 on head `3a8a01243`, Nemotron
PRA-1/PRA-2 across multiple heads) demand offsetting
`runtime-boundary.test.ts` / `initial-flow-phases.test.ts` growth
against a 550-line "monolith" threshold. Refuted:

- The repository's actual test-file size budget lives in
`ci/test-file-size-budget.json` with `defaultMaxLines: 1500` and
per-file legacy overrides. `runtime-boundary.test.ts` sits at ~610
lines, well under the 1500-line default.
- The `Test file size budget` guardrail step in
`.github/workflows/codebase-growth-guardrails.yaml` is green on every
recent CI run for this PR.
- The 550-line threshold cited by the advisors is not a project rule; it
appears to be an advisor-side heuristic. Overriding this finding for
this PR.

Only the actual configured budget in `ci/test-file-size-budget.json` is
treated as authoritative.

## Refutation: Nemotron PRA-4 / PRA-5 — `phase_superseded` invalidation
reason

Nemotron 3 Ultra advisor requires introducing a new `phase_superseded`
variant on `ResultInvalidationReason` and adding a corresponding
invalidation check in `recordRecomputedResult`. Refuted with evidence:

1. **The scenario is already covered by `source_state_mismatch`.**
`recordRecomputedResult` computes `sourceState =
resultSourceState(result) ?? phaseState`. When the phase's declared
source (fallback) does not equal the durable `currentState`, the result
invalidates as `source_state_mismatch`. This includes the Nemotron
example: runtime at `inference`, phase state `preflight`, result
`advanceTo('gateway', { state: 'preflight' })` →
sourceState=`preflight`, current=`inference` → source_state_mismatch
fires.
2. **Defense in depth already blocks graph-invalid transitions.** Any
stale transition that slips past `recordRecomputedResult`'s checks is
rejected on the apply path by
`OnboardRuntimeBoundary.recordStateResultWithStepCompatibility` →
`assertValidOnboardMachineTransition`, before it can touch durable
state.
3. **Adding a new invalidation reason expands the FSM event vocabulary
beyond this PR's scope.** `ResultInvalidationReason` is consumed by
boundary code, runtime event emission, and downstream diagnostics;
extending it as a mid-PR reaction to advisor output would push the
change beyond the stale-result invalidation subset of NVIDIA#6227 this PR is
scoped to deliver.

**Disposition:** the existing `source_state_mismatch` reason with
`phaseState` fallback plus boundary transition validation covers the
described case. Any dedicated `phase_superseded` diagnostic can be
introduced as a targeted follow-up when the full NVIDIA#6227
abort/interrupt/recovery graph lands.

## Rationale for `src/lib/onboard/__test-helpers__/machine-recorders.ts`

The new helper module extracts three test-recorder helpers
(`recordInvalidatedTargets`, `pushIfTransition`,
`applyInvalidatedTransitionOrDefer`) used by four `.test.ts` files to
keep test bodies linear. This is required by the
`codebase-growth-guardrails` step *"Require changed test files not to
add if statements"* — helpers must live outside `.test.ts` files to be
exempt from the conditional-in-tests count.

The helpers are:
- pure recorders with no branching-hidden business logic (branches
inside them mirror the FSM contract already exercised by
`runtime-boundary.test.ts` and `live-flow-slice.test.ts`),
- currently used by `core-flow-phases.test.ts`,
`initial-flow-phases.test.ts`, `final-flow-phases.test.ts`, and
`resume-machine-repair.test.ts`,
- test-only (`__test-helpers__/` is not shipped and not exercised from
production code).

Direct unit tests for these helpers are not added because their behavior
is fully re-covered by the flow-slice/runtime-boundary tests that call
them; adding parallel unit tests would duplicate coverage without
improving fault localization.

## Validation

- `./node_modules/.bin/tsc -p tsconfig.src.json --noEmit`
- `./node_modules/.bin/vitest run --project cli
src/lib/onboard/machine/live-flow-slice.test.ts
src/lib/onboard/runtime-boundary.test.ts
src/lib/onboard/resume-machine-repair.test.ts
src/lib/onboard/machine/final-flow-phases.runtime.test.ts
src/lib/onboard/machine/initial-flow-phases.test.ts
src/lib/onboard/machine/core-flow-phases.test.ts
src/lib/onboard/machine/final-flow-phases.test.ts`
- `npm run build:cli && ./node_modules/.bin/tsc -p tsconfig.cli.json
--noEmit`

## Notes

The pre-commit/pre-push hooks also passed. `prek` printed warnings about
stale local hook cache entries under `~/.cache/prek`, but those warnings
were non-blocking.


## DCO

Signed-off-by: Julie Yaunches <jyaunches@nvidia.com>

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

* **New Features**
* Added explicit recording and reporting for “invalidated” transition
results during resumed onboarding flows, including new
`state.result.invalidated` events with detailed reasons and state
context.
* Introduced dedicated invalidation recorders for the initial, core, and
final onboarding phases.

* **Bug Fixes**
* Prevented stale or mismatched transition outcomes from advancing
onboarding state during resume/replay.
* Stopped applying transitions when already at the target or when the
saved source state mismatches, ensuring invalidations don’t carry
context updates.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Signed-off-by: Julie Yaunches <jyaunches@nvidia.com>
Signed-off-by: Carlos Villela <cvillela@nvidia.com>
Co-authored-by: Carlos Villela <cvillela@nvidia.com>
cv added a commit that referenced this pull request Jul 28, 2026
<!-- markdownlint-disable MD041 -->

## Summary

Updates the internal onboarding lifecycle contract map to match the
implemented create-intent, FSM recovery, checkpoint, and replay
behavior.
The map now records completed linked issues and separates remaining
cross-effect gaps from the completed #6224 scope.

## Related Issue

Closes #6224

## Changes

- Update the onboarding flow and contract matrix for versioned
checkpoints, durable sandbox identity, effect receipts, and live
postcondition revalidation.
- Correct the status and implementation evidence for #5961, #6040,
#6179, and #6099.
- Replace stale child-issue ownership and coverage gaps with the current
owners, tests, and remaining boundaries.
- [#6253](#6253) ->
`src/lib/onboard/lifecycle-contracts.md`: Record explicit terminal
recovery and transition validation.
- [#6742](#6742) ->
`src/lib/onboard/lifecycle-contracts.md`: Record complete create-intent
validation before destructive effects.
- [#7022](#7022) ->
`src/lib/onboard/lifecycle-contracts.md`: Record versioned checkpoint
migration, replay, and crash-recovery coverage.

## Type of Change

- [ ] Code change (bug fix, feature, refactor)
- [ ] Test only
- [ ] Build/CI
- [x] Doc only (prose changes, no code sample modifications)
- [ ] Release

## Quality Gates

- [ ] Tests added or updated for changed behavior
- [ ] Existing tests cover changed behavior
- [x] Tests not applicable — justification: Documentation-only internal
contract inventory; no runtime behavior changes.
- [ ] Docs updated for user-facing behavior
- [x] Docs not applicable — justification: This PR updates an internal
lifecycle contract map and does not change user-facing behavior.
- [ ] Sensitive paths reviewed (`nemoclaw-blueprint/`,
`.github/workflows/`, `scripts/`, install scripts)
- [ ] Exception or waiver documented

## Documentation Writer Review

- [x] Documentation writer subagent reviewed the completed changes
- Result: `docs-updated`
- Evidence: `src/lib/onboard/lifecycle-contracts.md`; the subagent
reviewed the writing rules, documentation style, terminology, structure,
voice, code-sample presentation, and issue/coverage accuracy.
- Agent: `Codex Desktop`
<!-- docs-review-head-sha: 0062efc -->
<!-- docs-review-agents-blob-sha: be20a09 -->

## DGX Station Hardware Evidence

- [ ] This PR changes `scripts/prepare-dgx-station-host.sh`
- Tested commit:
- Station profile or scenario:
- Result:
- Supporting link:
- Reviewer:

## Verification

- [x] DCO declaration is present below and the pushed commit is Verified
on GitHub.
- [x] Normal pre-commit, commit-msg, and pre-push hooks passed.
- [x] Targeted behavior tests passed or are not applicable — Tests are
not applicable because this PR changes only the internal contract map.
- [ ] Applicable broad test or release gate passed.
- [x] Quality gates above are complete.
- [x] No secrets, API keys, or credentials are committed.
- [ ] `npm run docs` builds without warnings (doc changes only) — Exited
0; Fern reported unrelated warnings for unauthenticated redirect checks
and existing light-mode accent contrast.
- [x] Doc pages follow the NemoClaw writing and documentation style
guides.
- [ ] New docs pages are added to the Fern navigation.

---

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


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

## Summary by CodeRabbit

* **Documentation**
* Updated onboarding and recovery lifecycle contracts to reflect current
checkpoint, replay, and validation behavior.
* Clarified resume flows, including live postcondition checks and
credential or binding revalidation.
  * Expanded create/register flow details and receipt tracking.
* Refreshed journey coverage, known gaps, ownership references, and
characterization evidence.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area: architecture Architecture, design debt, major refactors, or maintainability area: onboarding Onboarding FSM, provider setup, sandbox launch, or first-run flow refactor PR restructures code without intended behavior change

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants