Skip to content

test(state): move MCP lifecycle-lock classifier properties to the source suite - #8436

Merged
prekshivyas merged 4 commits into
NVIDIA:mainfrom
harjothkhara:oss-find/nemoclaw-2026-08-06b
Aug 6, 2026
Merged

test(state): move MCP lifecycle-lock classifier properties to the source suite#8436
prekshivyas merged 4 commits into
NVIDIA:mainfrom
harjothkhara:oss-find/nemoclaw-2026-08-06b

Conversation

@harjothkhara

@harjothkhara harjothkhara commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

Summary

The MCP lifecycle-lock classifier properties lived in test/helpers/mcp-lifecycle-lock-properties.ts, which imported Vitest and registered a describe block. test/mcp-lifecycle-lock.test.ts pulled them in with a side-effect import, so src/lib/state/mcp-lifecycle-lock-identity.ts did not own the tests for its own classifier. This moves the unique properties into the source-local suite and deletes the helper. No production code changes.

Related Issue

Refs: #8356

Changes

  • Move four properties into src/lib/state/mcp-lifecycle-lock-identity.test.ts: the grace-boundary property, the live-owner age/grace property, the main/reaper token-parity property, and the fresh-read property.
  • Reuse the source-local owner, observation, probes, boundaryPidArbitrary, and processIdentityArbitrary, which are equal or broader than the helper's. Add durationArbitrary, and SEEDED_PROPERTY_PARAMETERS to keep 250 runs and the recorded seed 0x5876c0de.
  • Delete test/helpers/mcp-lifecycle-lock-properties.ts and its side-effect import.
  • Rename PROPERTY_IO_TIMEOUT_MS to PROPERTY_TIMEOUT_MS. The same 15s value now covers both describe blocks, so the IO qualifier no longer distinguishes a real case.
  • Force the grace-boundary ages in the moved boundary property (second commit, see below).

Two judgment calls a reviewer should check:

keeps foreign-host and foreign-namespace contenders active without local probing is not moved. Its host arm is already covered by never probes or reaps an owner from a different host and its namespace arm by the PID-namespace property, both of which vary the local identity itself instead of holding it fixed, so they are strictly broader. Its only other difference is nowMs = MAX_SAFE_INTEGER and graceMs = 1, and those are inert here: classifyMcpLifecycleLock reads nowMs, mtimeMs, and corruptLockGraceMs only on the no-owner or wrong-sandbox branch (src/lib/state/mcp-lifecycle-lock-identity.ts:209-213), which a present, correct-sandbox owner never reaches.

keeps ownership when a cached start mismatch disappears on refresh is deleted. The moved reaps a live PID only when a fresh identity read confirms the mismatch covers the same match case, adds the unavailable fresh-read case that nothing covered before, and asserts the whole read sequence instead of a single call. Keeping both would leave an equivalent property duplicated, which the issue asks to remove.

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: test-only change; the classifier is byte-identical, so no documented operator behavior changes. The lifecycle lock pages (docs/manage-sandboxes/manage-mcp-servers.mdx, docs/reference/troubleshoot-mcp-servers.mdx) document timeouts and recovery, none of which move. No documentation references the deleted helper.
  • 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:

Documentation Writer Review

  • Documentation writer subagent reviewed the completed changes
  • Result: no-docs-needed
  • Evidence: No documentation paths changed. The reviewer checked docs/ for pages covering the MCP lifecycle lock and confirmed each documents operator-visible behavior (timeouts, retry guidance, crash recovery) that this change does not touch, and found no reference to test/helpers/mcp-lifecycle-lock-properties.ts or to the root suite owning classifier properties anywhere in docs/, CLAUDE.md, AGENTS.md, CONTRIBUTING.md, test/e2e/README.md, vitest.config.ts, test/helpers/vitest-watch-triggers.ts, ci/, or scripts/.
  • Refresh note: An independent documentation writer reviewed the conflict-free current-main refresh and confirmed no-docs-needed. The PR-relative diff remains limited to the same three test files and does not change user-facing behavior.
  • 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 below
  • Applicable broad gate passed — npm test for broad runtime/test-harness changes; npm run check for repo-wide validation/coverage changes — command/result:
  • 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)

The issue's validation block

$ npx vitest run --project cli src/lib/state/mcp-lifecycle-lock-identity.test.ts
      Tests  15 passed (15)          # 12 before

$ npx vitest run --project integration test/mcp-lifecycle-lock.test.ts
      Tests  44 passed (44)          # 49 before

$ npm run test:projects:check
Vitest project membership is exact (2203 candidate files across 7 projects).

61 tests before, 59 after: 4 properties moved, 1 dropped as already covered, 1 pre-existing property removed as subsumed.

Also clean: npm run typecheck:cli, npm run test:titles:check, npm run test-size:check, npx biome check.

Proof that the coverage actually moved

A consolidation can silently drop coverage while every suite stays green, so I mutated the classifier and checked which lane notices. Before this change the cli lane — the source-local owner — was blind to both mutations:

Mutation cli before integration before cli after
identity.ts:212 "wait""stale" 12 passed 1 failed | 48 passed 1 failed | 14 passed
identity.ts:239 drop the refreshedIdentity !== null guard 12 passed 1 failed | 48 passed 1 failed | 14 passed

Each failure is the expected property: the grace-boundary one for the first mutation, the fresh-read one for the second. The classifier was restored to its committed state afterwards; this PR contains no production change.

Follow-up commit: the boundary property did not test its boundary

CodeRabbit caught a real gap, and it predates this PR — the property came over from the helper as-is. It is named for the grace boundary but drew ageMs and graceMs as two independent fc.integer({min:1,max:1_000_000}) values, so ageMs === graceMs was essentially never sampled. Relaxing the classifier from >= to > at mcp-lifecycle-lock-identity.ts:210 passed 15/15.

It now tests graceMs - 1, graceMs, graceMs + 1, and the original random ageMs, so the broad random coverage is kept rather than replaced. The same >= mutation now fails.

So one of the four properties is strengthened rather than relocated unchanged; the other three are verbatim.

Honest limits

  • Two suites in src/lib/state/ fail on my machine — state-file-key-merge-behavior.test.ts and state-file-key-merge-file-safety.test.ts, 16 tests. They fail identically with my three paths restored from origin/main, so they are pre-existing here and untouched by this change.
  • Across nine runs of test/mcp-lifecycle-lock.test.ts I saw one transient failure that did not reproduce in the eight runs after it. That file spawns real child processes and binds sockets, so it is timing-sensitive on a loaded machine. I could not attribute it to a specific test and it is not related to the moved properties, which are pure in-process property tests.
  • I have not run the E2E lanes; fork PRs need maintainer vetting before NVIDIA runners will start.

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

Summary by CodeRabbit

  • Tests
    • Expanded automated coverage for lifecycle-lock edge cases, including lock age, grace periods, owner liveness, process identity changes, and stale or invalid states.
    • Added deterministic, seeded property tests with consistent timeouts to improve reliability and repeatability.
    • Strengthened validation of fresh state reads, reused process identities, equivalent owner roles, and corrupt or cross-environment lock generations.
    • Removed redundant test helpers while retaining existing explicit lifecycle-lock test coverage.

…rce suite

The classifier properties lived in test/helpers/mcp-lifecycle-lock-properties.ts,
which imported Vitest and registered a describe block. test/mcp-lifecycle-lock.test.ts
pulled them in by side-effect import, so src/lib/state/mcp-lifecycle-lock-identity.ts
did not own the coverage of its own classifier.

Move the four unique properties into the source-local suite and delete the helper.

- 'keeps foreign-host and foreign-namespace contenders active' is not moved. Its
  host arm is already covered by 'never probes or reaps an owner from a different
  host' and its namespace arm by the PID-namespace property, both with broader
  arbitraries. Its distinct nowMs and grace values are inert: classifyMcpLifecycleLock
  reads nowMs, mtimeMs and corruptLockGraceMs only on the no-owner or wrong-sandbox
  branch (mcp-lifecycle-lock-identity.ts:209-213).
- 'keeps ownership when a cached start mismatch disappears on refresh' is replaced by
  the moved 'reaps a live PID only when a fresh identity read confirms the mismatch',
  which covers the same match case, adds the uncovered unavailable case, and asserts
  the full read sequence instead of one call.

The moved properties keep 250 runs, the recorded seed, and the 15s timeout.
No production code changes.

Refs: NVIDIA#8356
Signed-off-by: harjoth <harjoth.khara@gmail.com>
@copy-pr-bot

copy-pr-bot Bot commented Aug 6, 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 6, 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: f9e1ed73-1381-43e5-a829-e8fb52b12218

📥 Commits

Reviewing files that changed from the base of the PR and between e323de1 and 4484b01.

📒 Files selected for processing (3)
  • src/lib/state/mcp-lifecycle-lock-identity.test.ts
  • test/helpers/mcp-lifecycle-lock-properties.ts
  • test/mcp-lifecycle-lock.test.ts
💤 Files with no reviewable changes (2)
  • test/mcp-lifecycle-lock.test.ts
  • test/helpers/mcp-lifecycle-lock-properties.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/lib/state/mcp-lifecycle-lock-identity.test.ts

📝 Walkthrough

Walkthrough

The PR expands seeded lifecycle-lock property tests for owner liveness, fresh process identity, corrupt or wrong-sandbox locks, grace-period boundaries, and shared test timeouts. It also removes the former property-test helper.

Changes

Lifecycle lock identity tests

Layer / File(s) Summary
Property test setup
src/lib/state/mcp-lifecycle-lock-identity.test.ts
Uses a shared property timeout, deterministic seeds, and generated positive lock-age and grace-period values.
Owner liveness and identity outcomes
src/lib/state/mcp-lifecycle-lock-identity.test.ts
Validates live-owner activity, matching main and reaper liveness, and fresh identity outcomes for matching, unavailable, and mismatched identities.
Grace boundary and storage coverage
src/lib/state/mcp-lifecycle-lock-identity.test.ts
Validates corrupt or wrong-sandbox classification across the grace boundary and updates storage tests to use the shared timeout.
Property-test helper removal
test/helpers/mcp-lifecycle-lock-properties.ts, test/mcp-lifecycle-lock.test.ts
Removes the property-test helper and its import while preserving explicit lifecycle-lock tests.

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

Possibly related PRs

Suggested labels: refactor

Suggested reviewers: apurvvkumaria, cv

🚥 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 moving MCP lifecycle-lock classifier properties into the source test suite.
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.

@harjothkhara
harjothkhara marked this pull request as ready for review August 6, 2026 04:51

@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: 1

🤖 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/state/mcp-lifecycle-lock-identity.test.ts`:
- Around line 384-410: Update the property-based test around
classifyMcpLifecycleLock to derive the tested age values from the generated
graceMs, explicitly covering ageMs equal to graceMs and at least one
boundary-adjacent case. Replace the independent ageMs duration generator while
preserving the existing wrong-sandbox-owner setup and expected stale-versus-wait
assertion.
🪄 Autofix

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: 157bc657-b981-45cd-bdde-ae321677a669

📥 Commits

Reviewing files that changed from the base of the PR and between ce9d174 and 7e586eb.

📒 Files selected for processing (3)
  • src/lib/state/mcp-lifecycle-lock-identity.test.ts
  • test/helpers/mcp-lifecycle-lock-properties.ts
  • test/mcp-lifecycle-lock.test.ts
💤 Files with no reviewable changes (2)
  • test/mcp-lifecycle-lock.test.ts
  • test/helpers/mcp-lifecycle-lock-properties.ts

Comment thread src/lib/state/mcp-lifecycle-lock-identity.test.ts Outdated
@github-actions

github-actions Bot commented Aug 6, 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): Failed after a partial review · low confidence · 0 blockers · 0 warnings · 0 suggestions

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.

  • established — grace boundary at src/lib/state/mcp-lifecycle-lock-identity.test.ts:379: Retain the term. It precisely identifies the tested threshold.
  • established — fresh identity read at src/lib/state/mcp-lifecycle-lock-identity.test.ts:245: Retain the term. It identifies the required refresh behavior.
  • established — reaper lock at src/lib/state/mcp-lifecycle-lock-identity.test.ts:177: Retain the term. The role contrast is concrete.

E2E guidance

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

Recommended E2E: None

Workflow run details

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

harjothkhara added a commit to harjothkhara/NemoClaw that referenced this pull request Aug 6, 2026
The moved property is named for the grace boundary but drew ageMs and graceMs
as two independent durations, so ageMs === graceMs was almost never sampled and
the >= boundary went untested. Relaxing the classifier from >= to > at
mcp-lifecycle-lock-identity.ts:210 still passed 15/15 before this change.

Test ages graceMs - 1, graceMs, and graceMs + 1 alongside the random age, which
keeps the broad coverage the random draw gave. The >= mutation now fails.

Reported by CodeRabbit on NVIDIA#8436.

Refs: NVIDIA#8356
Signed-off-by: harjoth <harjoth.khara@gmail.com>
The lifecycle-lock grace property moved in 7e586eb is named for the grace
boundary but drew ageMs and graceMs as two independent durations, so
ageMs === graceMs was almost never sampled and the >= boundary went untested.
Relaxing the classifier from >= to > at mcp-lifecycle-lock-identity.ts:210
still passed 15/15 before this change.

Test ages graceMs - 1, graceMs, and graceMs + 1 alongside the random age, which
keeps the broad coverage the random draw gave. The >= mutation now fails.

Reported by CodeRabbit on NVIDIA#8436.

Refs: NVIDIA#8356

Signed-off-by: harjoth <harjoth.khara@gmail.com>
@harjothkhara
harjothkhara force-pushed the oss-find/nemoclaw-2026-08-06b branch from 1f13b35 to 4333809 Compare August 6, 2026 05:00
@coderabbitai

coderabbitai Bot commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

Note

GitHub couldn't provide a complete incremental comparison for this pull request, so CodeRabbit is performing a full review instead. This review may take a little longer.

@apurvvkumaria apurvvkumaria self-assigned this Aug 6, 2026
@apurvvkumaria

Copy link
Copy Markdown
Collaborator

Gate classification for the current branch revision:

  • Every required check is satisfied, and the PR is mergeable with no unresolved review threads.
  • The primary automated assessment completed with zero actionable findings and recommends no follow-up.
  • The already-rerun secondary review lane failed in review-tool infrastructure. No additional rerun is warranted.

The remaining merge gate is independent approval.

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

coderabbitai Bot commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

Note

GitHub couldn't provide a complete incremental comparison for this pull request, so CodeRabbit is performing a full review instead. This review may take a little longer.

@apurvvkumaria

Copy link
Copy Markdown
Collaborator

Maintainer refresh completed for the current branch revision (4484b01).

  • Merged current main conflict-free with a signed, GitHub Verified commit; contributor commits and attribution are preserved.
  • The PR-relative diff remains limited to the same three test files.
  • Post-refresh validation passed: lifecycle-lock identity tests 15/15, integration lifecycle-lock tests 44/44, Vitest project membership exact across 2,203 candidate files and 7 projects, and the pre-push CLI TypeScript gate.
  • Independent documentation writer review: PASS, no-docs-needed; no production behavior or documented lifecycle-lock semantics changed.
  • Maintainer security review: PASS across secrets, input handling, authentication, dependencies, data exposure, cryptography, authorization boundaries, test coverage, and fail-closed behavior. No findings.
  • The sole CodeRabbit thread remains resolved and outdated. The primary PR Review Advisor reported zero findings; the previously documented secondary model-lane failure is review-tool infrastructure, not a PR failure.

Fresh repository checks are now running. Independent approval remains required before merge.

@prekshivyas
prekshivyas merged commit 4ede416 into NVIDIA:main Aug 6, 2026
51 of 53 checks passed
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